@greenfavo
2015-12-14T14:37:59.000000Z
字数 1413
阅读 766
博客
其实call()和aply()功能完全一样,只是参数形式不同。知道它们为什么存在,比单纯地了解它们的区别更重要。
这两个方法看做是某个对象的方法,通过调用方法的形式来间接调用函数.call()和apply()的第一个实参是要调用函数的母对象,它是调用上下文,在函数体内通过this来获得对它的引用。
比如,要想以对象o的方法来调用函数f(),可以这样使用call()和apply():
f.call(o);
f.apply(o);
//上面每行代码都和下面代码的功能类似(假设对象o中预先不存在属性m)
o.m=f;//将f存储为o的临时方法
o.m();//调用它,不传入参数
delete o.m;//将临时方法删除
在javascript面向对象编程中,我们常常会这样定义
function Cat(){
}
Cat.prototype={
food:"fish",
say: function(){
alert("I love "+this.food);
}
}
var blackCat = new Cat();
blackCat.say();
但如果我们有一个对象Dog = {food:"bone"},我们不想对它重新定义say方法,那我们可以通过call或apply方法借用blackcat的say方法。
blackcat.say.call(Dog);
所以可以看出,call和apply是为动态改变this而存在的。当一个对象没有某个方法时,但其他对象有,这时就可以利用call和apply借用其他对象的该方法。
在ECMAScript5严格模式中,call和apply的第一个实参都会变为this的值,哪怕传入的实参是原始值甚至是null或undefined。在ECMAScript3和非严格模式中,传入的null和undefined都会被全局对象代替,而其他原始值则会被相应的包装对象所代替。
对于call()来说,第一个调用上下文实参之后的所有实参就是要传入待调用函数的值。比如,以对象o的方法的形式调用函数f(),并传入两个参数。
f.call(o,1,2);
apply与call类似,只不过它的实参都放入一个数组中。
如果一个函数的实参是任意数量,给apply传入的参数数组可以是任意长度,例如,找出数组中的最大值
var biggest=Math.max.apply(Math,[22,13,4545,1,.....]);
需要注意的是,传入apply()的参数数组可以是类数组对象也可以是普通的数组,实际上可以将当前函数的arguments数组直接传入apply()来调用另一个函数。
f.apply(this,arguments);
call与apply都是为了改变上下文this指向而存在的。像在java这类面向对象语言中,方法总是被对象调用的,谁调用这个方法,谁就是this。以对象o的方法的形式调用函数f(),就好像f()脱离了对象o,还可以被其他对象调用。它们的第一个参数都是要调用这个函数的对象,后面的参数就该函数所需的实参。只不过call是以普通参数的形式传入实参,apply是以数组的形式传入实参而已。
这部分内容参考了《javascript权威指南》还有知乎上的回答。特别是知乎上的回答,让我瞬间明白了它们的用途和神奇之处。