javascriptのFunction.prototype.bindを理解する方法


Javascriptを初めて勉強した時、関数バインディングの問題を心配する必要はないかもしれませんが、他の関数でコンテキストオブジェクトthisを維持する必要があると、対応する問題が発生します。多くの人がこのような問題を処理するのは先にthisを変数に割り当てます。this、thatなど)、特にvar that=thisは私が一番多く見たので、環境を変えたら使えます。これらはいいですが、もっといい、もっと専門的な方法があります。それはFuntion.prototype.bindを使って、詳しく説明します。  
第一部:解決すべき問題
まず下のコードを見てください。

var myObj = {

  specialFunction: function () {

  },

  anotherSpecialFunction: function () {

  },

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

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

myObj.render();

ここでは前の二つの一般的な方法を含めてオブジェクトを作成したいです。第3の方法は、関数を伝達して、入ってきたこの関数は直ちに実行されます。最後の方法はmyObjオブジェクトのget AyncDataメソッドを呼び出すことができます。ここではthisを使用して、get AyncDataメソッドに関数が入ってきました。この関数はこのオブジェクトの最初の2つの方法を引き続き呼び出します。thisを使用しています。この場合、多くの人が実際に問題点を見抜きます。上記のコードをコンソールに入力して、次の結果が得られます。

TypeError: this.specialFunction is not a function
第二部分:問題分析
オブジェクト中のレンダー法のthisは確かにmyObjオブジェクトを指すので、this.get AyncDataを通じてこのオブジェクトの関数を呼び出すことができますが、私たちはその伝達関数をパラメータとして渡すと、ここのthisはグローバル環境windowを指します。大域環境においてオブジェクトの最初の二つの方法がないため、エラーを報告します。
第三部分:問題を解決するいくつかの方法
したがって、私たちが必要とするのは、オブジェクトの最初の2つの方法を正しく呼び出すことです。多くの人が使う方法は、まずオブジェクトの環境でthis割り当て値を他の変数に取得することです。この場合、後の環境で呼び出すことができます。

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

この方法は可能ですが、Funtions.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

第四部分:ブラウザサポート
しかしながら、この方法はIE 8および以下ではサポートされていないので、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;
 };
}

以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。