美文网首页
js中 call、apply、bind 源码解析

js中 call、apply、bind 源码解析

作者: alokka | 来源:发表于2020-03-18 18:25 被阅读0次

    写在前面

    call、apply、bind其实用法都差不多 都是改变 this 指向,只是后面参数的传递有些许不同

    • call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔,直接放到后面 obj.myFun.call(db,'成都', ...,'string' )
    • apply 的所有参数都必须放在一个数组里面传进去 obj.myFun.apply(db,['成都', ..., 'string' ])
    • bind 除了返回是函数以外,它 的参数和 call 一样

    1. call 源码解析 es3 es6

    function add(c, d) {
      return this.a + this.b + c + d;
    }
    
    const obj = { a: 1, b: 2 };
    
    // ES3 call 实现
    Function.prototype.es3call = function (context) {
      var content = context || window;
      content.fn = this;
      var args = [];
      // arguments是传入的参数(实参)的类数组对象 函数自带
      for (var i = 1, len = arguments.length ; i < len; i++) {
        args.push('arguments[' + i + ']');
      }
      var result = eval('content.fn('+args+')');
      delete content.fn;
      return result;
    }
    console.error(add.es3call(obj, 3, 4)); // 10
    
    // ES6 call 实现
    Function.prototype.es6call = function (context) {
      var context = context || window;
      context.fn = this;
      var args = [];
      for (var i = 1, len = arguments.length; i < len; i++) {
        args.push(arguments[i]);
      }
      const result = context.fn(...args);
      delete context.fn;
      return result;
    }
    
    console.log(add.es6call(obj, 3, 4)); // 10
    

    apply、bind的 es6 写法大家可以自己尝试写一下

    2. apply 源码解析 es3 es6

    function add(c, d) {
      return this.a + this.b + c + d;
    }
    
    const obj = { a: 1, b: 2 };
    
    // ES3 apply 实现
    Function.prototype.es3apply = function (context, arr) {
      var context = context || window;
      context.fn = this;
      var result;
      if (!arr) {
        result = context.fn();
      } else {
        // 获取参数
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
          args.push('arr[' + i + ']');
        }
        // 执行函数
        result = eval('context.fn(' + args + ')')
      }
      delete context.fn;
      return result
    }
    
    console.log(add.apply(obj, [1, 2])); // 6
    // ES6 apply 实现
    Function.prototype.es6apply = function (context, arr) {
        var context = context || window;
        context.fn = this;
        var result;
        if (!arr) {
          result = context.fn();
        } else {
          if (!(arr instanceof Array)) throw new Error('params must be array');
          result = context.fn(...arr);
        }
        delete context.fn;
        return result;
      }
      
      console.error(add.es6apply(obj, [1, 2])); // 6
    

    3. bind 源码解析 es3 es6

    function add(c, d) {
      return this.a + this.b + c + d;
    }
    
    const obj = { a: 1, b: 2 };
    
    // ES3 apply 实现
    Function.prototype.es3bind= function (target) {
      target = target || window;//如果没有传入,就为window
      var self = this;//谁调用myBind,this就指向谁
      var args = [].slice.call(arguments, 1);//args:[arguments[1],arguments[2]....]
      var temp = function () { };
      var fn = function () {
          var fnArgs = [].slice.call(arguments, 0);
          //this 如果new fn()  this 指向构造出来的对象,否则为window ;this instanceof fn看this的原型链上有没有fn的原形
          return self.apply(this instanceof fn ? this : target, args.concat(fnArgs));
      }
      temp.prototype = this.prototype;
      fn.prototype = new temp();  //形成继续关系  fn.prototype.__proto__ == this.prototype  true
      return fn;
    }
    
    console.log(add.es3bind(obj, 3, 4)()); // 10
    
    // ES6 apply 实现
    Function.prototype.es6Bind = function(context, ...rest) {
      var self = this;//谁调用myBind,this就指向谁
      return function fn(...args) {
        return this instanceof fn ? new self(...rest, ...args) : self.apply(context, rest.concat(args))
      }
    }
    
    console.log(add.es6Bind(obj, 3, 4)()); // 10
    

    相关文章

      网友评论

          本文标题:js中 call、apply、bind 源码解析

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