Deconstruction assignment of objects in ES6

Keywords: Front-end ECMAScript


brief introduction

Deconstruction can be used not only for arrays, but also for objects.

let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

There is an important difference between the deconstruction of objects and arrays. The elements of the array are arranged in order, and the value of the variable is determined by its position;

The attributes of the object have no order, and the variable must have the same name as the attribute in order to get the correct value.

let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined

In the first example of the above code, the order of the two variables on the left of the equal sign is inconsistent with the order of the two attributes with the same name on the right of the equal sign, but it has no effect on the value.

The variable of the second example does not have a corresponding attribute with the same name, so the value cannot be obtained. Finally, it is equal to undefined.

If the deconstruction fails, the value of the variable is equal to undefined.

let {foo} = {bar: 'baz'};
foo // undefined

In the above code, the object to the right of the equal sign has no foo attribute, so the variable foo cannot get a value, so it is equal to undefined.

Object deconstruction assignment can easily assign the methods of existing objects to a variable.

// Example 1
let { log, sin, cos } = Math;
// Example 2
const { log } = console;
log('hello') // hello

Example 1 of the above code assigns the logarithm, sine and cosine of the Math object to the corresponding variables, which will be much more convenient to use. Example 2: assign console.log to the log variable.

If the variable name is inconsistent with the property name, it must be written as follows.

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'

This actually shows that the deconstruction assignment of an object is a short form of the following form (see the chapter on object extension).

let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };

In other words, the internal mechanism of object deconstruction assignment is to find the attribute with the same name first, and then assign it to the corresponding variable. What is really assigned is the latter, not the former.

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined

In the above code, foo is the matching pattern and baz is the variable.

What is really assigned is the variable baz, not the pattern foo.

Like arrays, deconstruction can also be used for nested objects.

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"

Note that p is a pattern, not a variable, so it will not be assigned. If p is also assigned as a variable, it can be written as follows.

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]

Here is another example.

const node = {
  loc: {
    start: {
      line: 1,
      column: 5
    }
  }
};

let { loc, loc: { start }, loc: { start: { line }} } = node;
line // 1
loc  // Object {start: Object}
start // Object {line: 1, column: 5}

The above code has three deconstruction assignments, which are the deconstruction assignments of loc, start and line attributes. Note that in the last deconstruction assignment of the line attribute, only line is a variable, and loc and start are patterns, not variables.

The following is an example of nested assignment.

let obj = {};
let arr = [];

({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });

obj // {prop:123}
arr // [true]

If the deconstruction mode is a nested object and the parent attribute of the child object does not exist, an error will be reported.

// report errors
let {foo: {bar}} = {baz: 'baz'};

In the above code, the foo attribute of the object to the left of the equal sign corresponds to a child object. The bar attribute of this sub object will report an error during deconstruction. The reason is very simple, because foo is equal to undefined, and an error will be reported if you take the sub attribute.

Note that the deconstruction assignment of the object can get the inherited attributes.

const obj1 = {};
const obj2 = { foo: 'bar' };
Object.setPrototypeOf(obj1, obj2);

const { foo } = obj1;
foo // "bar"

In the above code, the prototype object of object obj1 is obj2.

The foo attribute is not an attribute of obj1 itself, but an attribute inherited from obj2. This attribute can be obtained by deconstruction assignment.

Default value

Object deconstruction can also specify default values.

var {x = 3} = {};
x // 3
var {x, y = 5} = {x: 1};
x // 1
y // 5
var {x: y = 3} = {};
y // 3
var {x: y = 3} = {x: 5};
y // 5
var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"

The default value takes effect if the property value of the object is strictly equal to undefined.

var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null

In the above code, the attribute x is equal to null. Because null and undefined are not strictly equal, it is a valid assignment, so the default value 3 will not take effect.

Attention

(1) If you want to use a declared variable for deconstruction assignment, you must be very careful.

// Wrong writing
let x;
{x} = {x: 1};
// SyntaxError: syntax error

The above code will report an error because the JavaScript engine will interpret {x} as a code block, resulting in syntax errors. This problem can only be solved by not writing curly braces at the beginning of the line and avoiding JavaScript interpreting them as code blocks.

// Correct writing
let x;
({x} = {x: 1});

The above code puts the entire deconstruction assignment statement in a parenthesis, which can be executed correctly. See below for the relationship between parentheses and deconstruction assignment.

(2) Deconstruction assignment allows no variable name to be placed in the pattern to the left of the equal sign. Therefore, you can write very strange assignment expressions.

({} = [true, false]);
({} = 'abc');
({} = []);

Although the above expression is meaningless, the syntax is legal and can be executed.

(3) Because arrays are special objects in nature, they can be deconstructed.

let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3

The above code deconstructs the array object.

The value corresponding to the 0 key of array arr is 1, [arr.length - 1] is the 2 key, and the corresponding value is 3.

The writing of square brackets belongs to "attribute name expression" (see Chapter "object extension").

Posted by dgny06 on Sat, 27 Nov 2021 10:39:43 -0800