Ler em português

Object definition vs assignment

This article was taken from 2ality with study purpose. Reading, writing and rewriting is the way I chose to learn things and to register for consult on the future.

All credits to Dr. Axel Rauschmayer

The object definition and assignment are different things. The differences are subtle, but they exists.

Object definition uses a function to define a new property and is more verbose:

Object.defineProperty(user, "name", descriptors);

The main benefit of this approach is that you can pass descriptors, which allows you to configure the property behaviour. It can be use for either creating a property or modifying it.

Object assignment is the most common:

user.name = "John";

The assignment idea is to change a value. If there is a setter for the property name in user object or in its prototypes, it will be invoked. Otherwise the assigment will end up creating a new property in case ist doesn't exist, with default attributes.

Understanding the property attributes

In JavaScript, there are three kinds of properties:

  • Named accessor properties: They exists thanks to a getter or a setter.
  • Named data properties: A property that has a value. Those are the most common properties. They can be a method.
  • Internal properties: Used internally by JavaScript.

Property attributes

Every property has specific attributes (fields), and those fields will change the way a property works.

  • All properties:
    • [[Enumerable]]: If a property is enumerable, it allows some operations such as for...in and Object.keys().
    • [[Configurable]]: If a property is configurable, then all of its attributes can be changed. Otherwise, just the [[Value]] attribute can be changed via a definition.
  • Named data properties:
    • [[Value]]: is the value of the property.
    • [[Writable]]: determines if the value can be changed.
  • Names accessor properties:
    • [[Get]]: holds a getter method.
    • [[Set]]: holds a setter method.

Property descriptors

They are a set of property attributes aforementioned that composes a descriptor object. Example:

{
  value: 123,
  writable: false
}

They are used by methods, such as Object.defineProperty, Object.getOwnPropertyDescriptor and Object.create. In case there are properties missing from a descriptor, the default values takes place:

Property Default Value
value undefined
get undefined
set undefined
writable false
enumerable false
configurable false

Internal properties

Among others, there let's observe these internal properties:

  • [[Prototype]]: The prototype of the object.
  • [[Extensible]]: If the object is extensible - if new new properties can be added to it
  • [[DefineOwnProperty]]: Method for defining a property.
  • [[Put]]: Method for assigning a property.

What actually happens in definition and assignment

Defining a property is handled by the internal method [[DefineOwnProperty]](P, Desc, Throw). This internal function is called when Object.defineProperty or Object.defineProperties are called.

P is the name of a property. Throw specifies how the operation should reject a change: If Throw is true, then an exception is thrown, otherwise, the operation is silently aborted. When [[DefineOwnProperty]] is called:

  • If the object is not extensible, reject.
  • Otherwise, if the property doesn't exist, creates a new one.
  • In case the property exists and the object is not configurable it will be reject in case another property other than [[Value]] is changed.
  • Otherwise, the existing property is configurable and can be changed.

Assigning to a property is handled by the internal method [[Put]](P, Value, Throw). It is called on assignments such as:

user.name = "John";

P and Throw work the same way as on [[DefineOwnProperty]]. When [[Put]] is called, the following happens:

  • If P is read-only somewhere in the prototype chain, operation is rejected.
  • If there is setter called P somewhere in the prototype chain, it will be called.
  • If there is no property with name P and the object is not extensible, then reject.
  • Otherwise, a new property is created with the same previous mechanism from Object.defineProperty, with descriptors:
this[[DefineOwnProperty]](
  P,
  {
    value: Value,
    writable: true,
    enumerable: true,
    configurable: true,
  },
  Throw
);
  • In case a property exists and it's writable, that is invoked:
this[[DefineOwnProperty]](
  P,
  {
    value: Value,
  },
  Throw
);

Examples

Check some examples that explain how definition and assignment works.

Read-only properties does not prevent definition

"use strict";
const obj = {};
Object.defineProperty(obj, "foo", {
  value: "a",
  writable: false, // read-only
  configurable: true,
});

Assignment: results in exception:

obj.foo = 'b';
TypeError: obj.foo is read-only

Defiunition: creates a new own property:

Object.defineProperty(obj, "foo", {
  value: "b",
});
obj.foo; // 'b'

Assignment operator does not change properties in prototypes

Since prototype is shared by all descendants, when one decides to change a property, a new local property is created and the prototype is not affected.

let proto = { foo: "a" };
let obj = Object.create(proto);

obj.foo = "b";
obj.foo; // 'b'
proto.foo; // 'a'

Only definition allows you to customize the property attributes

Since assignment has default attribute values, if you want to create specific attributes, you must use definition.

The properties of a literal object are added via definition

This statement:

let obj = {
  foo: "a",
};

Is internally translated for:

let obj = new Object();
obj.foo = "a";

Which is the same of:

let obj = new Object();
Object.defineProperties(obj, {
  foo: {
    value: "a",
    enumerable: true,
    configurable: true,
    writable: true,
  },
});

Conclusion

Assignment will very likely be the better choice for most of the cases. I personally, can't remember when I needed to use definition. Assignment is easier to write/read and also more performatic, since definition is slow. However is good to know the difference and the nuances for them. In case you need to have more control over a property, for example, assignment can not be enough and definition the proper choice.