重构代码时出现Cannot read property 'push' of undefined问题(续)
理解这段代码中link.source被修改的原因
嘿,我来帮你拆解这段代码背后的逻辑,你遇到的现象其实是JavaScript里对象引用特性和短路赋值语法共同作用的结果,咱们一步步来理清楚:
核心代码的逻辑拆解
先看你这段关键代码:
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
这行代码用了JavaScript的||短路求值特性,工作流程是这样的:
- 先判断左侧表达式
nodes[link.source]是否为「真值」(比如存在的对象、非空字符串等) - 如果左侧是「假值」(比如
undefined,说明nodes里还没有link.source这个键),就会执行右侧括号里的代码:nodes[link.source] = {name: link.source} - 右侧的赋值语句会返回被赋值的对象(也就是
{name: "Baratheon"}),然后把这个对象赋值给link.source
为什么link.source会被修改?
因为link是links数组里的对象元素,JavaScript中对象属于「引用类型」——你操作link的时候,不是在操作一个拷贝,而是直接操作原数组里的那个对象本身。
举个具体例子:
- 初始时
link是{source: "Baratheon", target: "Lannister"},link.source是字符串 - 执行赋值后,你直接把
link.source这个属性的值从字符串替换成了新创建的对象,所以原links数组里的那个对象的source属性自然就变了
为什么不执行赋值nodes也有对应值?
这大概率是因为你之前已经执行过这段代码,或者其他逻辑已经给nodes添加了对应的键值对:
- 第一次执行时,
nodes[link.source]不存在,所以会执行右侧的赋值,把对象存入nodes - 之后再执行这段代码时,左侧的
nodes[link.source]已经是存在的对象(真值),||会直接返回这个对象,不会再执行右侧的赋值,但nodes里已经有之前存入的值了
总结一下这段代码的作用
它本质上是在做一个「映射替换」:把links数组中每个link的source(原本是字符串ID),替换成nodes中对应的对象;如果nodes里没有这个对象,就先创建一个并存入nodes,再替换link.source。
内容的提问来源于stack exchange,提问作者specialscene




