let [a, b, c] = [1, 2, 3];
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 // []
不彻底解构数组
let [x, y] = [1, 2, 3]; x // 1 y // 2 let [a, [b], d] = [1, [2, 3], 4]; a // 1 b // 2 d // 4
若是等号的右边不是数组(严格地说,不是可遍历的结构),那么将会报错。
解构赋值容许指定默认值。函数
let [foo = true] = []; foo // true let [x, y = 'b'] = ['a']; // x='a', y='b' let [x, y = 'b'] = ['a', undefined]; // x='a', y='b' let [x = 1, y = x] = []; // x=1; y=1 let [x = y, y = 1] = []; // ReferenceError: y is not defined
ES6 内部使用严格相等运算符(===),判断一个位置是否有值
若是默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。prototype
function f() { console.log('aaa'); } let [x = f()] = [1]; ///由于x能取到值,因此函数f根本不会执行
对象的解构与数组有一个重要的不一样。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。code
let { bar, foo } = { foo: "aaa", bar: "bbb" }; foo // "aaa" bar // "bbb" let { baz } = { foo: "aaa", bar: "bbb" }; baz // undefined //若是变量名与属性名不一致,必须写成下面这样 let obj = { first: 'hello', last: 'world' }; let { first: f, last: l } = obj; f // 'hello' l // 'world' first // undefined
若是要将一个已经声明的变量用于解构赋值,必须很是当心。对象
// 错误的写法 let x; {x} = {x: 1}; // SyntaxError: syntax error // 正确的写法 let x; ({x} = {x: 1});
因为数组本质是特殊的对象,所以能够对数组进行对象属性的解构。继承
let arr = [1, 2, 3]; let {0 : first, [arr.length - 1] : last} = arr; first // 1 last // 3
因为解构赋值要求等号右边是一个对象,因此若是等号右边是undefined或null,就会报错,由于它们没法转为对象。
let { x, y, ...z } = null; // 运行时错误 let { x, y, ...z } = undefined; // 运行时错误
解构赋值必须是最后一个参数,不然会报错。
let { ...x, y, z } = obj; // 句法错误 let { x, ...y, ...z } = obj; // 句法错误
解构赋值的拷贝是浅拷贝,即若是一个键的值是复合类型的值(数组、对象、函数),那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。
let obj = { a: { b: 1 } }; let { ...x } = obj; obj.a.b = 2; x.a.b // 2
扩展运算符的解构赋值,不能复制继承自原型对象的属性。
let o1 = { a: 1 }; let o2 = { b: 2 }; o2.__proto__ = o1; let { ...o3 } = o2; o3 // { b: 2 } o3.a // undefined
若是使用解构赋值,扩展运算符后面必须是一个变量名,而不能是一个解构赋值表达式。
let { x, ...{ y, z } } = o; // SyntaxError
字符串也能够解构赋值。这是由于此时,字符串被转换成了一个相似数组的对象。字符串
const [a, b, c, d, e] = 'hello'; a // "h" b // "e" c // "l" d // "l" e // "o" let {length : len} = 'hello'; len // 5
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。原型
let {toString: s} = 123; s === Number.prototype.toString // true let {toString: s} = true; s === Boolean.prototype.toString // true
function add([x, y]){ return x + y; } add([1, 2]); // 3
函数add的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成变量x和y。io
//默认值 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]