美文网首页
改变this指向之call()、apply()、bind()简单

改变this指向之call()、apply()、bind()简单

作者: saxon_y | 来源:发表于2020-12-02 17:41 被阅读0次

    本节将对 js 内置对象 Function 中改变 this 指向的方法进行简单实现,在这之前先复习一下改变 javascript 函数中 this 指向的几个方法:

    • Function.prototype.call() --> function.call(thisArg, arg1, arg2, ...)
    • Function.prototype.apply() --> function.apply(thisArg, [argsArray])
    • Function.prototype.bind() --> function.bind(thisArg[, arg1[, arg2[, ...]]])

    这里简明扼要,不是很清楚的同学,可以先学习一下具体用法。

    MDN规范点这里


    call() 实现

    • call() 可以被所有的函数继承,所以 call() 应该被定义在 Function.prototype
    • call()this 绑定到第一个入参指定的对象上,并根据传入的参数执行函数
    Function.prototype.myCall = function(context, ...args){
        // 不传第一个参数默认为windows
        context = context || window
        //普通函数的this指向调用者, 故this就是要改造的那个函数
        //将函数挂载到目标对象上
        context.func = this
        //执行函数,并保存返回值
        let res = context.func(...args)
        //删除之前挂载在目标对象上的函数,还原目标对象
        delete context.func
        //return返回值
        return res
    }
    

    apply() 方法实现

    apply()call() 唯一的区别就是前者需要将目标函数的入参逐个传入,后者的入参则以数组形式被传入。

    Function.prototype.myApply = function(context, args){
        context = context || window
        context.func = this
        let res = context.func(...args)
        delete context.func
        return res
    }
    

    Math 内置函数调用 apply()

    let arr = [1, 2, 3, 4, 5, 6]
    
    //Math.min/max 的参数是以逗号隔开逐个传入,这里可以调用 `apply()`
    Math.min.myApply(null, arr)
    Math.max.myApply(null, arr)
    

    bind() 实现

    bind() 入参方式是逐个传入, 但是 bind() 返回值是一个函数

    Function.prototype.myBind = function(context, ...args){
        let _this = this
        return function Fn(){
            //因为返回值是一个函数,需要判断 new Fn() 的情况
            //new 会让 this 指向这个新的对象,所以直接判断 Fn 是否在 this 的原型链上
            if(this instanceof Fn){
                   return new _this(...args, ...arguments)
            }
            //调用 call 改变 this 指向
            return _this.call(context, ...args, ...arguments)
        }
    }
    

    bind() 实现偏函数与柯里化:

    //地址生成器函数
    function addressGen(){
        let address = ""
        [...arguments].forEach( item => {
            address += item
        })
        return address
    }
    

    偏函数:

    let guangZhou = addressGen.myBind(null, "广东省", "广州市")
    let beiJing = addressGen.myBind(null, "北京市")
    
    let liWan = guangZhou("荔湾区")  //广东省广州市荔湾区
    let yueXiu = guangZhou("越秀区")  //广东省广州市越秀区
    let haiDian = beiJing("海淀区")  //北京市海淀区
    

    柯里化:

    let guangDong = addressGen.myBind(null, "广东省")
    let shenZhen = guangDong.myBind(null, "深圳市")
    let nanShan = shenZhen.myBind(null, "南山区")
    
    let baiShi = nanShan("白石洲")   //广东省深圳市南山区白石洲
    let taoYuan = nanShan("桃源村")  //广东省深圳市南山区桃源村
    

    点赞、收藏的人已经开上兰博基尼了 (´▽`ʃ♡ƪ)

    转载请注明出处!!!(https://www.jianshu.com/p/b5d39d2046ae)

    相关文章

      网友评论

          本文标题:改变this指向之call()、apply()、bind()简单

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