ECMAScript 6 之 解构

解构是一个非常实用的语言特性。比如,在封装一个组件时,经常会暴露一个 options,之前我们往往会这么写:

1
2
3
4
5
6
7
8
let options = { // 传入的 options
repeat: true,
save: false
};

// 解析
let repeat = options.repeat || true,
save = options.save || true;

对传入的 options 各项设置默认值,并取得实际值。稍微复杂点的 options 就能折磨得你对编程失去耐心。出于对前端工程师的怜悯,ECMAScript 6 引入解构来拯救大家。之后的代码就可以这么写:

1
2
3
4
let {
repeat = true,
save = true
} = options;

当然,这只是一个简单的示例。对照着 ECMAScript 6 规范,我们慢慢分析下。解构的目标对象有 对象 和 数组。我们先针对 对象看下。

对象解构

先看最简单的形式:

1
2
3
4
5
let node = {
type: "Identifier",
name: "foo"
};
let { type, name } = node;

对照规范中步骤,首先初始化绑定:

  1. 对表达式右侧进行求值,得到 value,value 不能为 null 和 undefined。如果 value 是基本类型,会转换为对象类型。
  2. 对属性列从做到右执行绑定初始化:使用 value,environment 作为参数
  3. 对每个属性的绑定初始化:
    使用 value,environment,propertyName 执行 KeyedBindingInitialization 。这儿的propertyName 如果有属性名就是 属性名,没有就是绑定名。
    1
    let { type: localType, name: localName } = node; // 这种情况的属性名 就是 type

执行 KeyedBindingInitialization 过程:
参数: value,environment,propertyName

SingleNameBinding: BindingIdentifierInitializer

  1. 令 bindingId 为 BindingIdentifier 的字符串值
  2. 令 lhs 为 ResolveBinding(bindingId, environment) 的值
  3. 令 v 为 GetV(value, propertyName) 值
  4. 如果存在 Initializer 并且 v 是 undefined 则:
    a. 令 defaultValue 为执行 Initializer 的结果
    b. 令 v 为 GetValue(defaultValue) 的值
    c. 如果 Initializer 是匿名函数, 则
    1. 令 hasNameProperty 为 HasOwnProperty(v, "name").
    2. 如果 hasNameProperty 为 false,执行 SetFunctionName(v, bindingId).   
    
  5. 如果 environment 是 undefined 返回 PutValue(lhs, v)
  6. 返回 InitializeReferencedBinding(lhs, v)

这个过程就是简单的 获取引用,设置绑定。

还有需要递归的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let node = {
type: "Identifier",
name: "foo",
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
}
};

// extract node.loc.start
let { loc: { start: localStart }} = node;

上面的 { start: localStart } 又需要解构,使用参数 node[loc]environment

数组解构

数组解构场景更多:比如交换数值
[ a, b ] = [ b, a ];
对照规范,解析数组解构步骤:

  1. 数组解构,右侧期望值一个 迭代器,或者能够转换为迭代器的对象。
  2. 从左至右执行绑定初始化。
  3. 执行 IteratorBindingInitialization

数组解构的绑定初始化,多了的剩余参数的处理。对剩余参数会收集迭代器余下元素到数组 A 中,然后以 A 和 environment 为参数执行 BindingInitialization 。

另外,还可以解构参数。可以详细阅读 解构参数


Understanding ECMAScript 6