普通函数直接调用时this指向globalThis(非严格模式)或undefined(严格模式);隐式绑定仅发生在obj.method()形式;箭头函数无this,继承外层非箭头函数的this,且不可被call/apply/bind修改。
这是最常踩坑的场景:直接调用函数,比如 foo(),此时 this 不指向调用它的对象,而是根据执行上下文决定。浏览器中非严格模式下是 window,Node.js 是 global;严格模式下统一为 undefined。
容易误以为“函数写在对象里,调用时就自动绑定该对象”,但只要不是通过对象属性形式调用(即没写 obj.method()),就不会触发隐式绑定。
const fn = obj.method; fn(); —— 这会丢失 this
handler() 也会掉 this
onClick={this.handleClick},点击时 this 是 undefined(严格模式)箭头函数的 this 在定义时就确定了,无法被 call/apply/bind 修改,也不能作为构造函数使用。它只看外层第一个非箭头函数的 this 绑定。
常见误用:在对象方法里用箭头函数想访问当前对象,结果拿到的是外层(比如模块顶层或 class 构造函数)的 this。
obj = { method: () => console.log(this) } —— this 不是 obj
methods 里写箭头函数,this 拿不到 Vue 实例handleClick = () => { ... } 是 OK 的(靠 class 字段初始化语法捕获实例 this),但这是靠语法糖,不是箭头函数“应该这么用”call 和 apply 是立即执行并强制指定 this;bind 返回新函数,其 this 被永久绑定。但注意:new 优先级高于显式绑定 —— 如果对一个已被 bind 的函数再用 new,this 会指向新实例,原绑定失效。
而 call/apply 在 new 场景根本不会发生,因为它们不是构造调用语法。
const bound = original.bind(obj); new bound() → this 是新实例,不是 obj
original.call(obj) 不能加 new,语法错误bind 时若要兼容 new,得在返回函数里判断是否被 new 调用(检查 this 是否是目标函数的实例)写成 obj.method() 时
,this 是 obj;但只要中间有变量赋值这一步,比如 const m = obj.method; m(),就退化为普通函数调用规则。
这个“点号左边是谁”非常关键,且只看**调用时的表达式结构**,不看函数从哪来。
(obj.method)() 和 obj.method() 等价,括号不打断隐式绑定(0, obj.method)() 或 let m = obj.method; m() 会丢失绑定 —— 因为逗号操作符和赋值都返回右值,不再带对象上下文const { method } = obj; method() → this 失效function foo() {
console.log(this);
}
const obj = { foo };
foo(); // 浏览器中输出 window 或 undefined(严格模式)
obj.foo(); // 输出 obj
const bar = obj.foo;
bar(); // 又回到第一行的行为
箭头函数的词法 this 和 new 对绑定的覆盖,是两个最容易被静态代码分析忽略的点。调试时如果发现 this 不是你预期的对象,先看调用形式有没有“断链”,再确认函数是不是箭头函数,最后检查有没有 new 干扰了你用 bind 设的意图。