簡單理解JS中的閉包

定義一個函數
<pre>
function fn(a,b,...rest){
var arr;
...
function fn2(){
引用外部函數fn的參數a,b...rest和局部變量arr

      };

return fn2;

}

fn();
</pre>

當調用fn ()這個函數時,返回的是fn2()這個函數,fn()的相關參數和變量都保存在返回的函數fn2()中,這種結構就稱為閉包。閉包就是函數fn2(),即能夠讀取其他函數內部變量的函數。

a,b...rest,arr這些局部變量在fn()這個函數外是無法被讀取的,但是有時候又想要讀取這些變量,怎么辦呢?

在fn的內部再定義一個函數fn2(),fn2()是可以訪問fn內部所有的局部變量的,在內部引用局部變量arr,將fn2()作為返回值,即可在外面調用fn的局部變量。

<pre>
function fn() {
var n = 999;
function fn2() {
console.log(n);
}
return f2;
}
var result = fn();
result(); //999
</pre>

調用fn()時,返回的并不是n的值,而是函數fn2(),因此我門要在外面將fn賦給一個函數result,利用調用result();返回的值才是n的值。返回的函數并沒有立刻執行,而是直到調用了result()才執行。

另一個例子

<pre>
function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()
f(); // 15
</pre>

同樣的,當我們調用lazy_sum()時,返回的并不是求和結果,而是求和函數。調用函數f
時,才真正計算求和的結果。

當我們調用lazy_sum()時,每次調用都會返回一個新的函數,即使傳入相同的參數:
<pre>var f1 = lazy_sum([1, 2, 3, 4, 5]);
var f2 = lazy_sum([1, 2, 3, 4, 5]);
f1 === f2; // false
</pre>

f1()和f2()的調用結果互不影響。

于在JavaScript語言中,只有函數內部的子函數才能讀取內部變量,因此可以把閉包簡單理解成“定義在一個函數內部的函數”。閉包最大的特點,就是它可以“記住”誕生的環境,比如fn2記住了它誕生的環境fn,所以從fn2可以得到fn的內部變量。在本質上,閉包就是將函數內部和函數外部連接起來的一座橋梁。

閉包的最大用處有兩個,一個是可以讀取函數內部的變量,另一個就是讓這些變量始終保持在內存中,即閉包可以使得它誕生環境一直存在。

內存泄露

因為result();一直存在在內存中,而result()的存在依賴于fn,因此也始終在內存中,不會在調用結束后,被垃圾回收機制回收,內存一直得不到釋放,JS釋放內存時就會漏掉這一部分,漸漸越積越多,造成內存泄露。

返回函數不要引用任何循環變量,或者后續會發生變化的變量。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 函數聲明和函數表達式有什么區別 (*)解析器會率先讀取函數聲明,并使其在執行任何代碼之前可以訪問;函數表達式則必須...
    coolheadedY閱讀 400評論 0 1
  • 閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包實現。 一、變量...
    zock閱讀 1,085評論 2 6
  • 郭芳艷 焦點網絡五期 堅持原創分享第81天 2017.8.11 假期里總是感覺比上班還忙,一個人在家...
    冰山藍鷹閱讀 92評論 0 0
  • 小朋友們,你們知道嗎?中國五岳名山有哪些?有東岳泰山,南岳衡山,北岳恒山,西岳華山,中岳嵩山。你們知道...
    fdeceb686cba閱讀 589評論 0 0
  • 今天在做一個menu的時候,需要改動item的高度和字體大小顏色。搜索了一下很多方法都不管用,最后是結合了 sta...
    seven_Android閱讀 8,123評論 4 3