Javascript 无法读取属性';推动';重构代码时未定义的

Javascript 无法读取属性';推动';重构代码时未定义的,javascript,d3.js,Javascript,D3.js,我想让这段代码更简单: links.forEach(function(link) { link.source = nodes[link.source] || (nodes[link.source] = { name: link.source }); link.target = nodes[link.target] || (nodes[link.target] = { name: lin

我想让这段代码更简单:

links.forEach(function(link) {
    link.source = nodes[link.source] ||
        (nodes[link.source] = {
            name: link.source
        });
    link.target = nodes[link.target] ||
        (nodes[link.target] = {
            name: link.target
        });
    console.log(nodes)
});
因此,我对其进行了如下重构:

links.forEach(function(link) {
    if (nodes[link.source] == null) {
        nodes[link.source] = {
            name: link.source
        };
    } else if (nodes[link.target] == null) {
        nodes[link.target] = {
            name: link.target
        };
    } else {
        console.log('Not problem');
    }
});
但是,现在我得到了这个错误:

无法读取未定义的属性“push”

这是完整的原始代码:

<DOCTYPE html>
<meta charset="utf-8">
<style>

 .node {
   fill: #4D00DD;
   stroke: #fff;
   stroke-width: 2px;
  }

 .link {
   stroke: #777;
   stroke-width: 8px;
  }

</style>
<body>
  <script src="https://d3js.org/d3.v3.min.js"></script>
<script>
    var width = 1080,
        height = 960;

    var links = [
      { source : "Baratheon", target : "Lannister"},
      { source : "Baratheon", target : "Stark"},
      { source : "Lannister", target : "Stark"},

    ];

    var nodes = {};

    // parse links to nodes

    links.forEach(function(link) {
      link.source = nodes[link.source] ||
        (nodes[link.source] = {name: link.source});
      link.target = nodes[link.target] ||
        (nodes[link.target] = {name: link.target});
      console.log(nodes)
    });

   // add svg to our body

    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height);

    var force = d3.layout.force()
        .size([width, height])
        .nodes(d3.values(nodes))
        .links(links)
        .on("tick", tick)
        .linkDistance(600)
        .start();

    var link = svg.selectAll(".link")
        .data(links)
        .enter().append("line")
        .attr("class", "link")

    var node = svg.selectAll(".node")
        .data(force.nodes())
        .enter().append("circle")
        .attr("class", "node")
        .attr("r", width * 0.03);

    function tick(e) {

      node.attr("cx", function(d) { return d.x; })
          .attr("cy", function(d) { return d.y; })
          .call(force.drag);

      link.attr("x1", function(d) { return d.source.x; })
          .attr('y1', function(d) { return d.source.y; })
          .attr('x2', function(d) { return d.target.x; })
          .attr("y2", function(d) { return d.target.y; })
    }
</script>

.节点{
填充:4D00DD;
冲程:#fff;
笔画宽度:2px;
}
.链接{
行程:777;
笔划宽度:8px;
}
可变宽度=1080,
高度=960;
变量链接=[
{来源:“Baratheon”,目标:“Lannister”},
{来源:“Baratheon”,目标:“Stark”},
{来源:“兰尼斯特”,目标:“斯塔克”},
];
var节点={};
//解析到节点的链接
links.forEach(函数(link){
link.source=节点[link.source]||
(节点[link.source]={name:link.source});
link.target=节点[link.target]||
(节点[link.target]={name:link.target});
console.log(节点)
});
//将svg添加到我们的身体中
var svg=d3.选择(“正文”).追加(“svg”)
.attr(“宽度”,宽度)
.attr(“高度”,高度);
var-force=d3.layout.force()
.尺寸([宽度、高度])
.节点(d3.值(节点))
.链接(links)
.on(“滴答”,滴答)
.linkDistance(600)
.start();
var link=svg.selectAll(“.link”)
.数据(链接)
.enter().append(“行”)
.attr(“类”、“链接”)
var node=svg.selectAll(“.node”)
.data(force.nodes())
.enter().append(“圆”)
.attr(“类”、“节点”)
.attr(“r”,宽度*0.03);
功能勾号(e){
attr(“cx”,函数(d){return d.x;})
.attr(“cy”,函数(d){返回d.y;})
.呼叫(强制拖动);
attr(“x1”,函数(d){返回d.source.x;})
.attr('y1',函数(d){返回d.source.y;})
.attr('x2',函数(d){返回d.target.x;})
.attr(“y2”,函数(d){返回d.target.y;})
}

您试图使该块更易于阅读,这是一个非常好的练习。但是,你忘了什么

在原始代码中,此任务

link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
。。。以非常详细的方式表示:

节点[link.source]
是否存在?如果是,则使
link.source=节点[link.source]
。如果否,则使
节点[link.source]={name:link.source}
,然后使
link.source=节点[link.source]

但是在
if
逻辑中,您从未设置
link.source
if
节点[link.source]
存在

此外,您不需要:

if (nodes[link.source] == null) {
一个简单的
if(!nodes[link.source]){
将起作用

最后,删除
else
。无论第一个
if
的结果如何,都必须对第二个
if
进行评估

综上所述,这应该是您的重构代码:

links.forEach(function(link) {
  if (!nodes[link.source]) {
    nodes[link.source] = {
      name: link.source
    }
  };
  //Look, Ma, no 'else' here!
  if (!nodes[link.target]) {
    nodes[link.target] = {
      name: link.target
    }
  };
  //add these lines:
  link.source = nodes[link.source];
  link.target = nodes[link.target];
});
下面是正在运行的演示:

var宽度=600,
高度=300;
变量链接=[{
资料来源:“Baratheon”,
目标:“兰尼斯特”
}, {
资料来源:“Baratheon”,
目标:“斯塔克”
}, {
资料来源:“兰尼斯特”,
目标:“斯塔克”
},
];
var节点={};
links.forEach(函数(link){
如果(!节点[link.source]){
节点[link.source]={
名称:link.source
}
};
如果(!节点[link.target]){
节点[link.target]={
名称:link.target
}
};
link.source=节点[link.source];
link.target=节点[link.target];
});
//将svg添加到我们的身体中
var svg=d3.选择(“正文”).追加(“svg”)
.attr(“宽度”,宽度)
.attr(“高度”,高度);
var-force=d3.layout.force()
.尺寸([宽度、高度])
.节点(d3.值(节点))
.链接(links)
.on(“滴答”,滴答)
.linkDistance(50)
.start();
var link=svg.selectAll(“.link”)
.数据(链接)
.enter().append(“行”)
.attr(“类”、“链接”)
var node=svg.selectAll(“.node”)
.data(force.nodes())
.enter().append(“圆”)
.attr(“类”、“节点”)
.attr(“r”,宽度*0.03);
功能勾号(e){
node.attr(“cx”,函数(d){
返回d.x;
})
.attr(“cy”,函数(d){
返回d.y;
})
.呼叫(强制拖动);
link.attr(“x1”,函数(d){
返回d.source.x;
})
.attr('y1',函数(d){
返回d.source.y;
})
.attr('x2',函数(d){
返回d.target.x;
})
.attr(“y2”,功能(d){
返回d.target.y;
})
}

在您的代码示例中没有
推送
。欢迎使用堆栈溢出。我对您的问题做了很多更改,请仔细查看,注意我更改了什么以及为什么更改。另外,请领导。非常感谢您的友好回答,但我有一个问题,我认为“link.source”、“link.target”毫无意义。Bec因为“link.source”已经有了“Baratheon”或“Lannister”这样的值。那么,为什么要有“link.source”、“link.target”呢分配行是必需的?我不知道这些行在哪里使用。它们不同:
links
是数组。
link
,它只是
forEach
函数的一个参数,是对象,它可以有任何其他名称。请检查我的另一个答案,不要评论。我需要你的帮助。我很抱歉我的巨大错误柯。@specialscene不用担心。谢谢你把它作为一个新问题发布。