深入理解 JavaScript 中 Function.prototype.bind 方法

作者:闭包旅人时间:2026-10-21 21:14:18浏览:259

本文详细解析 JavaScript 中 Function.prototype.bind 方法的作用与原理。通过对比 var that = this 的传统做法,阐述 bind 如何更清晰地绑定函数上下文。文章包含多个代码示例,说明 bind 在对象方法、回调函数中的应用,并提供 MDN 提供的 IE8 及以下版本兼容实现方案。

理解 Function.prototype.bind 方法

在初学 JavaScript 时,我们通常不会过多关注函数绑定的问题。然而,当需要在另一个函数内部保持上下文对象 this 的指向时,这个问题便会出现。许多开发者处理此类问题的方式是先将 this 赋值给一个变量(例如 self、_this 或 that 等),其中 var that = this 是最常见的做法,以便在环境改变后仍能通过该变量访问原对象。虽然这种方法可行,但还有一种更专业且专有的方法,即使用 Function.prototype.bind,下文将进行详尽讲解。

需要解决的问题

第一部分:需要解决的问题

首先观察以下代码示例。


var myObj = {

  specialFunction: function () {

  },

  anotherSpecialFunction: function () {

  },

  getAsyncData: function (cb) {
    cb();
  },

  render: function () {
this.getAsyncData(function () {
      this.specialFunction();
      this.anotherSpecialFunction();
    });
  }
};

myObj.render();

这里我们创建一个对象,其中包含前两个普通方法;第三个方法接收一个函数作为参数并立即执行;最后一个方法调用 myObj 对象的 getAsyncData 方法,此处使用了 this。在 getAsyncData 方法中传入的函数继续调用该对象的前两个方法,同样使用了 this。此时,许多人已经能看出潜在问题:将上述代码输入控制台,会得到如下结果:


TypeError: this.specialFunction is not a function

问题剖析

第二部分:问题剖析

在对象 render 方法中,this 确实指向 myObj 对象,因此我们可以通过 this.getAsyncData 调用该对象中的函数。然而,当我们把函数作为参数传递时,这里的 this 指向了全局环境 window。由于全局环境中不存在对象的前两个方法,因此会报错。

解决问题的几种方式

第三部分:解决问题的几种方式

因此,我们需要正确调用对象中的前两个方法。许多人采用的方法是在对象环境中获取 this 并赋值给另一个变量,从而在后续环境中调用,如下所示:


  render: function () {
    var that = this;
    this.getAsyncData(function () {
      that.specialFunction();
      that.anotherSpecialFunction();
    });
  }  

虽然这种方法可行,但使用 Function.prototype.bind() 会使代码更清晰、易懂,如下所示:


render: function () {

  this.getAsyncData(function () {

    this.specialFunction();

    this.anotherSpecialFunction();

  }.bind(this));

}

这里我们就成功地把 this 绑定到了环境中。

下面是另外一个简单的例子:


var foo = {
  x: 3
}

var bar = function(){
  console.log(this.x);
}

bar(); // undefined

var boundFunc = bar.bind(foo);

boundFunc(); // 3

下面的例子也是常见的:


this.x = 9;  // this refers to global "window" object here in the browser
var module = {
 x: 81,
 getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX();  
// returns 9 - The function gets invoked at the global scope

// Create a new function with 'this' bound to module
// New programmers might confuse the
// global var x with module's property x
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81

浏览器支持

第四部分:浏览器支持

但是这个方法在 IE8 及以下是不被支持的,所以我们可以使用 MDN 提供的方法来使得 IE 低版本支持 .bind() 方法:


if (!Function.prototype.bind) {
 Function.prototype.bind = function (oThis) {
  if (typeof this !== "function") {
   // closest thing possible to the ECMAScript 5 internal IsCallable function
   throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
  }

  var aArgs = Array.prototype.slice.call(arguments, 1),
    fToBind = this,
    fNOP = function () {},
    fBound = function () {
     return fToBind.apply(this instanceof fNOP && oThis
                 ? this
                 : oThis,
                aArgs.concat(Array.prototype.slice.call(arguments)));
    };

  fNOP.prototype = this.prototype;
  fBound.prototype = new fNOP();

  return fBound;
 };
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章