主题
call、apply 与 bind
call、apply、bind 都用于显式指定函数调用时的 this。它们解决的是“这次调用应该把 this 绑定给谁”。
三者分别做什么
call:立即调用,参数逐个传入apply:立即调用,参数以数组形式传入bind:不立即调用,返回一个绑定后的新函数
js
function greet(message) {
console.log(message, this.name)
}
const user = { name: 'Lee' }
greet.call(user, 'hi')
greet.apply(user, ['hello'])
const bound = greet.bind(user, 'welcome')
bound()为什么需要它们
最常见的原因是函数被单独传递后,原来的 this 绑定丢了。
js
const user = {
name: 'Lee',
sayHi() {
console.log(this.name)
},
}
const fn = user.sayHi
fn() // this 丢失这时可以显式绑定:
js
fn.call(user)call 的核心思路
call 可以理解成:临时把函数挂到目标对象上,再以“对象方法调用”的方式执行。
js
Function.prototype.myCall = function (ctx, ...args) {
const target = ctx == null ? globalThis : Object(ctx)
const key = Symbol('fn')
target[key] = this
const result = target[key](...args)
delete target[key]
return result
}这里有几个关键点:
this指向当前被调用的函数null/undefined需要兜到底层全局对象- 原始值需要先装箱成对象
- 临时属性名通常用
Symbol避免冲突
apply 和 call 的区别
实现思路几乎一样,主要区别只是参数形式:
js
Function.prototype.myApply = function (ctx, args = []) {
const target = ctx == null ? globalThis : Object(ctx)
const key = Symbol('fn')
target[key] = this
const result = target[key](...args)
delete target[key]
return result
}所以 apply 更适合“参数本来就是数组”的场景。
bind 的关键点
bind 和 call / apply 最大的不同是:它不会立刻执行,而是返回一个新函数。
js
Function.prototype.myBind = function (ctx, ...args) {
const fn = this
return function (...restArgs) {
return fn.apply(ctx, [...args, ...restArgs])
}
}这让它特别适合:
- 回调传递前先固定
this - 预填部分参数
bind 还涉及预置参数
js
function add(a, b) {
return a + b
}
const add10 = add.bind(null, 10)
console.log(add10(5)) // 15这里 10 在绑定时就已经被提前放进参数列表了。
手写 bind 时最容易漏的点
一个更完整的 bind 还要处理 new 调用场景:
js
Function.prototype.myBind = function (ctx, ...args) {
const fn = this
return function (...restArgs) {
if (new.target) {
return new fn(...args, ...restArgs)
}
return fn.apply(ctx, [...args, ...restArgs])
}
}因为绑定后的函数仍然可能被拿去当构造函数使用。
bind 不能简单理解成“永久改函数”
它不会修改原函数本身,而是返回一个新的包装函数。
js
const bound = greet.bind(user)
console.log(bound === greet) // false使用边界
手写实现时需要注意:
- 这里只是在模拟核心思路,不等于完整复刻规范细节
- 真正的原生行为还涉及函数长度、原型链、构造器语义等细节
- 日常面试题实现通常只要求掌握“绑定思路”,不是完全对齐规范
使用建议
- 需要立刻调用时,用
call或apply。 - 参数已经是数组时,
apply更顺手。 - 需要返回包装函数时,用
bind。 - 手写实现时,先抓住“临时挂载执行”和“返回新函数”这两个核心模型。
