call, apply, bind的模拟实现

call的模拟实现

    // 使用原生的ES3语法实现的call
    Function.prototype._call = function() {
      var context = context || window;
      context.fn = this;

      var args = [];
      for (var i = 1, len = arguments.length; i < len; i++) {
            args.push('arguments['+ i +']')
      }
      var res = eval('context.fn('+ args +')');

      delete context.fn;
      return res;
    }

    // 使用ES6语法实现一个call
    Function.prototype._call = function() {
      let context = arguments[0];
      context.fn = this;

      let args = [];
      for (let i = 0, len = arguments.length; i < len; i++) {
          args.push(arguments[i]);
      }

      // 把数组转换为一个伪数组
      let res = context.fn({...args});

      delete context.fn;
      return res;
    }

apply的模拟实现

    // 原生JS实现
    Function.prototype._apply = function(context, arr) {
      var context = Object(context) || window;
      context.fn = this;

      let res;
      if (!arr) {
          res = context.fn();
      }
      else {
          var args = [];
          for (var i = 0, len = arr.length; i < len; i++) {
              args.push('arr['+i+']');
          }
          res = eval('context.fn('+args+')');
      }
      delete context.fn;
      return res;
    }

    // 使用ES6语法实现的apply
    Function.prototype._apply = function(context) {
      context = context || window;
      context.fn = this;

      let res;
      if (arguments[1]) {
          // array
          res = context.fn(...arguments[1]);
      }
      else {
          // none args
          res = context.fn();
      }

      delete context.fn;
      return res;
    }

bind的模拟实现

    // 原生JS 的实现
    Function.prototype._bind = function(context) {
        if (typeof this !== 'function') {
            throw new Error('error callback');
        }

        var self = this;
        var args = Array.prototype.slice.call(arguments, 1);
        // 注意:这里如果直接将 fBound.prototype = this.prototype
        // ,我们直接修改 fBound.prototype 的时候,也会直接修改绑定函数的 prototype。
        // 解决方案:这个时候,我们可以通过一个空函数来进行中转
        var fnOP = function() {};

        var fnBind = function() {
            var bindArgs = Array.prototype.slice.call(arguments);
            return self.apply(this instanceof fnOP
                            ? this
                            : context
                            , args.concat(bindArgs));
        }
        // 通过间接地去修改这个中间函数的原型对象,new 的方式来避免直接修改原型上面的属性和对象参数信息
        fnOP.prototype = this.prototype;
        // 这里不就是原型链继承的实现吗?
        fnBind.prototype = new fnOP();
        return fnBind;
    }

    // ES6的写法一
    Function.prototype._bind = function(context, ...args) {
      let self = this;
      return function() {
        self.apply(context, args.concat(Array.prototype.slice.call(arguments)));
      }
    }

    // ES6的写法二
    Function.prototype._bind = function(context) {
      context = context || window;
      let args = Array.prototype.slice.call(arguments, 1);
      let self = this;
      // 构建一个中间的函数,维护原型之间的关系
      let temp = function(){};
      let F = function() {
        self.apply(this instanceof temp
                    ? this
                    : context
                    , args.concat(Array.prototype.slice.call(arguments)))
      }
      // 通过中间函数维护原型关系
      temp.prototype = this.prototype;
      F.prototype = new temp();

      return F;
    }

results matching ""

    No results matching ""