Protecting objects in JavaScript
This blog post is a quick refresher of how objects can be protected in JavaScript.
There are three levels of protection:
makes it impossible to add properties to obj. Example:
Now adding a propert fails silently in sloppy mode:
And throws an error in strict mode [1], which we switch to via an IIFE [2].
You can still delete properties, though.
checks whether obj is extensible:
prevents extensions and makes all properties “unconfigurable”. The latter means that the attributes [3] of properties can’t be changed, any more. Read-only properties stay read-only, enumerable properties stay enumerable, etc.
You can still change the property foo:
But you can’t change its attributes:
Additionally, obj is not extensible, any more.
checks whether obj is sealed:
makes all properties non-writable and seals obj. That is, obj is not extensible, all properties are read-only and there is no way to change that.
Once again, you get silent failures in sloppy mode:
And errors in strict mode:
checks whether obj is frozen:
There are three levels of protection:
- Preventing extensions is the weakest level,
- sealing is stronger,
- freezing is strongest.
Preventing extension
Object.preventExtensions(obj)
makes it impossible to add properties to obj. Example:
var obj = { foo: 'a' };
Object.preventExtensions(obj);
Now adding a propert fails silently in sloppy mode:
> obj.bar = 'b';
> obj.bar
undefined
And throws an error in strict mode [1], which we switch to via an IIFE [2].
> (function () { 'use strict'; obj.bar = 'b' }());
TypeError: Can't add property bar, object is not extensible
You can still delete properties, though.
> delete obj.foo
true
> obj.foo
undefined
Checking whether an object is extensible
Object.isExtensible(obj)
checks whether obj is extensible:
> Object.isExtensible(obj)
false
Sealing
Object.seal(obj)
prevents extensions and makes all properties “unconfigurable”. The latter means that the attributes [3] of properties can’t be changed, any more. Read-only properties stay read-only, enumerable properties stay enumerable, etc.
(As an aside, JavaScript does allow you to change an unconfigurable property from writable to read-only, due to historical reasons.)
The following example demonstrates that sealing makes all properties unconfigurable.
> var obj = { foo: 'a' };
> Object.getOwnPropertyDescriptor(obj, 'foo') // before sealing
{ value: 'a',
writable: true,
enumerable: true,
configurable: true }
> Object.seal(obj)
> Object.getOwnPropertyDescriptor(obj, 'foo') // after sealing
{ value: 'a',
writable: true,
enumerable: true,
configurable: false }
You can still change the property foo:
> obj.foo = 'b';
'b'
> obj.foo
'b'
But you can’t change its attributes:
> Object.defineProperty(obj, 'foo', { enumerable: false });
TypeError: Cannot redefine property: foo
Additionally, obj is not extensible, any more.
Checking whether an object is sealed
Object.isSealed(obj)
checks whether obj is sealed:
> Object.isSealed(obj)
true
Freezing
Object.freeze(obj)
makes all properties non-writable and seals obj. That is, obj is not extensible, all properties are read-only and there is no way to change that.
var point = { x: 17, y: -5 };
Object.freeze(point);
Once again, you get silent failures in sloppy mode:
> point.x = 2; // no effect, point.x is read-only
> point.x
17
> point.z = 123; // no effect, point is not extensible
> point
{ x: 17, y: -5 }
And errors in strict mode:
> (function () { 'use strict'; point.x = 2 }());
TypeError: Cannot assign to read-only property 'x'
> (function () { 'use strict'; point.z = 123 }());
TypeError: Can't add property z, object is not extensible
Checking whether an object is frozen
Object.isFrozen(obj)
checks whether obj is frozen:
> Object.isFrozen(point)
true
References
- JavaScript’s strict mode: a summary
- JavaScript variable scoping and its pitfalls
- Object properties in JavaScript
Comments
Post a Comment