基于对象属性值的参数是否不持有引用?递归对象赋值疑问
为什么递归赋值时对象引用表现不同?
其实核心原因在于JavaScript中变量保存的是对象引用的副本,而非直接持有原对象的“所有权”,我给你拆解两种场景的区别:
错误方案的问题所在
假设你的错误代码大概是这样的:
function setValue(obj, path, value) { let nestedObj = obj; // 遍历到路径的最后一个属性 for (const key of path) { nestedObj = nestedObj[key]; } // 试图直接赋值 nestedObj = value; }
当你循环走完所有路径后,nestedObj确实指向了原对象中目标属性的当前值,但这里的nestedObj只是一个保存了该属性引用的变量。当你执行nestedObj = value时,本质是把这个变量的引用指向了新的value,完全和原对象的那个属性没关系了——就像你拿着一张写着房间地址的纸条,然后把纸条上的地址改成了另一个房子,原来的房间并不会因此改变。
正确方案的逻辑
调整后的代码应该是提前停在路径的倒数第二步,拿到目标属性的父对象,然后通过父对象来修改目标属性:
function setValue(obj, path, value) { let nestedObj = obj; // 遍历到倒数第二个路径节点 for (let i = 0; i < path.length - 1; i++) { nestedObj = nestedObj[path[i]]; } // 通过父对象修改目标属性 nestedObj[path[path.length - 1]] = value; }
这时候,nestedObj指向的是原对象的一部分(目标属性的父级),你通过nestedObj[lastKey] = value修改的是这个父对象的属性,而父对象的引用一直和原对象关联着——相当于你走到了目标房间的门外(父对象),直接把房间里的东西换成新的,这样原对象的结构自然就被修改了。
简单总结:
- 直接给
nestedObj赋值:只是改变变量的引用指向,和原对象无关 - 修改
nestedObj的属性:是通过父对象的引用修改原对象的结构,所以能生效
内容的提问来源于stack exchange,提问作者Andrew Kim
相关产品推荐
相关产品推荐

