JavaScript中对象方法内this访问与对象名访问属性的差异及优势
为什么你现在测的两种写法输出完全一样?
你现在跑下来俩写法结果没差别,本质是刚好碰到了最理想的巧合场景:你定义完user之后全程没改它的指向,调用greet的时候也是直接通过user变量调的,根本没触发两种写法的核心逻辑差异。只要稍微调整下代码结构,写死对象名的写法马上就会埋隐蔽的bug。
两种写法的核心差异
两者本质上的绑定逻辑完全不同:
- 方法里直接写
user.name:永远沿着作用域链找叫user的变量,跟着外层变量的最终指向走,和你当前调用方法时实际关联的对象没有任何强绑定。 - 方法里用
this:永远绑定当前调用方法时,方法前缀的那个对象,跟外层变量叫什么名字、指向哪完全无关。
实际开发中用
this的具体优势 1. 避免外层变量重赋值导致的引用错位
如果你用let定义对象变量,后续是可以把变量指向完全不同的内存地址的,这时候写死对象名的逻辑就会直接跑偏:
let user = { name: "John", // 写死user.name的版本 greet: function() { alert(`hello ${user.name}`) } }; // 把原对象存到另一个变量上,再让原来的user变量指向新对象 const originalUser = user; user = { name: "Bob" }; originalUser.greet(); // 本来期望输出hello John,实际因为函数内部找的是外层最新的user变量,弹出hello Bob
换成this写法的版本,不管外层user变量指向哪,只要你通过originalUser.greet()调用方法,this就会稳定指向originalUser对象,输出符合预期的结果。
2. 让方法可以跨对象复用
如果一个通用方法想给多个不同对象共用,写死对象名的写法根本没有复用可能:
// 写死引用的greet,不管挂到哪个对象上,永远只找john的name const greetHardcoded = function() { alert(`hello ${john.name}`); }; const john = { name: "John", greet: greetHardcoded }; const bob = { name: "Bob", greet: greetHardcoded }; bob.greet(); // 输出hello John,完全不符合预期
而用this写的通用方法,只要挂到哪个对象上,就会自动读取对应对象的属性:
const genericGreet = function() { alert(`hello ${this.name}`); }; const john = { name: "John", greet: genericGreet }; const bob = { name: "Bob", greet: genericGreet }; john.greet(); // hello John bob.greet(); // hello Bob
3. 重构成本极低
因为this完全不依赖外层的变量名,你后续不管是把外层变量改名、把对象挪到别的作用域、甚至把这个方法拆出去单独定义,只要调用的时候是通过正确的对象引用来调,方法的逻辑就不需要改。
反过来写死对象名的写法,如果你后续把外层的user变量改名叫currentUser,就得同步把方法内部所有的硬编码引用都改一遍,漏改一个就会报user is not defined的错,非常容易出问题。
什么时候写死对象名也不会出问题?
如果你的代码满足所有以下条件,两种写法确实不会有结果差异:
- 定义对象用的是
const,全程不会把变量重新指向其他对象 - 方法从来不会被单独提取出来当独立函数调用(比如当定时器、事件监听的回调)
- 从来不会把同一个方法挂到其他不同的对象上复用
但这种场景在真实业务代码里极少存在,只要后续代码迭代调整,写死对象名的写法就很容易藏长期调试都找不到的bug。
内容的提问来源于stack exchange,提问作者nikinbaidar
相关产品推荐
相关产品推荐

