面試:對javascript的閉包的理解

smithdeng發表於2018-05-05

一、js變數作用域

js的變數作用域有兩種,全域性變數和區域性變數

需要注意的是,函式內部可以直接讀取全域性變數。


var global = 666;

function func() {
	alert(global);
}

func(); //666
複製程式碼

函式外部無法讀取到函式內部的區域性變數,因為函式在執行完之後,函式內部的環境就被銷燬了。


function func() {
	var  message = 888;
}

alert(message); // error
複製程式碼

如果函式內部沒有使用var,那麼實際上就相當於把這個變數宣告為全域性變數了。


function func() {
	message = 999;
}

func();	//這裡注意要執行一遍函式,`message`	才有定義

alert(message);

複製程式碼

二、如何從外部讀取到區域性變數?

function f1() {
	
	var message = 999;

	function f2() {
		alert(message); //999
	}

}
複製程式碼

上面的程式碼中,f2可以訪問到f1的區域性變數message,那麼我們只要把f2作為f1的返回值return出去,那麼就可以在外部訪問到message了。

function f1() {
	
	var message = 999;

	function f2() {
		alert(message); //999
	}

	return f2;

}
複製程式碼

三、簡單理解閉包

上面的f2函式就是閉包。

閉包就是能夠讀取其他函式內部變數的函式,所以,閉包實際上是一個函式。

閉包可以理解為“定義在一個函式內部的函式”,本質上,閉包是將函式內部和外部連線起來的一座橋樑。

這裡要注意一點,父函式內部定義的子函式,如果沒有引用父函式作用域中的變數,那麼這個子函式不是閉包,這點非常重要,也就是說,閉包是由函式和它所在的環境構成的,缺一不可。

四、 閉包的用途

1.讀取函式內部的變數 2.讓這些變數始終儲存在記憶體中

function f1() {
	var n = 999;
	nAdd = function() { n += 1 }; //nAdd是一個全域性函式
	function f2() {
		alert(n);
	}
	return f2;
}

var result = f1(); //result是一個函式,f1中return的字函式
result();//999
nAdd();//執行全域性函式
result();//1000

複製程式碼

理解:按照正常的函式執行,f1執行完了之後,f1的變數n會被銷燬,但是上面的n仍然保留著999的數值,原因是f1的返回值f2被賦值給全域性變數result , 而f2的存在依賴f1,所以f1也一直在記憶體中。

五、使用閉包的注意事項

閉包會讓函式中的變數都被儲存在記憶體中,記憶體消耗大,所以不能濫用閉包,可以在不使用該變數的時候將其delete。

閉包會在父函式外部改變父函式內部的值,如果把父函式當作object使用,把閉包當作公有方法,內部變數當作私有成員,那就要小心不要隨意改變父函式內部變數的值。


參考資料:

學習Javascript閉包(Closure) - 阮一峰的網路日誌

阮一峰關於 Javascript 中閉包的解讀是否正確? - 知乎

相關文章