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

本节将对 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()简单实现)