我们知道,函数内部 arguments 是一个类数组对象,不是真正的数组,因此也无法使用数组的各种方法。想详细了解 argument 对象可以前往函数中的 arguments。
(function fun(){
console.log(arguments.reverse()); //报错
})();
Array.prototype.slice.apply(arguments)
和[].slice.apply(arguments)
可以将 arguments 转换为一个真正的数组。
(function fun(){
var arr = Array.prototype.slice.apply(arguments);
var arr2 = [].slice.apply(arguments);
console.log(arr); //[18,23]
console.log(arr.reverse()); //[23,18]
console.log(arr2); //[18,23]
console.log(arr2.reverse()); //[23,18]
})(18,23);
当然这里用 call 方法或者 bind 方法也可以等到一样的结果。这三个方法的区别和使用方法可以参照apply()、call()与bind()的用法与区别。
(function fun(){
var arr = Array.prototype.slice.apply(arguments);
var arr2 = Array.prototype.slice.call(arguments);
var arr3 = Array.prototype.slice.bind(arguments)();
console.log(arr); //[18,23]
console.log(arr.reverse()); //[23,18]
console.log(arr2); //[18,23]
console.log(arr2.reverse()); //[23,18]
console.log(arr3); //[18,23]
console.log(arr3.reverse()); //[23,18]
})(18,23);
Array.prototype.slice.apply(arguments)
我们从外到里看一下这个式子。
apply() 方法能够将函数内部的 this 绑定为指定对象。这个方法接收两个参数:第一个是新的 this 对象,第二个是一个参数数组,如果函数调用不需要参数的话,则可以省略。因此这里是将 Array.prototype.slice() 内部的 this 对象绑定为 arguments 。
slice() 方法可从已有的数组中返回选定的元素。这个方法接收两个可选的参数:第一个是开始的选定的位置,第二个是结束的位置(不包括)。如果两个参数都不传,则默认从0开始直到结束。
我们知道,当一个函数调用存在上下文对象,就会应用隐式绑定规则,将函数内部的 this 绑定到这个上下文对象。想了解 this 的绑定规则可以前往JavaScript 中判断一个函数的 this 绑定。但是这个式子却将 this 对象绑定为 arguments 并且将其转化为数组,为什么要这样做呢?我们测试一下。
var arr = [1,2,3];
var arr2 = [4,5];
console.log(arr2.slice()); //[4,5]
console.log(arr2.slice.apply(arr)); //[1,2,3]
从上面可以看出,将 slice() 的 this 对象从 arr2 变为 arr 后,slice() 方法的作用对象就变成 arr 了。我们可以简单猜测一下 slice() 方法的实现代码:
Array.prototype.slice = function(start,end){
var result = new Array();
start = start || 0;
end = end || this.length;
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
}
从上面代码就可以看出为什么 Array.prototype.slice.apply(arguments) 为什么可以将 arguments 转化为一个真正的数组,它首先创建一个数组,然后将 this 对象按下标一个一个推入数组中,最后返回这个数组。
[].slice.apply(arguments)
我们知道,每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先从对象实例本身开始。如果在实例中找到了具有给定名字的属性,则返回该属性的值;如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。如果在原型对象中找到了这个属性,则返回该属性的值。
[] 是一个空数组,它的原型对象是 Array.prototype,我们可以测试一下。
console.log([].__proto__ === Array.prototype); //true
因此 [].slice.apply(arguments) 本质上跟 Array.prototype.slice.apply(arguments) 是一样的,目的都是调用 slice() 这个方法。