我知道它是用来使参数成为一个真正的数组,但我不明白当使用Array.prototype.slice.call(参数);时会发生什么。
当前回答
/*
arguments: get all args data include Length .
slice : clone Array
call: Convert Object which include Length to Array
Array.prototype.slice.call(arguments):
1. Convert arguments to Array
2. Clone Array arguments
*/
//normal
function abc1(a,b,c){
console.log(a);
}
//argument
function: function abc2(){
console.log(Array.prototype.slice.call(arguments,0,1))
}
abc1('a','b','c');
//a
abc2('a','b','c');
//a
其他回答
当正常调用.slice()时,底层发生的事情是,这是一个数组,然后它只是迭代该数组,并完成它的工作。
这是如何在.slice()函数数组?因为当你这样做的时候:
object.method();
...对象自动成为this在方法()中的值。所以有:
[1,2,3].slice()
...数组[1,2,3]被设置为.slice()中的this值。
但是如果你可以用别的东西代替这个值呢?只要你替换的东西有一个数值的。length属性,还有一堆数值索引的属性,它就可以工作。这种类型的对象通常称为类数组对象。
.call()和.apply()方法允许您在函数中手动设置this的值。因此,如果我们在.slice()中将this的值设置为一个类似数组的对象,.slice()将假设它正在处理一个数组,并将执行它的任务。
以这个普通对象为例。
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'];
这就是当你将参数对象设置为.slice()的this值时所发生的情况。因为参数有一个.length属性和一堆数值索引,.slice()就像在一个真正的数组上工作一样。
// We can apply `slice` from `Array.prototype`:
Array.prototype.slice.call([]); //-> []
// Since `slice` is available on an array's prototype chain,
'slice' in []; //-> true
[].slice === Array.prototype.slice; //-> true
// … we can just invoke it directly:
[].slice(); //-> []
// `arguments` has no `slice` method
'slice' in arguments; //-> false
// … but we can apply it the same way:
Array.prototype.slice.call(arguments); //-> […]
// In fact, though `slice` belongs to `Array.prototype`,
// it can operate on any array-like object:
Array.prototype.slice.call({0: 1, length: 1}); //-> [1]
arguments对象实际上不是Array的实例,也没有任何Array方法。因此,arguments.slice(…)将不起作用,因为arguments对象没有slice方法。
数组确实有这个方法,因为arguments对象与数组非常相似,所以两者是兼容的。这意味着我们可以在arguments对象中使用数组方法。由于数组方法是在考虑数组的情况下构建的,因此它们将返回数组而不是其他参数对象。
为什么使用array。prototype呢?Array是我们用来创建新数组的对象(new Array()),这些新数组被传递方法和属性,比如slice。这些方法存储在[Class]中。原型对象。因此,为了提高效率,我们不通过(new Array()).slice.call()或[].slice.call()来访问slice方法,而是直接从原型中获取它。这样我们就不必初始化一个新数组。
But why do we have to do this in the first place? Well, as you said, it converts an arguments object into an Array instance. The reason why we use slice, however, is more of a "hack" than anything. The slice method will take a, you guessed it, slice of an array and return that slice as a new array. Passing no arguments to it (besides the arguments object as its context) causes the slice method to take a complete chunk of the passed "array" (in this case, the arguments object) and return it as a new array.
正如MDN所指出的,这是因为
arguments对象不是数组。它类似于数组,但是 除了长度以外,没有任何数组属性。例如,它确实如此 没有pop方法。然而,它可以转换为一个真正的数组:
这里我们是在原生对象Array上调用slice,而不是在它的实现上调用slice,这就是为什么要使用额外的.prototype
var args = Array.prototype.slice.call(arguments);
它使用slice方法数组have并调用它,它的this是arguments对象。这意味着它会像调用arguments.slice()一样调用它,假设参数有这样一个方法。
创建一个不带任何参数的切片将简单地获取所有元素——因此它只是简单地将元素从参数复制到数组中。