關於 javascript 閉包的問題?
高洛峰
高洛峰 2017-05-18 10:50:47
0
9
985

為什麼變數 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教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

全部回覆(9)
给我你的怀抱

因為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,创建了另一个匿名函数,返回了另一个闭包。
我想大声告诉你

在這段程式碼中,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是全局变量。
nAddresult中涉及的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 是局部變數

黄舟
  1. var result=f1():f1函數回傳了f2函數
    把回傳的f2函數賦值給result全域變量,(f2的作用域鏈保存到result全域變數中)

  2. result():呼叫result(),這就形成閉包:有權訪問另外一個函數作用域中的變量
    因為在f2中的作用域引用了f1中的n這個局部變量,當f1執行完畢之後,垃圾回收機制發現n變數還在被result引用所以垃圾回收機制不會把n回收釋放。
    以至於n一直保存在result作用域鏈中。 result的作用域鏈正常能存取f1中的局部變數n,形成閉包。

  3. nAdd():nAdd沒有寫var所以nAdd是全域變量,在呼叫nAdd()和result()是一樣的都會形成閉包,匿名函數function(){n+=1}的作用域鏈中有n這個局部變量,所以當nAdd=funtion(){n+=1}時,這個匿名函數的作用域鏈保存到了全局變量nAdd形成閉包,調用nAdd()作用域鏈中找到f1局部變量n=999,n+ 1=1000。

  4. result():result()就輸出1000

只是本人理解,如有錯誤請拍磚告知

洪涛

n不是一個全域變量,這是一個閉包。為什麼n會改變,因為你的那個nAdd前面沒有寫var預設全域的,但是你的function是在閉包裡面定義的,作用域什麼的都是裡面的。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板