【问题标题】:What's the principle of Array.apply(null, obj)?Array.apply(null, obj)的原理是什么?
【发布时间】:2019-08-14 14:46:59
【问题描述】:
let a = {0: 'a', 1: 'b', length: 2}
Array.apply(null, a) // ['a', 'b']

使用 Array 构造函数是将类数组对象转换为数组的最快方法,例如jsperf

我想弄清楚它是如何工作的,但我失败了。在ECMAScript-262,我找不到对应的方法来解释那个代码。

为什么 Array 构造函数接受类似数组的对象可以将其转换为 Array。

Difference between Array.apply(null, Array(x) ) and Array(x)

Why does Array.apply(null, [args]) act inconsistently when dealing with sparse arrays?

【问题讨论】:

  • 既然你提到了 ECMAScript,你的答案就在这里:tc39.es/ecma262/#sec-array-items。简而言之,Array.apply(null, a); 就像用...items 调用构造函数一样。不过,我不确定是否调用了构造函数签名,或者是否调用了接受 ...items 和 length 的构造函数。

标签: javascript arrays ecmascript-6 ecma262


【解决方案1】:

使用Function#apply() 时,second 参数采用array-like。类数组基本上是一个具有数字键和length 属性的对象,但不一定是数组——例如the arguments object is an array-like

然后,该参数将提供给您调用 apply 的函数,就好像它是该函数的所有参数一样:

function foo(one, two, three) {
  console.log("one:", one);
  console.log("two:", two);
  console.log("three:", three);
}
//normal invocation
foo("hello", "world", "!");

//.apply using an array-like
foo.apply(null, {0: "nice", 1: "meeting", 2: "you", length: 3});

//.apply using an array
foo.apply(null, ["see", "you", "later"]);

因此,当您调用 Array.apply(null, {0: 'a', 1: 'b', length: 2}) 时,它等效于调用 Array('a', 'b') - using the array constructor 并使用多个参数从这些参数中生成一个数组:

console.log(Array("a", "b"));

因此,当您在构造函数上调用 apply 时,您会得到该行为。

在 ES6 中,将数组作为第二个参数传递给 .apply 与使用扩展语法几乎相同:

function foo(one, two, three) {
  console.log("one:", one);
  console.log("two:", two);
  console.log("three:", three);
}

const arrayArgs = ["hello", "world", "!"];
foo(...arrayArgs);

但是,这不适用于数组类:

function foo(one, two, three) {
  console.log("one:", one);
  console.log("two:", two);
  console.log("three:", three);
}

const arrayLikeArgs = {0: "hello", 1: "world", 2: "!", length: 3};
foo(...arrayLikeArgs);

【讨论】:

    【解决方案2】:

    使用apply(),您可以调用函数并传递应该用作类数组对象的参数。

    所以Array.apply(null, {0: 'a', 1: 'b', length: 2}) 等价于Array('a','b')

    并且可以使用 (MDN - Array) 构造数组:

    new Array(element0, element1[, ...[, elementN]])
    

    由于数组属于那些可以在没有new 的情况下构造的对象,因此给定的代码将使用这些元素构造一个数组。

    【讨论】:

    • 感谢您的帮助:) 从我的新测试中,Array.apply(null, '123')` 将抛出 CreateListFromArrayLike called on non-object 错误,因此,它似乎会在构造函数,同样,我在里面找不到任何描述。
    • @Eriice 问题与消息所暗示的完全一样——您没有 object。您传递的是原语,而不是具有数字键和 length 属性的东西。您可以对字符串进行数组访问,例如,"abc"[0],但这实际上会将字符串 primitive 转换为 object 并且仅用于手术。因此,如果您使用 .apply 传递一个字符串 object ,那么 Array.apply(null, new String("123"))
    • @VLAZ 谢谢,我已经弄清楚了。 Array.from('123')之所以能工作,是因为内部函数会通过Object('123')123转换为String{"123"}
    • @Eriice 不同之处在于Array.from() 接受类数组对象或可迭代对象。 Function.prototype.apply() 只接受类似数组的对象。一个字符串有[@@iterator]() 并且算作可迭代对象。 22.1.2.1Array.from 4-6 适用于当前规范中的字符串。另一方面,apply 函数中使用的7.3.17 CreateListFromArrayLike 具有If Type(obj) is not Object, throw a TypeError exception.
    • @Eriice Object(arrayLike) 不适用于字符串(即使它具有相同的效果),这在 MDN: Array.from - Polyfill 的 polyfill 中具有误导性。在引入Array.from 的同时添加了可迭代的字符串。
    猜你喜欢
    • 2015-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-07
    • 1970-01-01
    • 2011-04-14
    • 2023-04-02
    相关资源
    最近更新 更多