隐式绑定只看函数调用时点操作符左侧的直接对象,不穿透嵌套链;如obj.foo.bar.baz()中this指向obj.foo.bar而非obj;赋值后调用会丢失绑定,需用call/bind或保持点调用形式。

隐式绑定的核心是看函数调用时的“点前面是谁”——也就是 调用位置左侧的对象。面对复杂调用链(比如 a.b.c.d.method()),关键不是数有多少层,而是聚焦在 真正执行函数的那个点操作符左边的对象。
只看最后一级调用的左侧对象
JavaScript 引擎在执行函数调用时,只关心 method() 前面紧挨着的是谁。例如:
const obj = {
name: 'Alice',
foo: {
bar: {
baz: function() {
console.log(this.name);
}
}
}
};
obj.foo.bar.baz(); // 输出 'Alice'?不!输出 undefined
这里 baz 是作为纯函数被调用的,它左侧是 obj.foo.bar 这个对象,但该对象本身没有 name 属性。所以 this 指向 obj.foo.bar,this.name 是 undefined。
隐式绑定不“穿透”整条链去查找上层属性,它只认直接父对象。
立即学习“Java免费学习笔记(深入)”;
嵌套对象中 this 的归属由调用方式决定,而非定义位置
同一个函数,在不同调用方式下 this 可能完全不同:
-
obj.nested.method()→this是obj.nested -
const fn = obj.nested.method; fn();→this是undefined(严格模式)或全局对象(非严格) -
(obj.nested).method()→ 和第一种等价,括号不改变隐式绑定逻辑 -
(obj.nested.method)()→ 看似加了括号,但本质仍是“点+括号调用”,this仍是obj.nested
警惕中间变量赋值导致的隐式绑定丢失
这是最常见出错点:把方法提取到变量后调用,就断开了和原对象的绑定。
const user = {
name: 'Bob',
sayHi() {
return `Hi, I'm ${this.name}`;
}
};
const speaker = user.sayHi; // ← 赋值操作:只是复制函数引用
console.log(speaker()); // 'Hi, I'm undefined'(严格模式)
解决办法不是改写函数,而是确保调用时仍带对象前缀:
- 保持调用形式:
user.sayHi() - 用
.call()/.apply()/.bind()显式绑定:speaker.call(user) - 用箭头函数包装(但注意箭头函数不绑定
this,它继承外层作用域):const bound = () => user.sayHi() - ES6 解构时用冒号重命名并保留绑定:
const { sayHi: say } = user; say.call(user);
原型链上的方法也遵循同一规则
如果方法定义在原型上,隐式绑定依然看调用时的“点左侧对象”:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `Hello, ${this.name}`;
};
const p = new Person('Charlie');
console.log(p.greet()); // 'Hello, Charlie'
虽然 greet 在 Person.prototype 上,但调用时 p.greet() 左侧是实例 p,所以 this 就是 p。引擎会顺着原型链找到方法,但 this 始终是调用者本身。
同理:Object.prototype.toString.call([]) 中,toString 左侧是 Object.prototype,但通过 .call() 强制把 this 设为 [],这就覆盖了隐式绑定。


















