Array.prototype.slice.call()如何工作?
我知道它用于使参数成为一个真正的数组,但我不明白使用Array.prototype.slice.call(arguments)
时会发生什么情况。
在引擎盖下发生的是,当.slice()
被正常调用时, this
是一个数组,然后它只是迭代该数组,并完成它的工作。
如何为this
在.slice()
函数对数组? 因为当你这样做时:
object.method();
...的object
自动成为的值this
在method()
所以:
[1,2,3].slice()
...的[1,2,3]
数组被设置为的值this
在.slice()
但是如果你可以用别的东西替代this
值呢? 只要你替换的数值有.length
属性,以及一些属于数字索引的属性,它就可以工作。 这种类型的对象通常被称为类似数组的对象。
该.call()
和.apply()
方法让你手动设置的值, this
在一个函数。 因此,如果我们的值设置this
在.slice()
到一个数组类的对象, .slice()
将只是假设它的工作与Array,并会做它的东西。
以这个普通对象为例。
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
这显然不是一个数组,但是如果你可以将它设置为.slice()
的this
值,那么它就可以工作,因为它看起来就像一个数组,用于.slice()
正常工作。
var sliced = Array.prototype.slice.call( my_object, 3 );
例如: http : //jsfiddle.net/wSvkv/
正如你在控制台中看到的那样,结果就是我们所期望的:
['three','four'];
所以当你将arguments
对象设置为.slice()
的this
值时,会发生这种情况。 因为arguments
有一个.length
属性和一堆数字索引, .slice()
只是像工作在一个真实的数组上一样。
arguments
对象实际上不是数组的一个实例,也没有任何数组方法。 所以, arguments.slice(...)
将不起作用,因为arguments对象没有slice方法。
数组确实有这种方法,并且因为arguments
对象与数组非常相似,所以两者是兼容的。 这意味着我们可以使用参数对象的数组方法。 由于数组方法是在数组的基础上构建的,因此它们将返回数组而不是其他参数对象。
那么为什么要使用Array.prototype
? Array
是我们从( new Array()
)创建新数组的对象,并且这些新数组通过方法和属性(如slice)传递。 这些方法存储在[Class].prototype
对象中。 所以,为了提高效率,我们不是通过(new Array()).slice.call()
或[].slice.call()
来访问slice方法,而是直接从原型中获取它。 这样我们就不必初始化一个新的数组了。
但为什么我们首先要做到这一点? 那么,如你所说,它将一个参数对象转换为一个数组实例。 然而,我们使用分片的原因更多的是“黑客”。 切片方法将采取,你猜对了,切片数组并返回该切片作为一个新的数组。 除了参数对象作为其上下文之外,不传递任何参数(除了参数对象作为其上下文)都会导致切片方法获取传递的“数组”(本例中为参数对象)的完整块并将其作为新数组返回。
通常,打电话
var b = a.slice();
将数组a
复制到b
。 但是,我们做不到
var a = arguments.slice();
因为arguments
不是真正的数组,并且没有slice
作为方法。 Array.prototype.slice
是数组的slice
函数,并且call
this
arguments
设置为arguments
来运行该函数。