圖解JavaScript閉包面試題


由於最近在學習關於閉包相關的知識,並且閉包這個知識點讓我有點搞不太清楚其具體的定義,所以在網上也查閱了很多大佬的講解和對閉包的一個定義。

 

最后感覺還是MDN上的說法感覺比較好理解一些,對閉包還是不太理解的道友可以嘗試看一看。

MDN上是這樣說的:閉包是函數和聲明該函數的詞法環境的組合

原地址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

 

在了解閉包的過程中遇到一個很多地方都出現的一個面試題,按照自己的想法想了下發現幾乎沒對...所以就花了些時間分析了一下,供自己以后忘記了可以回顧一下。

同時,如果這里依舊存在一些誤區,希望各位大佬們在評論區幫忙指正,感激萬分!

 

原題如下:

        function fun(n, o) {
            console.log(o);
            return {
                fun: function (m) {
                    return fun(m, n);
                }
            };
        }

        var a = fun(0); // ?
        a.fun(1); // ?
        a.fun(2); // ?
        a.fun(3); // ?

        var b = fun(0).fun(1).fun(2).fun(3); // ?

        var c = fun(0).fun(1); // ?
        c.fun(2); // ?
        c.fun(3); // ?

有興趣的道友們也可以試着先想一想答案,看下是否一致?

 

以下是解題思路:

1. 首先我對這個題畫了下題目中兩個fun函數中的一些信息 (可能不太完整,但是解題應該夠用了)

2. 當執行 var a = fun(0); 時,內存中開辟了一塊新的空間給這個新的對象,這個對象中定義了一個方法fun。並且在fun(0)執行時,在當前作用域下的變量信息如下:

 

因此,當該語句執行時,控制台打印的值為 undefined

 

3. 當執行 a.fun(1) 時,因為對象a中的fun方法在定義時所處的環境( [[scope]] )中存在一個變量n和變量o,

並且在這條語句執行的時候,變量n( 此時n的值為0 ) 被第三方 (除了函數fun和方法fun)引用了,也就是被外部的對象a引用了,因此產生了Closure(閉包)。

然后,這條語句的return執行的時候先執行 調用fun函數----> 把m的值傳遞給了fun函數中的n,把n傳遞給了fun函數中的o, 因此控制台中打印o的結果為0。

然而事情並沒有結束,調用fun函數會返回一個新的對象,這個對象也會在內存中新開辟一個空間,而此時這個新對象中的方法fun被定義時所處環境中的變量n已經被賦值為m的值,也就是1了。

4. 當a.fun(2)執行的時候,發生了和上面一樣的故事,並且內存中又被返回了一個新的對象且這個新對象中的方法fun被定義時所處環境中的變量n已經被賦值為m的值,也就是2

5. a.fun(3)執行同上,且這個新對象中的方法fun被定義時所處環境中的變量n已經被賦值為m的值,也就是3

故: a.fun(2) 和 a.fun(3) 在控制台中打印o的結果都為0,且不管你傳的參數是多少,只要你沒有改變a對象的值,那么輸出的結果都是0,因為你傳的參數都存在新的對象中了。

 

當時我這里存在一個疑問,每次執行n的值不是都被修改了嗎,為什么結果都是0呢?

注意:因為你始終都是在調用a的方法,而你每次執行a的方法fun的時候又沒有把新返回的對象重新賦值給a,所以a里面的fun方法被定義時所處環境中的變量n一直都是0

 

6. 當 var b = fun(0).fun(1).fun(2).fun(3); 執行的時候就和上面疑問中的情形是一樣的了。

當 fun(0)執行的時候,同上面a.fun(0)一樣,返回結果是undefined,且此時產生的新對象中,方法fun被定義時所處環境中的變量n為0

當 fun(1)執行的時候,相當於上面的a.fun(1)一樣,都是輸出0 (此時fun方法所處環境中的n為0),且返回一個新對象,新對象中的變量n為1

當fun(2)執行的時候,就不太一樣了,因為是在前一條語句執行結果后面直接調用fun方法, 但此時的fun方法已經不再是fun(1)中的方法了,而是上面返回的新對象中的方法,也就是變量n為1的方法,所以,這里輸出的結果為1,且返回一個新對象,新對象中的變量n為2

當fun(3)執行的時候,和fun(2)的情況一樣,輸出結果為新的對象中的n,也就是2

 

7. 到這里,var c = fun(0).fun(1); 應該就能夠明白為什么這里輸出對的結果是 undefined 和 0 了

因為道理和前面一樣,第一個 fun(0) 給n傳遞了值,但是o沒有,所以打印o的結果為undefined,第二個 fun(1) 將n的值傳給了o, 所以打印的結果為0,且這里產生的對象被賦值給了變量c,此時方法fun被定義時的環境(也就是它的詞法作用域)中的n是被重新賦值的1 (方法fun的形參m把被傳過來的實參1,傳遞給了函數fun中的形參n)

故:c.fun(2) 和 c.fun(3)中c對象的fun方法被定義時的環境中的n都是1,所以輸出的結果也是把n的值傳遞給fun函數中的o, 即輸出1

 

此處是測試結果圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM