js中bind()使用詳細

3892 ワード

前言
最近はReactをやっていますが、bindまで使っています.彼の使い方はまだよく分かりません.ですから、今日はbindの使い方と私が出会ったのを合わせてこのようにブログを書きます.これは自分の印象を深めると同時に、いい方法を分析することができます.
1.じゃ、まず、ビッドを紹介します.
Function.prototype.bind()
   bind()の方法は主に関数をあるオブジェクトに結びつけることで、bind()は関数を作成し、関数の体内のthisオブジェクトの値は、ビnd()に入ってくる最初のパラメータの値に結び付けられます.例えば、f.bind(obj)は、実際にはobj.f()と理解できます.この時、f関数の体内のthisは、自然にobjを指します.
これはよく分かりました.次の例を見てみます.
  var a = {
    b: function() {
      var func = function() {
        console.log(this.c);
      }
      func();
    },
    c: 'hello'
  }
  a.b(); 
  console.log(a.c); 
答えは何ですか?undefinedとhelloは、みんなでプリントしてみてもいいです.これはfun()という関数が実行されるときの関数コンテキストがwindowです.a.b()のこの関数が実行されるときの関数コンテキストがaオブジェクトということですか?
  var a = {
    b: function() {
      console.log(this.c); //hello  
      var func = function() {
        console.log(this.c); //undefined
      }
      func();
    },
    c: 'hello'
  }
  a.b(); 
  
上の例とconsoline.log()を見たら、この関数の文脈は大体こういうことですか?ここを見て、ここにthisの方向についての問題の解析があったら、func()がほしいです.彼の出力の値はhrlloです.どうすればいいですか?
方法1:thisの値を変更する
  var a = {
    b: function() {
      var _this = this; //         this   that
      var func = function() {
        console.log(_this.c);
      }
      func();
    },
    c: 'hello'
  }
  a.b(); // hello
  console.log(a.c); // hello
方法2:結合thisの値が変更されました.
//   bind   
  var a = {
    b: function() {
      var func = function() {
        console.log(this.c);
      }.bind(this);
      func();
    },
    c: 'hello'
  }
  a.b(); // hello
  console.log(a.c); // hello

//   bind   
  var a = {
    b: function() {
      var func = function() {
        console.log(this.c);
      }
      func.bind(this)();
    },
    c: 'hello'
  }
  a.b(); // hello
  console.log(a.c); // hello
ポイントが来ました
みんなはビッドのここのthisは一体何なのかに気づきました.私達は何の例を通してaオブジェクトであるかを分かりました.問題はなぜaオブジェクトなのか、実はこうです.ビッドの中のthisは現在の関数の中の環境の関数コンテキストです.はい、ES 6の関数のthis表現と同じです.
関数が置かれている環境であれば、bind(this)はaオブジェクトにあり、関数が置かれている環境コンテキストを実行すると、fun()の関数コンテキストはwindowである.
なぜですか?例を見てみましょう.
    c = 10;
    var a = {
      b: function () {
        console.log(this);
        var func = function () {
          console.log(this.c);
        }.bind(this);
        func();
      },
      c: 'hello'
    }
    var d = a.b;
    d();
ここではd()の形でaオブジェクトのbという関数を実行しますか?d()の実行期間の文脈はwindowなので、aオブジェクトの中のbという関数の中のthisはwindowです.
bind()の原生は段階別解析を実現します.
1:callによって、バーargmentsは本物の配列を生成します.
Array.prototype.slice.call(arguments)                  ;
[].slice.call(arguments)                  ;
上の二つの方法の結果は同じです.
彼はクラスの配列です.彼はsliceを持っていません. ,上記のAray.prototype.sliceの書き方で彼にsliceを追加する方法がありますが、なぜできますか?
冒頭で言った:f.bind(obj)は、実際にはobj.f()と理解できます.
slice()パラメータがないデフォルトはkey 0から最後の項目まで、浅いコピーで、元の配列に影響しません.
実はargmentsも一つの対象であるので、argmentsでslice関数を実行した場合に、sliceという方法はパラメータを使わなくてもいいMDNと言いますが、W 3 Cはパラメータを必要とします.パラメータが不要な場合はkeyの下に表示されて完全な配列を返して、新しい配列を生成する効果があります.argmentsオブジェクトにはlength属性と0.12.という属性がありますが、sliceはこれらの0.1.2のkey(属性値とも呼ばれるもの)を元にして一つの配列に戻します.
原生bindの実現
if (!Function.prototype.bind) {
    Function.prototype.bind = function () {
        var self = this,                        //      
        context = [].shift.call(arguments), //        this   
        args = [].slice.call(arguments);    //          
        return function (11) {                    //        
            self.apply(context,[].concat.call(args, [].slice.call(arguments))); //   arguments 11
        }
    }
}
では[].shift.callの役割は、bind関数のパラメータを呼び出す最初の項目です.
self.apply(context,[].concat.cal(args,[].slie.cal); //これは実行後の結果です.
解析
bindはコンテキストを結合しているので、self.applyの最初のパラメータは前に保存したcontextです.次に、ビッドの残りのパラメータと、ビッドを呼び出して戻ってきた関数(returnが返したこの関数のパラメータである11)を実行中に受信したパラメータをつなぎ合わせて、1つの配列としてapplyの2番目のパラメータに入力します.これで完璧にbind関数を実行した結果、非常に巧妙と言わざるを得ません.