>>>> 1. 什么是解构赋值?
解构赋值允许你使用类似数组或对象字面量的语法将数组和对象的属性赋给各种变量。这种赋值语法极度简洁,同时还比传统的属性访问方法更为清晰。
通常来说,你很可能这样访问数组中的前三个元素:1
2
3var first = someArray[0];
var second = someArray[1];
var third = someArray[2];
如果使用解构赋值的特性,将会使等效的代码变得更加简洁并且可读性更高:1
var [first, second, third] = someArray;
SpiderMonkey(Firefox的JavaScript引擎)已经支持解构的大部分功能,但是仍不健全。你可以通过bug 694100(https://bugzilla.mozilla.org/show_bug.cgi?id=694100)跟踪解构和其它ES6特性在SpiderMonkey中的支持情况。
>>>> 2. 数组与迭代器的解构
以上是数组解构赋值的一个简单示例,其语法的一般形式为:
1 | [ variable1, variable2, ..., variableN ] = array; |
这将为variable1到variableN的变量赋予数组中相应元素项的值。如果你想在赋值的同时声明变量,可在赋值语句前加入var、let或const关键字,例如:1
2
3var [ variable1, variable2, ..., variableN ] = array;
let [ variable1, variable2, ..., variableN ] = array;
const [ variable1, variable2, ..., variableN ] = array;
事实上,用变量来描述并不恰当,因为你可以对任意深度的嵌套数组进行解构:1
2
3
4
5
6
7var [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo);
// 1
console.log(bar);
// 2
console.log(baz);
// 3
此外,你可以在对应位留空来跳过被解构数组中的某些元素:1
2
3var [,,third] = ["foo", "bar", "baz"];
console.log(third);
// "baz"
而且你还可以通过“不定参数(http://www.infoq.com/cn/articles/es6-in-depth-rest-parameters-and-defaults)”模式捕获数组中的所有尾随元素:1
2
3var [head, ...tail] = [1, 2, 3, 4];
console.log(tail);
// [2, 3, 4]
当访问空数组或越界访问数组时,对其解构与对其索引的行为一致,最终得到的结果都是:undefined。1
2
3
4
5console.log([][0]);
// undefined
var [missing] = [];
console.log(missing);
// undefined
>>>> 3. 对象的解构
通过解构对象,你可以把它的每个属性与不同的变量绑定,首先指定被绑定的属性,然后紧跟一个要解构的变量。
1 | var robotA = { name: "Bender" }; |
当属性名与变量名一致时,可以通过一种实用的句法简写:1
2
3
4
5var { foo, bar } = { foo: "lorem", bar: "ipsum" };
console.log(foo);
// "lorem"
console.log(bar);
// "ipsum"
与数组解构一样,你可以随意嵌套并进一步组合对象解构:1
2
3
4
5
6
7
8
9
10
11var complicatedObj = {
arrayProp: [
"Zapp",
{ second: "Brannigan" }
]
};
var { arrayProp: [first, { second }] } = complicatedObj;
console.log(first);
// "Zapp"
console.log(second);
// "Brannigan"
当你解构一个未定义的属性时,得到的值为undefined:1
2
3var { missing } = {};
console.log(missing);
// undefined
请注意,当你解构对象并赋值给变量时,如果你已经声明或不打算声明这些变量(亦即赋值语句前没有let、const或var关键字),你应该注意这样一个潜在的语法错误:1
2{ blowUp } = { blowUp: 10 };
// Syntax error 语法错误
为什么会出错?这是因为JavaScript语法通知解析引擎将任何以{开始的语句解析为一个块语句(例如,{console}是一个合法块语句)。解决方案是将整个表达式用一对小括号包裹:1
2({ safe } = {});
// No errors 没有语法错误
>>>> 5. 默认值
当你要解构的属性未定义时你可以提供一个默认值:1
2
3
4
5
6
7
8
9var [missing = true] = [];
console.log(missing);
// true
var { message: msg = "Something went wrong" } = {};
console.log(msg);
// "Something went wrong"
var { x = 3 } = {};
console.log(x);
// 3
(译者按:Firefox目前只实现了这个特性的前两种情况,第三种尚未实现。详情查看bug 932080:https://bugzilla.mozilla.org/show_bug.cgi?id=932080。)
>>>> 6. 解构的实际应用
函数参数定义
作 为开发者,我们需要实现设计良好的API,通常的做法是为函数为函数设计一个对象作为参数,然后将不同的实际参数作为对象属性,以避免让API使用者记住 多个参数的使用顺序。我们可以使用解构特性来避免这种问题,当我们想要引用它的其中一个属性时,大可不必反复使用这种单一参数对象。
1 | function removeBreakpoint({ url, line, column }) { |
这是一段来自Firefox开发工具JavaScript调试器(同样使用JavaScript实现——没错,就是这样!)的代码片段,它看起来非常简洁,我们会发现这种代码模式特别讨喜。
配置对象参数
延伸一下之前的示例,我们同样可以给需要解构的对象属性赋予默认值。当我们构造一个提供配置的对象,并且需要这个对象的属性携带默认值时,解构特性就派上用场了。举个例子,jQuery的ajax函数使用一个配置对象作为它的第二参数,我们可以这样重写函数定义:
1 | jQuery.ajax = function (url, { |
如此一来,我们可以避免对配置对象的每个属性都重复var foo = config.foo || theDefaultFoo;这样的操作。
编者按:不幸的是,对象的默认值简写语法仍未在Firefox中实现,我知道,上一个编者按后的几个段落讲解的就是这个特性。点击bug 932080:https://bugzilla.mozilla.org/show_bug.cgi?id=932080查看最新详情。
>>>> 6. 文后盘点
所以,正如你所见,解构在许多独立小场景中非常实用。在Mozilla我们已经积累了许多有关解构的使用经验。十年前,Lars Hansen在Opera中引入了JS解构特性,Brendan Eich随后就给Firefox也增加了相应的支持,移植时版本为Firefox 2。所以我们可以肯定,渐渐地,你会在每天使用的语言中加入解构这个新特性,它可以让你的代码变得更加精简整洁。
我说过,ES6很可能改变你写JavaScript的方式。这正是我日思夜想的特性:轻松学习,简单改进,合力出击,优化项目,在不断的进化中改革这门语言。
感谢团队对于整个ES6解构特性的努力,特别感谢Tooru Fujisawa(arai)和Arpad Borsos(Swatinem)的出色贡献。
Chrome中有关解构的支持正在开发中,其它浏览器也将适时增加支持。现在,如果你想在Web上使用解构功能,你需要使用Babel(http://babeljs.io/)或Traceur(https://github.com/google/traceur-compiler#what-is-traceur)将ES6代码转译为相应的ES5代码。