如何通过属性引用修改JavaScript对象?
嘿,这个问题问得挺到位的!先给你理清楚为啥你原来的代码没效果,再聊聊可行的解决方案——包括你提到的反射相关的思路。
为啥原代码不生效?
你遇到的核心问题是JavaScript中基本类型(比如数字、字符串、布尔值)是按值传递的。当你写let target = myObject.a时,target拿到的是myObject.a的副本值(也就是1),而不是指向myObject.a的“引用”。所以在test函数里修改destination,只是修改了这个副本,完全和原对象myObject没关系。
能不能用反射实现仅靠“属性引用”修改原对象?
直接说结论:没办法只凭借myObject.a这个基本类型值来反向修改原对象。因为基本类型值本身没有任何指向原对象的关联信息,反射API也做不到从一个孤立的数字值追溯到它来自哪个对象的哪个属性。
不过我们可以换个思路,用几种方式模拟出类似“属性引用”的效果,甚至用到反射API:
方案1:传递对象+属性名(最直接)
这是最常用的方式,直接把对象和属性名传给函数,函数里直接操作对象的属性:
let myObject = { a: 1 } let test = (obj, propName) => { obj[propName] += 1; } test(myObject, 'a'); console.log(myObject); // 输出 {a: 2}
如果想用反射API的话,也可以用Reflect.get和Reflect.set来操作:
let myObject = { a: 1 } let test = (obj, propName) => { const currentValue = Reflect.get(obj, propName); Reflect.set(obj, propName, currentValue + 1); } test(myObject, 'a'); console.log(myObject); // 输出 {a: 2}
这里反射的作用只是替代了.或[]的属性操作,本质还是需要同时拿到对象和属性名。
方案2:用包装对象模拟“引用”
如果你一定要传递类似“属性引用”的变量,可以把原属性值放在一个包装对象里——因为对象是引用类型,传递的是指向包装对象的引用:
let myObject = { a: { value: 1 } } // 这里target拿到的是myObject.a这个包装对象的引用 let target = myObject.a let test = (destination) => { destination.value += 1; } test(target); console.log(myObject); // 输出 {a: { value: 2 }}
这样修改destination.value就会直接影响原对象里的包装对象,间接实现了类似“属性引用”的效果。
总结
JavaScript里基本类型没有“引用传递”的说法,只有对象类型是按引用传递的。如果你想修改原对象的属性,要么直接操作对象+属性名,要么用包装对象来模拟引用。单纯靠一个孤立的基本类型值(比如myObject.a的数值1),是没办法反向找到原对象并修改的——哪怕用反射也做不到。
内容的提问来源于stack exchange,提问作者Constantin

