数组解构

数组解构的语法看起来与对象解构非常相似,只是将对象字面量替换成了数组字面量。数组解构时,解构作用在数组内部的位置上,而不是作用在对象的具名属性上,例如:

let colors = [ "red", "green", "blue" ];

let [ firstColor, secondColor ] = colors;

console.log(firstColor);        // "red"
console.log(secondColor);       // "green"

此处数组解构从 colors 数组中取出了 "red""green",并将它们赋值给 fristColorsecondColor 变量。这些值被选择,是由于它们在数组中的位置,实际的变量名称是任意的(与位置无关)。任何没有在解构模式中明确指定的项都会被忽略。记住,数组本身并没有以任何方式被改变。

你也可以在解构模式中忽略一些项,并且只给感兴趣的项提供变量名。例如,若只想获取数组中的第三个元素,那么不必给前两项提供变量名。以下展示了这种方式:

let colors = [ "red", "green", "blue" ];

let [ , , thirdColor ] = colors;

console.log(thirdColor);        // "blue"

此代码使用了解构赋值来获取 colors 的第三个项。模式中 thirdColor 之前的逗号,是为数组前面的项提供的占位符。使用这种方法,你就可以轻易从数组任意位置取出值,而无须给其他项提供变量名。

与对象解构相似,在使用 varletconst 进行数组解构时,你必须提供初始化器。

解构赋值

你可以在赋值表达式中使用数组解构,但是与对象解构不同,不必将表达式包含在圆括号内,例如:

let colors = [ "red", "green", "blue" ],
    firstColor = "black",
    secondColor = "purple";

[ firstColor, secondColor ] = colors;

console.log(firstColor);        // "red"
console.log(secondColor);       // "green"

此代码中解构赋值的工作方式与上例相似,唯一区别是 firstColorsecondColor 变量已经被声明过了。大多数情况下,以上可能就是数组解构赋值你需要了解的全部内容,但其实还有一个很细微却又可能很有用的用法。

数组解构赋值有一个非常独特的用例,能轻易地互换两个变量的值。互换变量值在排序算法中十分常用,而在 ES5 中需要使用第三个变量作为临时变量,正如下例:

// Swapping variables in ECMAScript 5
let a = 1,
    b = 2,
    tmp;

tmp = a;
a = b;
b = tmp;

console.log(a);     // 2
console.log(b);     // 1

其中的 tmp 变量对于互换 ab 的值来说是必要的。然而若使用数组解构赋值,就不再需要这个额外变量。以下演示了在 ES6 中如何互换变量值:

// Swapping variables in ECMAScript 6
let a = 1,
    b = 2;

[ a, b ] = [ b, a ];

console.log(a);     // 2
console.log(b);     // 1

本例中的数组解构赋值看起来如同镜像。赋值语句左侧(即等号之前)的解构模式正如其他数组解构的范例,右侧则是为了互换而临时创建的数组字面量。b 与 a 的值分别被复制到临时数组的第一个与第二个位置,并对该数组进行解构,结果两个变量就互换了它们的值。

与对象解构赋值相同,若等号右侧的计算结果为 nullundefined,那么数组解构赋值表达式也会抛出错误。

默认值

数组解构赋值同样允许在数组任意位置指定默认值。当指定位置的项不存在、或其值为 undefined,那么该默认值就会被使用。例如:

let colors = [ "red" ];

let [ firstColor, secondColor = "green" ] = colors;

console.log(firstColor);        // "red"
console.log(secondColor);       // "green"

此代码的 colors 数组只有一个项,因此没有能与 secondColor 匹配的项,又由于此处有个默认值,secondColor 的值就被设置为 "green",而不是 undefined

嵌套的解构

与解构嵌套的对象相似,可以用类似的方式来解构嵌套的数组。在整个解构模式中插入另一个数组模式,解构操作就会下行到嵌套的数组中,就像这样:

let colors = [ "red", [ "green", "lightgreen" ], "blue" ];

// later

let [ firstColor, [ secondColor ] ] = colors;

console.log(firstColor);        // "red"
console.log(secondColor);       // "green"

此处的 secondColor 变量指向了 colors 数组中的 "green" 值,该项被包含在第二个数组中,因此解构模式就要把 secondColor 包裹上方括号。与对象解构相似,你也能使用任意深度的数组嵌套。

剩余项

第三章介绍过函数的剩余参数,而数组解构有个类似的、名为剩余项(rest items)的概念,它使用 …​ 语法来将剩余的项目赋值给一个指定的变量,此处有个范例:

let colors = [ "red", "green", "blue" ];

let [ firstColor, ...restColors ] = colors;

console.log(firstColor);        // "red"
console.log(restColors.length); // 2
console.log(restColors[0]);     // "green"
console.log(restColors[1]);     // "blue"

colors 数组的第一项被赋值给了 firstColor 变量,而剩余的则赋值给了一个新的 restColors 数组;restColors 数组则有两个项:"green""blue"。若要取出特定项并要求保留剩余的值,则剩余项是非常有用的,但它还有另一个有用的功能。

方便地克隆数组在 JS 中是个明显被遗漏的功能。在 ES5 中开发者往往使用的是一个简单的方式,也就是用 concat() 方法来克隆数组,例如:

// cloning an array in ECMAScript 5
var colors = [ "red", "green", "blue" ];
var clonedColors = colors.concat();

console.log(clonedColors);      //"[red,green,blue]"

尽管 concat() 方法的本意是合并两个数组,但不使用任何参数来调用此方法,就会获得原数组的一个克隆品。而在 ES6 中,你可以使用剩余项的语法来达到同样效果。实现如下:

// cloning an array in ECMAScript 6
let colors = [ "red", "green", "blue" ];
let [ ...clonedColors ] = colors;

console.log(clonedColors);      //"[red,green,blue]"

在本例中,剩余项被用于将 colors 数组的值复制到 clonedColors 数组中。虽然从感觉上来说,使用这种技术未必让开发者复制数组的意图体现得比使用 concat() 方法更明显,但这依然是个值得关注的技巧。

剩余项必须是数组解构模式中最后的部分,之后不能再有逗号,否则就是语法错误。