函数原型方法call/apply/bind源码实现

前言

这三个方法都是改变其函数this指向的,首先给出call/apply/bind方法的区别:

  1. bind:不会立即执行函数,传参形式为参数序列
  2. call:立即执行函数,传参形式为参数序列
  3. apply:立即执行函数,传参形式为数组

基本思路

  1. bind

运用柯里化函数的思想,执行bind()之后,返回了一个新的函数,也是闭包的一个运用场景。

  1. call

主要是搞清楚执行call时,干了啥,1. 把this方法执行,这是的this就是那个调用call方法的函数,这里假设为fn1。 2. 将这个fn1this指向改为你指定的那个。

  1. apply

applycall方法思路相同,只是传的参数类型不同。

上代码

   let obj = {
      fn(x, y) {
        console.log(this, x, y)
      }
    }
复制代码

运用自执行函数形成闭包,以免影响全局,保护了方法。

~function anonymous(proto) {
      function bind(context) {
        context == null ? window : context // 考虑特殊情况null和undefined
        let _this = this
        let args = [].slice.call(arguments, 1) 
        //这里运用es5来处理,将类数组转换为数组。
        //也可以写Array.prototype.slice.call(arguments, 1)
        // console.log(args) [10,20]
        return function proxy() {
          _this.apply(context, args)
        }
      }
      function call(context, ...args) {
        /* 干了三件事:
        1. 将this执行,假设为fn1
        2. 将fn1中的this指向context 
        3. 要考虑到特殊情况,如果context不是引用类型的话,则需要自己转换
        */
        context == null ? window : context
        const type = typeof context
        if (type !== 'object' && type !== 'function' && type !== 'symble') {
          //基本数据类型
          switch (type) {
            case ('number'): context = new Number(context); break;
            case ('string'): context = new String(context); break;
            case ('Boolean'): context = new Boolean(context); break;
          }
        }
        context.$fn = this
        const res = context.$fn(...args)
        return res
      }
      function apply(context, args) {
        context == null ? window : context
        const type = typeof context
        if (type !== 'object' && type !== 'function' && type !== 'symble') {
          //基本数据类型
          switch (type) {
            case ('number'): context = new Number(context); break;
            case ('string'): context = new String(context); break;
            case ('Boolean'): context = new Boolean(context); break;
          }
        }
        context.$fn = this
        const res = context.$fn(...args) //展开
        return res
      }
      proto.bind = bind
      proto.call = call
      proto.apply = apply
    }(Function.prototype)
复制代码

测试:

    setTimeout(obj.fn.bind(window, 10, 20), 1000)
    obj.fn.call('4', 10, 20) // String {'4', $fn: ƒ} 10 20
    obj.fn.apply('4', [10, 20]) // String {'4', $fn: ƒ} 10 20
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享