讓我試着解釋這一點,而不用吐出湯字,並拋出許多有趣的詞語,如「異步」,「作用域鏈」或「關閉」。
問題發生是因爲即使第一個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