const person = {
name: 'Brendan',
bread: true
}
it can be changed/modified
person.jam = true
Thanks to the dynamic nature of JS we don't need any ceremonious ways to add jam
even though it was not in the original definition of the object, the tradeoff is that we do not get any type-checking.
person.getIngedients = function() {
return { jam: this.jam, bread: this.bread }
}
if an object property is not a value, but a function, we call it a method.
the keyword this
is used to reference other properties within the object
Sets the object key to the variable name.
const firstName = 'Brendan';
const bread = true;
const person = {
firstName,
bread
}
Shorthand for functions:
const person = {
value: 22,
traditional: function() { return this.value },
shorthand() { return this.value }
}
Object.keys(myObject)
: Returns an array of all keys. The for..in
loop, will loop over the keys or "property names"
Object.assign(ob1, ob2)
: Copies properties from ob2
into ob1
, mutates obj1
.
==
it's not type safe, will equate "42" == 42
as true. It should be avoided unless you know exactly what you are doing.
===
Type-safe, compares the memory address
Object.is()
Almost the same as ===
, but has some cases where it gives a different result:
NaN equals NaN
+0 not equal -0
When comparing two objects, the memory address is compared for all the equality checks above, for any JS [[Primitive]], the actual value is compared.
[[Constructor Function]]
These two objects are essentially identical:
// Object Literal
let personA = {
firstName: 'Kate',
lastName: 'Tobo',
age: 42
}
// Object constructor function
let personB = Object.create(
Object.prototype,
{
firstName: {value: 'Kate', enumerable: true, writable: true, configurable: true},
lastName: {value: 'Tobo', enumerable: true, writable: true, configurable: true},
firstName: {value: 42, enumerable: true, writable: true, configurable: true},
}
)
const a1cKey = 'user-a1c'
const person = {
name: 'Hulu',
['height']: 174,
[a1cKey]: 7
}
person['person age'] = 32;
console.log(person[a1cKey])
This allows us to define keys that would otherwise be invalid, for example with spaces. Or, more useful: you can use variables as keys, this comes in especially handy when checking for properties in a loop:
for (let propName in person) {
person['computed-key-' + propName] = person[propName];
}
A property is more than just a name and a value, you can see the guts of the property by doing:
const guts = Object.getOwnPropertyDescriptor(person, 'name');
// Object {
// value: "Hulu",
// writable: true,
// enumerable: true,
// configurable: true,
// }
these are the same things we had to set when using Object.create
determines if the value can be modified, you can change the writable
attribute like this:
Object.defineProperty(person, 'name', {writable: false});
Now when you try to change the person.name
, the JS runtime will throw an error.
If the name
property is an object, and not a primitive, you could still change the properties on the name object person.name.xx
.
To prevent the whole object from being changed, you can use Object.freeze
:
person.name = { first: 'Hulu', last: 'Van Damme' }
Object.freeze(person.name);
by default all properties on an object are enumerable, that means they will show up in a for..in
loop
if we change that:
Object.defineProperty(person, 'name', {enumerable: false});
the name
object will not show up when enumerating over the object, it will also not show up in Object.keys(person)
Finally it will also be hidden when serializing the object, for example with JSON.stringify(person)
.
prevents the property descriptors of being changed, it also prevents the property from being deleted from the object.
Object.defineProperty(person, 'name', {configurable: false});
Now if we try to change the enumerable
or property to false, like above, an error will be thrown. You also cannot set the configurable
property back to true again.
You can still change the writable
descriptor.
delete person.name;
would also cause an error if configurable
is false.
a getter allows you to write a function that returns a value, a setter allows you to set a value with a function, they are, however, used as if they were normal properties on the object.
You need to use Object.defineProperty
to add getters and setters:
const person = {
name: {
first: 'Yaoo',
last: 'Juual'
},
age: 29
}
let's add a getter to get the person's full name, and a setter:
Object.defineProperty(person, 'fullName', {
get: function() {
return this.name.first + ' ' + this.name.last;
},
set: function(value) {
var parts = value.split(' ');
this.name.first = parts[0];
this.name.last = parts[1];
}
})
now we can get the full name with just using the fullName
property:
console.log(person.fullName) // result: "Yaoo Juual"
when we use the setter:
person.fullName = 'Het Faar';
console.log(person.name.first) // result: Het
console.log(person.name.last) // result: Faar
- [[Primitive Values]]
- [[Prototype]]