【问题标题】:Difference between Array.apply(null, Array(x) ) and Array(x)Array.apply(null, Array(x) ) 和 Array(x) 之间的区别
【发布时间】:2015-02-09 18:16:24
【问题描述】:

两者之间到底有什么区别:

Array(3)
// and
Array.apply(null, Array(3) )

第一个返回[undefined x 3],而第二个返回[undefined, undefined, undefined]。第二个可以通过Array.prototype.functions 链接,例如.map,但第一个不是。为什么?

【问题讨论】:

  • Array.apply(null, Array(9))不是 new Array(9)。它将Array(9) 作为九个参数传播到Array()。即使它有效,它也几乎是错误的方式。例如,您可以new Array(1e7),但不能Array.apply(null, Array(1e7))

标签: javascript


【解决方案1】:

有一个区别,一个非常重要的区别。

Array 构造函数either 接受一个数字,给出数组的长度,并创建一个具有“空”索引的数组,或者更准确地说是长度已设置,但数组实际上不包含任何内容

Array(3); // creates [], with a length of 3

当使用数字作为唯一参数调用数组构造函数时,您会创建一个空数组,并且无法使用通常的 Array 方法进行迭代。

或者... Array 构造函数接受多个参数,而创建一个数组,其中每个参数都是数组中的一个值

Array(1,2,3); // creates an array [1,2,3] etc.

当你调用它时

Array.apply(null, Array(3) )

它变得更有趣了。

apply 接受this 值作为第一个参数,由于这里没有用,所以设置为null

有趣的部分是第二个参数,其中传入了一个空数组。
由于apply 接受一个数组,它就像调用

Array(undefined, undefined, undefined);

这会创建一个包含三个非空索引的数组,但实际上将值设置为 undefined,这就是它可以被迭代的原因。

TL;DR
主要区别在于Array(3) 创建了一个包含三个空索引的数组。事实上,它们并不存在,数组的长度只是3

使用apply将这样一个索引为空的数组传递给Array构造函数与使用Array(undefined, undefined, undefined);相同,后者创建一个具有三个undefined索引的数组,而undefined实际上是一个值,所以它不像第一个示例中那样为空。

map() 这样的数组方法只能遍历实际值,而不是空索引。

【讨论】:

    【解决方案2】:

    .map() API 不会遍历完全未初始化的数组元素。当您使用new Array(n) 构造函数创建一个新数组时,您会得到一个包含您要求的.length 但不存在的元素的数组,这些元素将被.map() 等方法跳过。

    表达式Array.apply(null, Array(9))undefined 显式填充新创建的数组实例,但这已经足够了。诀窍在于in 运算符是否会报告该数组在给定索引处包含一个元素。那就是:

    var a = new Array(9);
    alert(2 in a); // alerts "false"
    

    那是因为数组中2 位置确实没有元素。但是:

    var a = Array.apply(null, Array(9));
    alert(2 in a); // alerts "true"
    

    对 Array 构造函数的外部调用将显式填充元素。

    【讨论】:

    • 感谢您的回答,我不太确定每个插槽中的内容与未定义的值不同,因为索引到任何给定位置都会返回未定义。
    • @mb_s88 考虑0 in Array(9); // false
    • @mb_s88 回答扩展了一点
    • es5.github.io/#x15.3.4.3 Function.prototype.apply 也不关心argArray 是否是一个真正的 Array,只要它是一个可读的 Object , Array.apply(null, {length: "2.5"}); // [undefined, undefined]
    【解决方案3】:

    这是apply 工作原理的产物。当你这样做时:

    new Array(9)
    

    创建一个长度为 9 的空数组。map 不访问不存在的成员,所以什么也不做。但是,apply 使用 CreateListFromArrayLike 将数组转换为列表,因此它将以前的空数组转换为参数列表,例如:

    [undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined];
    

    传递给 Array 以创建一个包含 9 个成员的数组,所有成员的值都为 undefined。所以现在地图将访问它们。

    顺便说一句,ECMAScript 2015 对此有 Array.prototype.fill(另请参阅 MDN),因此您可以这样做:

    Array(9).fill(0);
    

    【讨论】:

    • 问题是如果性能方面你最好使用 Array.apply(null,length) 或 Array(length).fill()
    • @Jony-Y——不是一个重要的人。我会使用最适合我情况的那个,微优化应该是最后的考虑因素。 :-)
    【解决方案4】:

    因为第一个数组没有有序的属性arr[0] === undefined 而第二个有。像 forEach 和 map 这样的数组函数将从 0 迭代到数组的长度 - 1 并且第一个属性缺乏顺序是一个问题。第二个版本产生一个具有正确顺序的数组,即

    arr = Array.apply(null, Array(3));
    arr[0] === undefined //true
    arr[1] === undefined //true
    //etc.
    

    您注意到的第一个版本没有。此外,将new 添加到第一个版本不会使其工作。

    【讨论】:

      【解决方案5】:

      在第一种情况下,您有一个操作

      数组(3)

      它创建了一个包含三个空槽的数组。不是具有三个未定义值的数组,而是完全 - 空的。

      第二种情况

      Array.apply(null, Array(3))

      我们可以将其展开为三个操作:

      • first: Array(3) - 你得到一个有 3 个空槽的数组;

      • second: Array(3) 通过 Function.prototype.apply() 函数传播到它传递给 Array() 函数的 3 个参数。在这个阶段,给定数组中的 3 个空槽通过 apply() 转换为 3 个未定义值(看起来如果 apply() 看到一个空槽,它会自动将其在任何稀疏数组中转换为未定义)。

      • 第三个:我们得到一个数组(未定义,未定义,未定义)。这将对我们产生一个包含 3 个未定义(非空)值的数组。

      因为现在你有 3 个未定义但不是空的插槽,你可以将它们与 map() 函数一起使用。

      请注意,不仅 Function.prototype.apply() 具有通过这种方式分解数组的这种行为。您也可以在 ECMAScript 6 中通过“...” - 扩展运算符来执行此操作。

      Array(...new Array(3));
      

      这也将返回一个包含 3 个未定义且分别可以映射的槽的数组。

      这里我给出更详细的解释。 https://stackoverflow.com/a/56814230/11715665

      【讨论】:

        猜你喜欢
        • 2018-08-30
        • 2012-05-21
        • 2019-01-28
        • 2016-05-12
        • 1970-01-01
        • 2016-05-03
        • 1970-01-01
        • 2023-03-27
        相关资源
        最近更新 更多