解构赋值语法是一个 Javascript 表达式,这使得可以将值从数组或属性从对象提取到不同的变量中。
解构赋值的分类:数组解构赋值、对象解构赋值 、字符串解构赋值、布尔值解构赋值、 函数解构赋值、数值解构赋值。
1.数组解构赋值
等号右边不是数组的解构
let [a]=1;
let [a]=false;
let [a]=NaN;
let [a]=undefined;
let [a]=null;
let [a]={};
上面的表达式会报错,因为右边的值转化成对象后不具备可遍历的结构(前五个表达式),或者本身就不具备可遍历的结构(最后一个表达式)。
变量声明并赋值时的解构
let [a,b]=[1,2];
console.log(a,b); // 1 2
变量先声明后赋值时的解构
通过解构分离变量的声明,可以为一个变量赋值。
let a,b;
[a,b]=[1,2];
console.log(a,b); // 1 2
有默认值时的解构
let a,b;
[a=7,b=1]=[1];
console.log(a,b); // 1 1
如果一个数组的成员不严格等于undefined,默认值是不会生效的。
var [x=1] = [undefined]
console.log(x); // 1;
var [y=1] = [null];
console.log(y); // null
上面代码中,null 不严格等于 undefined,所以默认值不会生效。
默认值也可以是个表达式。
function a(){
console.log("aaa");
}
var [x=a()] = [1];
console.log(x); // 1
x可以取到值,所以a()不会执行。
默认值也可以是变量,但是该变量必须已经声明。
let [x=1,y=x] = [2];
console.log(x,y); // 2 2
let [a=b,b=1] = [2];
// ReferenceError
上述后面一个表达式报错,因为a用到默认值b时b还没声明。
不完全解构
即等号左边的模式只匹配等号右边数组的一部分。
let a,b;
[a,b]=[1,5,9];
console.log(a,b); // 1 5
这时候也是可以解构成功的。
左边的数组长度大于右边的数组长度时的结构
let [x] = [];
console.log(x); // undefined
let [a,b] = [5];
console.log(a,b); // 5 undefined
此时x和b都结构不成功,值都会等于undefined。
忽略某些返回值
function f(){
return [1,2,3,4,5]
}
let a,b,c;
[a,,,b]=f();
console.log(a,b); // 1 4
将剩余数组赋值给一个变量
当解构一个数组时,可以使用剩余模式,将数组剩余部分赋值给一个变量。
let a,b,rest;
[a,b,...rest] = [1,2,3,4,5,6]
console.log(a,b,rest); //1 2 [3,4,5,6]
右边数组长度不够时:
let a,rest;
[a,...rest] = [1]
console.log(a,rest); // 1 []
此时rest会返回空数组,这点需要额外注意。
注意:如果剩余元素右侧有一个逗号,会抛出SyntaxError,因为剩余元素必须是数组的最后一个元素。
2.对象解构赋值
对象的解构与数组类似,但有所不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
var {name,age}={name:"张三",age:45}
console.log(name,age); // "张三" 45
var {city} = {name:"张三"}
console.log(city); // undefined
上面代码city与右边的属性名不相同,导致取不到值,所以等于undefined。
基本赋值
var o = {p: 42, q: true};
var {p, q} = o;
console.log(p); // 42
console.log(q); // true
无声明赋值
通过解构可以无需声明来赋值一个变量。
var a, b;
({a, b} = {a: 1, b: 2});
赋值语句周围的( .. ) 是使用对象字面解构赋值时不需要声明的语法。{a, b} = {a: 1, b: 2}不是有效的独立语法,因为左边的{a, b}被认为是一个块而不是对象字面量。然而,({a, b} = {a: 1, b: 2})是有效的,正如 var {a, b} = {a: 1, b: 2}
注意:你的( .. ) 表达式需要一个分号在它前面,否则它也许会被当成上一行中的函数来执行。
解构嵌套对象
解构方式跟对象取值类似。
var obj={
p:[
"world",
{x:"hello"}
]
}
var {p:[text,{text2}]} = obj;
console.log(text,text2); // "world" "hello"
如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。
var {foo:baz} = {baz:'baz'} //报错
上面的代码中,等号左边对象的foo属性对应一个子对象。该子对象的baz属性解构时会报错,因为foo这时等于undefined,再取子属性就会报错。
3.字符串解构赋值
字符串也是可以解构赋值的。
const [a,b,c,d,e] = "hello";
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
上面的代码,字符串被转换成了一个类似数组的对象.
let {length:len} = "hello";
len // 5
类似数组的对象有length属性,所以可以对这个属性解构赋值。
4.数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
上面代码中,数值和布尔值的包装对象都有toString属性,因此变量s都能取到值。
解构赋值的规则是,只要等号右边的值不是对象,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
5.函数的解构赋值
函数的参数也可以使用解构赋值。
function add([x, y]){
return x + y;
}
add([1, 2]) // 3
上面代码中,函数add的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成变量x和y。对于函数内部的代码来说,它们能感受到的参数就是x和y。
6.解构赋值的用途
- 变量交换
- 接受函数返回值
- 选择性接受返回值
- 当不知道返回值数组长度时,取所需要的的数值。