本文爲飢人谷講師方方原創文章,首發於 前端學習指南。html
大名鼎鼎的閉包!面試必問。
請用本身的話簡述前端
假設上面三行代碼在一個當即執行函數中(爲簡明起見,我就不寫當即執行函數了,影響讀者理解)。面試
評論裏沒看完就說我寫得有問題的,請看清楚哦:編程
上面三行代碼在一個當即執行函數中。ruby
三行代碼中,有一個局部變量 local,有一個函數 foo,foo 裏面能夠訪問到 local 變量。微信
好了這就是一個閉包:閉包
「函數」和「函數內部能訪問到的變量」(也叫環境)的總和,就是一個閉包。編程語言
就這麼簡單。函數
有的同窗就疑惑了,閉包這麼簡單麼?學習
「我據說閉包是須要函數套函數,而後 return 一個函數的呀!」
好比這樣:
function foo(){ var local = 1 function bar(){ local++ return local } return bar } var func = foo() func()
這裏面確實有閉包,local 變量和 bar 函數就組成了一個閉包(Closure)。
爲何要函數套函數呢?
是由於須要局部變量,因此才把 local 放在一個函數裏,若是不把 local 放在一個函數裏,local 就是一個全局變量了,達不到使用閉包的目的——隱藏變量(等會會講)。
這也是爲何我上面要說「運行在一個當即執行函數中」。
有些人看到「閉包」這個名字,就必定以爲要用什麼包起來才行。其實這是翻譯問題,閉包的原文是 Closure,跟「包」沒有任何關係。
因此函數套函數只是爲了造出一個局部變量,跟閉包無關。
爲何要 return bar 呢?
由於若是不 return,你就沒法使用這個閉包。把 return bar 改爲 window.bar = bar 也是同樣的,只要讓外面能夠訪問到這個 bar 函數就好了。
因此 return bar 只是爲了 bar 能被使用,也跟閉包無關。
閉包經常用來「間接訪問一個變量」。換句話說,「隱藏一個變量」。
假設咱們在作一個遊戲,在寫其中關於「還剩幾條命」的代碼。
若是不用閉包,你能夠直接用一個全局變量:
window.lives = 30 // 還有三十條命
這樣看起來很不妥。萬一不當心把這個值改爲 -1 了怎麼辦。因此咱們不能讓別人「直接訪問」這個變量。怎麼辦呢?
用局部變量。
可是用局部變量別人又訪問不到,怎麼辦呢?
暴露一個訪問器(函數),讓別人能夠「間接訪問」。
代碼以下:
!function(){ var lives = 50 window.獎勵一條命 = function(){ lives += 1 } window.死一條命 = function(){ lives -= 1 } }()
簡明起見,我用了中文 :)
那麼在其餘的 JS 文件,就可使用 window.獎勵一條命() 來漲命,使用 window.死一條命() 來讓角色掉一條命。
看到閉包在哪了嗎?
五年前,我也被這個問題困擾,因而去搜了 stackoverflow 並總結下來。你在百度搜閉包,那篇《JavaScript閉包——懂不懂由你,反正我是懂了》就是我寫的。當時我仍是新手,一直不理解爲何你們口中的閉包這麼模糊、這麼琢磨不定呢。
咱們從新來審視一下閉包的代碼:
第一句是變量聲明,第二句是函數聲明,第三句是 console.log。
每一句我都學過,爲何合起來我就看不出來是閉包?
我告訴你答案,你根本不須要知道閉包這個概念,同樣可使用閉包!
閉包是 JS 函數做用域的副產品。
換句話說,正是因爲 JS 的函數內部可使用函數外部的變量,因此這段代碼正好符合了閉包的定義。而不是 JS 故意要使用閉包。
不少編程語言也支持閉包,另外有一些語言則不支持閉包。
只要你懂了 JS 的做用域,你天然而然就懂了閉包,即便你不知道那就是閉包!
若是咱們在寫代碼時,根本就不知道閉包,只是按照本身的意圖寫,最後,發現知足了閉包的定義。
那麼請問,這算是閉包的做用嗎?
這個問題,留給你思考。
閉包會形成內存泄露?
錯。
說這話的人根本不知道什麼是內存泄露。內存泄露是指你用不到(訪問不到)的變量,依然佔居着內存空間,不能被再次利用起來。
閉包裏面的變量明明就是咱們須要的變量(lives),憑什麼說是內存泄露?
這個謠言是如何來的?
由於 IE。IE 有 bug,IE 在咱們使用完閉包以後,依然回收不了閉包裏面引用的變量。
這是 IE 的問題,不是閉包的問題。參見司徒正美的這篇文章。
編程界崇尚以簡潔優雅惟美,不少時候
若是你以爲一個概念很複雜,那麼極可能是你理解錯了。
完。
加微信號: astak10或者長按識別下方二維碼進入前端技術交流羣 ,暗號:寫代碼啦
每日一題,每週資源推薦,精彩博客推薦,工做、筆試、面試經驗交流解答,免費直播課,羣友輕分享... ,數不盡的福利免費送