apply call bind 这三个函数可以改变 this 的绑定,语法上有略微差别,可以看我很早之前的一篇文章做过简单的介绍 浅谈JavaScript中的apply、call、bind。
this 优先级
-
new关键字。函数被new调用,this指向由new新构建出来的这个对象 - 函数通过
apply call bind调用,this指向绑定的对象 - 函数被调用时,
this指向调用的对象 - 默认。非严格模式情况下,this指向window, 严格模式下,this指向undefined。
总结一下优先级
new 关键字 > apply call bind > 函数调用 > 默认
实现
我们既然要重写 apply,那前两个优先级是用不了的。我们使用第三个优先级——函数调用——改变 this 的指向。
先看下代码
Function.prototype.myApply = function (context, args) {
context = context || window
args = args || []
const key = Symbol() // 保证key的唯一性,避免覆盖原有的属性方法
context[key] = this // 此时的this指向myApply的调用者
const result = context[key](...args)
delete context[key] // 删掉新建的key
return result
}
上面的代码忽略一些边界情况,实现了简易版的 apply。
看下使用的效果
const person = {
name: 'A',
getName(prefix, suffix) {
return `${prefix} ${this.name} ${suffix}`
}
}
const result = person.getName.myApply({name: 'apply'}, ['one', 'two'])
console.log(result) // one apply two
首先我们创建了一个 Symbol 对象作为 context 的 key,并把 this 赋值给他。此时的 this 值为 getName,因为是 getName 调用了 myApply,所以 this 指向调用者。
当我们以 context[key](...args) 这种方式调用 getName 时,this 指向了 context,因为是 context 调用了 getName 方法。借此完成了 this 值得转换。
call 和 bind 同理
call
Function.prototype.myCall = function (context, ...args) {
context = context || window
const key = Symbol()
context[key] = this
const result = context[key](...args)
delete context[key]
return result
}
bind 的实现可以使用我们写的 call 函数。需要注意的是 bind 可以传参,新生成的函数也可以传参。
Function.prototype.myBind = function (context, ...args) {
const self = this
return function newFn(...newFnArgs) {
return self.myCall(context, ...args, ...newFnArgs)
}
}









网友评论