深入解析JavaScript中bind、call与apply的区别及手动实现

作者:半夏

时间:2026-10-25

浏览:495

本文详细解析JavaScript中bind、call和apply三个方法的核心区别,重点阐述它们对this指向的改变及传参方式的差异。文章通过原型链机制深入剖析方法执行过程,并提供了这三个方法的完整手动实现代码,帮助开发者理解底层原理并掌握高级用法如柯里化。

文章目录

call的基本使用

var ary = [12, 23, 34];
ary.slice();

上述两行简单代码的执行流程如下:ary。该实例首先通过原型链查找机制定位到Array.prototype上的slice方法,随后调用找到的slice方法。在slice方法的执行过程中,ary数组被进行截取操作。

需要注意的是:slice方法在执行前存在一个原型查找过程(若当前实例中未找到,则依据原型链继续向上查找)。

明确了对象调用方法时存在查找过程后,我们进一步分析:

var obj = {name:'iceman'};
function fn() {
    console.log(this);
    console.log(this.name);
}
fn(); // this --> window
// obj.fn(); // Uncaught TypeError: obj.fn is not a function
fn.call(obj);

call方法的作用机制为:首先尝试寻找call方法,若未找到则通过原型链在Function的原型中定位到call方法,接着执行call方法。在call方法执行期间,将fn方法中的this绑定为第一个参数值obj,最后执行fn函数。

理解了上述原型机制后,我们可以着手分析并实现这三个方法。

bind、call、apply 区别

  • call 和 apply 均用于改变 this 的指向,二者作用相同,主要区别在于传参方式。
  • 除第一个参数外,call 可以接收多个独立参数,而 apply 仅接受一个包含所有参数的数组。
let a = {
    value: 1
}
function getValue(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value)
}
getValue.call(a, 'yck', '24')
getValue.apply(a, ['yck', '24'])

bind 与其他两个方法的作用一致,但其独特之处在于会返回一个新函数。此外,我们可以通过 bind 来实现函数柯里化。

如何实现一个 bind 函数

在实现上述几个函数时,可从以下几个维度进行思考:

  • 若未传入第一个参数,则默认使用 window 作为上下文。
  • 该方法改变了 this 的指向,使得新对象能够执行该函数。思路是否可以转化为:为新对象添加一个函数,执行完毕后将其删除?

答案是肯定的,具体实现如下:

Function.prototype.myBind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  var _this = this
  var args = [...arguments].slice(1)
  // 返回一个函数
  return function F() {
    // 因为返回了一个函数,我们可以 new F(),所以需要判断
    if (this instanceof F) {
      return new _this(...args, ...arguments)
    }
    return _this.apply(context, args.concat(...arguments))
  }
}

如何实现一个 call 函数

Function.prototype.myCall = function (context,...arg) {
  var context = context || window  // 给 context 添加一个属性
  // getValue.call(a, 'yck', '24') => a.fn = getValue
  //使用symbol 选择一个独一无二的值作为新添加的属性
  let symbol = new Symbol();
  context[symbol] = this;
  let result = context[symbol](...arg)
  // 删除添加的函数
  delete context[symbol]  
  return result
}

如何实现一个apply 函数

apply的实现原理与call基本类似,主要区别在于参数传递的方式不同。

Function.prototype.myApply = function (context,arg) {
  var context = context || window // 给 context 添加一个属性
 // getValue.call(a, 'yck', '24') => a.fn = getValue
 //使用symbol 选择一个独一无二的值作为新添加的属性
 let symbol = new Symbol();
 context[symbol] = this;
 let result = context[symbol](arg)
 // 删除添加的函数
 delete context[symbol]
 return result
}

经过对以上函数的测试,均完美通过。

const obj = {  
 name : 'xiaoxiao',  
 getName : function (arg) {  
 console.log(`我是${this.name}里面的,我里面有${arg}`);  
 }  
}  
obj.getName([0,0,0,0,0]); // 我是xiaoxiao里面的  
const obj2 = {  
 name : 'huahua'  
}  
//传值不一样  
obj.getName.myCall(obj2,1,1,1,1,1,1);  
obj.getName.myBind(obj2)(2,2,2,2,2,2);  
obj.getName.myApply(obj2,[3,3,3,3,3,3]);

更多关于JS中call、apply三个方法的区别与使用方式请查看下面的相关链接

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章