原生jsはbind、call、appyを実現します.


オリジナルJavaScriptを使用したアナログ実装:bind call apply.
まず、この3つは全部thisの指し示しを変えるためのものです.ほとんどの人はbindの使用に慣れていないと信じています.他の2つについて分からないことがあれば、私のブログを見に行きます.JavaScriptのcallとappy()
  • は例を挙げます.
    this.name = 81;
    var obj = {
           
        name: 9,
        getName:function(){
           
            console.log(this.name);
        }
    }
    obj.getName();
    //    9 【this  obj】
    
    var res = obj.getName;
    res();
    //    81 【this  window】
    
    はなぜこのような違いが生じたのですか?
  • 私たちがobj.getNameをグローバル変数に与えたとき、彼のthisはobjを指すことからwindowを指すようになりました.
  • ですので、this.nameは81を出力します.
  • では、賦課後のthisの指し方が変わらないことをどう保証しますか?
    //          bind
    var res = obj.getName.bind(obj);
    res();
    //          call
    obj.getName.call(obj);
    //          apply
    obj.getName.apply(obj);
    
    にはこの3つの方法があります.thisの指摘問題を簡単に修正できます.なお、callとappyは直接呼び出しを行い、変数受信を定義する必要はなく、bindとは少し違っています.
    咳(無駄口ing—上から持ち上げます):
    優秀なプログラマは、もちろん表面に流れてはいけません.APIを呼び出すと同時に、私たちも考えてみたいです.もし自分でこの三つのAPIを書いたら、どうやってそれらの効果を実現しますか?
    原生js実現bind:
  • Functionと言ってください.
  • このゲームは、すべての関数の祖先であり、いずれかのJavaScript関数は、実際にはFunctionオブジェクトです.
  • 大域のFunctionオブジェクトには独自の属性と方法がないが、それ自体も関数であるため、プロトタイプチェーンを介して自身のプロトタイプチェーンFunction.prototypeからいくつかの属性と方法を継承することもある.【MDNから来た】
  • もしあなたがプロトタイプチェーンをよく理解していないなら、私が説明を簡単にします.
  • のすべての関数とFunctionという祖先との間には密接な関係があり、チェーンが互いに繋がっているようです.
  • で、このチェーンは__proto__で、__proto__Functionprototypreを指しています.Function.prototypeはこのゲーム自体がFunctionです.
  • ですので、簡単に言えば、私たちの関数ごとに呼び出される方法を実現するには、Function.prototype上でしかないです.何しろ祖先です.私たちが定義した関数は、プロトタイプチェーンを通して見つけられ、それを実現することができます.
  • ちょっと言ってください.
  • Object.create()方法は、新たに作成されたオブジェクトを既存のオブジェクトを使用して提供する新しいオブジェクトを作成する.proto_
  • は、オブジェクトを継承し、オブジェクトの属性をオブジェクトのプロトタイプの下に追加することができるという簡単な理解ができる.
    //  Function        myBind   
    Function.prototype.myBind = function(){
             };
    
  • 以下、具体的にビッドコードを実現することを見ます.
    var a = {
             name:'syw'};
    var b = Object.create(a);
    console.log(b); // {}
    console.log(b.__proto__); // {name:'syw'}
    console.log(b.name); // syw
    
    コード解説:
  • まず、ビッドがn個のパラメータを受信することを知っています.2種類のものに分けられます.
  • 第一類:つまり、bindの最初のパラメータであり、必須のパラメータであり、thisの正確な方向を指す.
  • 第二類:私たちが伝えたい他のパラメータ.
    var obj = {
         
        name: 9,
        getName:function(){
         
            console.log(this.name);
        }
    }
    //  Function    myBind
    Function.prototype.myBind = function (objThis, ...params) {
         
        //           
        const this_copy = this;
    
        let myBindFun = function (...params2) {
         
            //        ,    this   。【      】
            const isNew = this instanceof myBindFun;
            const thisArg = isNew ? this : objThis;
    
            return this_copy.call(thisArg, ...params, ...params2);
        }
    	//   myBindFun   ,  
        myBindFun.prototype = Object.create(this_copy.prototype);
        return myBindFun;
    }
    
    var res = obj.getName.bind(obj);
    res(); //    9
    
  • コードの中で、後のすべての送信のパラメータを、S 6の拡張演算子を使用して、統一的にObject.create()を受信しました.
  • に続いて、現在のthisを保存します.この時、thisは関数get Nameを指します.
  • 次いで、...params関数を定義した.
  • は上のビッドの例を観察することによって、ビッド動作が最後に戻ったのは関数であることが分かります.だから、私たちは追加の変数を定義して受信-呼び出しを受ける必要があります.
    豆知識:
  • は、関数呼び出し時にパラメータを伝えることができるということを知っていますが、myBindFunはどうなりますか?
  • は、上記の例でこの動作を行ったと仮定します.
    //   :function.bind(thisArg[, arg1[, arg2[, ...]]])
    obj.getNmae.bind(obj,1,2,3);
    // obj    
    // 1 2 3       
    
    bind , 関数でgetNameを印刷したら、パラメータが統合されています.
  • これにより、私たちはまた、マイビドーFunで伝達されたパラメータを受け取る必要があり、同じくEs 6の拡張演算子でargumentsを受信することができる.
  • ...params2
  • この時、私達が理解したいのは、このmyBindFunは誰を指していますか?
    var res = obj.getName.bind(obj,1,2,3);
    res(4,5,6);
    
    なぜですか?それとも閉じますか?興味があります.このコードを実行してください.
    console.log(myBindFun.prototype); //   :getName {}
    
  • はmyBindFun内部に入ります.まずこのthisを判断します.現在の例ですか?
    instance解釈:
    例えば、myBind myBind ,myBindFun は同じ場所を指すかどうか.
  • どうしてこの判断を行いますか?関数を呼び出すときはnewの場合がありますので、例を挙げてください.
  • このとき、a instance b a.__proto__ b.prototypenew res()の関数内部のthisは、調整者myBindFungetNameの指向が同じである.
  • これは問題があります.元々はクローズドの場合、myBindFun.prototype関数内部のmyBindFunthisオブジェクトを指すべきです.
  • ですので、私たちはこの状況を排除したいので、windowを使用して、現在のthis instaceof myBindFunが同じ場所を指すかどうかを検出します.
  • もしそうであれば、現在のthis.__proto__をそのまま使用し、存在しない場合は、着信myBindFun.prototypeを使用する.
  • は次に、thisを通じて、私たちが最初に保存したthisの方向を変更し、パラメータを呼び出して、それを返します.
    function syw(a){
             
        console.log('this1',this);
        return function(b){
             
            console.log('this2',this);
            return a + b;
        }
    }
    const a = syw(2);
    console.log('a: ', a); // a    return   
    const b = a(1);
    console.log('b', b); // b 3
    const c = new a(1);
    console.log('c', c); // c {}
    //     :new a(1)      ,    c    {}
    
  • 最後に、もう一つの点があります.objThisは父の構造関数のすべての属性を継承することに相当します.ですから、callを通じてobj.bind(obj)の中のすべての属性を継承していく必要があります.
  • テスト:
    let res = obj.getName.myBind(obj);
    new res(); //【      :res    myBind】
    //          this.name     undefined
    
    はい、これで終わります.
    callとappyの実現について、次のブログで話しています.転送ゲート:元生jsシミュレーションでbind call appyを実現します.