javascriptのFunction.prototye.bind

5789 ワード

関数バインディング(Function binding)はJavaScriptを使用し始めた時に最も関心のある点かもしれませんが、他の関数でthisコンテキストを維持するには解決策が必要だと認識したとき、本当に必要なのはFuntions.prototype.bindです.
この問題が初めて発生した時には、変数にthisを設定する傾向があります.これはコンテキストを変えてからも引用できます.多くの人がselfを使います.thisまたはcontextを変数名として使用します.これらの方法はすべて役に立ちます.もちろん問題はありません.しかし、より良い、より専用の方法があります.
本当に解決したい問題は何ですか?次の例のコードでは、名前を付けて、コンテキストを変数にキャッシュすることができます.

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

私たちが簡単にthis.special Functionを使ってメソッドを呼び出すと、次のエラーが発生します.
Uncaght Type Errror:Object[object global]hasのmethod'special Funct'は、コールバック関数の実行のためにmyObjオブジェクトのコンテキストに対する参照を維持する必要があります.that.special Functionを呼び出して、私たちはスコープコンテキストを維持し、正確に関数を実行することができます.しかしながら、Funtions.prototype.bindを使用すると、より簡潔で清潔な方法があり得る.

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

私たちは先ほど何をしましたか?bind()は、この関数が呼び出されたときに、そのthisキーワードが着信された値(ここではbind()を呼び出したときに入ってくるパラメータ)に設定される関数を作成しました.したがって、私たちは希望の文脈に入ってきました.そして、コールバック関数が実行されると、thisはmyObjオブジェクトを指す.
もし興味があれば、Funtion.prototype.bind()の内部の長さはどうですか?またどのように働きますか?ここでは非常に簡単な例があります.

Function.prototype.bind = function (scope) {
  var fn = this;
  return function () {
    return fn.apply(scope);
  };
}
もう一つの非常に簡単な用例があります.

var foo = {
  x: 3
}
 
var bar = function(){
  console.log(this.x);
}
 
bar(); 
// undefined
 
var boundFunc = bar.bind(foo);
 
boundFunc(); 
// 3
私たちは新しい関数を作成しました.実行されると、そのthisはfooに設定されます.私たちがbar()を呼び出した時のようなグローバルスコープではありません.
ブラウザサポートBrowser Version support Chrome 7 Firefox(Gecko) 4.0(2)インターネットExplorer 9 Opera 11.60 Safari 5.1.4あなたが見ているように、残念ながら、Funtions.prototype.bindはIE 8および以下のバージョンではサポートされていませんので、予備案がないと運転中に問題が発生する可能性があります.
幸いなことに、Mozila Developer Networkは、自身の実現がないために絶対的に信頼できる代替案を提供しています.

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

適用モード
技術のポイントを学ぶ時、役立つのは徹底的に概念を学ぶことだけではなくて、更に手元の仕事の中でそれを適用するところがあるかどうかを見てみます.あるいはそれに近いものです.私は次のいくつかの例があなたのコードに適用されることを望んでいます.あるいはあなたが直面している問題を解決します.
CLICK HANDLERS(クリック処理関数)はクリックイベントを記録する用途(またはクリック後に操作を実行する)です.

var logger = {
  x: 0,    
  updateCount: function(){
    this.x++;
    console.log(this.x);
  }
}

以下のようにクリック処理関数を指定して、ロゴオブジェクトのudateCount()を呼び出すかもしれません.

document.querySelector('button').addEventListener('click', function(){
  logger.updateCount();
});
しかし、私たちはudateCount関数のthisキーワードが正しい値を持つことを確認するために、余分な匿名関数を作成しなければなりません.
私たちは次のようなきれいな方法を使うことができます.
Dcument.querySelector('button').addEvent Listener('click',logger.udateCount.bind(logger);便利なBind()関数を巧みに使用して新しい関数を作成し,その作用領域をloggerオブジェクトとして結びつけた.
SETTIMEOUTはテンプレートエンジン(例えば、Handlebars)を使用したことがあるか、または特定のMV*フレーム(私の経験からBackbone.jsしか話せません)を使用したことがあるなら、次のような議論はテンプレートをレンダリングした直後に新しいDOMノードを訪問する時に発生する問題について知っているかもしれません.
もし私たちがjQueryプラグインを実装したいなら、

var myView = {
 
  template: '/*