解析ES6数组的解构赋值


基本用法

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
以前,为变量赋值,只能直接指定值。


数组的解构赋值

var a = 1
var b = 2
var c = 3

ES6允许写成下面这样。

var [a, b, c] = [1, 2, 3];

上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。

var [foo = true] = [];
foo // true
[x, y = 'b'] = ['a'] // x='a', y='b' [x, y = 'b'] = ['a', undefined] // x='a', y='b'

注意,ES6内部使用严格相等运算符(=== ),判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined ,默认值是不会生效的。


对象的解构赋值

对象字面量的语法形式是在一个赋值操作符左边放置一个对象字面量;

对象的解构与数组有一个重要的不同。

数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

var { bar, foo } = { foo: "aaa", bar: "bbb" }; 
foo // "aaa"
bar // "bbb"
var { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined

上面代码的第一个例子,等号左边的两个变量的次序,与等号右边两个同名属性的次序不一致,但是对取值完全没有影响。第二个例子的变量没有对应的同名属性,导致取不到值,最后等于undefined 。
如果变量名与属性名不一致,必须写成下面这样。

var { foo: baz } = { foo: "aaa", bar: "bbb" }; 
baz // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'

这实际上说明,对象的解构赋值是下面形式的简写

var { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };

也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。


基本数组结构

let [a, b, c] = [1, 2, 3];
// a = 1 // b = 2 // c = 3

解析一个从函数返回的数组

从一个函数返回一个数组是十分常见的情况。解构使得处理返回值为数组时更加方便。

在下面要让 [1, 2] 成为函数的 f() 的输出值,可以使用解构在一行内完成解析。

function f() {
  return [1, 2];
}

var a, b;
[a, b] = f();
console.log(a); // 1
console.log(b); // 2

解构对象时会查找原型链(如果属性不在对象自身,将从原型链中查找)

// 声明对象 和 自身 self 属性
var obj = {self: 'hello'};
// 在原型链中定义一个属性 prot
obj.__proto__.prot = 'word';
// test
const {self, prot} = obj;
// self "hello"
// prot "word"(访问到了原型链)

将剩余数组赋值给一个变量

当解构一个数组时,可以使用剩余模式,将数组剩余部分赋值给一个变量。

var [a5, ...b5] = [1, 2, 3];
console.log(a5); // 1
console.log(b5); // [2, 3]
let {a, b, ...res} = {a: 10, b: 20, c: 30, d: 40};
console.log(a) // a = 10 
console.log(res)  // res = {c: 30, d: 40};

圆括号问题

解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。
由此带来的问题是,如果模式中出现圆括号怎么处理。ES6的规则是,只要有可能导致解构的歧义,就不得使用圆括号。
但是,这条规则实际上不那么容易辨别,处理起来相当麻烦。因此,建议只要有可能,就不要在模式中放置圆括号。

三种解构赋值不得使用圆括号。

  • 变量声明语句中,模式不能带有圆括号。
  • 函数参数中,模式不能带有圆括号
  • 不能将整个模式,或嵌套模式中的一层,放在圆括号之中

可以使用圆括号的情况:

[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确

可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。


Author: xt_xiong
转载要求: 如有转载请注明出处 :根据 CC BY 4.0 告知来自 xt_xiong !
评论
  标题