持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情
前言
昨天重新梳理了一下手写 call 的基本思路和实现,今天重新整理一下 bind 的基本思路和实现。
bind 与 call 十分相似,不同的是,bind 会返回一个被改变 this 指向的函数,而且不会立即执行该函数,需要使用者手动调用。
还有一处很大的不同,就是 thisArg 参数,本人习惯将它称呼为上下文(ctx),说白了,就是函数新的 this 指向,在 call 中,如果没有传入该参数,则默认指向 window;而在 bind 中,如果没有传入该参数,返回函数的执行作用域的 this 将被视为新函数的 thisArg。
基本实现
首先,依旧是先创建自定义的 bind 函数,并且 bind 函数是返回一个新的函数,所以整体代码如下:
// 参数分为两个部分,一个是新的 `this` 指向,另一部分是执行函数的参数
Function.prototype.myBind = function (thisArg, ...arg1) {
// 返回新的函数,不能使用箭头函数,可接受参数
return funtcion (...arg2) {}
}
注意:不论是定义函数获取返回的函数,都不能使用箭头函数,因为箭头函数无法获取到需要的
this;如果返回的函数使用了箭头函数,则无法实现该功能:如果没有传入thisArg,返回函数的执行作用域的this将被视为新函数的thisArg。
因为箭头函数的this在定义时就已经确定了,所以不能使用。
记录下被执行的函数,也就是定义时的 this :
Function.prototype.myBind = function (thisArg, ...arg1) {
// 记录需要被执行的函数,也就是这里的 this
const targetFun = this
return funtcion (...arg2) {}
}
然后在返回的函数中判定新的 this 指向,如果存在 thisArg,就是使用 thisArg,没有,就是使用返回函数执行时的 this;然后执行函数,返回结果,这部分与 call 基本一致:
Function.prototype.myBind = function (thisArg, ...arg1) {
const targetFun = this
return funtcion (...arg2) {
// 确定作用域
const ctx = thisArg || this
// 挂载函数
const key = Symbol()
ctx[key] = targetFun
// 接受全部参数,执行函数,获取结果
const res = ctx[key](...arg1, ...arg2)
// 删除函数挂载
delete ctx[key]
// 返回结果
return res
}
}
测试一下:
const bear_1 = {
name: 'Bear_1',
write (writer = 'unkonw', time = 'now') {
console.log(`My name is ${this.name} --by ${writer} in ${time}`)
}
}
const bear_2 = {
name: 'Bear_2'
}
const bear_3 = {
name: 'Bear_3'
}
Function.prototype.myBind = function (thisArg, ...arg1) {
const targetFun = this
return function (...arg2) {
const ctx = thisArg || this
const key = Symbol()
ctx[key] = targetFun
const res = ctx[key](...arg1, ...arg2)
delete ctx[key]
return res
}
}
// 不指定新的作用域
bear_3.bear_2_write = bear_1.write.myBind()
bear_3.bear_2_write('writerB', '2023-03-15')
// 输出:My name is Bear_3 --by writerB in 2023-03-15
// 指定新的作用域
bear_3.bear_2_write = bear_1.write.myBind(bear_2)
bear_3.bear_2_write('writerB', '2023-03-15')
// 输出:My name is Bear_2 --by writerB in 2023-03-15
至此,就基本完成了。