1 、数组的解构赋值(数组的元素是按次序排列的,变量的取值由它的位置决定)
1.1、依次将右边数组的 1,2 赋值给左边数组的变量 a 和 b
let a, b, rest;
[a,b] = [1,2]
console.log(a,b)
1.2、剩余参数的解构赋值
let a,b,reset;
[a,b,...reset] = [1,2,3,4,5,6];
console.log(a,b,reset);
1.3、参数个数不一致的情况
let a,b,reset;
[a,b,c] = [1,2];
console.log(a,b,c);//1 2 undefined
结论:
- 如果变量多, 值少, 多出来的变量为 undefined
- 如果变量少, 值多, 依次对应即可
1.4、默认值
let a, b, c, rest;
[a, b, c = 3] = [1, 2]
console.log(a, b, c) // 1 2 3
结论:数组的解构赋值可以解决的实际问题
1.1、变量交换
//例2:变量交换
let a=1,b=2;
[a,b] = [2,1]
console.log(a,b)
1.2:只使用返回值的一部分
//例1.2.1:只使用返回值的一部分
function foo(){
return [1,2,3,4,5]
}
let [a,,,,b] = foo()
console.log(a,b)//1,5
//例1.2.2:只使用返回值的一部分
function foo(){
return [1,2,3,4,5]
}
let [a,,...b] = foo()
console.log(a,b)//1,[3,4,5]
2 、对象的解构赋值(对象的属性没有次序,变量必须与属性同名,才能取到正确的值)
2.1、将右边对象中的属性 a 和 b 提取出来分别赋值给变量 a 和变量 b
let { a, b } = { a: 1, b: 2 }
console.log(a, b)//1,2
1.2、默认值
let {a=3,b=5} = {a:1};
console.log(a,b)//1,5
1.3、使用场景
function getData(id){
return {
number: 10,
price: 99
}
}
let {number, price} = getData(1);
console.log("totle="+ number * price)
//对象的解构也可以用于嵌套解构的对象
const medaData = {
title: 'outter',
msg: [{
title: 'inner',
desc: 'description'
}]
};
let {
title: outTitle,
msg: [{
title: innerTitle
}]
} = medaData
console.log(outTitle, innerTitle)//outter inner
// 如果变量名与属性名不一致,必须写成下面这样。
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'
//嵌套赋值:分别是对loc、start、line三个属性的解构赋值。注意,最后一次对line属性的解构赋值之中,只有line是变量,loc和start都是模式,不是变量。
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}
// 如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。
let {foo: {bar}} = {baz: 'baz'};
上面代码中,等号左边对象的foo属性,对应一个子对象。该子对象的bar属性,解构时会报错。原因很简单,因为foo这时等于undefined,再取子属性就会报错。
// 对象的解构赋值可以取到继承的属性
const obj1 = {};
const obj2 = {foo: 'bar'};
//为现有对象设置原型,返回一个新对象Object.setPrototypeOf(现有对象, 原型对象)
Object.setPrototypeOf(obj1, obj2)
const { foo } = obj1
console.log(foo) // // "bar"
// 在这里,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
由上述可知title、msg是匹配模式真正被赋值的是outTitle、innerTitle、baz、f、l
//下面是嵌套赋值的例子
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
obj // {prop:123}
arr // [true]
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
这实际上说明,对象的解构赋值是下面形式的简写:
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };
2.2.1、对象的结构也可以指定默认值
// 对象的结构也可以指定默认值
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"
// 默认值生效的条件是,对象的属性值严格等于undefined。
var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null ——>属性x等于null,因为null与undefined不严格相等,所以是个有效的赋值,导致默认值3不会生效
对象结构的注意事项:
1、因为 JavaScript 引擎会将
{x}
理解成一个代码块,从而发生语法错误,所以不能将大括号写在行首,避免 JavaScript 将其解释为代码块。let x; {x} = {x: 1}; // SyntaxError: syntax error // 正确的写法 let x; ({x} = {x: 1});
2、解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式。
({} = [true, false]); ({} = 'abc'); ({} = []);
3、由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
let arr = [1,2,3]; let {0:first, [arr.length-1]:last} = arr first // 1 last // 3
3、函数参数的解构赋值
3.1、函数的参数也可以使用解构赋值。
function add([x, y]){
return x + y;
}
add([1, 2]); // 3
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]
上面等价于
let arr =[[1, 2], [3, 4]];
arr.map(([a, b]) => {
console.log(a + b)
})
map遍历的时候[a,b]参数对应的是arr数组中的第一项[1,2];所以第一次输出3,再次输出7