我知道它用于制作arguments
真实的Array
,但我不明白使用Array.prototype.slice.call(arguments);
.
`Array.prototype.slice.call` 是如何工作的?
在幕后发生的事情是,when.slice()
被正常调用,this
是一个数组,然后它只是遍历该数组,并完成其工作。
如何this
在.slice()
功能的阵列?因为当你这样做时:
object.method();
...该object
自动成为valuethis
的method()
。所以用:
[1,2,3].slice()
...[1,2,3]
数组被设置为this
in的值.slice()
。
但是如果你可以用其他东西代替this
value呢?只要你替换的任何东西都有一个数字.length
属性,以及一堆数字索引的属性,它应该可以工作。这种类型的对象通常称为类数组对象。
该.call()
和.apply()
方法让你手动设置的值this
的函数。因此,如果我们的值设置this
在.slice()
一个阵列状物体,.slice()
只会认为它的工作与Array,并会做它的东西。
以这个普通对象为例。
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
这显然不是一个数组,但如果你可以将它设置为 的this
值.slice()
,那么它就可以正常工作,因为它看起来足够像一个数组,.slice()
可以正常工作。
var sliced = Array.prototype.slice.call( my_object, 3 );
示例: http : //jsfiddle.net/wSvkv/
正如您在控制台中看到的,结果是我们所期望的:
['three','four'];
所以这就是当您将arguments
对象设置为 的this
值时会发生的情况.slice()
。因为arguments
有一个.length
属性和一堆数字索引,所以.slice()
它的工作就像在一个真正的数组上工作一样。
该arguments
对象实际上不是 Array 的实例,并且没有任何 Array 方法。因此,arguments.slice(...)
将不起作用,因为参数对象没有 slice 方法。
数组确实有这个方法,而且由于arguments
对象和数组非常相似,所以两者是兼容的。这意味着我们可以将数组方法与参数对象一起使用。并且由于数组方法是在考虑数组的情况下构建的,因此它们将返回数组而不是其他参数对象。
那么为什么要使用Array.prototype
?的Array
是,我们创建从(新阵列的对象new Array()
),而这些新的阵列被传递的方法和属性,像切片。这些方法存储在[Class].prototype
对象中。因此,为了效率起见,我们不是通过(new Array()).slice.call()
或访问切片方法[].slice.call()
,而是直接从原型中获取它。这样我们就不必初始化一个新数组。
但是为什么我们首先要这样做呢?好吧,正如您所说,它将参数对象转换为 Array 实例。然而,我们使用切片的原因更多是“黑客”而不是任何东西。slice 方法将接受一个你猜对了的数组切片并将该切片作为一个新数组返回。不向它传递任何参数(除了参数对象作为其上下文)会导致 slice 方法获取传递的“数组”的完整块(在本例中为参数对象)并将其作为新数组返回。
通常,调用
var b = a.slice();
将数组复制a
到b
. 然而,我们做不到
var a = arguments.slice();
因为arguments
没有slice
作为方法(它不是真正的数组)。
Array.prototype.slice
是slice
数组的函数。.call
运行此slice
函数,并将this
值设置为arguments
。
首先,您应该阅读JavaScript 中函数调用的工作原理。我怀疑仅此一项就足以回答您的问题。但这里是正在发生的事情的摘要:
Array.prototype.slice
从的原型中提取方法。但是直接调用它是行不通的,因为它是一个方法(不是一个函数),因此需要一个上下文(一个调用对象,),否则它会抛出.slice
Array
this
Uncaught 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);
Array.prototype.slice.call(arguments) 是将参数转换为数组的老式方法。
在 ECMAScript 2015 中,您可以使用 Array.from 或扩展运算符:
let args = Array.from(arguments);
let args = [...arguments];