数组解构和展开运算符

Array destructuring and spread operator

我不是 100% 清楚这段代码是如何工作的:

var a = [1, 2, 3];

[x, y, ...a ] = [0, ...a, 4];

// OUTPUT:  [0, 1, 2, 3, 4]

我正在使用 ... 运算符解构数组 a

我期待在第二行中进行大量作业。

x 将被赋值给 0,y 将被赋值给 ...a(它将数组 a 中的元素作为单独的值传递)。

不过,我不清楚 ...a 是如何分配给 4 的。实际上,JS 在执行以下操作时会抛出异常:

...a = 4;
// Uncaught SyntaxError: Rest parameter may not have a default initializer

为什么这段代码输出修改后的数组,结尾为4,而不是抛出异常?这究竟是如何工作的?

执行如下

var a = [1, 2, 3];
[x, y, ...a ] = [0, ...a, 4];
[x, y, ...a ] = [0, 1, 2, 3, 4];

这意味着 RHS 数组中的第一个值分配给 x,RHS 数组中的第二个值分配给 y,其余值分配给 a.

因此,x 的值为 0y1a[2, 3, 4]

...a 等于 .slice(start, end)(左,解构)或 .concat(a)(右,扩展):

 [0, ...a, 4]

等于:

[0].concat(a).concat([4]) // [0,1,2,3,4]

鉴于:

[x, y, ...a] = array

等于:

x = array[0];
y = array[1];
a = array.slice(2);

It's not clear to me, though, how the ...a get assigned to 4.

不是。

让我们把事情分开一点:

在作业的右侧,您正在使用带有 展开元素 的数组文字。 a的值是"flattened"到新数组中。

因此,[0, ...a, 4] 等同于 [0].concat(a, [4])。结果是一个新数组。

var a = [1, 2, 3];

console.log('spread element', [0, ...a, 4]);
console.log('concat', [0].concat(a, [4]));

在左侧,您正在使用带有 剩余元素 的数组解构。 [x, y, ...a ]表示

  • 将可迭代对象的第一个值赋给x
  • 将可迭代对象的第二个值赋给y
  • 将可迭代的剩余值作为数组分配给a

这两个是等价的:

var a = [1,2,3,4];
var [x, y, ...z] = a;
console.log('destructuring', x, y, z);

var x = a[0];
var y = a[1];
var z = a.slice(2);
console.log('manual + slice', x, y, z);


当然把这两者结合起来就可以了。在赋值中,左侧不关心右侧的计算方式,反之亦然。

您的示例令人困惑的是,您在解构赋值中再次使用 a,但这与用新值覆盖 a 的值相同。然而最终的结果是

  • [0, ...a, 4] 结果是 [0,1,2,3,4] 因此
  • x 的值为 0
  • y 的值为 1
  • a 的值为 [2,3,4]

In fact, JS throws an exception when doing: ...a = 4;

您收到的错误消息很奇怪。这真的应该只是一个语法错误。

... 本身没有任何意义。它不是运算符,它是一个标点符号(如 ;,),根据使用(和允许)的上下文具有不同的含义。

另见

在第一个示例中,传播即 ... 在 LHS 中充当收集器,而在 RHS 中它充当 spread/rest。 IE 你正在为变量 a 赋值,当它在 LHS 上时。

var a = [1, 2, 3];

[x, y, ...a ] = [0, ...a, 4];

console.log(a)

让我们一步步来:

让我们从 RHS 开始。执行 [0, ...a, 4] 将生成 [0, 1, 2, 3, 4]。自己看看:

var a = [1, 2, 3];

console.log([0, ...a, 4]);

现在,LHS 是进行分配的一侧。在 RHS 上,将任何带有扩展运算符的变量想象成一个 array 准备好分配新值。

因此,我们尝试将 [0, 1, 2, 3, 4] 分配给变量 x,然后分配给 y,其余分配给数组 ain该订单)。因此,数组 a 将拥有前两次赋值后剩下的任何内容(即 2, 3, 4)。

var a = [1, 2, 3];

// a will get overwritten
[x, y, ...a ] = [0, 1, 2, 3, 4];
// same as [x, y, ...a ] = [0, ...a, 4];

console.log(a);

最后,回到你的最后一个问题:"It's not clear to me, though, how the ...a get assigned to 4? "

答:不是。但是,如果您执行 [...a] = [4] 之类的操作,则会生成一个名为 a 的数组,其中包含 [4]

您可以阅读有关传播语法的更多信息 here (MDN) and here (YDKJS)