2014-07-24 69 views
2

我一直在寻找一些伟大的d3.js code examples当我看到这样的:变量声明有条件语法

var links = [ 
    {source: "test1", target: "test2"}, 
    {source: "test1", target: "test3"}, 
    {source: "test2", target: "test3"}, 
    {source: "test3", target: "test4"} 
]; 

var nodes = {}; 

// Compute the distinct nodes from the links. 
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}); 
}); 

如何VAR节点正在宣布我没有马上得到。

我的第一个猜测是把它翻译成:

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

但链接不再被绘制。

这两种方法有什么区别?

初始语法的意义是什么,仅仅是一个快捷方式还是增加了性能?

在这种情况下是否有最佳做法?

编辑

所以,如果我试图充分了解

link.source = nodes[link.source] || (nodes[link.source] = {name: link.source}); 
  1. 由于节点[link.source]是一个对象link.source采取它的参考。这一直在发生。

  2. 或者条件,我不确定那部分。

    我想,如果节点[link.source]定义link.source =节点[link.source]返回真的,我们并不需要更进一步。

    如果它没有定义并返回false,or子句力走得更远......

  3. 节点[link.source]得到一个值,由于link.source指向的参考达到相同的价值。

    我想在此阶段link.source尚未包含到节点[link.source]的引用,但是它的初始值。它将在逗号后面包含新的参考。

我错了吗?点2对我来说似乎很陌生。

回答

2

本示例中使用的代码只是一个合成快捷方式。它相当于

links.forEach(function(link) { 
    if(nodes[link.source]) { // we already know about the source of this link 
    link.source = nodes[link.source]; 
    } else { // we haven't seen this source before, create a new node for it 
    nodes[link.source] = {name: link.source}; 
    link.source = nodes[link.source]; 
    } 

    if(nodes[link.target]) { // we already know about the target of this link 
    link.target = nodes[link.target]; 
    } else { // we haven't seen this target before, create a new node for it 
    nodes[link.target] = {name: link.target}; 
    link.target = nodes[link.target]; 
    } 
}); 

所有这一切是必要的,因为节点通过这些链接只能隐式声明的 - 也就是说,没有节点列表,它只是通过遍历链接和“收获”的组装来源和目标。这是存储在nodes中的内容 - 它是从节点的ID(从链接)到代表节点的对象的映射。

上面的代码通过为看不见的节点(即映射中不存在的节点)创建新的对象并插入相应的映射来同时填充此映射。然后链接的源和目标被更新为指向那些对象(稍后将由力布局设置它们的位置来操作)而不是原始数据中引用的节点的ID。

编辑:您编辑的解释是正确的。这基本上是发生了什么。

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

可以翻译成:

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

(同样的事情link.target

所以:

var links = [ 
    {source: "test1", target: "test2"}, 
    {source: "test1", target: "test3"}, 
    {source: "test2", target: "test3"}, 
    {source: "test3", target: "test4"} 
]; 

将被转换成:

links = [ 
    {source: { name: "test1" }, target: { name: "test2" }}, 
    {source: { name: "test1" }, target: { name: "test3" }}, 
    {source: { name: "test2" }, target: { name: "test3" }}, 
    {source: { name: "test3" }, target: { name: "test4" }} 
]; 

和节点将等于:

nodes = { 
    "test1": { name: "test1" }, 
    "test2": { name: "test2" }, 
    "test3": { name: "test3" }, 
    "test4": { name: "test4" }, 
} 
+0

外校验'如果(link.source!=节点[link.source]){'是不是在这种情况下实际需要的(并且不存在于原始代码中)。 –

+0

这是隐含的('link.source'应该和'nodes [link.source]'最后一样),并且会阻止设置'link.source = nodes [link.source];'重复值不止一次。 – manji

+0

这是一张地图 - 不知道你将如何获得重复值?不,这不是隐含的。如果有重复的值,原始代码将进行多个分配。 –

0

我认识到

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

,如果nodes[link.source]不存在

然后只是做link.source = nodes[link.source] = {name: link.source};