让我试着解释这一点,而不用吐出汤字,并抛出许多有趣的词语,如“异步”,“作用域链”或“关闭”。
问题发生是因为即使第一个MongoDB查询返回之前,您的循环已经完成很久。当你的回调运行时,变量k
已经经过5次循环,现在等于5.因此,当你回调的所有五次回来时,console.log("Filename: " + filename[k]);
每次都会是console.log("Filename: " + filename[5]);
。
正在进行正确的查询,因为新的查询开始于循环的每次迭代,并且在正确值时使用k
;然而,该变量k
的范围定义上述回调,所以当回调终于开火,k
将长着递增到5
试试这个完成:
for(var k =0; k<(filename.length)-2;k++) {
(function (k) {
collection.count({ "display.Name": filename[k] } , function(err, count) {
console.log("Filename: " +filename[k]);
console.log(" Trips: " + count);
});
})(k);
}
现在将工作,因为我们已经创建了一个围绕变量k
的新范围。所有这一切意味着从外行的角度来说,技术上你有两个变量名为k
。第一个是你在for循环中定义的那个,第二个是在自调用函数自行调用时创建的,传入k
。函数的参数也被称为k
,但它在技术上是一个全新的变量定义。这意味着第二个k
变量将在循环的每次迭代中变化而不是,只有外部范围中的一个正在变化。
在每次迭代中定义一个新的匿名函数,并将k
传递给它。现在当回调触发时,它们的每个k
变量将是唯一的,并且不会与外部变量k
相同。
为了让事情更容易理解,只需在匿名函数中更改变量名称,使其与外部变量名称不同,然后您就会明白为什么这会起作用。
for(var k =0; k<(filename.length)-2;k++) {
(function (x) {
collection.count({ "display.Name": filename[x] } , function(err, count) {
console.log("Filename: " +filename[x]);
console.log(" Trips: " + count);
});
})(k);
}
另一种奇特的方式来完成同样的事情是只包裹回调函数在一个新的范围,而不是整个查询。虽然我把它留给你来决定,如果它真的是更容易阅读或不:P
for(var k =0; k<(filename.length)-2;k++) {
collection.count({ "display.Name": filename[k] } , (function (x) {
return function(err, count) {
console.log("Filename: " +filename[x]);
console.log(" Trips: " + count);
};
})(k));
}
在这一个自我调用函数作为第二个参数collection.count
供应。自调用函数通过k
,在自调用函数内部变为x
。它立即返回另一个函数;该函数实际上将作为第二个参数传递给collection.count
。自我调用函数变成了一种迷你工厂,它返回另一个函数,该函数现在可以引用外部作用域中定义的变量(自调用函数内的作用域),我们知道这不会改变,因为从技术上讲有一个新的匿名函数(在x
参数定义中完成)在每次迭代中定义。换句话说,我相信你明白你定义的回调函数被定义了五次;一次循环的每次迭代。那么匿名自调用函数也是如此。它也被创建了五个独立的时间,包括它现在被锁定的值,以及函数被调用时的值k
。
希望这是有道理的。这不是一个复杂的概念,因为它很难解释清楚。
优秀的解释。也许还需要添加这个选项。除了创建函数k或X之外,只需执行'var vIndex = 0;'和console.log(“Filename:”+ filename [vIndex]); \t \t \t \t vIndex ++;' – krikara
是的,我想,除了它是递增的额外不必要的变量,如果你需要的变量是什么比一个整数计更复杂,将无法正常工作。如果我只是用黑客修复你的代码,你也不会学到任何新东西。教一个人钓鱼;) – Chev
是的,我明白你的意思。只要我开始做更多的工作,这个指数就证明是不可靠的。 – krikara