美文网首页前端程序员
原生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