为什么要在arguments中使用Array.prototype.slice.call?

5

我正在使用apply调用一个方法,但我不知道要传递多少参数:

目前我的代码如下:

selectFolder: function(e){
  e.preventDefault();

  this.addSelectedClass.apply(this, Array.prototype.slice.call(arguments));
},

我之所以使用Array.prototype.slice,只是因为它在大多数示例中都有。

为什么我不能直接像这样传递参数:

 this.addSelectedClass.apply(this, arguments);
2个回答

6

apply() 方法中的 arguments 是可以使用的

在调用函数的 apply 方法时,可以直接使用原始的 arguments。因此,在您的示例中,您可以轻松地将该行替换为以下内容:

this.addSelectedClass.apply(this, arguments);

call()中的arguments不太好用

但是,如果您要调用call,并且希望向函数传递任意对象/值的数组,则应将arguments转换为实际的数组(通过slice()调用)。这就是为什么当您知道要传递的参数数量并单独传递它们时,通常使用call()

arguments不是一个真正的数组对象。它们似乎是(例如具有length属性),但它们不是。

Mozilla开发者网络上的Arguments

进一步解释以使其完全清晰

apply()call()相关的文档如下:

func.apply(thisArg[, argsArray]);
func.call(thisArg[, arg1[, arg2[, ...]]]);

我们可以使用以下任何一种方法执行相同的功能。
  1. 当使用apply()时,我们可以一次传递所有参数。通常使用slice()来省略调用中的特定参数或将arguments转换为实际数组。
  2. 当使用call()时,我们逐个传递参数,需要多少个就传递多少个。如果我们提供转换为数组的参数,则被调用函数将得到一个类型为数组的参数,该数组包含在特定数组中提供的所有参数。
我希望这更加清晰明了。

.call() 接受参数列表,而不是数组。.apply() 接受数组。 - Alessandro Vendruscolo
@MisterJack,apply可以接受任何“类似于数组”的对象,例如:(function(a, b) { return a+b; }).apply(this, {0:5, 1:10, length:2}); // 15 - Christian C. Salvadó
我的意思是应该使用call作为foo.call(this, 'aa', 2)(一个列表),而不是像foo.call(this, ['aa', 2])这样,因为在声明function foo(a, b) {}的情况下,后者示例将具有数组作为第一个参数和未定义作为第二个参数。 - Alessandro Vendruscolo
@MisterJack:您当然是正确的。我编辑了我的答案,以使它完全清楚,您仍然可以将参数作为数组提供给call(),但函数将会将它们作为单个类型为数组的参数接收。这就是与您评论相关的混淆所在。因此,我添加了更多信息以使其更清晰明了。 - Robert Koritnik

3
因为arguments不是一个数组。运行Array.prototype.slice可以将其转换为具有像mapforEach这样的函数的普通数组。基本上,Array.prototype中的任何内容都可以使用。没有这个方法,arguments只是一个带有length属性的对象。
在您的特定情况下,仅传递arguments可能会起作用。

1
我认为你的意思是“因为参数不是一个数组”。 - jbabey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接