【Javascript高级知识】封装实现一个自己的call, apply, bind函数(原生版+ES6版)

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;
    }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值