The Object preventExtensions() method

By

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:

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: