【前端芝士樹】Js中的閉包是怎麼一回事 && 筆試問題集錦

【前端芝士樹】Js中的閉包是怎麼一回事 && 筆試問題集錦

爲什麼會有閉包的出現?

這涉及到var作爲變量聲明的關鍵詞時所出現的一些問題。
比如,var 的 變量提升 以及 函數級作用域

Javascript語言的特殊之處,就在於函數內部可以直接讀取全局變量。
另一方面,在函數外部自然無法讀取函數內的局部變量。

需要注意的是,如果在函數內部聲明變量時沒有使用var關鍵詞,實際上聲明的是一個全局變量,如下:

function f1(){
    n = 999;
}
//console.log(n); // ReferenceError: n is not defined
f1();
console.log(n); // 999

這裏爲什麼第一處會報錯呢?關於這個問題下面有比較基礎的解釋:

JS的解析過程分爲兩個階段:預編譯期(預處理)執行期

  • 預編譯期 JS會對本代碼塊(兩個script塊互不影響)中的所有var聲明的變量和函數進行處理(類似與C語言的編譯)
    此時處理函數的只是聲明式函數,而且變量也只是進行了聲明但未進行初始化以及賦值。>
  • 執行期 會按照代碼塊的順序築行執行

正因爲從外部訪問在函數內部進行聲明的局部變量是不可能的,所以出現了閉包這種形式,在函數內部再定義一個函數。

閉包(Closure)是什麼?

查閱了一些文章和資料,發現還是下面的定義最容易理解:

閉包:定義在函數內部的一個函數。

擴展一些講,可以參考一下阮一峯的講解:

閉包:能夠讀取其他函數內部變量的函數。

俗話說的好,看定義不如看代碼更直觀一些,如下

function f1(){
    var n=999;
    function f2(){
        console.log(n);
    }
    return f2;
}

var result=f1();
result(); // 999

如此段代碼所示,f2()就是其中的閉包函數,通過f2()我們可以訪問到f1()內部的n
更常見的一種簡寫形式:

function f1(){
    var n=999;
    return function(){
        console.log(n);
    };
}

var result=f1();
result(); // 999

閉包的優缺點

優點:

  1. 可以讀取函數內部的變量
  2. 讓這些變量的值始終保持在內存中。

缺點:

  1. 由於閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
  2. 閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。

閉包面試題集錦(持續更新)

var a = 1;
function foo(){
    var a = 2;
    c = 0;
    return function () {
        console.log(a);
        console.log(b++);
        console.log(c);
    }
}
console.log(a);// 1

//console.log(c); // Reference Error
var b = 3;
var x = foo();
x(); //2 3 0
console.log(a); // 1
console.log(b); // 4
console.log(c); // 0

參考文章

《學習Javascript閉包(Closure) - 阮一峯的網絡日誌》
《閉包 - 廖雪峯的官方網站》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章