一.目标
从对象或者数组里取值并赋值给其它变量,以前得这样做:
var arr = [1, 2, 3, 4];
var first = arr[0];
var senond = arr[1];
var third = arr[3];
分解数组拿到元素值,并赋值。上面的过程就是:解构-赋值
ES6提出了新的概念:destructuring(解构赋值),能让上面的过程具有更好的可读性,避免类“硬编码”风格的代码
二.iterable解构
var/let/const [var1, var2...] = iterable
语法表示声明变量的同时进行数组/迭代器解构赋值
被解构的值必须是iterable,可以通过生成器语法便捷地让自定义对象成为iterable(见黯羽轻扬:for…of循环_ES6笔记1),iterable解构的特点如下:
可以对任意深度的嵌套数组进行解构
可以留空位跳过某些元素
可以用不定参数(
...var
语法,详细请查看黯羽轻扬:默认参数和不定参数_ES6笔记4)捕获所有剩余元素
例如:
// 数组
var [[first, [second]], third] = [[1, [2]], 4];
console.log(`first = ${first}`); // 1
console.log(`second = ${second}`); // 2
console.log(`third = ${third}`); // 4
// iterable
var iter = (function*(start) {
while (true) {
yield start++;
}
})(0);
var [v1, v2, v3, v4] = iter;
console.log(`v1 = ${v1}`); // 0
console.log(`v2 = ${v2}`); // 1
console.log(`v3 = ${v3}`); // 2
console.log(`v4 = ${v4}`); // 3
// 跳过元素、捕获剩余元素
var arr = [1, 2, 3, 4];
var [, sec, ...aRest] = arr;
console.log(`sec = ${sec}`); // 2
console.log(`aRest = ${aRest}`); // [3, 4]
类“硬编码”风格的代码都没有了,而且解构赋值更加清晰直观(左右对应)
三.对象解构
var/let/const {key: varName, ...} = obj
语法表示对象解构
特别注意:赋值顺序是从左向右的,实际效果是:varName = obj[key]
被解构的值必须能被强制转换为对象,所以解构undefined/null
会报错TypeError
对象解构的特点如下:
变量名与对象属性名一致时可以简写
可以只对特定属性名进行赋值(不需要留空位跳过)
支持复杂嵌套(对象+数组)
例如:
// obj
var obj = {name: 'aae', age: 12, sex: 'F'};
// 只对特定属性名进行赋值
var {name: mName, sex: mSex} = obj;
console.log(`mName = ${mName}`); // mName = aae
console.log(`mSex = ${mSex}`); // mSex = F
// 变量名与属性名相同时简写
var {name, sex} = obj;
console.log(`name = ${name}`); // name = aae
console.log(`sex = ${sex}`); // sex = F
注意,如果解构赋值左边没有var/let/const
(即忘记了声明变量,或者变量已经有了不希望再声明),会引发语法错误,如下:
// var key;
{key} = {key: 'val'};
// 报错:Uncaught SyntaxError: Unexpected token =(…)
因为赋值号左边的{key}
会被当作一个块({}
)来解析,避免这种行为的方案是给解构赋值添上圆括号,例如:
({key} = {key: 'val'});
console.log(`key = ${key}`); // key = val
圆括号里面的都是表达式,{key}
不会被误解析为块
四.解构同时设置默认值
语法与默认参数语法类似,例如:
// default val
var [val = 'default val'] = [];
var {key: val = 'default val'} = {};
// 属性名相同时可以简写为
// FF43,45都不支持,thinkjs,Chrome50支持
// var {val = 'default val'} = {};
console.log(`val = ${val}`);
一条语句既设置默认值,又解构赋值,但语法在更复杂的情况下语法有些难读(例如上面的var {key: val = 'default val'} = {};
)
五.总结
该特性也属于锦上添花的东西,减少类“硬编码”风格代码,增强其可读性
用途:
函数定义中的对象参数,比如
function ajax(config)
,改为function ajax({url, data, callback})
后API可读性更好,配合默认值非常方便(避免了类似var attr = config.attr || defultVal;
的操作)配合迭代器,遍历map很方便([key, val]遍历键值对,[key]遍历键集,[, val]遍历值集)
实现函数返回多个值(返回数组,接受返回值时解构为各个变量)
导入部分CommonJS模块,只解构需要用的部分。ES6模块的import支持相似的功能
例如:
// use
// 1
function ajax({url, data, callback}) {
console.log(`ajax(${url}, ${data}, ${callback})`);
}
ajax({url: 'www.xxx.xx', data: 'data'});
// log print: ajax(www.xxx.xx, data, undefined)
// 2
for (var [key, val] of new Map([['name', 'eea'], ['age', 12]])) {
console.log(`key = ${key}, val = ${val}`);
}
// log print: key = name, val = eea
// key = age, val = 12
// 3
var [res1, res2] = (function() {
return [1, {a: 1}];
})();
console.log(`res1 = ${res1}, res2 = ${res2}`);
// res1 = 1, res2 = [object Object]
参考资料
- 《ES6 in Depth》:InfoQ中文站提供的免费电子书