2013-04-07 160 views
-2
function addLinks() { 
    for (var i=0, link; i<5; i++) { 
     link = document.createElement("a"); 
     link.innerHTML = "Link " + i; 
     link.onclick = function (num) { 
      return function() { 
       alert(num); 
      }; 
     }(i); 
}} 

爲每個鏈接創建閉包;每個封閉都參考它創建的範圍。由於參數num已在每個循環上更新,因此在第一個鏈接上的click上應該提示4。不是嗎?局部變量和參數之間的區別

+0

參數num從不更新,它是每個調用的新變量。 – bfavaretto 2013-04-07 16:06:25

回答

2

根本不是,每個函數調用得到num變量的新副本,以便第一個鏈接應該提醒0

如果你真的想擁有所有的回調共享相同的變量...然後只是有它們共享相同的變量(包裝「民」的東西正是要避免這個問題,讓回調是獨立的):

//now all the inner closures use the same "i" variable 
//since the variable gets mutated by the for loop 
//all links are going to print "5" after the loop ends. 
for (var i=0, link; i<5; i++) { 
    link = document.createElement("a"); 
    link.innerHTML = "Link " + i; 
    link.onclick = function() { 
     alert(i); 
    }; 
} 

BTW,這只是發生,因爲不像在其他語言,JS沒有塊循環索引的範圍。因爲如果你做了

var i; 
while(i < 5){ 
    //... 
    i++ 
} 
+1

你應該提到JS有一個功能範圍,而'i'「活在」函數中,而不是循環中(也不是每次循環)。 – Joseph 2013-04-07 16:07:21

1

for循環的行爲而由於你混淆兩件事情:

  1. 函數的參數是函數的局部(用大「除非」,保存爲2號)
    它們旨在以您選擇的任何名稱爲函數的作用域別名一個對象(包括數組/函數)或值。
    目標是允許您將參數重命名爲任何您想要的內容,以使內部代碼變得有意義,而不管您從外部代碼傳入的參數是什麼。
    這與範圍無關。

  2. JS中的變量通過引用傳遞(如果它們是對象),如果它們是標量,則通過值傳遞。
    傳遞i到一個新的封閉的整點是,i被作爲參數傳遞,而不是參考i,這是發生了什麼,如果你不要」 t包括關閉。

如果你要傳遞一個對象,該對象是什麼了就可以了iobj.i += 1),然後再次關閉與否,每個功能將指向的i相同的值,因爲他們」 d都與同一個對象共享相同的參考。

對象參考通過,標量通過。
儘管技術上有字符串和數字對象,但只要您沒有對它們進行任何面向對象的操作,它們就會直接轉換爲標量值。

var i = 3, 
    say_i = function() { console.log(i); }; 

var i = 3, 
    say_i = (function (val) { return function() { console.log(val); }(i)); 

第一個給出了一個參考i
say_i運行時,它實時查看i的值,並將其吐出到控制檯中。

第二個已通過一個到返回的函數的外範圍,別名爲名稱val
由於數字是按值傳遞的,而不是通過引用,所以val將永遠等於相同的東西,除非從裏面改變。

你也可以做到這一點相同的結果,如果你犯了一個功能一次,循環外:

var add_log = function (el, val) { el.onclick = function() { console.log(val); }; }, 
    i = 0, 
    el; 

for (; i < ........) { 
    el = .... 
    add_log(el, i); 
} 

i正在按值傳遞的,因此,所有的元素將在其範圍表中的不同val因此,每個元素都會記錄一個不同的數字。

相關問題