1. 程式人生 > 實用技巧 >三、Python基礎(3)

三、Python基礎(3)

閉包

定義

閉包是指有權訪問另外一個函式作用域中的變數的函式。——《JavaScript高階程式設計》

函式和對其周圍狀態(lexical environment,詞法環境)的引用捆綁在一起構成閉包closure)。——MDN

例子

舉個栗子:

function makeFunc() {
    var name = "Mozilla";
    function displayName() {
        alert(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();

上述程式碼是MDN中的樣例程式碼,在makeFunc函式內部定義了一個displayName的函式,並將其作為返回值。在displayName中,其執行的功能是彈窗顯示makeFunc中的定義的變數name。拋開程式碼細節,從上述程式碼實現的功能也就是將name輸出。

你可能覺得上述寫法過於冗長,多此一舉,你可能會寫出如下更加精簡的程式碼。

function makeFunc() {
    var name = "Mozilla";
  	alert(name);
}

makeFunc();

但是,現在增加了一個需求,在顯示完name之後,在name名稱後面新增一個!

號。

如果沿用剛才改寫過的程式碼的話,你需要改寫成如下程式碼:

var name = "Mozilla";

function makeFunc() {
  	alert(name);
  	name += '!';
}

makeFunc();
makeFunc();

因為如果不將var name移到makeFunc外部的話,當你呼叫makeFunc結束後,函式內部變數將被垃圾回收機制回收,無法實現新增!的功能。但是這樣帶來的壞處是汙染全域性的名稱空間且全域性中的任意函式都能呼叫到name,而且如果我想對於另外一個name做同樣的操作,則需要建立新的變數名加以區分。

如果我們使用最開始的程式碼的話,我們只需要改寫成如下形式:

function makeFunc() {
	var name = "Mozilla";
	function displayName() {
		console.log(name);
		name += '!';
	}
	return displayName;
}

var myFunc = makeFunc();
myFunc();
myFunc();

可以理解為我們將name作為了makeFunc()的私有變數,var myFunc = makeFunc(); 建立了一個詞法環境,這個詞法環境不會在第一次呼叫後銷燬。displayNamedisplayName所處的詞法環境就構成了一個閉包.

閉包產生的條件

從上面的例子中我們大致能瞭解到閉包產生的條件:

  1. 存在函式巢狀;
  2. 巢狀的內部函式必須引用在外部函式中定義的變數;
  3. 巢狀的內部函式必須被執行。

閉包的作用

同時我們也能瞭解到閉包的作用:

  1. 變數常駐記憶體,對於實現某些業務很有幫助,比如計數器之類的。

  2. 架起了一座橋樑,讓函式外部訪問函式內部變數成為可能。

  3. 私有化,一定程式上解決命名衝突問題,可以實現私有變數

但是缺點是變數一直存在於記憶體中,無法被釋放,可能隨著這些碎片的累計會造成記憶體溢位。

釋放記憶體

那麼如何釋放記憶體呢?

以上述例子為例,令myFunc=null 即可。

參考

  1. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

  2. https://juejin.im/post/6858052418862235656#heading-13