在 ES6 之前的版本中,从对象或数组中获取信息,并将特定数据存入本地变量,需要书写许多并且相似的代码,例如:
1 | let options = { |
此代码提取了 options
对象的 repeat
与 save
值,并将其存在同名的本地变量上。
ES6 的解构实际使用的语法就是对象与数组的字面量语法,即在赋值语句的左侧使用对象字面量,例如:
1 | let node = { |
在此代码中,node.type
的值被存储到 type
本地变量中,node.name
的值则存储到 name
变量中。此语法相同于简写的属性初始化器。
1.初始化器
当使用解构配合 var
、let
或 const
来声明变量时,必须提供初始化器(即等号右边的值)。
下面的代码都会因为缺失初始化器而抛出错误:
1 | // 语法错误 |
const
总是要求有初始化器,即使没有使用解构的变量;而 var
与 let
仅在使用解构时才作此要求。
2.解构赋值
以上对象解构都用于变量声明。不过,也可以在赋值的时候使用解构。例如,你可能想在变量声明之后改变它们的值,例如:
1 | let node = { |
在本例中,type
与 name
属性在声明时被初始化,而两个同名变量也被声明并初始化为不同的值。接下来一行使用了解构表达式,通过读取 node
对象来更改这两个变量的值。
必须使用圆括号包裹解构赋值语句,这是因为暴露的花括号会被解析为代码块语句,而块语句不允许在赋值操作符(=
)左侧出现。圆括号标示了里面的花括号并不是块语句,而应该被解析为表达式,从而允许完成赋值操作。
解构赋值表达式的值为表达式右侧的值,也就是说在任何期望有个值的位置都可以使用解构赋值表达式。例如,传递值给函数:
1 | let node = { |
outputInfo()
函数被使用一个解构赋值表达式进行了调用。该表达式计算结果为 node
,因为这就是表达式右侧的值。对 type
与 name
的赋值正常进行,同时 node
也被传入了 outputInfo()
函数。
当解构赋值表达式右侧的计算结果为 null
或 undefined
时,会抛出错误。因为任何读取 null
或 undefined
的企图都会导致‘运行时’错误(runtime error
)。
3.默认值
当使用解构赋值语句时,如果所指定的本地变量在对象中没有找到同名属性,那么该变量会被赋值为 undefined
。例如:
1 | let node = { |
此代码定义了一个额外的本地变量 value
,并试图对其赋值。然而,node
对象中不存在同名属性,因此 value
不出预料地被赋值为 undefined
。
你可以选择性地定义一个默认值,以便在指定属性不存在时使用该值。若要这么做,需要在属性名后面添加一个等号并指定默认值,例如:
1 | let node = { |
4.赋值给不同的本地变量名
ES6 有一个扩展语法,允许在给本地变量赋值时使用一个不同的名称,而且该语法看上去就像是使用对象字面量的非简写的属性初始化。例如:
1 | let node = { |
此代码使用解构赋值来声明 localType
与 localName
变量,分别获得了 node.type
与 node.name
属性的值。
type: localType
这种语法表示要读取名为 type
的属性,并把它的值存储在变量 localType
上。
该语法实际上与传统对象字面量语法相反,传统语法将名称放在了冒号左边、值放在冒号右边;而在本例中,则是名称在右边,需要进行值读取的位置则被放在了左边。
也可以给变量别名添加默认值,依然是在本地变量名称后面添加等号与默认值,例如:
1 | let node = { |
5.嵌套的对象解构
使用类似于对象字面量的语法,可以深入到嵌套的对象结构中去提取想要的数据。例如:
1 | let node = { |
本例中的解构模式使用了花括号,表示应当下行到 node
对象的 loc
属性内部去寻找 start
属性。
每当有一个冒号在解构模式中出现,就意味着冒号之前的标识符代表需要检查的位置,而冒号右侧则是赋值的目标。当冒号右侧存在花括号时,表示目标被嵌套在对象的更深一层中。
还能更进一步,在对象的嵌套解构中同样能为本地变量使用不同的名称:
1 | let node = { |
在此例中,node.loc.start
的值被存储在一个新的本地变量 localStart
上,解构模式可以被嵌套在任意深度的层级,并且在每个层级的功能都一样。
对象解构十分强大并有很多可用形式,而数组解构则提供了一些独特的能力,用于提取数组中的信息。
语法难点
使用嵌套的解构时需要小心,因为你可能无意中就创建了一个没有任何效果的语句。空白花括号在对象解构中是合法的,然而它不会做任何事。例如:
1 | // 没有变量被声明! |
在此语句中并未声明任何变量绑定。由于花括号在右侧,loc
被作为需检查的位置来使用,而不会创建变量绑定。这种情况仿佛是想用等号来定义一个默认值,但却被语法判断为想用冒号来定义一个位置。
这种语法将来可能是非法的,然而现在它只是需要留意的一个疑难点。