美文网首页前端程序员
原生JS - 封装call、apply、bind方法

原生JS - 封装call、apply、bind方法

作者: docman | 来源:发表于2019-12-28 08:35 被阅读0次

    call、apply、bind是在前端开发过程中常用的,改变函数中this指向的方法,关于三种方法的详细使用,本文不做过多赘述。主要分享call、apply、bind三种方法的区别,即各自的封装方式。

    1、call、apply、bind区别

    • call、apply

      • 直接执行函数,替代函数中的this
      • 一般应用于要即时执行的函数中替代this
      • call和apply的第一个参数都是为了替换函数中的this指向
      • call的其他参数正常传入,apply的其他参数以数组方式传入
      function fn(a, b) {
          this.a = a;
          this.b = b;
          console.log(this);
          return this;
      }
      
      /* 直接执行函数 */
      fn(3, 5); // 结果:Window
      console.log(a, b); // 结果:3 5
      // 函数执行后,this指向window,此时a和b是window下的属性,可以直接打印出来
      
      /* 如果使用call或apply */
      // call和apply的第一个参数是为了替换函数中的this指向
      
      // call
      fn.call({}, 5, 9); // 结果:{a: 3, b: 5}
      // apply
      fn.apply({}, [12, 15]); // 结果:{a: 12, b: 15}
      
    • bind

      • 返回一个新函数,这个函数中的this都被替代为绑定的对象,当执行时this就会全部指向这个对象
      • 一般用于回调函数中替代this指向
      function fn(a, b) {
          this.a = a;
          this.b = b;
          return this;
      }
      
      var fn1 = fn.bind({});
      var obj = fn1(3, 5);
      console.log(obj); // 结果:{a: 3, b: 5}
      
      // 在开发过程中,常见的还有以下写法
      var obj2 = fn.bind({})(3, 5);
      console.log(obj2); // 结果:{a: 3, b: 5}
      

    2、方法封装

    • call

      Function.prototype.callHarvey = function (obj) {
          // 如果该方法的调用者不是一个函数,则抛出错误信息
          if (typeof this !== "function") throw new Error(this + "is not a function!");
          
          // 重定向this
          var _this = Object(obj) || window;
          
          // 创建一个新数组,用于获取第一个参数后的所有参数
          var newArr = [];
          
          // 将call的调用函数传给重新定向的this
          _this.callback = this;
          
          // 遍历arguments,第一个之后的参数push到newArr中
          for (let i = 1; i < arguments.length; i++) newArr.push(arguments[i]);
          
          // 使用apply方法,传入重新定向的this和newArr
          _this.callback.apply(_this, newArr);
          
          // 清除callback,防止污染this指向的对象
          delete _this.callback;
      }
      
    • apply

      Function.prototype.applyHarvey = function (obj, initArr) {
          // 如果该方法的调用者不是一个函数,则抛出错误信息
          if (typeof this !== "function") throw new Error(this + "is not a function!");
          
          // 重定向this
          var _this = Object(obj) || window;
            
          // 如果没有传入其他参数,则将一个空数组赋值给arr
          var arr = initArr || [];
          
          // 将call的调用函数传给重新定向的this
          _this.callback = this;
          
          // 使用ES6进行解构赋值,执行_this.callback
          _this.callback(...arr);
          
         // 防止污染this指向的对象
          delete _this.callback;
      }
      
    • bind

      Function.prototype.bindHarvey = function (obj) {
          // 如果该方法的调用者不是一个函数,则抛出错误信息
          if (typeof this !== "function") throw new Error(this + "is not a function!");
          
          // 重定向this
          var _this = Object(obj) || window;
          
          // 将call的调用函数传给重新定向的this
          _this.callback = this;
          
            // 返回函数
          return function () {
              _this.callback.apply(_this, Array.from(arguments));
              
              // 防止污染this指向的对象
            delete _this.callback;
          }
      }
      

    封装这三种Function方法的形式不唯一,常见的方法还有使用eval方式进行封装(即通过拼接字符串,然后通过eval方法执行),但是因为个人认为eval方法非常耗性能,且在实际项目中影响安全性,所以不推荐使用。

    如果有什么不准确的地方,欢迎私信或留言指出,共同进步~~

    相关文章

      网友评论

        本文标题:原生JS - 封装call、apply、bind方法

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