Previously, to assign a value to a variable, you had to specify a value directly. ES6 proposes deconstructive assignment, which can greatly reduce the amount of code and make the structure of our programs clearer in practice. So you have to wonder how attractive is deconstructing assignment? Let’s demystify it


1. Concept and essence

Let’s first look at its concept and nature:

concept nature
ES6 allows you to extract values from ** arrays and objects (as well as strings, numbers, booleans, function parameters, and so on) ** and assign values to variables according to their respective positions in a certain pattern “Pattern matching”As long as the pattern on both sides of the equal sign is the same, the variable on the left side will be assigned the corresponding value.

Is there a face of confusion, deconstruction assignment is what the hell? Slowly look down, there will be unexpected harvest oh.


2. Deconstruct the classification of assignment

This part we will have a detailed introduction of deconstruction assignment and deconstruction assignment are divided into the following categories: an array of deconstruction assignment | | object of deconstruction assignment string of deconstruction assignment | | deconstruction of numerical and Boolean value assignment function parameters of deconstruction assignment — — — — — — — – |

ES6 allows assignment in this form:

let [a, b, c] = [5, 6, 7];
   a // 5
   b // 6
   c // 7
Copy the code

In the code above, we can assign values to variables on both sides of the equal sign. So we can see that the characteristic of array deconstruction assignment is to perform the assignment according to the data subscript, is orderly. 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

** Any data structure that has an Iterator interface. Or go to see ruan yifeng teacher “ES6 standard introduction” this book), can be used in the form of array deconstruction assignment. Otherwise, an error will be reported.

  • Success stories

For example, with a Set structure, which has an Iterator interface, you can use a deconstructed assignment of an array.

let [x, y, z] = new Set(['a'.'b'.'c']);
x // "a"
Copy the code
  • The following statements will all fail because the values to the right of the equals sign will either not have an Iterator interface when converted to an object (the first five expressions) or will not have an Iterator interface (the last expression).
/ / an errorlet [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let[foo] = {}; `Copy the code

Next we will introduce two other cases: one is unsuccessful deconstruction, and the other is incomplete deconstruction.

  • If the deconstruction fails, the value of the variable is equal to undefined.
let [foo] = [];
let [bar, foo] = [1];
Copy the code

In both cases, the deconstruction fails and the value of foo is equal to undefined.

  • Incomplete deconstruction incomplete deconstruction, in which 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 [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
Copy the code

The above two examples, both incomplete deconstruction, can be successful. 2.1.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

There are several cases:

  • The default 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

In the above code, if an array member is null, the default value does not take effect because NULL is not exactly equal to undefined.

  • The default value is an expression, which is lazily evaluated, meaning it is evaluated only when it is used
function f() {
  console.log('aaa');
}

let [x = f()] = [1];
Copy the code

In the above code, f will not be executed at all because x can be evaluated.

  • 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

The last expression above fails because y has not yet been declared when x uses y as the default.

Ok, so that’s the end of array deconstruction assignment. Do you have a general understanding of deconstruction assignment? Let’s take a look at what a deconstructive assignment of an object is. How is it different from array deconstruction assignment?

Object deconstruction differs from arrays in one important way. The elements of an array are arranged in order, and the value of a variable is determined by its position. The attributes of an 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

In the first example of the code above, the order of the two variables to the left of the equals sign is inconsistent with the order of the two properties with the same name to the right of the equals sign, but it has no effect on the value at all. In the second example, the variable has no corresponding property of the same name, so it cannot get a value and finally equals undefined.

  • 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

The internal mechanism for deconstructing 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

In the code above, foo is the matching pattern and Baz is the variable. It is the variable baz that is actually assigned, not the pattern foo.

  • 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

Note that p is a mode, not a variable, and therefore will not be assigned. If p is also assigned as a variable, it can be written as follows.

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}
Copy the code

The above code has three deconstruction assignments, respectively for loC, start and line. Note that in the last deconstruction assignment of the line property, only line is a variable, loc and start are modes, not variables.

  • 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

In the code above, the attribute x is null, and since null is not exactly equal to undefined, it is a valid assignment, causing the default value 3 not to take effect.

Here are some things to watch out for:

  • If deconstruction fails, the value of the variable is equal to undefined
let {foo} = {bar: 'baz'};
foo // undefined
Copy the code
  • The destruct pattern is a nested object, and the parent property of the child object does not exist, then an error is reported
/ / an errorlet {foo: {bar}} = {baz: 'baz'};
Copy the code
  • If you want to use an already declared variable to destruct an assignment, you must be very careful
// This is not the caselet x;
{x} = {x: 1};
// SyntaxError: syntax error
Copy 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.

// The correct way to writelet x;
({x} = {x: 1});
Copy the code

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

  • Object deconstruction assignment, it is very convenient to assign the method of an existing object to a variable
let { log, sin, cos } = Math;
Copy the code

This code makes it much easier to use by assigning the logarithm, sine, and cosine methods of the Math object to the corresponding variables.

Knock, knock, knock, knock, knock, knock, knock, knock. Okay? It needs to be digested. So let’s see what happens when we deconstruct string assignments, okay?

2.3 String Deconstruction Assignment Strings can also be destructed. 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

2.4 Deconstructive assignment of values and Boolean types

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.

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.

  • 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

Function arguments can also be destructively assigned.

function add([x, y]){
  returnx + 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.

  • 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. Notice the difference between the following code and the above code!

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

2.6 Parentheses The parentheses problem was mentioned in Section 2.2, and this section will deal with parentheses. While deconstructing assignments is convenient, it’s not easy to parse. There is no way for the compiler to know from the start whether an expression is a pattern or an expression. It must be parsed to (or not) the equals sign. This raises the question of what to do if parentheses are present in the schema. The rule of ES6 is that parentheses should not be used whenever there is a possibility of ambiguity about deconstruction. However, this rule is actually not so easy to discern and can be quite troublesome to deal with. Therefore, it is recommended that parentheses not be placed in schemas whenever possible.

  • There is only one case in which parentheses can be used: for the non-schema part of an assignment statement, parentheses can be used
[(b)] = [3]; {p: (d)} = {}); // Correct [(parseint.prop)] = [3]; / / rightCopy the code

All three of the above lines execute correctly because they are assignment statements, not declarations; Second, their parentheses are not part of the schema. In the first line, the schema takes the first member of the array, regardless of parentheses; In the second line, the mode is P, not D; The third line of statements has the same properties as the first.


3. Use

Destructive assignment of variables has many uses. Here are some common uses.

3.1 Exchange values of variables

let x = 1;
let y = 2;

[x, y] = [y, x];
Copy the code

The above code exchanges the values of variables X and y, which is not only concise, but also easy to read, semantic very clear.

3.2 Returning Multiple Values from a Function A function can return only one value. If you want to return multiple values, you must return them in an array or an object. With deconstructing assignments, it’s very convenient to pull out these values.

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();
Copy the code

3.3 Definition of function parameters

Destructuring assignments makes it easy to map a set of parameters to variable names.

// Arguments are an ordered set of valuesfunctionf([x, y, z]) { ... } f([1, 2, 3]); // Arguments are an unordered set of valuesfunction f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
Copy the code

3.4 Input Method When loading a module, you usually need to specify the input method. Deconstructing assignment makes the input statement very clear.

const { SourceMapConsumer, SourceNode } = require("source-map");
Copy the code

You can also extract JSON data and walk through Map deconstruction, which I won’t go over here. Finally post a summary chart!!