非严格模式下this指向window或globalThis是因函数独立调用时引擎自动绑定到全局对象;严格模式下this为undefined以修复该漏洞;ES6模块默认严格模式;setTimeout等API传入函数引用导致this丢失;this绑定取决于调用形式而非定义位置。

非严格模式下 this 指向 window 或 globalThis 是怎么发生的
这不是“设计成这样”,而是历史遗留行为:函数独立调用时,引擎找不到明确的调用者对象,就自动把 this 绑定到运行时的全局对象上。浏览器中是 window,Node.js 中是 globalThis(注意不是 global,后者在某些老版本里存在但不标准)。
常见触发场景包括:
-
foo()直接调用 const fn = obj.method; fn();setTimeout(obj.method, 100)(function(){ console.log(this); })()
只要没通过点号、call/apply/bind、new 或箭头函数介入,就走这条路。它不看函数定义在哪,只看调用那一行左边有没有“对象.”。
严格模式下 this 为什么是 undefined
ES5 引入严格模式就是为了堵住这个“自动兜底”的漏洞。一旦启用 "use strict",默认绑定就不再装箱,直接让 this 保持为 undefined。
这会导致两种典型报错:
-
Cannot read property 'xxx' of undefined—— 访问this.xxx时崩 -
Cannot set property 'xxx' of undefined—— 赋值时崩
ES6 模块(.mjs 或 type="module" 的脚本)顶层默认就是严格模式,所以你在模块里写 function foo() { console.log(this); } foo();,输出一定是 undefined,不是 window。
setTimeout 和 addEventListener 里 this 丢失的本质
这些 API 接收的是“函数引用”,不是“方法调用”。比如 setTimeout(obj.method, 100),传进去的是一个纯函数值,引擎根本不知道它曾经属于 obj —— 所以执行时只能走默认绑定。
对比一下:
-
setTimeout(obj.method, 100)→this是undefined(严格模式) -
setTimeout(() => obj.method(), 100)→ 箭头函数没有this,内部调用仍走obj.method()的隐式绑定 -
setTimeout(obj.method.bind(obj), 100)→ 显式绑定,this锁死为obj
DOM 事件监听器同理:btn.addEventListener('click', handler) 中,handler 是被引擎回调的,不是 btn.handler(),所以不满足隐式绑定条件。
为什么不能靠“谁定义的”来判断 this
因为 JavaScript 的 this 绑定发生在**调用时刻**,而不是定义时刻。下面这段代码很能说明问题:
const obj = {
name: 'Alice',
greet() {
console.log(this.name);
}
};
const fn = obj.greet;
fn(); // 输出 undefined(严格模式)或 window.name(非严格)
greet 函数体内明明写在 obj 里,但赋值给 fn 后再调用,this 就和 obj 彻底无关了。真正起作用的只有调用形式:obj.greet() vs fn()。
最容易被忽略的一点:嵌套调用也不改变规则。obj.nested.method() 中的 this 是 obj.nested,不是 obj;如果把它解构出来再调用,照样退化为默认绑定。










