【问题标题】:Javascript unusual behavior regarding Array containing 1...N using spread operator关于使用扩展运算符包含 1...N 的数组的 Javascript 异常行为
【发布时间】:2021-04-28 06:52:59
【问题描述】:

在 Javascript 中,我通过扩展运算符制作了这个简单的升序数组。

[...Array(5).keys()]
// printed list
[0, 1, 2, 3, 4]

但我只是添加了 1 并生成了这个意想不到的数组。 (我只是预计这会是一个错误)

[...Array(5).keys() + 1] 
// printed list
["[", "o", "b", "j", "e", "c", "t", " ", "A", "r", "r", "a", "y", " ", "I", "t", "e", "r", "a", "t", "o", "r", "]", "1"]

我想知道是什么造成了这种行为。

【问题讨论】:

    标签: javascript arrays object key


    【解决方案1】:

    首先,计算... 右侧的表达式。也就是说,Array(5).keys() + 1 被评估,然后该评估的结果被传播。对表达式进行分组可能会使事情变得更清晰:

    [...(Array(5).keys() + 1)] 
    

    所以,在上面,我们从计算Array(5).keys() + 1 的结果开始。 + 运算符在原始操作数之间工作。当您执行Array(5).keys() 时,您会得到一个未归类为原语的迭代器。因此,JS 会尝试将其转换为原语。当 JS 尝试在这种情况下将迭代器转换为原语时,它会尝试:

    1. 调用迭代器的Symbol.toPrimitive 方法,因为它不存在,它继续尝试下一步
    2. 调用迭代器的.valueOf() 方法。这成功了,但是它返回了迭代器,它不是一个原语,所以我们进入下一步
    3. 调用.toString() 方法。这导致非对象类型(即:字符串),因此这是成功的。

    当迭代器的.toString() 方法被调用时,它被评估为"[object Array Iterator]"。当它与数字 1 相加时,我们将字符串与数字连接(而不是相加),给出:

    [..."[object Array Iterator]1"]
    

    由于字符串是可迭代的,展开语法将使用字符串的迭代器循环遍历字符串中的代码点,从而使字符串的每个字符都成为自己的元素:

    ["[", "o", "b", "j", "e", "c", "t", " ", "A", "r", "r", "a", "y", " ", "I", "t", "e", "r", "a", "t", "o", "r", "]", "1"]
    

    要为迭代器中的每个项目添加一个,您可以使用Array.from(),它可以接受一个迭代器,并对每个元素应用一个映射函数:

    const res = Array.from(Array(5).keys(), i => i+1);
    console.log(res);

    由于 Array.from() 的参数不必是迭代器,您也可以只使用 Array(5) 并使用索引作为要添加的值:

    const res = Array.from(Array(5), (_,i) => i+1);
    console.log(res);

    【讨论】:

      【解决方案2】:

      当您添加 + 1 时,它将处理来自 ...Array(5).keys() 的返回作为字符串。 看看这些额外的例子:

      console.log(Array(5).keys()) 输出: [对象数组迭代器]

      console.log(Array(5).keys() + 1) 输出: [对象数组迭代器]1

      console.log(...Array(5).keys() + 1) 输出: [ o b j e c t A r r a y I t e r a t o r ] 1

      【讨论】:

        【解决方案3】:

        详细了解 JavaScript 中使用不同运算符时的类型转换

        为了简化答案,如果你尝试做Object() + 1,你会得到"[object Object]1",它不能转换为数字,JS将Object()转换为字符串,你可以得到相同的通过String(Object())

        在您的示例中,Array(5).keys() 是一个从 Array Iterator 继承的对象,因此当转换为字符串时,您会得到 "[object Array Iterator]",当然,通过加 1,您会得到 "[object Array Iterator]1",如果您这样做,它现在是一个字符串使用扩展运算符,它将被拆分为字符,这是您示例的预期结果

        相反,要加 1,您可以:[...Array(5).keys()].map(i=> i+1)

        【讨论】:

          【解决方案4】:

          就像您输入 [...(Array(5).keys() + 1)] 一样,这意味着 + 优先于 ...

          【讨论】:

            猜你喜欢
            • 2017-11-15
            • 2018-02-16
            • 1970-01-01
            • 2016-06-12
            • 1970-01-01
            • 2022-07-06
            • 2021-05-10
            • 2020-12-22
            相关资源
            最近更新 更多