全局定时器回调中this指向window或globalThis,因默认绑定规则生效;箭头函数无this故继承外层词法作用域;可靠解法是bind绑定、闭包包装或显式call/apply。

在全局直接执行定时器回调时,this 指向 window(浏览器)或 globalThis(Node.js),根本原因在于默认绑定规则生效——函数作为“普通调用”运行,而非作为对象方法、构造函数或通过 call/apply/bind 显式绑定。
默认绑定触发的典型场景
当把一个对象方法赋值给变量后传入 setTimeout,该函数就脱离了原对象上下文:
-
setTimeout(obj.method, 100):此时method被当作独立函数调用,不带任何调用者前缀 - 引擎按规范进入“非严格模式下的默认绑定”,
this自动设为全局对象;严格模式下则为undefined - 这和
const fn = obj.method; fn();的行为完全一致,与是否在定时器中无关
为什么箭头函数“看起来”能解决?
箭头函数没有自己的 this,它继承外层词法作用域的 this 值,而非运行时绑定:
- 若在对象方法内部定义箭头函数,且该方法本身是通过正常方式调用(如
obj.method()),则箭头函数捕获到的是obj - 但若写成
setTimeout(() => obj.method(), 100),真正被定时器执行的是箭头函数,而obj.method()是在其内部被调用的——此时this由method自身的调用方式决定,仍可能出问题 - 更稳妥的是:
setTimeout(() => this.method(), 100)(在对象方法内使用),确保this是当前实例
真正可控的修复方式
绕过默认绑定,需让函数调用时明确关联对象:
-
bind 绑定:
setTimeout(obj.method.bind(obj), 100)—— 创建永久绑定的新函数 -
包装函数(闭包):
setTimeout(function() { obj.method(); }, 100)或 ES6 写法setTimeout(() => obj.method(), 100) -
bind 替代品:call/apply + 匿名函数(较少用):
setTimeout(function() { obj.method.call(obj); }, 100)
注意 this 绑定优先级陷阱
显式绑定(bind)、new 绑定、隐式绑定(点号调用)优先级高于默认绑定,但一旦函数被提取出来,隐式绑定就丢失了:
-
obj.method()→ 隐式绑定,this === obj -
const f = obj.method; f()→ 默认绑定,this不再是obj - 定时器本质就是这种“提取+调用”过程,所以必须手动补回绑定关系
不复杂但容易忽略:定时器不是特殊环境,它只是把函数放到任务队列里等执行;真正决定 this 的,永远是函数被调用的那一行代码的语法形式。

















