JavaScript中call, apply, bind的用法对比分析

作者:拾光

时间:2026-10-28

浏览:587

本文深入解析JavaScript中call、apply和bind三个核心函数的用法与区别。通过代码示例说明call和apply如何借用对象方法并改变this指向,重点对比两者在参数传递方式上的差异(逐个列出与数组包装)。同时介绍bind方法如何实现函数柯里化及事件绑定中的上下文保留,并总结三者的兼容性与适用场景。

文章目录

引言:JavaScript核心函数概述

在JavaScript开发中,call、apply和bind是必须掌握的核心知识点。本文将详细总结这三个函数的具体用法及其常见应用场景。

call函数的原理与应用

首先分析call函数,其核心概念可以理解为“借用”或“请求”。设想这样一个场景:你独自在外遇到急事需要打电话回家,但手机因欠费、没电或损坏无法使用。此时,你可以借用朋友、邻居或公用电话完成通话,至于使用谁的电话并不重要,最终效果与使用自己的手机一致。call函数的设计初衷与此类似,旨在借用其他对象的方法来实现当前需求。以下代码模拟了这一应用场景:


  var frog = {
    name : 'frog',
    say : function(){
      alert(this.name);
    }
  }
  var rabbit = {
    name : 'rabbit'
  }
  frog.say.call(rubbit) // rabbit

假设rubbit对象是一个无法发声的哑巴,它希望输出自己的名字,但仅靠自身能力无法实现。幸运的是,它有一个名为frog的朋友具备说话能力。于是,rubbit请求frog代为执行say方法。在调用frog.say.call()时,第一个参数必须指定“委托人”,即方法执行时this指向的对象。这里rubbit请求frog帮忙,因此传入rubbit。这样,say方法执行时会查找rubbit的name属性,而非frog的name。如果传入frog,则相当于自己执行自己的方法,例如:


 var frog = {
    name : 'frog',
    say : function(){
      alert(this.name);
    }
  }
  var rabbit = {
    name : 'rabbit'
  }
  frog.say.call(frog) // frog

显然,自己执行自己的方法会输出自己的名字,这符合预期。接下来我们看call的经典用法:


//把参数转化成真正的数组对象
function frog(){
  var arr = [].slice.call(arguments);
  console.log(arguments.slice,arr.slice)
    // undefined function slice() { [native code] }
}
  frog(1,2,3,4)

通过call方法,我们可以将arguments对象转换为真正的数组对象,从而使用数组方法。在jQuery源码中,这种用法非常常见。回到之前的比喻,借电话只是基础操作,打完电话后可能还需要捎带物品回家。考虑到现代生活压力大,请假不仅扣薪还要花费路费,性价比极低。此时,call函数可以帮忙“顺道携带”物品,且无需额外费用、不限数量或重量。以下代码演示了这一过程:


 var frog = {
    name : 'frog',
    send : function(money,food,milk,suagate){
      alert(money+food+milk+suagate);
    }
  }
  var rabbit = {
    name : 'rabbit'
  }
  frog.send.call(rubbit,'money','food','milk','suagate')

如果预算充足,甚至可以寄送iPhone 6 Plus等贵重物品回家。

至此,call函数的讲解基本结束。希望上述情景类比能帮助你理解call的工作原理。如果引发了你的思乡之情,对此表示歉意。

apply函数的参数传递差异

call还有一个“同父异母”的兄弟,名为apply。如果理解了call,apply的原理也类似,主要区别在于参数传递方式:apply不喜欢逐个传递参数,而是提供一个“大箱子”(即数组)来包装所有参数。以上述例子使用apply实现如下:


var frog = {
    name : 'frog',
    send : function(money,food,milk,suagate){
      alert(money+food+milk+suagate);
    }
  }
  var rabbit = {
    name : 'rabbit'
  }
                //注意参数的区别
  frog.send.apply(rubbit,['money','food','milk','suagate'])

bind函数的特性与兼容性

以上就是call和apply的核心用法。此外,它们的“父亲”(即Function原型)早年还生有一个名为bind的“私生子”。虽然bind比call和apply晚出现几年,但能力不容小觑。需要注意的是,bind在部分旧版浏览器(如IE6)中不受支持。以下代码演示其功能:


  var name = 'rubbit';
  var frog = {
    name : 'frog',
    say : function(){
      setTimeout(function(money,milk){
        alert(this.name+money+milk)
      }.bind(this,'money','milk'),1000)
    }
  }
  frog.say();

对比发现,bind可以直接链接在函数定义之后使用,相当于省略了call和apply的步骤,直接在函数后指定委托人和传递参数。从传参风格来看,bind更接近call。

再看一段bind的经典用法:


var obj = {
  name : 'frog'
}
document.addEventListener('click',function(){
  alert(this.name); // frog
}.bind(obj),false);

三者对比总结

总结来说,apply、call和bind这三个函数的相同点在于:

1. 第一个参数均用于绑定作用域,即指定方法执行时的this指向。

2. 三者均支持传递参数。

不同点在于:

apply和call具有更好的浏览器兼容性,而bind在部分低版本浏览器中不支持。

apply要求传递的参数必须封装在数组中,而call和bind则是将参数逐一列出。

希望本文能帮助你更深入地理解call、apply和bind三个函数的用法,对JavaScript开发有所助益。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章