默认绑定失效是因函数脱离原调用上下文而裸调用,非严格模式下this指向window/global,严格模式下为undefined;常见场景包括赋值调用、事件监听器直接传入、定时器使用及解构调用;防御需锁定(bind)、代理(箭头函数)或显式调用(call/apply)。

默认绑定失效,不是 this “坏了”,而是它根本没按你预期的方式被调用。核心问题在于:函数脱离了原本的调用上下文,变成“裸调用”,此时规则启动——非严格模式指向 window 或 global,严格模式直接是 undefined。一旦你在方法里访问 this.xxx,就极易报错或取到错误值。
常见失效场景:函数被“摘出来”调用
这是最典型也最容易忽略的情况。当对象方法被赋值给变量、传入回调、或作为事件处理器时,调用关系断裂,隐式绑定丢失,退回到默认绑定。
-
赋值后调用:
const fn = obj.method; fn();→ this 指向全局(非严格)或 undefined(严格) -
事件监听器直接传方法:
btn.addEventListener('click', obj.handleClick);→ 浏览器内部以obj.handleClick()形式调用,等价于独立调用 -
定时器/异步回调中使用:
setTimeout(obj.method, 100);→ 同样失去对象上下文 -
解构获取方法:
const { method } = obj; method();→ 本质仍是变量引用+独立调用
防御性编程三原则:锁定、代理、显式
不依赖调用者“记得绑好 this”,而是主动控制执行上下文。
-
提前 bind(this):在构造函数或初始化阶段绑定,生成稳定引用
例如:this.handleClick = this.handleClick.bind(this);,再传给事件监听器 -
使用箭头函数(仅限类字段写法):箭头函数不绑定自己的 this,而是继承外层词法作用域(通常是类实例)
例如:handleClick = () => { console.log(this.name); };—— 注意这是语法糖,本质是闭包捕获 -
调用时显式指定上下文:用
call/apply或包装一层匿名函数
例如:btn.addEventListener('click', () => obj.method());或setTimeout(() => obj.method(), 100);
严格模式是“安全哨兵”,不是万能解药
启用 "use strict" 后,this 默认为 undefined 而非 window,能让错误提前暴露(比如 this.xxx 报 TypeError),避免静默失败。但它不修复问题本身,只是让 bug 更早浮现。
- 建议整个项目开启严格模式(ES6 模块默认就是严格模式)
- 但不能因此省略绑定逻辑——undefined 依然无法访问属性,照样崩
- 尤其注意 Node.js 环境下 global 和浏览器 window 行为差异,统一用严格模式可减少环境迁移风险
现代写法推荐:class fields + 箭头函数 + 构造器绑定
兼顾可读性与健壮性,适合大多数业务组件。
- 把事件处理方法声明为类字段箭头函数:
handleSubmit = (e) => { ... } - 对需要复用或传参的方法,在 constructor 中绑定:
this.fetchData = this.fetchData.bind(this); - 避免在 render 或模板中写内联箭头函数(如
onClick={() => this.fn()}),防止重复创建函数影响性能











