解构不仅可以用于数组,还可以用于对象,直接来看个简单粗暴的
let { first, second } = { first: 1, second: 2 };
console.log(first, second); //1 2
与数组解构不同的是,数组的元素是按次序排列的,变量取值是由它的位置(下标)决定。在对象的属性中没有次序,变量与属性同名,才能取到正确的值
//等号左边两个变量的次序跟右边不一致,对取值完全没影响
let { second, first } = { first: 1, second: 2 };
console.log(first, second); //1 2
//等号左边的变量没有对应的同名属性,所以取不到值,遂等于undefined
let { thrid } = { first: 1, second: 2 };
console.log(thrid); // undefined
如果变量名与属性名不一样,需要写成下面这样
let { foo: first } = { foo: 'AAA', bar: 'BBB' };
console.log(first); // AAA
let obj = { first: 'AAA', second: 'BBB' };
let { first: a, second: b } = obj;
console.log(a, b); // AAA BBB
//上两例说明,对象的解构赋值其实就是下面形式的简写
let { first: first, second: second } = { first: 1, second: 2 };
console.log(first, second); //1 2
对象的解构赋值机制是先找到同名属性,再赋值给对应的变量。真正被赋值的是后者,而不是前者
//first是匹配的模式,second才是变量,被赋值的是变量second,
let { first: second } = { first: 'FIRST', second: 'SECOND' };
console.log(first); //报错:first is not defined
console.log(second); // FIRST
解构也可以用于嵌套解构的对象
let obj = {
first: [
'AAA',
{
second: 'BBB'
}
]
}
let { first: [a, { second }] } = obj;
//此时,first为匹配模式,相当于[a, { second }] = ['AAA',{second: 'BBB'}]
//先是数组的解构赋值,然后是对象的解构赋值
console.log(a, second);// AAA BBB
此时,first是模式,不是变量,不会被赋值,如果first也要作为变量赋值的话,可以写成这样
let obj = {
first: [
'AAA',
{
second: 'BBB'
}
]
}
let { first, first: [a, { second }] } = obj;
//相当于 let { first: first, first: [a, { second }] } = obj;
console.log(a, second); // AAA BBB
console.log(first); // ["AAA", {second: "BBB"}]
再举个
const obj = {
loc: {
start: {
line: 1,
column: 2
}
}
}
let { loc, loc: { start }, loc: { start: { line } } } = obj;
//相当于这样:let { loc: loc, loc: { start: start }, loc: { start: { line: line } } } = obj;
//分别有三次解构赋值,分别是对loc,start,line三个属性的解构赋值
//在最后一次对line属性解构赋值中,只有line是变量,loc和start都是模式
console.log(loc); // {start: {line: 1, column: 2}}
console.log(start); // {line: 1, column: 2}
console.log(line); // 1
再来个嵌套赋值的
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true })
//此时,foo和bar是匹配模式,被赋值的是 obj和 arr
console.log(obj); // {prop: 123}
console.log(arr); // [true]
为什么上面的代码中({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true })用括号包起来,是因为JavaScript引擎会将 { foo: obj.prop, bar: arr[0] }理解为一个代码块,从而发生语法错误。
-
错误写法
let x; { x } = { x: 1 }; //报错
-
正确写法
let x; ({ x } = { x: 1 }); console.log(x); // 1
对象的解构也可以指定默认值
let { a = 3 } = {};
console.log(a); // 3
let { b, c = 3 } = { b: 1 };
console.log(b); // 1
console.log(c); // 3
let { x: y = 3 } = {};
console.log(y); // 3
let { j: i = 3 } = { j: 1 };
console.log(i); // 1
let { message: msg = 'Hello Mr Wang' } = {};
console.log(msg); // Hello Mr Wang
默认值的生效条件是:对象的属性值严格等于undefined
let { x = 1 } = { x: undefined };
console.log(x); // 1
let { x = 1 } = { x: null };
//相当于这样:let { x: x = 1 } = { x: null };
console.log(x); // null
解构失败的话,变量值等于undefined
let { x } = { y: 1 }
console.log(x); // undefined
如果解构模式是嵌套的对象,子对象所对应的父属性不存在会报错
let { x: { y } } = { y: y }
console.log(y); //报错
对象的解构赋值,可以很方便的将现有对象的方法,赋值到某个变量
//将Math对象的其中三个方法,赋值到对应变量上,使用起来会很方便
let { abs, max, min } = Math;
console.log(abs(-10)); //10
console.log(max(1, 2)); //2
console.log(min(1, 2)); //1
数组的本质是特殊的对象,因此可以对数组进行对象的解构
let arr = [1, 2, 3];
let { 0: first, [arr.length - 1]: last } = arr;
//数组arr的下标(键)0 ,对应值是 1
//[arr.length-1]就是数组arr的下标 2,对应的值是 3
console.log(first); // 1
console.log(last); // 3