javascript - 重构代码时无法读取未定义的属性 'push'

标签 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: 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');
    }
});

但是,现在我得到这个错误:

Cannot read property 'push' of undefined

这是完整的原始代码:

<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>

最佳答案

您尝试使该 block 更易于阅读,这是一个很好的练习。但是,您忘记了一些东西。

在原始代码中,这个赋值......

link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});

... 以一种非常冗长的方式表示:

Does nodes[link.source] exist? If yes, make link.source = nodes[link.source]. If no, make nodes[link.source] = {name: link.source}, and then make link.source = nodes[link.source].

但是在您的 if 逻辑中,如果 nodes[link.source] 存在,您永远不会设置 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 width = 600,
  height = 300;

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

];

var nodes = {};

links.forEach(function(link) {
  if (!nodes[link.source]) {
    nodes[link.source] = {
      name: link.source
    }
  };
  if (!nodes[link.target]) {
    nodes[link.target] = {
      name: link.target
    }
  };
  link.source = nodes[link.source];
  link.target = nodes[link.target];
});

// 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(50)
  .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 src="https://d3js.org/d3.v3.min.js"></script>

关于javascript - 重构代码时无法读取未定义的属性 'push',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48165794/

相关文章:

javascript - 如何将 json 对象数组准备为 d3 分层树结构

javascript - 在回调中访问对象属性

javascript - 成功登录 azure AD 后弹出窗口未重定向

javascript - 让 capybara 在 Rails 中与 Vue.js 一起工作

javascript - (JavaScript) 尝试通过复选框调用方法

javascript - 外部 JS 文件在我的 HTML 文件中不起作用

javascript - 拖动过程中旋转矩形 D3

javascript - 将数组附加到 ul block - 错了吗?!查询

javascript - D3.js折线图方向错误

javascript - 使用拖动行为时,具有链接力的 D3.js v4 力布局会导致奇怪的移动