重构代码时无法读取未定义的属性"push" [英] Cannot read property 'push' of undefined when refactoring code

查看:78
本文介绍了重构代码时无法读取未定义的属性"push"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使这段代码更简单:

I want to make this code easier:

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)
});

所以,我像这样重构它:

So, I refactored it like this:

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

但是,现在出现此错误:

However, now I get this error:

无法读取未定义的属性"push"

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>

推荐答案

您试图使该块更易于阅读,这是一个非常不错的练习.但是,您忘记了一些东西.

You tried to make that block easier to read, which is a very nice exercise. However, you forgot something.

在原始代码中,此任务...

In the original code, this assignment...

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

...意味着,非常冗长:

... means, in a very verbose way:

nodes[link.source]是否存在?如果是,请创建link.source = nodes[link.source].如果否,请先创建nodes[link.source] = {name: link.source},然后再创建link.source = nodes[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

But in your if logic you're never setting link.source if nodes[link.source] exists!

此外,您不需要:

if (nodes[link.source] == null) {

一个简单的if (!nodes[link.source]) {即可使用.

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

Finally, drop that else. The second if must be evaluated, regardless the result of the first if.

话虽如此,这应该是您的重构代码:

All that being said, this should be your refactored code:

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>

这篇关于重构代码时无法读取未定义的属性"push"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆