The Object preventExtensions() method
By Flavio Copes
Learn how Object.preventExtensions() blocks new own properties and prototype changes while existing properties can still be changed or removed.
Object.preventExtensions() makes an object non-extensible: you can no longer add new properties to it.
After calling it:
- you cannot add new own properties
- you cannot change the object’s prototype
- you can still change or delete existing properties when their descriptors allow it
Why would you want this? It locks the shape of an object. If another part of the code tries to attach a property it should not, the operation fails instead of silently growing the object. That makes it useful for objects with a fixed, known set of properties.
The method mutates and returns the same object:
const dog = {
breed: 'Siberian Husky'
}
const result = Object.preventExtensions(dog)
result === dog //true
Object.isExtensible(dog) //false
You can check any object with Object.isExtensible(). Regular objects start out extensible.
There is no way to make the object extensible again.
See the MDN Object.preventExtensions() reference and the ECMAScript specification for the complete behavior.
Adding a property fails
In strict mode, assigning a new property throws a TypeError:
'use strict'
const dog = {
breed: 'Siberian Husky'
}
Object.preventExtensions(dog)
dog.name = 'Roger' //TypeError
Without strict mode, the assignment fails silently. The property is not added, but you get no error either. This is the pitfall to watch for: you assign dog.name, nothing complains, and later dog.name is undefined. ES modules and class bodies run in strict mode automatically, so modern code usually gets the error.
Object.defineProperty() throws in both modes when it tries to add a property.
Existing properties can still change
preventExtensions() does not freeze existing properties:
const dog = {
breed: 'Siberian Husky',
name: 'Roger'
}
Object.preventExtensions(dog)
dog.name = 'Syd'
delete dog.breed
dog //{ name: 'Syd' }
The normal writable and configurable descriptor rules still apply.
The protection is shallow
preventExtensions() only affects the object you pass to it. Objects stored in its properties stay extensible:
const dog = {
details: {}
}
Object.preventExtensions(dog)
dog.details.color = 'white' //works
Call it on the nested objects too when you need to lock them as well.
The prototype cannot change
Making an object non-extensible also fixes its current prototype:
const dog = Object.preventExtensions({})
Object.setPrototypeOf(dog, {
speak() {
return 'Hello'
}
}) //TypeError
Use Object.seal() when you also want to prevent deleting or reconfiguring properties.
Use Object.freeze() when you additionally want to make existing data properties non-writable.
Related posts about js: