為什麼變數 n 不會被重置?
function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
說明變數 n 是個全域變量,是不是在 f2 中變數 n 被提升為了全域變數?
给我你的怀抱2017-05-18 10:52:47
因為js會為每個函式呼叫建立一個棧,函式內的函式也可以存取這個棧。
首先你能調用nAdd
,是因为你没加var
,等于是在函数调用时定义了一个全局作用域下的nAdd
,你加上var
再這麼寫會報錯。
你的var result=f1();
调用了函数f1
,也就创建了一个栈,保存了n=999
,并返回了f2
。之后你再怎么调用result()
,其实都是在调用同一个f2
,而这个f2
引用的外部栈,自然还是第一次调用f1
时候创建的那个。同样的nAdd
雖然作用在全局,但存取的也是同一個堆疊內的資料。
所以,並不是你說的因為nAdd是全域變量,所以n被提升成全域變量,而是nAdd所指向的函數和你回傳的那個閉包根本是在存取同一份資料。
你可以嘗試改寫成
function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
alert(n);
}
return f2;
}
f1()(); // 调用f1,创建了一个栈,栈内n=999,创建了一个匿名函数,返回了一个闭包。
nAdd(); // 调用了那个匿名函数
f1()(); // 又调用f1,又创建了一个栈,栈内n=999,创建了另一个匿名函数,返回了另一个闭包。
我想大声告诉你2017-05-18 10:52:47
在這段程式碼中,result其實就是閉包f2函數。它總共運行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數f1中的局部變數n一直保存在記憶體中,並沒有在f1呼叫後被自動清除。
為什麼會這樣呢?原因就在於f1是f2的父函數,而f2被賦給了一個全域變量,這導致f2始終在記憶體中,而f2的存在依賴f1,因此f1也始終在記憶體中,不會在呼叫結束後,被垃圾回收機制(garbage collection)回收。
這段程式碼中另一個值得注意的地方,就是"nAdd=function(){n+=1}"這一行,首先在nAdd前面沒有使用var關鍵字,因此nAdd是一個全域變量,而不是局部變數。其次,nAdd的值是匿名函數(anonymous function),而這個匿名函數本身也是閉包,所以nAdd相當於一個setter,可以在函數外部對函數內部的局部變數進行運算。
http://www.ruanyifeng.com/blo...
ringa_lee2017-05-18 10:52:47
不是 n
被提升为全局变量了,这就是闭包。。。。
是nAdd
是全局变量。nAdd
和result
中涉及的n
都是 var n = 999
那个n
,而没有全局的n
http://zonxin.github.io/post/...
仅有的幸福2017-05-18 10:52:47
var nAdd = ... 你再試試你就知道為什麼了
沒有var宣告 就會被提升為全域變數
變數n不是全域變數 只是這樣寫讓這個n的記憶體總是無法釋放
ringa_lee2017-05-18 10:52:47
n還是局部變量,因為一直都是在函數f1中進行對局部變量n的操作。而nAdd()是一個全域下的函數,在他執行的時候,會將他所屬作用域中的n進行了加1
阿神2017-05-18 10:52:47
var result=f1(); 呼叫時,返回了一個內部函數f2,並且引用了外部函數的變數n,由於垃圾回收機制,f1被執行完畢的時候,。 n一直沒有被回收,result()執行第二次的時候,n變成了1000
nAdd 全域變量,沒有加var,所以是全域作用域
n 是局部變數
黄舟2017-05-18 10:52:47
var result=f1()
:f1函數回傳了f2函數
把回傳的f2函數賦值給result全域變量,(f2的作用域鏈保存到result全域變數中)
result()
:呼叫result(),這就形成閉包:有權訪問另外一個函數作用域中的變量
因為在f2中的作用域引用了f1中的n這個局部變量,當f1執行完畢之後,垃圾回收機制發現n變數還在被result引用所以垃圾回收機制不會把n回收釋放。
以至於n一直保存在result作用域鏈中。 result的作用域鏈正常能存取f1中的局部變數n,形成閉包。
nAdd()
:nAdd沒有寫var所以nAdd是全域變量,在呼叫nAdd()和result()是一樣的都會形成閉包,匿名函數function(){n+=1}的作用域鏈中有n這個局部變量,所以當nAdd=funtion(){n+=1}時,這個匿名函數的作用域鏈保存到了全局變量nAdd形成閉包,調用nAdd()作用域鏈中找到f1局部變量n=999,n+ 1=1000。
result()
:result()就輸出1000
只是本人理解,如有錯誤請拍磚告知
PHP中文网2017-05-18 10:52:47
n不是一個全域變量,這是一個閉包。為什麼n會改變,因為你的那個nAdd前面沒有寫var預設全域的,但是你的function是在閉包裡面定義的,作用域什麼的都是裡面的。