javascript之實現bind

minghu發表於2018-11-11

前言

bind函式的主要特性:

  • 建立一個新的繫結函式,這個函式與被呼叫的函式具有相同的函式體
  • 當這個新函式被呼叫的時候,函式中this 指向 bind 方法中第一個引數
  • 可以傳遞引數,bind 方法中傳遞的引數會在繫結函式實參之前

正文

實現bind函式

1、實現繫結指定this與傳遞引數

    'use strict';
    
    Function.prototype.mybind = function(context) {
        var _this = this;
        var outerArgs = Array.prototype.slice.call(arguments, 1);
        return function() {
            var innerArgs = Array.prototype.slice.call(arguments);
            return _this.apply(context, outerArgs.concat(innerArgs));
        }
    }
複製程式碼

2、當把返回的函式當作建構函式的時候,bind方法中第一個引數會被忽略(即不會繫結this)。

   'use strict';
    
    Function.prototype.mybind = function(context) {
        var _this = this;
        var outerArgs = Array.prototype.slice.call(arguments, 1);
        var BoundFn = function() {
            var innerArgs = Array.prototype.slice.call(arguments);
            // 當此時Fn函式返回出去,被當作建構函式,用new操作符呼叫的時候,this指向Fn的例項
            return _this.apply(this instanceof BoundFn ? this : context, outerArgs.concat(innerArgs));
        }
        // 把當前函式的prototype賦值給返回函式的prototype
        BoundFn.prototype = this.prototype;
        return BoundFn;
    } 
複製程式碼

3、上面的程式碼雖然bind功能實現了,但是存在一個問題,當改變BoundFn函式例項的原型的時候,會影響到原函式的原型,相反也一樣,兩者的原型是同一個引用,所以需要完善一下。

    'use strict';
    
    Function.prototype.mybind = function(context) {
        if(typeof this !== 'function') {
            throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
        };
        var _this = this;
        var outerArgs = Array.prototype.slice.call(arguments, 1);
        var BoundFn = function() {
            var innerArgs = Array.prototype.slice.call(arguments);
            // 當此時BoundFn函式返回出去,被當作建構函式,用new操作符呼叫的時候,this指向BoundFn的例項
            return _this.apply(this instanceof BoundFn ? this : context, outerArgs.concat(innerArgs));
        };
        var Fn = function() {};
        fn.prototype = this.prototype;
        BoundFn.prototype = new Fn();
        return BoundFn;
    }
複製程式碼

此時bind函式已經實現了,bind函式在 ECMA-262 第五版才被加入,它可能無法在所有瀏覽器上執行,所以需要做下相容:

    if(!Function.prototype.bind) {
        Function.prototype.bind = function(context) {
            if(typeof this !== 'function') {
                throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
            };
            var _this = this;
            var outerArgs = Array.prototype.slice.call(arguments, 1);
            var BoundFn = function() {
                var innerArgs = Array.prototype.slice.call(arguments);
                // 當此時Fn函式返回出去,被當作建構函式,用new操作符呼叫的時候,this指向Fn的例項
                return _this.apply(this instanceof BoundFn ? this : context, outerArgs.concat(innerArgs));
            };
            var Fn = function() {};
            fn.prototype = this.prototype;
            BoundFn.prototype = new Fn();
            return BoundFn;
        }
    }
複製程式碼

相關文章