标准答案
- call 接收 thisArg 和参数列表,apply 接收 thisArg 和参数数组。
- 实现 call/apply 可以临时把函数挂到 thisArg 上调用,再删除临时属性。
- bind 不会立即执行,而是返回一个新函数,调用时合并预置参数和本次参数。
- bind 返回的函数如果被 new 调用,this 应该指向新实例,而不是绑定时传入的对象。
- 实现时要处理 null、undefined thisArg,以及避免临时属性名冲突。
题目解析
这类手写题本质是在考函数调用时 this 怎么确定。call/apply 是把一次调用的接收者改掉,bind 则是提前做一层包装,把未来调用的 this 和部分参数固定下来。
call/apply 的简化实现可以借助“对象方法调用时 this 指向对象”这个规则。把函数临时放到目标对象上执行,就能模拟显式绑定。
bind 的 new 场景是常见加分点。绑定函数作为构造函数使用时,实例创建规则优先,不能再把 this 强行指向原来绑定的对象。
代码示例
下面是简化版 call 和 bind,重点展示 this 绑定思路。
JavaScript
Function.prototype.myCall = function myCall(thisArg, ...args) {
const context = thisArg == null ? globalThis : Object(thisArg)
const key = Symbol('fn')
context[key] = this
const result = context[key](...args)
delete context[key]
return result
}
Function.prototype.myBind = function myBind(thisArg, ...presetArgs) {
const fn = this
function bound(...args) {
const isNewCall = this instanceof bound
return fn.apply(isNewCall ? this : thisArg, [...presetArgs, ...args])
}
bound.prototype = Object.create(fn.prototype)
return bound
}常见误区
- bind 实现成直接执行函数,而不是返回新函数。
- 没有处理 bind 后再 new 的情况。构造调用时 this 应该是新实例。
- 用普通字符串做临时属性名,可能覆盖目标对象已有属性。