我试图理解以下代码中发生的事情:
var dataset = [
{source: "Microsoft", target: "Amazon", type: "licensing"},
{source: "Microsoft", target: "HTC", type: "licensing"},
{source: "Samsung", target: "Apple", type: "suit"},
{source: "Motorola", target: "Apple", type: "suit"},
{source: "Nokia", target: "Apple", type: "resolved"},
{source: "HTC", target: "Apple", type: "suit"},
{source: "Kodak", target: "Apple", type: "suit"},
{source: "Microsoft", target: "Barnes & Noble", type: "suit"},
{source: "Microsoft", target: "Foxconn", type: "suit"},
{source: "Oracle", target: "Google", type: "suit"},
{source: "Apple", target: "HTC", type: "suit"},
{source: "Microsoft", target: "Inventec", type: "suit"},
{source: "Samsung", target: "Kodak", type: "resolved"},
{source: "LG", target: "Kodak", type: "resolved"},
{source: "RIM", target: "Kodak", type: "suit"},
{source: "Sony", target: "LG", type: "suit"},
{source: "Kodak", target: "LG", type: "resolved"},
{source: "Apple", target: "Nokia", type: "resolved"},
{source: "Qualcomm", target: "Nokia", type: "resolved"},
{source: "Apple", target: "Motorola", type: "suit"},
{source: "Microsoft", target: "Motorola", type: "suit"},
{source: "Motorola", target: "Microsoft", type: "suit"},
{source: "Huawei", target: "ZTE", type: "suit"},
{source: "Ericsson", target: "ZTE", type: "suit"},
{source: "Kodak", target: "Samsung", type: "resolved"},
{source: "Apple", target: "Samsung", type: "suit"},
{source: "Kodak", target: "RIM", type: "suit"},
{source: "Nokia", target: "Qualcomm", type: "suit"}
];
var nodes = {};
update(dataset);
function update(links){
var i = 1;
links.forEach(function(link){
// Pre iteration checks
console.log(i);
console.log(link.source);
console.log(nodes[link.source]);
// Observations – initial dataset is being overwritten?
// Should the following be read as “if one evaluates to true, do both?”
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source, linkCount:0}); // Initialize new nodes with zero links
link.source.linkCount++;
// Post iteration checks
console.log(link.source);
console.log(nodes[link.source]); // This is undefined if link.source is now an object. This is effectively saying console.log(nodes[object])
console.log(nodes[link.source.name]); // This now says console.log(nodes["Microsoft"]) (for ex)
i++;
});
}
如果我写下我认为每次迭代中发生的事情,我会看到以下内容:
"Microsoft" = nodes["Microsoft"]
?假。nodes["Microsoft"] = { name: "Microsoft", linkCount: 0 }
linkCount + 1
,以便nodes["Microsoft"] = { name:
"Microsoft", linkCount: 1 }
"Microsoft" = nodes["Microsoft?"]
?真。linkCount + 1
,以便nodes["Microsoft"] = { name: "Microsoft", linkCount: 2 }
"Samsung" = nodes["Samsung"]
?假。nodes["Samsung"] = { name: "Samsung", linkCount: 0 }
linkCount + 1
以及nodes["Samsung"] = { name: "Samsung", linkeCount: 1 }
我怀疑我的混淆与OR(||
)运算符的工作原理有关。我的想法是,如果LHS评估为假,跳过它并进行RHS。这是错的吗?
编辑:
如果我只看第一次迭代;
dataset[0].source = nodes[dataset[0].source] || (nodes[dataset[0].source] = { name: dataset[0].source })
我们希望双方都能实现。 dataset [0] .source应设置为nodes [dataset [0] .source]并且我们要为节点[dataset [0] .source]设置'value'。
如果我试图像这样跑;
dataset[0].source = nodes[dataset[0].source];
nodes[dataset[0].source] = { name: dataset[0].source };
然后第一行运行正常,可能是交换“Microsoft”指向节点[“Microsoft”](当前未定义)的指针,但随后尝试用数据集[0]更新节点[“Microsoft”]的名称.source值,未定义,仅将nodes [“microsoft”]的名称值设置为undefined。
如果我尝试这样的代码;
dataset[0].source = nodes[dataset[0].source] || nodes[dataset[0].source] = { name: dataset[0].source };
然后我收到错误“Uncaught ReferenceError:赋值中的左侧无效” - 不确定为什么会这样?
最后,如果我尝试
dataset[0].source = nodes[dataset[0].source] || (nodes[dataset[0].source] = { name: dataset[0].source });
在RHS周围加上括号,一切正常。 dataset [0] .source是对象,节点[dataset [0] .source]也是对象。
为什么这三种不同的代码结构出现这种情况最终是我不明白的,具体为什么第三种代码工作
答案 0 :(得分:0)
binary logical operator ||
也称为“默认”运算符。它通常不返回布尔值,而是返回第一个值,除非它是假的,在这种情况下返回第二个值。换句话说,
a || b
字面上返回 a 或 b 。
e.g。 null || 4
返回4.
是的,如果左侧是真的,则右侧表达式被完全忽略(解析但未计算)。
对于link.source
,通过尝试为该字符串分配属性,代码隐式将字符串转换为对象。字符串和数字都可以用这种方式装箱,既可以使用继承的方法和属性(例如link.source.length
来获取字符串的长度),也可以为它们分配新的方法和属性。他们通过这样做来保留他们的类型,不像你做new String(link.source)
时发生的那样:它创造了一个在各方面都表现得像一个真实的对象。
答案 1 :(得分:0)
我不确定混淆在哪里,但代码正在以这种方式工作:
var dataset = [ /*data*/]
var nodes = {}
update(dataset);
正如预期的那样,将大量数据和节点初始化为空对象文字,然后调用更新函数。
-
function update(links) {
var i = 1;
links.forEach(function(link)
{
//content
i++;
});
}
这是迭代你的数组,增加i的值。
这里有两个略微相切的点 - 而不是自己递增,传递给foreach的回调将index作为其第二个参数;如果支持旧浏览器,请小心使用forEach,因为它不适用于IE8之前的浏览器。
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source, linkCount:0}); // initialize new nodes with zero links
link.source.linkCount++;
这是你的循环代码的关键。懒惰的“OR”运算符与你提到的完全相同 - 如果左侧是真实的,那么它不会评估第一部分,所以
true || foo();
永远不会评估“foo”功能。因此,如果nodes [link.source]确实存在(并且是真实的,但定义的对象总是真实的),那么它会忽略第二部分并将该值分配给link.source,从而覆盖现有的数据集。
如果左侧的表达式为false,则它将评估您的右侧并在节点中创建节点并将其分配给link.source。
这意味着在运行代码的最后,节点将是一个包含linkCounts和名称属性的对象;和数据集将是相同的数组,但每个对象的source属性由相同的linkCount / name对象关联。
-
我不完全确定您希望代码如何工作,因此我不确定这与您预期的运行有何不同。
可能有问题的一件事是你讨论比较link.source和节点[link.source],但这不会发生在你编写的代码中,因为你使用的是单个等号(“=”)赋值运算符,而不是比较运算符的double或triple equals(“==”或“===”)?如果你想要,那么相关的行将是:
(link.source == nodes[link.source]) || (nodes[link.source] = {name: link.source, linkCount:0});
我会谨慎使用这种技巧方式的操作符,因为聪明的代码通常很难读懂,如果这就是你想要的,我会赞成标准的提高可读性的声明:
if(link.source !== nodes[link.source]) {
nodes[link.source] = {name: link.source, linkCount:0}
}
但是,如果这就是你想要的,那么它会给你一个奇怪而毫无意义的输出... = \