let me = { name: 'James' }; // object expression
someFn({ color: 'red' }); // object literal passed to a function
let friend = {
name: 'amy'
};
console.log(friend.name);
Get with dot notation:
console.log(friend['name']);
let prop = 'name';
console.log(friend[prop]);
Get with square brackets notation:
Set with dot notation:
friend.name = 'sophie';
Set with square brackets notation:
friend['name'] = 'sophie';
const person = {
firstName: 'James',
lastName: 'Sherry',
get fullName(){
return `${this.firstName} ${this.lastName}`;
},
};
console.log(person.fullName); // James Sherry
person.fullName = 'Fred Durst';
console.log(person.fullName); // Fred Durst
Name collision:
const rapper = {
_name: 'snoop',
get name(){
return this._name + ' dogg';
}
};
// Arrays
const trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
0 in trees // returns true
3 in trees // returns true
6 in trees // returns false
'bay' in trees // returns false (you must specify the
// index number, not the value at that index)
'length' in trees // returns true (length is an Array property)
Symbol.iterator in trees // returns true (arrays are iterable, works only in ES2015+)
// Predefined objects
'PI' in Math // returns true
// Custom objects
const mycar = {make: 'Honda', model: 'Accord', year: 1998};
'make' in mycar // returns true
'model' in mycar // returns true
key in object => true or false
for...in loop
const obj = {a: 1, b: 2, c: 3};
for (const key in obj) {
if (obj.hasOwnProperty(key)) { // stops it searching the prototype chain
console.log('obj.' + key, '=', obj[key]);
}
}
// Creates a new object, myobj, with two properties, a and b.
const myobj = {};
myobj.a = 5;
myobj.b = 12;
// Removes the 'a' property, leaving myobj with only the b property.
delete myobj.a;
console.log ('a' in myobj); // "false"
Removes configurable properties (see later)
A property can be:
enumerable
writable
configurable
They can be set with:
Object.defineProperty(obj, propName, setting);
Object.defineProperties(obj, { propName1: setting1, propName2: setting2 });
and Read with: Object.getOwnPropertyDescriptor( obj, 'c' );
See this article for more
const obj = {a: 1, b: 2, c: 3};
console.log(Object.entries(obj)); // [["a", 1], ["b", 2], ["c", 3]]
Object.entries(<object>);
Object.keys(<object>);
Object.keys() returns an array whose elements are strings corresponding to the enumerable properties found directly upon object.
const tutor1 = {
n: 'james',
a: 39,
get age(){return this.a*2},
get name(){return this.n+' dogg'}
};
const arr = ['dog', 'cat', 'fish'];
Object.keys(tutor1); // ["n", "a", "age", "name"]
Object.keys(arr); // [0, 1, 2]
const obj = {a: 1, b: 2, c: 3};
console.log(Object.getOwnPropertyNames(obj)); // ["a", "b", "c"]
Object.getOwnPropertyNames(<object>);
Unlike Object.keys(), this shows non-enumerable properties too...
const obj = {a: 1, b: 2, c: 3};
console.log(Object.values(obj)); // [1, 2, 3]
Object.values(<object>);
const formdata = new FormData(myForm);
const data = Object.fromEntries(formdata);
console.log('data', data);
Object.fromEntries(<various>);
// Copying
const obj = { a: 1 };
const copy = Object.assign({}, obj);
obj.a = 2;
console.log(obj); // { a: 2 }
console.log(copy); // { a: 1 }
// Merging ( First object is mutated )
const obj1 = { a: 1 };
const obj2 = { b: 2 };
Object.assign(obj1, obj2);
console.log(obj1); // { a: 1, b: 2 }
// INSTEAD
const newObj = Object.assign({}, obj1, obj2);
console.log(obj1); // { a: 1 }
console.log(newObj); // { a: 1, b: 2 }
Object.assign(<targetObj>, <object2>[, <object3>, etc.]);
Used for shallow copying and merging
Object.freeze(<object>);
(test: Object.isFrozen(<object>);)
Object.seal(<object>);
(test: Object.isSealed(<object>);)
Object.preventExtension(<object>);
(test: Object.isExtensible(<object>);)
(Works on all object family members!!)
WARNING: These methods are SHALLOW. For true immutability, either recurse through the object or try immutable.js constructs
Can't add new properties:
Can't add new properties, delete props or change prop definitions:
Can't add new properties, delete props or change prop definitions or property values:
const obj = { a: 1 };
const obj2 = Object.create(obj);
console.log(obj2); // { }
console.log(obj2.__proto__); // { a: 1 }
console.log(obj2.a); //1
Object.create(<object1>);
More on prototypes next...
Array.prototype.myCoolNewFunction = function(){/*....*/};
function SuperArray(){}
SuperArray.prototype = Object.create(Array.prototype);
SuperArray.prototype.constructor = SuperArray;
SuperArray.prototype.myCoolNewFunction = function(){/*..*/};
A way to re-use common code
const Snake = {};
Snake.sound = 'Hiss';
Snake.speak = function () {
return this.sound + '!!';
};
const Constrictor = Object.create(Snake);
Constrictor.constrict = function () {
return 'The ' + this.name.toLowerCase() +' squeezes you to death!';
};
const Venomous = Object.create(Snake);
Venomous.invenomate = function () {
return 'The ' + this.name.toLowerCase() +' bites you and the venom kills you!';
};
const python = Object.create(Constrictor);
python.name = 'Python';
const cobra = Object.create(Venomous);
cobra.name = 'Cobra';
The way it was supposed to be
(function() {
function Snake(name) { // super class
let sound = 'Hiss'; // private variable
this.name = name; // public property (this is the object created, of type 'Snake')
this.getSound = function() { // privileged method (goes on each object, can see private vars)
return sound;
};
}
Snake.getAgeInSnakeYears = function(age){ // Static method (useful methods to be used with that type/class of thing, e.g. Array.from() or Array.isArray())
return age * 13;
};
Snake.prototype.speak = function() { // shared public method (aka 'instance method') - all objects produced have access
console.log(`${this.name } says ${this.getSound()}`);
};
// SUB-CLASS INHERITANCE
function Constrictor(name, coils) { // sub class
// Snake.call(this, ...arguments);
Snake.call(this, name);
this.coils = coils;
}
// Constrictor.prototype = new Snake();
Constrictor.prototype = Object.create(Snake.prototype); // Better way
Constrictor.prototype.constructor = Constrictor;
Constrictor.prototype.constrict = function() {
console.log('The ' + this.name.toLowerCase() + ' squeezes you to death!');
};
function Venomous(name) { // sub class
// Snake.call(this, ...arguments);
Snake.call(this, name);
}
// Constrictor.prototype = new Snake();
Venomous.prototype = Object.create(Snake.prototype); // Better way
Venomous.prototype.constructor = Venomous;
Venomous.prototype.invenomate = function() {
return 'The ' + this.name.toLowerCase() + ' bites you and the venom kills you!';
};
const python = new Constrictor('python', 8);
console.log('python', python);
const cobra = new Venomous('cobra', 8);
console.log('cobra', cobra);
console.log('From the base class both can \'speak\' using a shared method and shared private variable');
python.speak();
cobra.speak();
console.log('They have access to their sub-class methods: \n');
// python.constrict();
// cobra.invenomate();
console.log('...but not to each others: \n');
try {
console.log(python.name + ' invenomating: \n');
python.invenomate();
} catch (e) {
console.log('A python cannot invenomate\n', e);
}
try {
console.log(cobra.name + ' constricting: \n');
cobra.constrict();
} catch (err) {
console.log('A cobra cannot constrict\n', err);
}
}());
Because new thoughts are hard for old programmers
“Favor object composition over class inheritance.” ~ The Gang of Four, Design Patterns: Elements of Reusable Object Oriented Software
Programatically assemble your objects like a factory process, using if statements to decide what goes in an object...