Array destruct assignment

1. Basic usage

let [a, b, c] = [1, 2, 3];
Copy the code

The above code shows that you can extract values from an array and assign values to variables in their respective locations.

Essentially, this is “pattern matching”, where the variable on the left is assigned a value as long as the pattern on both sides of the equal sign is the same. Here are some examples of destructuring using nested arrays.

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
Copy the code

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

Another case is incomplete deconstruction, where the pattern to the left of the equals sign matches only part of the array to the right of the equals sign. In this case, deconstruction can still succeed.

let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
Copy the code

If the right-hand side of the equals sign is not an array (or, strictly speaking, not a traversable structure), an error will be reported.

// let [foo] = 1; let [foo] = false; let [foo] = NaN; let [foo] = undefined; let [foo] = null; let [foo] = {};Copy the code

All of the above statements will fail because the values to the right of the equals sign will either have no Iterator interface when converted to an object (the first five expressions) or will have no Iterator interface (the last expression).

For Set structures, arrays can also be destructively assigned.

let [x, y, z] = new Set(['a', 'b', 'c']);
x // "a"
Copy the code

In fact, any data structure that has an Iterator interface can be destructively assigned in the form of an array.

function* fibs() {
  let a = 0;
  let b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5
Copy the code

In the above code, FIBS is a Generator function that natively has an Iterator interface. Deconstructing assignments in turn fetch values from this interface.

2. The default value

Destruct assignment allows you to specify default values.

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
Copy the code

Note that ES6 internally uses the strict equality operator (===) to determine whether a position has a value. Therefore, the default value is valid only if an array member is strictly equal to undefined.

let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null
Copy the code

The default value can refer to another variable of the deconstructed assignment, but that variable must already be declared.

let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError: y is not defined
Copy the code

2. Object deconstruction assignment

1. Introduction

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

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

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

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

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

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

Object deconstruction assignment, it is very convenient to assign the method of an existing object to a variable.

// let {log, sin, cos} = Math; // const {log} = console; log('hello') // helloCopy the code

If the variable name does not match the attribute 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'
Copy the code

What this actually shows is that the deconstructed assignment of an object is shorthand for the following.

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

In other words, the internal mechanism of deconstructive assignment of an object is to find the property of the same name and then assign it to the corresponding variable. It is the latter, not the former, that is really assigned.

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

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

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

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

An error is reported if the deconstruction pattern is a nested object and the parent property of the child object does not exist.

Let {foo: {bar}} = {baz: 'baz'};Copy the code

Because foo is equal to undefined, an error will be reported if you take a child attribute.

2. The default value

The deconstruction of an object 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"
Copy the code

The default is valid only if the object’s attribute value is strictly equal to undefined.

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

var {x = 3} = {x: null};
x // null
Copy the code

3. Pay attention to the point

If you want to use an already declared variable to destruct an assignment, you must be very careful.

// let x; {x} = {x: 1}; // SyntaxError: syntax errorCopy the code

The above code is written incorrectly because the JavaScript engine interprets {x} as a block of code, resulting in syntax errors. The only way to solve this problem is to not put curly braces at the beginning of the line and avoid JavaScript interpreting them as blocks of code.

// let x; ({x} = {x: 1});Copy the code

The above code puts the entire destruct assignment statement in parentheses and executes correctly.

Since arrays are special objects in nature, they can be deconstructed as object properties.

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

String deconstruction assignment

Strings can also deconstruct assignments. This is because at this point, the string is converted to an array-like object.

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
Copy the code

Array-like objects have a length attribute, so you can also deconstruct and assign to this attribute.

let {length : len} = 'hello';
len // 5
Copy the code

4. Deconstruction of values and Boolean values

When deconstructing an assignment, if the value and Boolean are to the right of the equals sign, the object is converted first.

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true
Copy the code

In the code above, both numeric and boolean-wrapped objects have toString attributes, so the variable S can take a value.

The rule for deconstructing assignment is to turn the value to the right of the equals sign into an object whenever it is not an object or array. Undefined and NULL cannot be converted to objects, so destructuring assignments to them will result in an error.

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
Copy the code

5. Deconstruction assignment of function parameters

function add([x, y]){ return x + y; } add([1, 2]); / / 3Copy the code

In the above code, the arguments to the function add are ostensibly an array, but the moment they are passed in, the array arguments are resolved to form variables X and y. For the code inside the function, the arguments it senses are x and y.

Here’s another example.

[[1, 2], [3, 4]].map(([a, b]) => a + b); // [3, 7]Copy the code

Function arguments can also be destructed using default values.

function move({x = 0, y = 0} = {}) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, 0] move({}); // [0, 0] move(); / / [0, 0]Copy the code

In the above code, the function move takes an object, which is deconstructed to get the values of the variables x and y. If deconstruction fails, x and y are equal to the default values.

Note that the following will give you different results.

function move({x, y} = { x: 0, y: 0 }) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, undefined] move({}); // [undefined, undefined] move(); / / [0, 0]Copy the code

The above code specifies default values for the arguments to move, not for the variables x and y, so the result is different from the previous one.

Undefined triggers the default values of function arguments.

[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]
Copy the code