ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。
以前这样定义变量
let a = 1; let b = 2; let c = 3; console.log(a, b, c);
ES6这样定义:
let [a, b, c] = [1 ,2, 3]; console.log(a,b,c)
二者结果相等。
只要等号两边的模式结构相等,值就能一一对应上,如果模式结构不相等,则按照顺序匹配对应,Such as:
let [x, y] = [1, 2, 3]; let [a, [b], c] = [5, [6, 7], 8]; console.log("x:" + x, "y:" + y, "a:" + a, "b:" + b, "c:" + c);
结果
x:1 y:2 a:5 b:6 c:8
按照顺序对应即可,对应不上的值会报undefined。
解构赋值还可以是对象,只要数据结构具有iterator接口,都可采用数组进行解构赋值。
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
前5个例子转为对象之后并没有实现iterator接口,而最后一个例子本身便不具备Iterator接口。
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();
functon* fibs其实是定义 一个数组,每个值都是a(yield语句本身是没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值),而数组的长度由解构内容决定,这里每次a b的值如下:
第一次遇到yield直接暂停,所以 a = 0;
第二次:[1, 1]
第三次:[1, 2]
第四次:[2, 3]
第五次 :[3, 5]
第六次: [5, 8]
而这个函数返回的始终是值为a 的数组,也就是返回[1, 1, 2, 3, 5]
大彻大悟,在阳锅的指导下
默认值使用
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
只有当数组内的成员严格等于(===)undefined的时候才会使用默认值,如果是null的话值为null而不是为默认值。
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null
对象的结构赋值
解构同时也可用于对象,这不像数组,按次序排序而进行赋值,只要变量于属性同名即可对应上:
let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
第二个例子在其解构的对象中并没有baz的属性,所以便无法给 baz赋值,结果为undefined。
如果变量名与属性名对不上,却仍需要对其赋值,可以将变量名使用对象名将其囊括:
let { foo: baz } = { foo: "aaa", bar: "bbb" };
这样baz便可得其值为aaa,这也实际上说明了对象的解构赋值实是下面的简写:
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
对象解构赋值,先是找到同名的属性,再赋值给变量,真正被赋值的是模式(foo)后的变量(baz),而不是模式。
let { foo: baz } = { foo: "aaa", bar: "bbb" };
对于嵌套结构对象也可以解构赋值,只要结构对的上即可:
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
这里p 只是模式,如果还需要整个p的变量解构的话,可以增加多一个变量名p。
let{ p, p:[x,{y}]} = obj;
对象解构赋值详解:
1、变量名如果和解构对象属性名不一致,可以给变量名加上与对象名相同的模式名称,然后访问该模式名称下对应的变量名即可。
2、这里的loc: a,意思为定义变量a,其模式名为loc,模式loc与node对象下的第一个loc进行匹配,输出的便是start对象,而loc:{start}等同于loc:{start: start},解构赋值给start的是loc对象下start对象的属性。
3、loc:{start:a}等同于loc:{start}/loc:{start: start},只是变量名由a变为了start。
const node = { loc: { start: { line: 1, column: 5 } } };
let {loc, loc:d, loc:{start: a}, loc:{start}, loc:{start:{line: x, column: y}}} = node; console.log(d); console.log(a); console.log(start);
函数参数的解构赋值
妈了个卖批,真的是啥都可以解构,俺解还不成吗。
[[1, 2], [3, 4]].map(([a, b]) => a + b);
map遍历数组,第一个元素[1, 2],进入函数function([a, b]),这个函数参数表面是一个数组,在数组传入的一刻就被解构为变量a和b,进行计算后返回存入数组。
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]
这里的方法参数是一个对象,传入一个对象后对对象属性进行解析并且赋值给x和y。
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]
这里是为参数设置默认值,而不是为解构后赋值设默认值,单传入对象{x:3}的话,参数识别到了对象,但不为空,所以不启动默认值,而是用对象本身的值,也就是undefined,返回的最终结果也就是[3, undefined],要理解什么是对象,怎么样才是对象的解构。