為什麼變數 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 被提升為了全域變數?
拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...
因為js會為每個函式呼叫建立一個棧,函式內的函式也可以存取這個棧。
首先你能調用nAdd,是因为你没加var,等于是在函数调用时定义了一个全局作用域下的nAdd,你加上var再這麼寫會報錯。
nAdd
var
你的var result=f1();调用了函数f1,也就创建了一个栈,保存了n=999,并返回了f2。之后你再怎么调用result(),其实都是在调用同一个f2,而这个f2引用的外部栈,自然还是第一次调用f1时候创建的那个。同样的nAdd雖然作用在全局,但存取的也是同一個堆疊內的資料。
var result=f1();
f1
n=999
f2
result()
所以,並不是你說的因為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,创建了另一个匿名函数,返回了另一个闭包。
在這段程式碼中,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...
不是 n 被提升为全局变量了,这就是闭包。。。。是nAdd是全局变量。nAdd和result中涉及的n 都是 var n = 999那个n,而没有全局的n
n
result
var n = 999
http://zonxin.github.io/post/...
var nAdd = ... 你再試試你就知道為什麼了
沒有var宣告 就會被提升為全域變數
變數n不是全域變數 只是這樣寫讓這個n的記憶體總是無法釋放
f2函數中對f1函數內的局部變數n持久引用,f2返回後,n不會被釋放,而nAdd作為一個全域函數,當然可以操作n
n還是局部變量,因為一直都是在函數f1中進行對局部變量n的操作。而nAdd()是一個全域下的函數,在他執行的時候,會將他所屬作用域中的n進行了加1
var result=f1(); 呼叫時,返回了一個內部函數f2,並且引用了外部函數的變數n,由於垃圾回收機制,f1被執行完畢的時候,。 n一直沒有被回收,result()執行第二次的時候,n變成了1000
nAdd 全域變量,沒有加var,所以是全域作用域
n 是局部變數
var result=f1():f1函數回傳了f2函數 把回傳的f2函數賦值給result全域變量,(f2的作用域鏈保存到result全域變數中)
var result=f1()
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。
nAdd()
result():result()就輸出1000
只是本人理解,如有錯誤請拍磚告知
n不是一個全域變量,這是一個閉包。為什麼n會改變,因為你的那個nAdd前面沒有寫var預設全域的,但是你的function是在閉包裡面定義的,作用域什麼的都是裡面的。
因為js會為每個函式呼叫建立一個棧,函式內的函式也可以存取這個棧。
首先你能調用
nAdd
,是因为你没加var
,等于是在函数调用时定义了一个全局作用域下的nAdd
,你加上var
再這麼寫會報錯。你的
var result=f1();
调用了函数f1
,也就创建了一个栈,保存了n=999
,并返回了f2
。之后你再怎么调用result()
,其实都是在调用同一个f2
,而这个f2
引用的外部栈,自然还是第一次调用f1
时候创建的那个。同样的nAdd
雖然作用在全局,但存取的也是同一個堆疊內的資料。所以,並不是你說的因為nAdd是全域變量,所以n被提升成全域變量,而是nAdd所指向的函數和你回傳的那個閉包根本是在存取同一份資料。
你可以嘗試改寫成
在這段程式碼中,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...
不是
n
被提升为全局变量了,这就是闭包。。。。是
nAdd
是全局变量。nAdd
和result
中涉及的n
都是var n = 999
那个n
,而没有全局的n
http://zonxin.github.io/post/...
var nAdd = ... 你再試試你就知道為什麼了
沒有var宣告 就會被提升為全域變數
變數n不是全域變數 只是這樣寫讓這個n的記憶體總是無法釋放
f2函數中對f1函數內的局部變數n持久引用,f2返回後,n不會被釋放,而nAdd作為一個全域函數,當然可以操作n
n還是局部變量,因為一直都是在函數f1中進行對局部變量n的操作。而nAdd()是一個全域下的函數,在他執行的時候,會將他所屬作用域中的n進行了加1
var result=f1(); 呼叫時,返回了一個內部函數f2,並且引用了外部函數的變數n,由於垃圾回收機制,f1被執行完畢的時候,。 n一直沒有被回收,result()執行第二次的時候,n變成了1000
nAdd 全域變量,沒有加var,所以是全域作用域
n 是局部變數
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只是本人理解,如有錯誤請拍磚告知
n不是一個全域變量,這是一個閉包。為什麼n會改變,因為你的那個nAdd前面沒有寫var預設全域的,但是你的function是在閉包裡面定義的,作用域什麼的都是裡面的。