Array.prototype.slice.call()如何工作?

我知道它用于使参数成为真实的数组,但是我不明白使用时会发生什么 Array.prototype.slice.call(arguments)

GilL2020/03/13 00:41:46

Maybe a bit late, but the answer to all of this mess is that call() is used in JS for inheritance. If we compare this to Python or PHP, for example, call is used respectively as super().init() or parent::_construct().

This is an example of its usage that clarifies all:

function Teacher(first, last, age, gender, interests, subject) {
  Person.call(this, first, last, age, gender, interests);

  this.subject = subject;
}

Reference: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance

路易Itachi2020/03/13 00:41:46

It uses the slice method arrays have and calls it with its this being the arguments object. This means it calls it as if you did arguments.slice() assuming arguments had such a method.

Creating a slice without any arguments will simply take all elements - so it simply copies the elements from arguments to an array.

Davaid阳光小卤蛋2020/03/13 00:41:45

Array.prototype.slice.call(arguments) is the old-fashioned way to convert an arguments into an array.

In ECMAScript 2015, you can use Array.from or the spread operator:

let args = Array.from(arguments);

let args = [...arguments];
达蒙Itachi理查德2020/03/13 00:41:45

Dont forget, that a low-level basics of this behaviour is the type-casting that integrated in JS-engine entirely.

Slice just takes object (thanks to existing arguments.length property) and returns array-object casted after doing all operations on that.

The same logics you can test if you try to treat String-method with an INT-value:

String.prototype.bold.call(11);  // returns "<b>11</b>"

And that explains statement above.

Jim米亚西里2020/03/13 00:41:45

arguments对象实际上不是Array的实例,并且不具有任何Array方法。因此,arguments.slice(...)将不会起作用,因为arguments对象没有slice方法。

数组确实具有此方法,并且由于arguments对象与数组非常相似,因此两者是兼容的。这意味着我们可以将数组方法与arguments对象一起使用。而且由于数组方法是在考虑数组的基础上构建的,因此它们将返回数组而不是其他参数对象。

那为什么要使用Array.prototype呢?Array是,我们创建从(新阵列的对象new Array()),而这些新的阵列被传递的方法和属性,像切片。这些方法存储在[Class].prototype对象中。因此,出于效率的考虑,我们不必直接通过原型直接获取切片方法,而不必通过(new Array()).slice.call()or 来访问slice方法[].slice.call()这样一来,我们不必初始化新的数组。

但是为什么我们必须首先这样做呢?好了,正如您所说,它将参数对象转换为Array实例。但是,我们使用slice的原因更多的是“ hack”。您猜到了,slice方法将获取一个数组的切片,并将该切片作为新数组返回。不向其传递任何参数(以arguments对象作为上下文除外)会使slice方法获取传递的“数组”(在本例中为arguments对象)的完整块,并将其作为新数组返回。

Jim米亚西里2020/03/13 00:41:45

通常,打电话

var b = a.slice();

将数组复制a到中b但是,我们不能

var a = arguments.slice();

因为arguments它不是一个真正的数组,也没有slice作为方法。Array.prototype.sliceslice数组函数,并callthis设置运行函数arguments

Near理查德路易2020/03/13 00:41:45

Its because, as MDN notes

The arguments object is not an array. It is similar to an array, but does not have any array properties except length. For example, it does not have the pop method. However it can be converted to a real array:

Here we are calling slice on the native object Array and not on its implementation and thats why the extra .prototype

var args = Array.prototype.slice.call(arguments);
卡卡西逆天2020/03/13 00:41:45

首先,您应该阅读JavaScript中函数调用的工作方式我怀疑仅此一项就足以回答您的问题。但是,这里是正在发生的事情的摘要:

Array.prototype.slice提取方法原型但是直接调用它是行不通的,因为它是方法(不是函数),因此需要上下文(调用对象),否则会抛出slice ArraythisUncaught TypeError: Array.prototype.slice called on null or undefined

call()方法允许您指定方法的上下文,基本上使这两个调用等效:

someObject.slice(1, 2);
slice.call(someObject, 1, 2);

除了前者要求该slice方法存在于someObject原型链中(就像它所做的那样Array),而后者则允许将上下文(someObject)手动传递给该方法。

另外,后者的缩写为:

var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);

与以下内容相同:

Array.prototype.slice.call(someObject, 1, 2);