[关闭]
@greenfavo 2015-12-14T14:37:59.000000Z 字数 1413 阅读 766

js call()与apply()用法解析

博客


前言

其实call()和aply()功能完全一样,只是参数形式不同。知道它们为什么存在,比单纯地了解它们的区别更重要。

一,call/apply是什么

这两个方法看做是某个对象的方法,通过调用方法的形式来间接调用函数.call()和apply()的第一个实参是要调用函数的母对象,它是调用上下文,在函数体内通过this来获得对它的引用。
比如,要想以对象o的方法来调用函数f(),可以这样使用call()和apply():

  1. f.call(o);
  2. f.apply(o);
  3. //上面每行代码都和下面代码的功能类似(假设对象o中预先不存在属性m)
  4. o.m=f;//将f存储为o的临时方法
  5. o.m();//调用它,不传入参数
  6. delete o.m;//将临时方法删除

二,为什么会有这两种方法

在javascript面向对象编程中,我们常常会这样定义

  1. function Cat(){
  2. }
  3. Cat.prototype={
  4. food:"fish",
  5. say: function(){
  6. alert("I love "+this.food);
  7. }
  8. }
  9. var blackCat = new Cat();
  10. blackCat.say();

但如果我们有一个对象Dog = {food:"bone"},我们不想对它重新定义say方法,那我们可以通过call或apply方法借用blackcat的say方法。

  1. blackcat.say.call(Dog);

所以可以看出,call和apply是为动态改变this而存在的。当一个对象没有某个方法时,但其他对象有,这时就可以利用call和apply借用其他对象的该方法。

三,call与apply区别

在ECMAScript5严格模式中,call和apply的第一个实参都会变为this的值,哪怕传入的实参是原始值甚至是null或undefined。在ECMAScript3和非严格模式中,传入的null和undefined都会被全局对象代替,而其他原始值则会被相应的包装对象所代替。
对于call()来说,第一个调用上下文实参之后的所有实参就是要传入待调用函数的值。比如,以对象o的方法的形式调用函数f(),并传入两个参数。

  1. f.call(o,1,2);

apply与call类似,只不过它的实参都放入一个数组中。
如果一个函数的实参是任意数量,给apply传入的参数数组可以是任意长度,例如,找出数组中的最大值

  1. var biggest=Math.max.apply(Math,[22,13,4545,1,.....]);

需要注意的是,传入apply()的参数数组可以是类数组对象也可以是普通的数组,实际上可以将当前函数的arguments数组直接传入apply()来调用另一个函数。

  1. f.apply(this,arguments);

四,总结

call与apply都是为了改变上下文this指向而存在的。像在java这类面向对象语言中,方法总是被对象调用的,谁调用这个方法,谁就是this。以对象o的方法的形式调用函数f(),就好像f()脱离了对象o,还可以被其他对象调用。它们的第一个参数都是要调用这个函数的对象,后面的参数就该函数所需的实参。只不过call是以普通参数的形式传入实参,apply是以数组的形式传入实参而已。

这部分内容参考了《javascript权威指南》还有知乎上的回答。特别是知乎上的回答,让我瞬间明白了它们的用途和神奇之处。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注