先记住这个答案
call 和 apply 在调用时临时指定 this 并立刻执行函数,区别仅在参数传递方式:call 逐个列出,apply 用数组。bind 不执行函数,而是返回一个新函数,该函数永久绑定了 thisArg,且调用时会把 bind 传入的参数排在实际参数之前,形成部分应用。bind 返回的函数还有 length、name 等变化,并可与 new 一起使用,但提供的 this 会被忽略。
- call/apply 立即调用,bind 返回新函数
- bind 可预置参数,形成部分应用
- bind 后 this 不可再被 call/apply 改变
调用时机与参数传递差异
call 和 apply 都是立即调用函数,区别仅在参数形式:fn.call(thisArg, a, b) 与 fn.apply(thisArg, [a, b])。它们适合需要临时借用方法且只执行一次的场合,如把 arguments 对象传给数组方法时,slice.call(arguments) 立刻得到新数组。
bind 则创建了一个新函数,内部存储了 thisArg 和若干前置参数。当新函数被调用时,目标函数以这些存储值和调用时传入的新参数作为最终参数执行。这种延迟执行使得 bind 常见于事件处理器、定时器回调,或需要反复调用同一固定 this 的场景。
定时器回调丢失 this 的处理
假设一个计数器对象拥有 increment 方法,每次点击按钮需要调用该方法。若直接把 method 传给 addEventListener,回调里的 this 会变成按钮元素,导致读取不到对象内的 count。使用 bind 将方法绑定到对象,再传给 addEventListener,回调执行时 this 始终指向对象。
对比 call/apply 无法直接用于这种场景,因为它们在事件触发时无法介入;必须放在一个包装函数里,如 () => obj.increment()。bind 的优势在于返回的函数本身可独立传递,调用方无感知,且可预先固定第一个参数,例如 bind 一个基准值使 getOffset(step) 变成固定步长的函数。
function log(prefix, ...nums) {
console.log(prefix + nums.join(','));
}
const logSum = log.bind(null, 'sum:');
logSum(1, 2, 3);
const logFirst = log.bind(null, 'first:', 10);
logFirst(20, 30);查看输出与解释
sum:1,2,3
first:10,20,30bind 的第二个参数起会预置到目标函数参数列表的前部,实际调用时只附加后续参数。
bind 结果的可变与不可变边界
已经 bind 后的函数,再次使用 call 或 apply 修改 this 不会生效,因为内部存储的 this 是固定的。但 bind 返回的函数还可以继续 bind,只是第二次 bind 提供的 this 会被忽略,参数仍会累加在前一次预置的参数之后。
bind 函数没有 prototype 属性,因此不能作为 extends 的基类;但可以作为构造函数用 new 调用,此时预置的参数正常传给目标函数,而绑定的 this 被忽略。若要限制只能用 new 或只能用普通调用,目标函数需自行检查 new.target。
容易答错的地方
- bind 会立即执行函数
- 实际 bind 只返回新函数,不会触发目标函数体。立即执行应使用 call/apply,或对 bind 的结果手动加括号调用。
- bind 后用 call 能改变 this
- 绑定后的 this 是永久的,call 只会传递调用时的参数,无法覆盖 bind 设置的 thisArg。MDN 明确说明绑定函数的 this 值在构造时被忽略,普通调用时固定不变。
面试官还会怎么问?
bind 返回函数的 length 属性如何计算?
length 等于原函数 length 减去 bind 时预置的参数个数,最小为 0。例如 function f(a,b){} 的 length 是 2,f.bind(null,1) 返回函数的 length 是 1。
箭头函数内使用 bind 有意义吗?
箭头函数的 this 由词法作用域决定,bind 无法改变它。对箭头函数调用 bind 只会预置参数,thisArg 被忽略,且不能作为构造函数。
bind 与闭包手动保存 this 相比有何优劣?
bind 语法简洁且返回函数的 name 会以 “bound ” 开头并保留原函数名,但会额外创建函数对象。闭包方式灵活但需自行保存 this 变量,选择取决于可读性和是否需要预置参数。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。