按照一定模式,从数组和对象中提取,对变量进行赋值,称为解构
通过解构我们可以让赋值更优雅便捷
// 一般赋值
var a = 1,
b = 2,
c = 3;
//解构赋值
var [a, b, c] = [1, 2, 3];
当然不仅仅是var,let和const也可以
let arr = [1, 2, 3]
const [a, b, c] = arr;
语法本质
实质上这个语法就是一种模式匹配
如果等号两边模式相同
左边变量就会被赋予相应值
所以下面的形式也可以正常赋值
var [a, [b, [c, d]]] = [1, [2, [3, 4]]];
console.log(a, b, c, d);//1 2 3 4
不过我们完全没有必要写这么复杂
特殊用法
解构赋值还可以和“…”配合使用
如果“…”在等号左边
那么就会把剩余的值合并为一个数组
这个操作符只能写在最后一个变量前面
var [left, ...right] = [1, 2, 3, 4, 5];
console.log(left, right);//1 [2,3,4,5]
如果“…”在等号右边
就是把数组展开再赋值
var arr = [2, 3, 4];
var [a, b, c, d] = [1, ...arr];
console.log(a, b, c, d);//1 2 3 4
(“…”叫做展开操作符,以后我还会细讲)
解构失败与不完全解构
如果没有在匹配中没有对应值,那么它的值就是undefined
也就是解构失败
等号右边少值
var [a, b, c] = [1, 2];
console.log(a, b, c);//1 2 undefined
与它相对的就是不完全解构
等号左边少值
var [a, b] = [1, 2, 3];
console.log(a, b);//1 2
错误解构
如果等号右边不是数组(不是可遍历解构)
就会报错
比如说这些情况是不能赋值解构的
var [foo] = 1/true/NaN/undefined/null/{};
下面的情况也是不可以的
var [a, [b]] = [1, 2];
它可以拆成var a = 1;
和var [b] = 2;
第二个同样不能解构赋值所以会报错
默认赋值
可以使用下面这种语法实现默认的赋值
var [foo = 1] = [];
console.log(foo); //1
只有当右侧的值严格等于undefined才会使用默认赋值
var [foo = 1] = [null];
console.log(foo); //null
由于 null !== undefined
所以这里foo被赋予null
惰性赋值
惰性赋值说的是默认赋值的机制
只有在需要使用默认值的时候
才会去求值
function foo(){
alert(' ');
return 123;
}
var [a = foo()] = [1]; //不弹窗
console.log(a); //1
var [a = foo()] = []; //弹窗
console.log(a); //123
解构顺序
解构赋值首先会看右边有没有与之对应的值
没有的话从左向右解析
var [a = 1, b = a] = [];
console.log(a, b); //1 1
这段代码就相当于
var a = 1;
var b = a;
var [a = b, b = 1] = [];
console.log(a, b); //undefined 1
注意
如果这里var 换成let就不一样了
let [a = b, b = 1] = [];
console.log(a, b); //报错
这段代码可以看成
let a = b;
let b = 1;
由于let声明没有变量提升
所以此时b还未声明就会报错
可以看看这道题
var [x1 = 1, y1 = x1] = [];
var [x2 = 1, y2 = x2] = [2];
var [x3 = 1, y3 = x3] = [1,2];
var [x4 = y4, y4 = 1] = [];
console.log(x1,y1);//1 1
console.log(x2,y2);//2 2
console.log(x3,y3);//1 2
console.log(x4,y4);//undefined 1
同理如果上面的第四行的var换成let会报错
对象解构
上面我们通过数组的形式了解了解构赋值
其实解构赋值不仅仅可以用数组
对象也可以
它们类似的地方就不再赘述了
基本用法
对象的解构赋值是按照属性名(键)决定的
如果没有找到对应的属性,那就赋予undefined
var {foo, bar, foobar} = {
foo: 1,
bar: 2
}
console.log(foo, bar, foobar);//1 2 undefined
对于已经声明过的变量要注意
var a;
{a} = {a: 1}; //错误
浏览器会报错
因为js引擎把它理解成了代码块
而内部的代码它不认识
解决办法就是加上括号
这样浏览器就可以知道这是一个表达式
var a;
({a} = {a: 1});
但是如果我们想要声明的变量与属性名不同怎么办呢
我们可以使用另一种模式
var {foo: a, bar: b, foobar: c = 100} = {
foo: 1,
bar: 2
}
console.log(a, b, c);//1 2 100
这相当于声明了a和b变量
同样可以使用默认赋值
字符串解构赋值
var [a, b, c, d, e] = 'hello';
console.log(a, b, c, d, e); //h e l l o
字符串被转化为基本包装对象(类数组对象)
所以可以实现
var {length : len} = 'hello';
console.log(len); //5
同理这个类数组对象中有length属性
基本值解构赋值
如果等号右边是数字或者布尔值
也同样会转化为包装对象
let {toString: a} = 123;
let {toString: b} = true;
console.log( a === Number.prototype.toString); //true
console.log( b === Boolean.prototype.toString); //true
但注意null和undefined没有封装对象
下面的代码会报错
let {toString: x } = undefined; //错误
let {toString: y } = null; //错误
函数参数的结构赋值
function add([x, y]) {
return x + y;
}
console.log(add([1, 2]));
函数参数表面上是一个数组
但在传入参数时,数组参数就被结构成变量 x 和 y
相当于var [x, y] = [1, 2]
function foo({x = 0, y = 0} = {}){
console.log([x, y]);
}
foo({x: 1,y: 2}); //[1, 2]
foo({x: 1}); //[1, 0]
foo({}); //[0, 0]
foo(); //[0, 0]
function bar({x, y} = {x: 0, y: 0}){
console.log([x, y]);
}
bar({x: 1,y: 2}); //[1, 2]
bar({x: 1}); //[1, undefined]
bar({}); //[undefined, undefined]
bar(); //[0, 0]
解构赋值的应用
除了交换变量以外
解构赋值还有很多用途
函数多值返回
function demo(){
return [1, 2, 3];
}
var [a, b, c] = demo();
函数定义参数
function demo({a, b, c}){
...
}
demo({a: 1, b: 2, c: 3});
提取JSON数据
var jsonData= {
id: 66,
status: 'OK',
data: [123, 456]
}
let {id, status, data:number} = jsonData;