javascript之实现bind

441 阅读2分钟

前言

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