03.12 簡單點,6分鐘讓你認識JavaScript閉包

更多技術分享,點擊右上角紅色的"關注",感謝你的支持!


簡單點,6分鐘讓你認識JavaScript閉包

閉包基本的概念

閉包並不是JavaScript特有的,在PHP、Scala、Groovy、Ruby、 Python、swift 以及Java(Java8及以上)等很多語言中,都有對閉包特性的支持。

簡單來說,閉包就是能夠讀取其他函數內部變量的函數。例如在javascript中,只有函數內部的子函數才能讀取局部變量,所以閉包可以理解成“定義在一個函數內部的函數“。

在本質上,閉包是將函數內部和函數外部連接起來的橋樑。

只看這些概念,是不是有點蒙圈了,別急,且往下看。


結合代碼來說明

如果一個函數a定義在另一個函數b裡面,那麼,這個函數a就是一個閉包。

簡單點,6分鐘讓你認識JavaScript閉包

重要的關鍵點,函數a能夠直接讀取函數b中定義的變量,這個就是閉包的特性

簡單點,6分鐘讓你認識JavaScript閉包

再來一段有意思的代碼例子:

簡單點,6分鐘讓你認識JavaScript閉包

函數b這次不再直接執行a了,而是直接返回了函數a,所以func本質上是對函數a實例的引用,

而func()竟然能記住x,這就是JavaScript的閉包機制的神奇之處。

到這裡,我們結合以上代碼說明,閉包就是函數a和變量x。


閉包可以用來做什麼

工作中,不知不覺,我們其實經常用到閉包,比如下面這個例子,一個初始化函數里麵包含一個按鈕點擊事件:

簡單點,6分鐘讓你認識JavaScript閉包

另一個具體點的例子,一段發送驗證碼的Demo:

簡單點,6分鐘讓你認識JavaScript閉包

可以看到,在onclick函數里面,是可以正常操作time_wait和time_left變量的,細心的朋友可能已經發現,

代理裡邊已經出現兩個閉包的應用了,一處是onclick,還有一處就是setInterval這個定時函數。

簡單點,6分鐘讓你認識JavaScript閉包

我們再想想,為什麼要用閉包?什麼場景需要呢?

  • JavaScript語言特性需要(setTimeout、setInterval...)

  • 事件綁定需要(onclick...)

還有一個重要的原因,那就是OO思想,把上面發送驗證碼的代碼改造一下來看看

簡單點,6分鐘讓你認識JavaScript閉包

這樣,已經變成面向對象的編程風格了。


什麼時候不該用閉包

注意了朋友,不要為了秀技巧,到處使用閉包。因為濫用閉包可能會導致腳本執行緩慢,以及消耗不必要的內存。尤其是以下兩種情況時,應該儘量避免。

1.循環

簡單點,6分鐘讓你認識JavaScript閉包

頁面上測試,你會發現無論你點擊哪個按鈕,都會彈出4,因為click函數是個閉包,頁面加載後循環開始執行,當你點擊按鈕的時候,循環已經執行完了,此時i值為4,而閉包記得它周圍的變量,所以彈出的都是4。

要解決這個問題,可以把打印的代碼提煉到另一個函數里面,這樣就會產生一個新的作用域:

簡單點,6分鐘讓你認識JavaScript閉包

或者用立即執行函數表達式:

簡單點,6分鐘讓你認識JavaScript閉包

2.構造器

方法應該關聯於對象的原型,而不要定義到對象的構造器中。原因是這將導致每次對象實例化時,方法都會被重新定義一次。

簡單點,6分鐘讓你認識JavaScript閉包

應該這樣改寫,讓繼承的原型可以為所有實例共享:

簡單點,6分鐘讓你認識JavaScript閉包


結論

閉包就是一個函數引用另外一個函數的變量,因為變量被引用著所以不會被回收,因此可以用來封裝一個私有變量。這是優點也是缺點,不必要的閉包只會徒增內存消耗!另外使用閉包也要注意變量的值是否符合你的要求,因為他就像一個靜態私有變量一樣。閉包通常會跟很多東西混搭起來,接觸多了才能加深理解,這裡只是開個頭說說基礎性的東西。

簡單點,6分鐘讓你認識JavaScript閉包


分享到:


相關文章: