【问题标题】:Array destructuring and spread operator数组解构和扩展运算符
【发布时间】:2018-12-21 00:20:50
【问题描述】:

我不是 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结尾,而不是抛出异常?这究竟是如何工作的?

【问题讨论】:

  • ...a 如何分配给4 它没有。什么让你有那个想法?您看到的输出是评估[0, ...a, 4] 的结果。 [x, y, ...a ] = foo 表示“将可迭代foo 的第一个值分配给x,第二个分配给y,其余作为数组分配给a
  • 我明白了。现在可以理解为什么a 的输出是[2, 3, 4]

标签: javascript arrays destructuring


【解决方案1】:

在第一个例子中,spread 即... 在 LHS 中充当收集器,而在 RHS 中它充当spread/rest。即,当变量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,其余分配给数组a按此顺序)。因此,数组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);

最后,回到你的最后一个问题:“不过,我不清楚 ...a 是如何分配给 4 的?”

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

您可以阅读有关扩展语法here (MDN)here (YDKJS) 的更多信息。

【讨论】:

    【解决方案2】:

    不过,我不清楚 ...a 是如何分配给 4 的。

    不是。

    让我们分开一点:

    在赋值的右侧,您使用了一个带有 spread element 的数组字面量。 a 的值被“展平”到新数组中。

    因此,[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]));

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

    • 将iterable的第一个值赋给x
    • 将iterable的第二个值赋给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]

    其实JS在做的时候会抛出异常:...a = 4;

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

    ... 本身并不意味着什么。它不是运算符,而是标点符号(如 ;,),根据使用(和允许)的上下文具有不同的含义。

    另见What is SpreadElement in ECMAScript documentation? Is it the same as Spread operator at MDN?

    【讨论】:

      【解决方案3】:

      ...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);
      

      【讨论】:

        【解决方案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]

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-12-20
          • 2018-11-01
          • 2018-02-16
          • 1970-01-01
          • 1970-01-01
          • 2016-06-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多