美文网首页前端基础
apply、call、bind模拟实现

apply、call、bind模拟实现

作者: Luigi_Lin | 来源:发表于2019-02-19 00:01 被阅读0次

    call

    call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。

    例如:

        var foo = { x: 10 };
    
        function test(y) {
            console.log(this.x,y);
        }
    
        test.call(foo,20); //10 20
    
    1. 为达到绑定this的效果,可以将函数加到传入的对象上进行调用。
        Function.prototype.call2 = function (self) {
            self.fn = this;
            return self.fn();
        }
    

    但这样传入的对象就多了一个属性了

    1. 在调用后删除掉这个属性
        Function.prototype.call2 = function (self) {
            self.fn = this;
            var result = self.fn();
            delete self.fn();
            return result;
        }
    
    1. 将提供的参数传入
        Function.prototype.call2 = function (self) {        
            self.fn = this;
    
            var params = [];
            for (var i = 1; i < arguments.length; i++) {
                params.push(`arguments[` + i + `]`);
            }
    
            var result = eval('self.fn(' + params + ')');
            delete self.fn;
            return result;
        }
    
    1. 当传入对象为空时,this绑定到window
        Function.prototype.call2 = function (self) {
            self = self || window;
            self.fn = this;
    
            var params = [];
            for (var i = 1; i < arguments.length; i++) {
                params.push(`arguments[` + i + `]`);
            }
    
            var result = eval('self.fn(' + params + ')');
            delete self.fn;
            return result;
        }
    

    apply

    与call类似,区别时apply传入的参数列表为数组

        Function.prototype.apply2 = function (self, args) {
            self = self || window;
    
            self.fn = this;
    
            var result;
            if (!args || !args.length) {
                result = self.fn();
            } else {
                var params = [];
                for (var i = 0; i < args.length; i++) {
                    params.push(`args[` + i + `]`);
                }
                result = eval('self.fn(' + params + ')');
    
            }
            delete self.fn;
    
            return result;
        }
    

    bind

    1. bind会返回一个函数,该函数的this绑定到第一个参数上。
      Function.prototype.bind2 = function (self) {
          var fn = this;
    
          return function () {
              return fn.apply(self);
          }
      }
    
    1. bind返回的函数可以接收参数
        Function.prototype.bind2 = function (self) {
            var fn = this;
    
            return function () {
                var bindArgs = Array.prototype.slice.call(arguments);
                return fn.apply(self,bindArgs);
            }
        }
    
    1. 调用bind的时候可以先绑定一部分参数,在调用其返回的函数时传入的参数会跟在bind绑定的那部分参数后面
        Function.prototype.bind2 = function (self) {
            var fn = this;
            var args = Array.prototype.slice.call(arguments, 1);
    
            return function () {
                var bindArgs = Array.prototype.slice.call(arguments);
                return fn.apply(self, args.concat(bindArgs));
            }
        }
    
    1. 对bind返回的新函数进行构造调用时,this绑定到新构造的对象上,而非bind绑定的对象。
        Function.prototype.bind2 = function (self) {
            var fn = this;
            var args = Array.prototype.slice.call(arguments, 1);
    
            var fBound = function () {
                var bindArgs = Array.prototype.slice.call(arguments);
                //如果this是此函数的实例,证明是被构造调用了,此时绑定新构造的对象
                return fn.apply( this instanceof fBound ? this : self, args.concat(bindArgs));
            }
    
            return fBound;
        }
    
    1. 维护原型关系,否则会有这样的问题
      function Test(){}
      var t = Test.bind({});
      var o = new t();
      o instanceof Test // false
    
        Function.prototype.bind2 = function (self) {
            var fn = this;
            var args = Array.prototype.slice.call(arguments, 1);
    
            var f = function(){};
            var fBound = function () {
                var bindArgs = Array.prototype.slice.call(arguments);
                return fn.apply(this instanceof fBound ? this : self, args.concat(bindArgs));
            }
    
            if(this.prototype){
                f.prototype = fn.prototype;
            }
            fBound.prototype = new f();
    
            return fBound;
        }
    

    6.调用bind的不是函数要报错

    if (typeof this !== "function") {//加上判断
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }
    

    相关文章

      网友评论

        本文标题:apply、call、bind模拟实现

        本文链接:https://www.haomeiwen.com/subject/fzazeqtx.html