2013-08-16 41 views
1

爲了您的方便,here's an interactive jsfiddle version of my code.這裏是有問題的代碼:在一個循環中,我添加了一個標籤來提醒循環索引計數。爲什麼它總是提醒循環的最後一個索引?

for i in [1, 2, 3, 4, 5, 6, 7, 8] 
    console.log "cell #{i} was created!" 
    cell = $('<div class="inventory-cell"></div>').mousedown (event) -> 
    alert "#{i} was clicked!" 
    $("#inventory-grid").append(cell) 

而這裏的HTML:

<div id="inventory-dialog" class="dialog">  
    <div id="inventory-grid"></div>  
</div> 

這裏是它如何工作。這將在循環中生成一堆單元格。如果我點擊第一個,我希望它提醒,「1被點擊!」當我點擊最後一個時,我想讓它說,「8被點擊!」但由於某種原因,每一個我點擊說,「8被點擊」。這是爲什麼發生?

+2

你需要讀入javascript的閉包和變量引用,我在執行時的值是8,如果你能夠點擊hypersonically快速,你會得到一個值在1-8之間的取決於哪個迭代你的外部循環創建閉包在 – Bryan

+0

我認爲這是@BryanMoyles正在談論的一個很好的鏈接。不幸的是,它不是專門幫助我解決問題,但瞭解這些信息非常重要:http://stackoverflow.com/questions/111102/how-do-javascript-closures-work –

+1

這對您的問題更具體:http:/ /stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – bfavaretto

回答

4

所有的回調指的是它們的主體中相同的i變量,在任何這些回調被調用的時候,它的值都是8

你需要創建一個局部變量,其在回調創建時持有的i每一個具體的回調:

(function(j) { 
    var cell = $('<div class="inventory-cell"></div>').mousedown(function(event) { 
     alert("#{j} was clicked!"); 
    }); 

    $("#inventory-grid").append(cell); 
})(i); 

相同功能的CoffeeScript是:

do (i) -> 
    cell = $('<div class="inventory-cell"></div>').mousedown (event) -> 
    alert "#{i} was clicked!" 

    $("#inventory-grid").append(cell) 

唯一的區別是do會影響i而不是創建一個新變量,但結果是一樣的。

一個確切的翻譯是:

do (j = i) -> 
    cell = $('<div class="inventory-cell"></div>').mousedown (event) -> 
    alert "#{j} was clicked!" 

    $("#inventory-grid").append(cell) 
+0

IIFE是什麼意思? –

+0

@tieTYT:Go​​ogle它。 – Blender

+0

這似乎是一個很好的文章:http://benalman.com/news/2010/11/immediately-invoked-function-expression/ –

2
for i in [1, 2, 3, 4, 5, 6, 7, 8] 
    do (i) -> 
     console.log "cell #{i} was created!" 
     cell = $('<div class="inventory-cell"></div>').mousedown (event) -> 
      alert "#{i} was clicked!" 
     $("#inventory-grid").append(cell) 

Fiddle.

+0

什麼是'做'?我以前從來沒有見過。這是一個JavaScript的事情或CoffeeScript的事情? –

+2

「CoffeeScript提供了do關鍵字,它立即調用傳遞的函數,轉發任何參數。」 - http://coffeescript.org/ – pdoherty926

1

你已經在使用jQuery,由於換的循環不應該在陣列使用(cofeeScript很爛並顯然重命名原生JavaScript的東西),你可以避免與$.each,如下這樣的關閉問題:

$.each([1, 2, 3, 4, 5, 6, 7, 8], function(_,i) { 
    var cell = $('<div />', { 
     'class': 'inventory-cell', 
     on : { 
        click: function() { alert('#{'+i+'} was clicked!'); } 
       } 
    }); 
    $("#inventory-grid").append(cell); 
}); 

FIDDLE

+0

Upvote,但IMO我原來的代碼(雖然不工作)看起來比這更乾淨。爲什麼數組中不應該使用for-in循環? –

+1

CoffeeScript'for ... in'循環與JS'for ... in'循環中的不一樣。 – Blender

+0

你打敗了我,@Blender。 「你在CoffeeScript中編寫的大多數循環都是對數組,對象和範圍的理解,理解用循環替換(並編譯成),並帶有可選的guard子句和當前數組索引的值。理解是表達式,並且可以被返回和分配。「 – pdoherty926

0

不知道CoffeeScript的...,要麼不知道爲什麼(function(){...})();是fsfiddle錯誤..

for(var i=1; i<9;i++){ 
console.log("cell "+ i + "was created!") 
~function(i){ 
    var cell = $('<div class="inventory-cell"></div>').mousedown(function(){ 
    alert(i+" was clicked!") 
    }); 
    $("#inventory-grid").append(cell) 
}(i); 
} 
1

這兩個CoffeeScript的迭代產生相同的JavaScript函數。他們只是以不同的方式迭代它。 One使用for (var i=0 ...),其他$.each()

for i in [1..8] 
    do (i) -> 
    console.log "cell #{i} was created!" 
    cell = $('<div class="inventory-cell"></div>').mousedown (event) -> 
     alert "#{i} was clicked!" 
    $("#inventory-grid").append(cell) 
    return 

$.each([1..8], (_,i)-> 
    console.log "cell #{i} was created!" 
    cell = $('<div class="inventory-cell"></div>').mousedown (event) -> 
     alert "#{i} was clicked!" 
    $("#inventory-grid").append(cell) 
    return 
    ) 

本地JavaScript陣列迭代也可用於:

[1..8].forEach (i)-> 

的其他JavaScript迭代法:

for (i in [1,2,3..]) {} 

將有相同的問題原來的Coffeescript,如果它沒有注意將cell定義中使用的i本地化。

相關問題