手写 call、apply 与 bind
手写 call、apply 与 bind
理解 this 之后,手写这三个方法是经典进阶题。核心思路一句话:把函数挂到目标对象上,作为对象的方法调用,this 自然就是它。
手写 call
Function.prototype.myCall = function (ctx, ...args) {
ctx = ctx == null ? globalThis : Object(ctx) // null/undefined 指向全局;原始值包装
const key = Symbol() // 唯一键,避免覆盖原有属性
ctx[key] = this // this 就是调用 myCall 的那个函数
const result = ctx[key](...args) // 隐式绑定,函数内 this = ctx
delete ctx[key] // 用完清理
return result
}
greet.myCall({ name: 'Dong' }, 1, 2)
手写 apply
与 call 完全一样,只是参数以数组形式接收:
Function.prototype.myApply = function (ctx, args = []) {
ctx = ctx == null ? globalThis : Object(ctx)
const key = Symbol()
ctx[key] = this
const result = ctx[key](...args)
delete ctx[key]
return result
}
手写 bind
bind 要复杂些:返回新函数,且参数可以分两次传入(柯里化):
Function.prototype.myBind = function (ctx, ...prevArgs) {
const fn = this
return function (...nextArgs) {
return fn.myApply(ctx, [...prevArgs, ...nextArgs])
}
}
处理 new 的边界
原生 bind 有个细节:返回的函数如果被 new 调用,this 应指向新实例而非绑定值。判断依据是 new.target(或 this instanceof fn):
function bound(...nextArgs) {
const isNew = typeof new.target !== 'undefined'
return fn.myApply(isNew ? this : ctx, [...prevArgs, ...nextArgs])
}
// 还要让实例能继承原函数原型上的方法:
bound.prototype = Object.create(fn.prototype)
这三个手写题考的本质都是同一件事:this 由调用方式决定,而"对象.方法()"是制造 this 最趁手的工具。
看到这里了?如果这篇文章帮到过你
请我喝瓶可乐就好 🥤

评论0 条
还没有评论,来抢沙发~