人们常说,要学好js,多尝试自己实现一些polyfill。但是呢,一般人会去先使用它,然后才去手撕它。我们今天并不想说手撕的问题,因为我觉得我还没有使用好它,你呢?不妨看看下面怎么说的。
1.我们都知道apply可以改变this指向的问题
2.我们还知道apply接受的第二个参数是一个数组,是一个数组。
3.甚至知道apply和call都是改变this指向的,而区别就是call的第二个、第三个等参数是序列。
但是呢?
有一天,问题出现了,觉得apply没什么好难得,会用皆大欢喜,但是你真的会用吗?
看看一个例子:
function bar(x,y){
console.log(x,y); //x=[1, 2, 3],y=undefined
console.log(arguments);
}
bar([1,2,3]);
arguments如下:
是不是很正常。
再看看一个例子:
function bar(x,y){
console.log(x,y); // x=1 ,y=2
console.log(arguments);
}
bar.apply(window,[1,2,3]);
arguments如下:
咦,怎么arguments的length变为3. 怎么传过去的数组展开了。
是怎么回事呢?bug?不对?
但是,可爱的小伙伴,还是知道问题所在。那试问一下,你真的理解apply的第二个参数是一个数组吗?
听我说说看:理解apply的第二个参数是一个数组,要知道数组的作用,收集所用要传给被调函数于一个容器(数组),传过去方便。但是不能理解为一个参数。正所谓在被调函数的参数这边依然是展开的,而不是一个数组。所以arguments的length是3不是1.
不妨我们再看看call吧:
function bar(x,y){
console.log(x,y); //x=[1,2,3] ,y=undefined
console.log(arguments);
}
bar.call(window,[1,2,3]);
同样还是再看看arguments:
和apply不一样吧,能是这样的结果,就是因为call的第二、第三等参数是序列。你既然传了一项,那么在那边被调参数那边也就一项,即使你是数组。
总结一个小技巧:如果要将arguments传给另一个函数,那么选择apply最好。被调函数里面的arguments[0],arguments[1],arguments[2]等同样可以获取到。如同call传过来的一样,只不过call的实参要传一个arguments展开写不方便。
还有一个小技巧:实现两个数组的拼接。
var arr=[1,2];
[].push.apply(arr,[3,4,5]) 等价于 [].push.call(arr,...[3,4,5])