destructuring(解构赋值)_ES6笔记5

一.目标

从对象或者数组里取值并赋值给其它变量,以前得这样做:

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 [[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中文站提供的免费电子书

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code