面試官問我:什麼是JavaScript閉包,我該如何回答

閉包,有人說它是一種設計理念,有人說全部的函數都是閉包。到底什麼是閉包?這個問題在面試是時候常常都會被問,不少小白一聽就懵逼了,不知道如何回答好。
這個問題也有不少朋友在公衆號給李老師留言了,問題表達方式不同,都是終歸到一點,就是對閉包沒有很清晰的理解。你們常常去網上找相關資料,可是對閉包的說法都是各類各樣的,讓你們對閉包的定義沒有一個概念。
因此今天咱們來一塊兒講講什麼是閉包,幫助你們理解,今天的內容能夠直接收藏起來。方便之後看。javascript

什麼是閉包(Closure)

簡單講,閉包就是指有權訪問另外一個函數做用域中的變量的函數。
MDN 上面這麼說:閉包是一種特殊的對象。
它由兩部分構成:函數,以及建立該函數的環境。環境由閉包建立時在做用域中的任何局部變量組成。前端

這種官方的概念是比較難理解的,在面試的時候說出來也不是很專業,由於沒辦法有個具體的邏輯。
我我的認爲,理解閉包的關鍵在於:外部函數調用以後其變量對象本應該被銷燬,但閉包的存在使咱們仍然能夠訪問外部函數的變量對象,這就是閉包的重要概念。
10692java

產生一個閉包

建立閉包最多見方式,就是在一個函數內部建立另外一個函數。下面例子中的 closure 就是一個閉包:
10698
閉包的做用域鏈包含着它本身的做用域,以及包含它的函數的做用域和全局做用域。面試

閉包的注意事項

.一般,函數的做用域及其全部變量都會在函數執行結束後被銷燬。可是,在建立了一個閉包之後,這個函數的做用域就會一直保存到閉包不存在爲止。
10747
從上述代碼能夠看到add5 和 add10 都是閉包。它們共享相同的函數定義,可是保存了不一樣的環境。在 add5 的環境中,x 爲 5。而在 add10 中,x 則爲 10。最後經過 null 釋放了 add5 和 add10 對閉包的引用。
在javascript中,若是一個對象再也不被引用,那麼這個對象就會被垃圾回收機制回收;
若是兩個對象互相引用,而再也不被第3者所引用,那麼這兩個互相引用的對象也會被回收。數組

閉包只能取得包含函數中任何變量的最後一個值
10758
你們看一下上面這個代碼,arr數組中包含了10個匿名函數,每一個匿名函數都能訪問外部函數的變量i,那麼i是多少呢?
當arrFunc執行完畢後,其做用域被銷燬,但它的變量對象仍保存在內存中,得以被匿名訪問,這時i的值爲10。
要想保存在循環過程當中每個i的值,須要在匿名函數外部再套用一個匿名函數,在這個匿名函數中定義另外一個變量而且當即執行來保存i的值。
10763
這時最內部的匿名函數訪問的是num的值,因此數組中10個匿名函數的返回值就是1-10。安全

閉包中的this對象

10772
在上面這段代碼中,obj.getName()()其實是在全局做用域中調用了匿名函數,this指向了window。
這裏要理解函數名與函數功能是分割開的,不要認爲函數在哪裏,其內部的this就指向哪裏。
window纔是匿名函數功能執行的環境。
若是想使this指向外部函數的執行環境,能夠這樣改寫:
10779
在閉包中,arguments與this也有相同的問題。下面的狀況也要注意:
10782
obj.getName();這時getName()是在對象obj的環境中執行的,因此this指向obj。
(obj.getName = obj.getName)賦值語句返回的是等號右邊的值,在全局做用域中返回,因此(obj.getName = obj.getName)();的this指向全局。要把函數名和函數功能分割開來。閉包

內存泄漏

閉包會引用包含函數的整個變量對象,若是閉包的做用域鏈中保存着一個HTML元素,那麼就意味着該元素沒法被銷燬。因此咱們有必要在對這個元素操做完以後主動銷燬。
10791模塊化

函數內部的定時器

當函數內部的定時器引用了外部函數的變量對象時,該變量對象不會被銷燬。
10795函數

閉包的應用

應用閉包的主要場合是:設計私有的方法和變量。
任何在函數中定義的變量,均可以認爲是私有變量,由於不能在函數外部訪問這些變量。私有變量包括函數的參數、局部變量和函數內定義的其餘函數。
把有權訪問私有變量的公有方法稱爲特權方法(privileged method)。
10803
在這裏,咱們須要理解兩個概念:
模塊模式(The Module Pattern):爲單例建立私有變量和方法。
單例(singleton):指的是隻有一個實例的對象。JavaScript 通常以對象字面量的方式來建立一個單例對象。
10809
上面是普通模式建立的單例,下面使用模塊模式建立單例:
10813
匿名函數最大的用途是建立閉包,而且還能夠構建命名空間,以減小全局變量的使用。從而使用閉包模塊化代碼,減小全局變量的污染。
10817
在這段代碼中函數 addEvent 和 removeEvent 都是局部變量,但咱們能夠經過全局變量 objEvent 使用它,這就大大減小了全局變量的使用,加強了網頁的安全性。性能

運用閉包的關鍵

閉包引用外部函數變量對象中的值;
在外部函數的外部調用閉包。
閉包的缺陷
閉包的缺點就是常駐內存會增大內存使用量,而且使用不當很容易形成內存泄露。
若是不是由於某些特殊任務而須要閉包,在沒有必要的狀況下,在其它函數中建立函數是不明智的,由於閉包對腳本性能具備負面影響,包括處理速度和內存消耗。
最後 來一道有關閉包的面試題
下面代碼中,標記 ? 的地方輸出分別是什麼?
10829
你們結合今天講解的內容,思考一下答案,你們能夠把答案發到留意上吧。

好了,今天的講解就那麼多,若是你還有什麼前端問題想提問的,或者你想李老師下次給你們講什麼內容,能夠直接留意提問,說不定下次文章就會講解了。若是你以爲這篇文章對你有幫助,請轉發點贊支持一下!

相關文章
相關標籤/搜索