[].slice.call() 常用来将类数组转化为真正的数组。要理解其中的原理,必须了解以下几个知识点:
-
继承
这里的空数组是Array构造函数的实例,继承了Array.prototype的slice()方法,因此有以下关系:
[].slice() === Array.prototype.slice(); // true
-
函数的call()方法
call()方法是得以转化的关键所在。
call()是所有函数都具备的方法,其作用有两个,即调用函数并改变函数内部this指向。- 调用函数
调用 调用call()方法的这个函数,例如:fn.call()可以粗略的理解为fn()(暂时先不考虑参数的情况下)。
- 改变函数内部this指向
将函数fn内部的this指向call()方法的第一个对象参数,这么做的意义是可以使这个对象把fn这个函数(或者说方法)据为己有。 -
数组的slice()方法
MDN的解释是:slice() 方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。且原始数组不会被修改。
也就是说,slice用来截取一部分数组元素并返回新数组。接收两个可选参数,表示目标数组的下标范围:[begin, end)。begin省略则默认为0,end省略默认一直截取到数组末尾。
再回过头看[].slice.call(),如果传入一个类数组
var arrayLike = {
0: 'a',
1: 'b',
2: 'c',
length: 3
}
[].slice.call(arrayLike)将经历这些步骤:让arrayLike拥有数组的slice方法,slice方法被调用,其作用目标为arrayLike,由于没有传入其他参数,slice()默认返回所有下标的元素并返回新数组,最终得到:
var array = [].slice.call(arrayLike);
array; // ['a', 'b', 'c']
通过上文分析,我们知道apply和call具有同样的作用,那为什么不用apply呢?两者的区别在于传参的形式,从第二个参数开始(都是可选参数),都会成为调用的函数的参数,call接收一个个参数,而apply接收一个由这些参数组成的数组。如果只是原封不动的转换成数组的话,用apply和call没有任何区别,如果在转换的过程中需要对slice传参,call就更合适了。
网友评论