Provide a way to draw a distinction between the characteristics of properties, such as whether the property was read-only or not.
var myObject = {
a: 2
};
Object.getOwnPropertyDescriptor(myObject, 'a'); // => {value: 2, writable: true, enumerable: true, configurable: true}
-
The property descriptor includes three characteristics other than the value of a property:
writable
,enumerable
andconfigurable
. -
We can use
Object.defineProperty()
to add a new property, or modify an existing one (if it's configurable). E.g
var myObject = {};
Object.defineProperty(myObject, 'a', {
value: 2,
writable: true,
configurable: true,
enumerable: true
});
myObject.a; // => 2
The ability to change the value of a property is controlled by writable
. E.g
var myObject = {};
Object.defineProperty(myObject, 'a', {
value: 2,
writable: false, // not writable
configurable: true,
enumerable: true
});
myObject.a = 3;
myObject.a; // => 2
- In strict mode the parser will return an error if we try to modify the property
var myObject = {};
Object.defineProperty(myObject, 'a', {
value: 2,
writable: false, // not writable
configurable: true,
enumerable: true
});
myObject.a = 3; // => TypeError: 'a' is read-only
As long as a property is currently configurable we can modify its descriptor definition using the same defineProperty()
utility. E.g
var myObject = {
a: 2
};
myObject.a = 3;
myObject.a; // => 3
Object.defineProperty(myObject, 'a', {
value: 4,
writable: true,
configurable: false, // not configurable
enumerable: true
});
myObject.a; // => 4
myObject.a = 5;
myObject.a // => 5
Object.defineProperty(myObject, 'a', {
value: 6,
writable: true,
configurable: true,
enumerable: true
}); // => TypeError: can't redefine non-configurable property "a"
-
Changing
configurable
tofalse
is a one-way action and can't be undone -
configurable: false
also prevents the ability to use thedelete
operator to remove an existing property. E.g
var myObject = {
a: 2
};
myObject.a; // => 2
delete myObject.a;
myObject.a // => undefined
Object.defineProperty(myObject, 'a', {
value: 2,
writable: true,
configurable: false,
enumerable: true
});
myObject.a; // => 2
delete myObject.a;
myObject.a // => 2
Controls if a property will show up in certain object-property enumerations, such as for...in
loop. E.g
var myObject = {
a: 1,
b: 2,
c: 3
};
Object.defineProperty(myObject, 'b', {
value: 2,
writable: true,
configurable: true,
enumerable: false
});
for (prop in myObject) {
console.log(myObject[prop]);
} // => 1, 3
- Object constant: By combining
writable: false
andconfigurable: false
, you can create a constant as an object property. E.g
var myObject = {};
Object.defineProperty(myObject, 'FAV_NUMBER', {
value: 42,
writable: false,
configurable: false
});
'use strict';
var myObject = {
a: 2
};
Object.preventExtensions(myObject);
myObject.b = 3; // TypeError: can't define property "b": Object is not extensible
Creates a "sealed" object, which means it takes an existing object and essentially calls Object.preventExtensions()
on it, but it also marks all existing properties as configurable: false
. E.g
'use strict'
var myObject = {
a: 1,
b: 2,
c: 3
};
Object.seal(myObject);
myObject.d = 4; // => TypeError: can't define property "d": Object is not extensible
Object.defineProperty(myObject, 'b', {
enumerable: false
}); // => TypeError: can't redefine non-configurable property "b"
- So not only can we not add any more properties, but we also can't reconfigure or delete any existing properties (though you can still modify their values)
Creates a frozen object, which means it takes an existing object and essentially calls Object.seal()
on it, and it also marks all "data accessor" properties as writable: false
so their values can't be changed. E.g
'use strict'
var myObject = {
a: 1,
b: 2,
c: 3
};
Object.freeze(myObject);
myObject.a = 4; // => TypeError: "a" is read-only
-
This approach is the highest level of immutability that you can attain for an object as it prevents any changes to the object or any of its direct properties
-
Though the contents of any referenced other objects are unaffected.