A way to understand Function. prototype. bind in javascript

  • 2021-07-15 04:12:06
  • OfStack

When learning Javascript, We may not need to worry about function binding, but when we need to keep the context object this in another function, we will encounter corresponding problems. I have seen many people deal with this problem by assigning this to a variable (such as self, _ this, that, etc.), especially var that = this, which is the most I have seen, so that you can use it after changing the environment. All of this is OK, but there is a better and more proprietary way to use Function. prototype. bind, which is explained in detail below.   

Part 1: Problems to be solved

Look at the following code first


var myObj = {

  specialFunction: function () {

  },

  anotherSpecialFunction: function () {

  },

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

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

myObj.render();

Here I want to create an object that contains the first two common methods; The third method can pass a function, and the passed function is executed immediately; The last method will call the getAsyncData method of the myObj object, where this is used, and then a function is passed in the getAsyncData method. This function continues to call the first two methods of this object, and still uses this. At this time, many people can actually see the problem. Enter the above code into the console and get the following results:


TypeError: this.specialFunction is not a function

Part 2: Problem analysis

The this in the render method in the object does point to the myObj object, so we can call the function in this object through this. getAsyncData, but when we pass the function as a parameter, the this here points to the global environment window, because there are no first two methods in the object in the global environment, so an error will be reported.

Part 3: Several ways to solve problems

Therefore, what we need to do is to call the first two methods in the object correctly. The method used by many people is to first get this in the object environment and assign it to another variable. At this time, we can call it in the following environment, as follows:


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

Although this approach is feasible, using Function. prototype. bind () will make the code clearer and easier to understand, as follows:


render: function () {

  this.getAsyncData(function () {

    this.specialFunction();

    this.anotherSpecialFunction();

  }.bind(this));

}

Here we successfully bind this into the environment.

Here's another simple example:


var foo = {
  x: 3
}

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

bar(); // undefined

var boundFunc = bar.bind(foo);

boundFunc(); // 3

The following examples are also common:


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

Part 4: Browser support

However, this method is not supported in IE 8 and below, so we can use the method provided by MDN to make the lower version of IE supported. bind () method:


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;
 };
}


Related articles: