Skip to content

Instantly share code, notes, and snippets.

@0bie
Created February 10, 2017 00:34
Show Gist options
  • Save 0bie/37e5aab969b0463d8fc7b67e1f3cd020 to your computer and use it in GitHub Desktop.
Save 0bie/37e5aab969b0463d8fc7b67e1f3cd020 to your computer and use it in GitHub Desktop.

Object property descriptors

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 and configurable.

  • 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
writable

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
configurable

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 to false is a one-way action and can't be undone

  • configurable: false also prevents the ability to use the delete 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
enumerable

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

Immutability

  • Object constant: By combining writable: false and configurable: 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
});
Object.preventExtensions()
'use strict';
var myObject = {
  a: 2
};

Object.preventExtensions(myObject);

myObject.b = 3; // TypeError: can't define property "b": Object is not extensible
Object.seal()

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)
Object.freeze()

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment