This is the 7th day of my participation in the August Text Challenge.More challenges in August

ES6 allows you to extract values from arrays and objects and assign values to variables in a pattern called Destructuring.

1. Array deconstruction

1. Completely deconstruct

Previously, assigning a value to a variable could only be specified directly

let name = 'xiaoqi';
let age = 18;
Copy the code

ES6 could be written like this, taking the values out of the array, and assigning them to the variables where they are

let [name, age] = ['xiaoqi'.18];
Copy the code

This is “pattern matching”. If the pattern on both sides of the equal sign is the same, the variable on the left side will be assigned the corresponding value. It can also be assigned to multiple arrays.

let [foo, [[bar], baz]] = [1The [[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.

let [foo] = [];
let [bar, foo] = [1];
Copy the code

2. Incomplete deconstruction

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. But 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

However, 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.

/ / an error
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
foo // All above are TypeError
Copy the code

3. For Set structures, arrays can also be destructively assigned

let [x, y, z] = new Set(['1'.'2'.'3']);
x / / "1"
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) {
    yielda; [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.

4. 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

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.

If the default value is an expression, the expression is lazy, that is, evaluated only when it is used.

function f() {
  console.log('I was executed.'); // This line will not be printed
}

let [name = f()] = ['xiaoqi'];
Copy the code

In the above code, f() does not execute at all because x can be evaluated. The code above is equivalent to the code below.

let x;
if (['xiaoqi'] [0= = =undefined) {
  x = f();
} else {
  x = ['xiaoqi'] [0];
}
Copy the code

The default value can refer to another variable in the deconstructed assignment, but that variable must have been declared first.

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. Deconstruction can be applied to objects as well as arrays

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

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 the object have no order, and the variable must have the same name as the attribute to get the correct value. If there is no such variable name, it is undefined.

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

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

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

/ / a
let { log, sin, cos } = Math;

/ / two cases
const { log } = console;
log('hello') // hello
Copy the code

2. You can also alias variables

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

3. Object deconstruction assignment can take inherited properties

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

const { foo } = obj1;
foo // "bar"
Copy the code

In the code above, the prototype object of object obj1 is obj2. The foo property is not a property of obj1 itself, but a property inherited from obj2 that can be retrieved by deconstruction assignment.

4. Arrays are special objects in nature, so they can be deconstructed into object properties

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

The above code deconstructs the array object. [arr. Length-1] = 2; [arr. Length-1] = 3; Square brackets are “attribute name expressions”.

5. The default value

The deconstruction of an object can also specify default values

let {x = 3} = {};
x / / 3

let {x, y = 5} = {x: 1};
x / / 1
y / / 5

let {x: y = 3} = {};
y / / 3

let {x: y = 3} = {x: 5};
y / / 5

let { name: n = 'xiaoqi' } = {};
n // "xiaoqi"
Copy the code

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

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

let {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.

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

1. Function arguments can also be destructively assigned

function add([x, y]){
  return x + y;
}

add([1.2]); / / 3
Copy 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

2. The default value

Similarly, function arguments can 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