最近朋友面試被問到了 JS 閉包的問題,本人一時語塞,想起了袁華的一句話:“這道題太難了,我不會做,不會做啊!”。
JS 閉包屬于面向對象的一個重要知識點,特此本人又開始了一段說走就走的旅程。
閉包就是外層函數的作用域(AO)對象被內層函數所引用,無法被釋放。
上面那句話聽起來可能不是很理解,本人在之前寫過一篇Python 閉包小記》的關于 Python 閉包的一些知識的文章,里面寫了百度百科對于閉包的理解,雖然由于才疏學淺大部分都是引用的他人的知識架構,但語言這種東西都是相通的,我們不需要去記那些晦澀的名詞,對于閉包,作為初學者我們只需知道:
函數作為返回值,函數作為參數傳遞。就可以將其理解為閉包。
話不多說,先上個代碼緩和一下尷尬的氣氛:
function outer() { var max = 10; function inner(num) { if (num > max) { console.log(num) } } return inner;}var foo = outer();foo(20); // 20上面代碼滿足函數作為返回值的條件,所以是一個閉包函數。
根據 JS 函數的執行機制,先執行第 10 行的 foo 代碼,在函數執行完之后會被 JS 的垃圾回收機制將 outer 函數回收,但是在執行到第 3 行的時候我們發現 outer 函數內部又出現了一個 inner 函數,且 inner 函數里引用著 outer 函數的 max = 10; 的變量,這就無法被回收并且留在了內存里,當執行到第 11 行時由于 outer 函數內的 max = 10; 被留在內存中,所以會被 inner 函數調用,并滿足 if 條件判斷,所以輸出 20;
以上我們實現了一個簡單的閉包函數,但是卻產生了一個問題,那就是無法被釋放的對象留在了內存當中,造成了不必要的內存開銷。
再看如下代碼:
var max = 10, foo = function (num) { if (num > max) { console.log(num); } };(function (bar) { var max = 100; bar(20)})(foo); // 20上面代碼滿足函數作為參數傳遞的條件,所以是一個閉包函數。
函數 foo 作為一個參數被傳入函數中,賦值個 bar 參數,當執行到 bar() 函數時,函數內部的 max 并不是 100,而是 10,這似乎匪夷所思。我們暫且將 7 — 10 行的函數叫 “父作用域”,其余叫“全局作用域”,當執行到 bar(20) 時,函數去執行第 2 行的代碼,此時 foo 函數內部的 max 要去取值,而 max = 10; 正好在他所在的 “全局作用域” 內,所以會取 max = 10; 的值而不是 max = 100; 的值。由此可見,取值時要去創造這個函數的作用域內取值,而不是所謂的 “父作用域” 或者離函數近的地方取值。
我們再來看一段代碼:
var num = 20;function outer() { var max = 10; function inner() { if (num > max) { console.log(num); } } return inner;}var foo = outer(), num = 30;foo(); //30
|
新聞熱點
疑難解答
圖片精選