ES6中的解构赋值,在我的理解来看,就是把一个类型的数据分解构造,然后把值赋给另一个同样分解了构造的变量。下面是几种类型的解构赋值。
数组的解构赋值可以将等号右边对应位置的数值赋值给等号左边对应位置的变量
let [a,b,c]=[1,2,3];
a;//1
b;//2
c;//3
如果等号右边的数组长度小于左边数组的长度,就会出现解构不成功的情况,没有对应值的变量会被赋值为undefined,即使它之前有值。而如果等号右边数组的长度大于左边数组的长度,就会出现部分解构的情况,会把等号右边的数组的前几个值赋值给等号左边的数组中的变量。
let [a,b,c]=[1,2];
a;//1
b;//2
c;//undefined
let [a,b,c]=[1,2,3,4];
a;//1
b;//2
c;//3
而通过使用扩展运算符,当左边的参数个数少于右边的值的时候,就会把后边的值和为一个数组传给扩展运算符后的那个参数,如下代码,可以看到最后的z被赋了后面的3,4组成的数组。
var [x,y,...z]=[1,2,3,4];
console.log(x,y,z);
// 1 2 [3, 4]
上面的情况虽然有的变量会被赋值为undefined,但是至少没有报错,如果等号右边为不可遍历的结构,那么就会报错(转为对象后没有Iterator 接口,或者本身就没有Iterator 接口)Set和Map可以放在数组结构赋值的右边。
let [foo] = 1; //Uncaught TypeError: 1 is not iterable
let [foo] = false; //Uncaught TypeError: false is not iterable
let [foo] = NaN; //Uncaught TypeError: NaN is not iterable
let [foo] = undefined; //Uncaught TypeError: undefined is not iterable
let [foo] = null; //Uncaught TypeError: null is not iterable
let [foo] = {}; //Uncaught TypeError: {} is not iterable
同时,结构赋值允许使用默认值,如果变量严格等于undefined时,就会使用默认值,如果是null,是不会使用默认值的
var [a,b=2]=[1];
console.log("a:"+a+"b:"+b);//a:1b:2
var [a,b=2]=[1,undefined];
console.log("a:"+a+"b:"+b);//a:1b:2
var [a,b=2]=[1,null];
console.log("a:"+a+"b:"+b);//a:1b:null
如果默认值是一个表达式的话,那么只有在用到该默认值时才会执行该表达式
function fn(){
console.log('aaa');
}
let [a=fn()]=[1];
在上面的代码中,因为a会被赋值为1,默认值没有使用,所以里面的console语句没有执行。
在数组的解构赋值中,变量和值的位置是一一对应的,但是在对象中,值是不用按照一定顺序的,因为对象的解构赋值时通过找到相同的键名,然后给对应的键名键值,达到赋值的结果。
let {a,b}={a:1,b:2};
a;//1
b;//2
let {c,d}={d:4,c:3};
c;//3
d;//4
数组是特殊的对象,可以对数组使用对象的解构赋值,对应的属性名是索引
var {0:a,1:b,2:c}=[1,2,3];
a;//1
b;//2
c;//3
对象解构允许多次列出同一个源属性,即使用同一个源属性为多个变量赋值
var {a:x,a:y}={a:1};
console.log(x,y);
// 1 1
上面可以看到,x和y使用了同一个源属性a,所以最后的值都为1。
可以把解构赋值和扩展运算符结合来使用,同上面的数组运用一个道理
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
这里使用扩展运算符可以把除了对应赋值外的值合为一个对象赋给扩展运算符后的变量,若没有剩余的值,则扩展运算符后的变量被赋一个空对象。
var {x,y,...z}={x:3,y:4}
x//3
y//4
z//{}
要注意的是,扩展运算符必须放在最后的位置,否则会报错,在同一个解构赋值中使用两个扩展运算符也会报错,因为使用两个扩展运算符必然就会有一个扩展运算符不在最后的位置,从下面代码中浏览器报的错就可以看出来了。
var {x,...y,z}={x:3,y:4,a:1,b:2}
//Uncaught SyntaxError: Rest element must be last element
var {x,...y,...z}={x:3,y:4,a:1,b:2}
//Uncaught SyntaxError: Rest element must be last element
要注意的是,对于对象来说,如果省略了var/let/const,即是在赋值时使用扩展运算符而没牵扯到声明时,必须把整个赋值表达式用()括起来,否则左侧的花括号会被当作一个块级作用域,里面的都一个元素会被当作一个块语句。
var x,y;
var a={x:1,y:2};
{x,y}=a;
// Uncaught SyntaxError: Unexpected token =
var x,y;
var a={x:1,y:2};
({x,y}=a);
x // 1
y // 2
字符串的解构赋值是将字符串拆成一个个字符,对应赋值,使用对象的解构赋值来对字符串进行解构赋值,可以获得字符串的长度
let [a,b,c]='str';
a;//"s"
b;//"t"
c;//"r"
let {length:len}='str';
len;//3
这里可以通过解构赋值的规则来理解,只要等号右边的值不是对象或者数组,就先将其转为对象,而字符串对象有length属性,所以这里是先找到了'str'的length属性,将其值3赋值给len。
和字符串一样,数值和布尔值也是先转化为对象,然后找到对应的属性值进行赋值。
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
这与函数参数的默认赋值是相同的,通过在变量后直接使用=语法来给变量一个默认值
var [a=2,b=3,c=4]=[1,1];
console.log(a,b,c); // 1 1 4
var {x=5,y=6,z=7}={x:1,y:1};
console.log(x,y,z); // 1 1 7
可以看到上面代码中,最后一个变量对应的位置都没有值,所以最后使用了默认值。
如果解构的值中有嵌套的数组或对象,也可以解构这些嵌套的值
var [a,[b,c]]=[1,[2,3]];
console.log(a,b,c); // 1 2 3
var {x:{y:{z:w}}}={x:{y:{z:6}}};
console.log(w); // 6
var a=1;
var b=2;
console.log("a:"+a+" b:"+b);//a:1 b:2
[a,b]=[b,a];
console.log("a:"+a+" b:"+b);//a:2 b:1
function fn(){
return [1,2,3,4];
}
var [a,b,c,d]=fn();
a;//1
b;//2
c;//3
d;//4
function fn({a,b}){
console.log("a:"+a+" b:"+b);
}
fn({b:2,a:1});//a:1 b:2
通过上面的这种方法,可以给方法传入几个固定命名的值,在很多情况相当方便实用。
var json={
user:"me",
id:111
}
var {user,id}=json;
console.log("user:"+user+" id:"+id);//user:me id:111
对于数组解构赋值和对象解构赋值来说,不需要把存在的所有值都用来赋值,可以只用其中一部分,数组是通过空出不需要的值的位置,而对象是显式写出需要的值所处的位置。
var arr=[1,2,3];
var [,x,]=arr;
console.log(x); // 2
var obj={x:4,y:5,z:6};
var {y:a}=obj;
console.log(a); // 5
参考自阮一峰的《ECMAScript6入门》
Kyle Simpson的《你不知道的JavaScript 下卷》
ES6学习笔记目录(持续更新中)
ES6学习笔记(一)let和const
ES6学习笔记(二)参数的默认值和rest参数
ES6学习笔记(三)箭头函数简化数组函数的使用
ES6学习笔记(四)解构赋值
ES6学习笔记(五)Set结构和Map结构
ES6学习笔记(六)Iterator接口
ES6学习笔记(七)数组的扩展
ES6学习笔记(八)字符串的扩展
ES6学习笔记(九)数值的扩展
ES6学习笔记(十)对象的扩展
ES6学习笔记(十一)Symbol
ES6学习笔记(十二)Proxy代理
ES6学习笔记(十三)Reflect对象
ES6学习笔记(十四)Promise对象
ES6学习笔记(十五)Generator函数
ES6学习笔记(十六)asnyc函数
ES6学习笔记(十七)类class
ES6学习笔记(十八)尾调用优化
ES6学习笔记(十九)正则的扩展
ES6学习笔记(二十)ES Module的语法