bind()とcall/apply()方法の違いを深く理解する

7284 ワード

callapplyの機能は同じで、異なるのは、参照の仕方が異なることである.
  • fn.call(obj, arg1, arg2, ...),は、指定されたthis値と、それぞれ提供されるパラメータ(パラメータのリスト)とを有する関数を呼び出します.
  • fn.apply(obj, [argsArray])は、1つの指定されたthis値と、1つの配列(またはクラスの配列オブジェクト)として提供されるパラメータとを有する関数を呼び出します.
  • callコア:
  • は、関数を着信パラメータの属性
  • に設定する.
  • は、thisから関数を指定し、与えられたパラメータ実行関数
  • に入力する.
  • 着信パラメータまたはパラメータがnullでなければ、デフォルトはwindow / global
  • を指す.
  • パラメータ上の関数
  • を削除します.
    Function.prototype.call = function (context) {
        /**             null     undefined,     this   window/global */
        /**             null   undefined,           */
        if (!context) {
            //context null   undefined
            context = typeof window === 'undefined' ? global : window;
        }
        context.fn = this; //this         (Function   )
        let rest = [...arguments].slice(1);//    this         ,    slice          
        let result = context.fn(...rest); //    ,     this   context.
        delete context.fn;
        return result;
    }
    
    //    
    var foo = {
        name: 'Selina'
    }
    var name = 'Chirs';
    function bar(job, age) {
        console.log(this.name);
        console.log(job, age);
    }
    bar.call(foo, 'programmer', 20);
    // Selina programmer 20
    bar.call(null, 'teacher', 25);
    //      : Chirs teacher 25; node   : undefined teacher 25
    
    apply:applyの実装およびcallは類似しているが、applyの第2のパラメータは配列またはクラス配列であることに注意が必要である.
    Function.prototype.apply = function (context, rest) {
        if (!context) {
            //context null   undefined ,     
            context = typeof window === 'undefined' ? global : window;
        }
        context.fn = this;
        let result = context.fn(...rest);
        delete context.fn;
        return result;
    }
    var foo = {
        name: 'Selina'
    }
    var name = 'Chirs';
    function bar(job, age) {
        console.log(this.name);
        console.log(job, age);
    }
    bar.apply(foo, ['programmer', 20]);
    // Selina programmer 20
    bar.apply(null, ['teacher', 25]);
    //      : Chirs programmer 20; node   : undefined teacher 25
    
    
    bind:bindcall/applyは重要な違いがあります.一つの関数がcall/applyによって呼び出されると、直接に呼び出されますが、bindは新しい関数を作成します.この新しい関数が呼び出されると、bind()の最初のパラメータはその動作時のthisとして使用され、その後のシーケンスパラメータは、そのパラメータとして転送された実際の参照の前に渡される.
    Function.prototype.bind = function(context) {
        if(typeof this !== "function"){
           throw new TypeError("not a function");
        }
        let self = this;
        let args = [...arguments].slice(1);
        function Fn() {};
        Fn.prototype = this.prototype;
        let bound = function() {
            let res = [...args, ...arguments]; //bind                  
            context = this instanceof Fn ? this : context || this;
            return self.apply(context, res);
        }
        //   
        bound.prototype = new Fn();
        return bound;
    }
    
    var name = 'Jack';
    function person(age, job, gender){
        console.log(this.name , age, job, gender);
    }
    var Yve = {name : 'Yvette'};
    let result = person.bind(Yve, 22, 'enginner')('female');
    
    
    bind()とcall/apply()方法の違いを深く理解する