一、基本用法
对象的解构赋值,必须变量名与属性名一样,与次序,位置无关
let {foo,bar} = {foo : 'aaa',bar : 'bbb'};
// foo = aaa ; bar = bbb
//属性名与变量名不匹配,则 undefine
let {baz} = {foo : 'aaa',bar : 'bbb'};
//baz 为 undefine
//若是必须不相同,则可以写成
let {foo : baz} = {foo : 'aaa',bar : 'bbb'};
//baz = aaa;
//foo undefine
//对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量
let {sin,cos,tan} = Math;
let {log} = console;
log('aaa');//aaa
所以对象的解构赋值本质是
let {foo,bar} = {foo : 'aaa',bar : 'bbb'};
本质为:
let {foo:foo,bar : bar} = {foo : 'aaa',bar : 'bbb'};
第一个foo 只是匹配的模式,真正赋值的是第二个 foo
二、嵌套结构的结构赋值
let obj = [
p : {'hello',
{y : 'world'}
}
]
let {p : [x,[y]] }= obj;
//x= hello; y = world;
//p 为undefine p只是为匹配模式
//若想给p也赋值,则写成
let {p,p:[x,[y]] } = obj;
//p p = p : {'hello',{y : 'world'}}
//x = hello ; y = world;
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}
上面代码有三次解构赋值,分别是对loc、start、line三个属性的解构赋值。
注意,最后一次对line属性的解构赋值之中,只有line是变量,loc和start都是模式,不是变量。
嵌套赋值
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
obj // {prop:123}
arr // [true]
嵌套对象中,若子对象所对应的父属性不在,则报错
let {foo : {bar}} = {baz : 'baz'}
//会报错
等号左边的 foo 会对应有一个子对象,bar 为子对象的属性,但是因为此时 foo 只为匹配模式,为undefine 再取子对象的属性就会报错
注意,对象的解构赋值可以取到继承的属性。
const obj1 = {};
const obj2 = { foo: 'bar' };
Object.setPrototypeOf(obj1, obj2);
const { foo } = obj1;
foo // "bar"
上面代码中,对象obj1的原型对象是obj2。foo属性不是obj1自身的属性,而是继承自obj2的属性,解构赋值可以取到这个属性。
三、默认值
对象的解构也可以指定默认值。
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"
一个已经声明的变量解构赋值
//错误写法
let x;
{x} = {x:1};
以为JavaScript引擎会将 {x} 理解为一个代码块,只有不将{}写在行首,不让引擎将其理解为一个代码块,就不会报错
//所以正确的写法为
let x;
({x} = {x:1})
解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式。
({} = [true, false]);
({} = 'abc');
({} = []);