2017-02-21 145 views
4
var addCount; 
function s1() { 
    var count = 0; 
    addCount = function() { 
     count++; 
    }; 
    function s12() { 
     console.log(count) 
    } 
    return s12 
} 
var result1 = s1(); 
var result2 = s1(); 
addCount(); 
result1(); // count = 0; 
result2(); // count = 1; 

In the picture I marked the puzzled place 然後,下一步將通過這種方式 This is where I am really puzzled爲什麼這段代碼有兩個不同的結果?

+0

每次調用s1後,addCount引用由該調用創建的閉包中引用的count變量。所以addCount()被調用時引用了result2引用的閉包中的count變量 – antlersoft

+0

這個問題正在討論中,但我想直接引用你的(Rodney_Dian)注意:你接受的答案是不正確的,會混淆你的理解進一步。您可以通過在代碼末尾添加更多對'result1()'和'result2()'的調用來證明它是錯誤的。你會發現無論你調用多少次或以什麼順序調用它們,每次調用'result1()'都會返回0,並且每次調用'result2()'都會返回1.(除非再次調用'addCount()' ,這會進一步增加'result2()',同時使'result1()'仍然爲0)。閱讀下面的其他答案,看看爲什麼。 –

回答

5

因爲result是聲明爲調用s1函數的結果的函數。調用s1將返回s12函數,該函數使用名爲count的變量,該變量在比其自身更高的級別(範圍)聲明(稱爲「自由變量」)。

當自由變量是具有壽命比在自由變量被宣佈爲功能不再是一個函數中使用時,"closure"是圍繞自由變量創建,它甚至功能後停留在範圍它被宣佈終止。

當您第一次致電result時,count將增加1,並且該值將保留在內存中,以便當您第二次調用該值時,您正在使用最後一個值。

+0

非常感謝! –

+0

@Rodney_Dian不客氣。不要忘記投票並標記爲答案。 –

+0

調用'result'(我想你的意思是'result1'或'result2')不會增加'count'。 –

1

顯示被是因爲變量addCount具有全局範圍。

+3

我想我不會說這是錯誤的,但它肯定會讓我們對一些奇怪的假設有所瞭解,差距將是 –

0

運行函數s1兩次時,將生成兩個名稱計數變量,每個變量都在當前方法調用的範圍內。

除此之外,您的addCount方法對於這兩個調用都是全局的。你的第二個電話覆蓋第一個電話。

因此,在新的addCount方法中,您有第二個s1調用的範圍。

因此,您致電addCount有第二個count變量的範圍和增量這一個。

當您打印結果時,您將返回到兩個範圍,並在您的第一個調用範圍內獲得count = 0的正確值,並在第二個範圍內獲得count = 1的正確值。

+0

您不會生成兩個名爲'count'的變量。圍繞單個'count'變量有一個閉包,並且這個函數的兩個調用都共享它。您不能有兩個在相同範圍內聲明的同名實體。如果你這樣做了,最後一個會覆蓋前一個。一旦值從1變爲2,就不會返回並再次獲得1。 –

+0

@ScottMarcus - 你錯了。如本例所示,變量是**不是**共享的。關閉全部關於回頭再次獲得1;那*就是*他們做的。 –

+0

@MarkAdelsberger不,你錯了。閉包都是關於自由變量的共享範圍。解決意外的關閉後果是通過創建變量的副本或創建專用範圍來創建單獨的範圍(比如,用'let')。 –

5

要理解這種行爲,您需要真正理解閉包的功能。短(但如果你是不是真的與關閉調可能混淆)的回答是這樣的:

s1每次調用執行以下操作:

A)創建一個名爲變量計數和初始化爲0

這似乎足夠直截了當......

B)創建一個從(A遞增變量)的功能,並設置addCount變量指向它

一些重要的細節隱藏在這裏。該函數將更新的變量是,在的步驟(A)中創建的變量是s1的相同調用這是關閉機制的結果。

當然時的s1的第二調用到達此步驟中,它會覆蓋的addEvent值,代替該遞增的s1現有調用一個新的函數創建的count該遞增這個當前調用創建的count功能的s1

C)創建並返回記錄在(A)

與(B)創建的變量的值的函數,該函數也看到了由當前調用的步驟A 創建的變量的s1

那麼這是什麼意思?

好吧,你叫s1一次,它創建一個變量,值爲0,並返回該記錄是變量(函數你存儲爲result1)的功能。

作爲副作用,該調用已將addCount設置爲一個函數,該函數將更改由result1記錄的變量的值(如果調用該函數,但您不稱之爲)。

而是再次調用s1,該函數用一個新函數替換addCount,該函數更新一個新變量(也初始化爲0)。它返回一個函數,記錄這個新變量,它存儲爲result2

現在您通過addCount一個電話,它調用功能更新變量。然後你打電話result1記錄第一個變量(從未更新),然後你呼叫result2記錄第二個變量(你增加一次)。

相關問題