手写call,apply与bind(一)

69 阅读1分钟

call

  • 对原型链和继承的知识比较熟悉
  • call是用来改变函数内部this

简单的案例

    var obj = {name:'zxx',age:18}
    function cc(){
      console.log(this.name);
    }
    cc.call(obj)//'zxx'
  • 这里,我们可以看到函数cc的this指向了对象obj中的name。

原理

  • 其实就是在Function.prototype注册了一个call方法,并且这个函数通过调用call方法,实现对象能够调用函数,实现了this的隐式绑定。

实现代码

//因为函数(方法)都是Function构造函数的实例,因此都会每个方法都可以调用call
    Function.prototype.myCall=function(ctx){
     //边界判断,如果传入的不是对象,那么先包装成对象,如果还是错误window兜底
      ctx = Object(ctx) || window;
      //拿到传入的多余参数:cc.call(obj,a,b...)
      //注意call的第一个参数是obj,因此要把它剔除
      let args = [...arguments].slice(1);
      //防止覆盖对象上的fn属性
      let fn = Symbol()
      //这步是核心思想
      //联系构造函数的知识,this指向构造的实例,就是函数(方法)
      //其实就是让对象引用这个方法并调用,实现this的隐式绑定
      ctx[fn] = this;
      //如果函数有返回值就再最后返回,同时传入
      let result = ctx[fn](...args);
      //注意,要进行删除引用
      delete ctx.fn;
      //如果有结果就返回结果
      return result;
    }

apply

  • apply和call差距只在于传入的第二个参数不同,apply是一个数组。
  • 因此我们别的步骤都可以和call一致,只需要改变传入多余的参数
    Function.prototype.myApply = function(ctx){
      ctx = Object(ctx) || window;
      //传进来的是一个二维数组,我们处理成为一位数组
      //别的步骤都不需要改变
      let args = [...arguments].slice(1)[0];
      let fn = Symbol()
      ctx[fn] = this;
      let result = ctx[fn](...args);
      delete ctx.fn;
      return result;
    }