探索奧祕~閉包
在我學習初期我對閉包的理解也不是很深,最近在學習了js更深入的知識後,對閉包有了更加深入的瞭解,下面我就跟大家詳細解讀一“閉包”!
一、首先什麼是閉包?
“官方”的解釋是:所謂“閉包”,指的是一個擁有許多變數和繫結了這些變數的環境的表示式(通常是一個函式),因而這些變數也是該表示式的一部分。
當一個函式能夠記住並訪問到其所在的詞法作用域及作用域鏈,特別強調是在其定義的作用域外進行的訪問,此時該函式和其上層執行上下文共同構成閉包。
相信很少有人能直接看懂這句話,因為他描述的太學術。我想用如何在Javascript中建立一個閉包來告訴你什麼是閉包,因為跳過閉包的建立過程直接理解閉包的定義是非常困難的。看下面這段程式碼:
function a(){
var i=0;
function b(){
alert(++i);
}
return b;
}
var c = a();
c();
這段程式碼有兩個特點:
1、函式b巢狀在函式a內部;
2、函式a返回函式b。
這樣在執行完var c=a()後,變數c實際上是指向了函式b,再執行c()後就會彈出一個視窗顯示i的值(第一次為1)。這段程式碼其實就建立了一個閉包,為什麼?因為函式a外的變數c引用了函式a內的函式b,就是說:
當函式a的內部函式b被函式a外的一個變數引用的時候,就建立了一個閉包。
**需要明確的幾點:
1、閉包一定是函式物件(wintercn大大的閉包考證)
2、閉包和詞法作用域,作用域鏈,垃圾回收機制息息相關
3、當函式一定是在其定義的作用域外進行的訪問時,才產生閉包
4、閉包是由該函式和其上層執行上下文共同構成
二、接下來我們來看下閉包是如何產生的?
現在我假設JS引擎執行到這行程式碼
let baz = foo();
此時,JS的作用域氣泡是這樣的:
這個時候foo函式已經執行完,JS的垃圾回收機制應該會自動將其標記為”離開環境”,等待回收機制下次執行,將其記憶體進行釋放(標記清除)。
但是,我們仔細看圖中粉色的箭頭,我們將bar的引用指向baz,正是這種引用賦值,阻止了垃圾回收機制將foo進行回收,從而導致bar的整條作用域鏈都被儲存下來。
接下來,baz()執行,bar進入執行棧,閉包(foo)形成,此時bar中依舊可以訪問到其父作用域氣泡中的變數a。
我們藉助chrome的除錯工具看下閉包產生的過程:
當JS引擎執行到這行程式碼let baz = foo();時:
圖中所示,let baz = foo();已經執行完,即將執行baz();,此時Call Stack中只有全域性上下文。
接下來baz();執行:
我們可以看到,此時bar進入Call Stack中,並且Closure(foo)形成。
三、閉包的應用場景
1、保護函式內的變數安全。以最開始的例子為例,函式a中i只有函式b才能訪問,而無法通過其他途徑訪問到,因此保護了i的安全性。
2、在記憶體中維持一個變數。依然如前例,由於閉包,函式a中i的一直存在於記憶體中,因此每次執行c(),都會給i自加1。
以上兩點是閉包最基本的應用場景,很多經典案例都源於此!
閉包的奧妙
閉包,它並不是很神祕,反而是在我們的程式中隨處可見,讓我們靜下心來,品味閉包的味道,走進“閉包”世界,感受它的魅力所在!
相關文章
- 前端小祕密系列之閉包前端
- Netty 原始碼分析之拆包器的奧祕Netty原始碼
- 探索低程式碼高擴充性背後的奧祕
- javascript忍者祕籍-第五章 閉包和作用域JavaScript
- 走進英特爾中國研究院,探索科技創新無窮奧祕
- 閉包:私有化變數 《JavaScript高程3》 《JavaScript忍者祕籍》變數JavaScript
- 帶你探索主資料系統的奧祕--開源軟體誕生14
- 探索 Python 來反補 JavaScript,帶你 Cross Fire —— JS 資料型別的奧祕PythonJavaScriptROSJS資料型別
- 機器之心GitHub專案:從迴圈到卷積,探索序列建模的奧祕Github卷積
- 閉包
- Swift-逃逸閉包、自動閉包Swift
- 閉包 | 淺談JavaScript閉包問題JavaScript
- Android App秒開的奧祕AndroidAPP
- MyBatis和Spring整合的奧祕MyBatisSpring
- 【集合論】關係閉包 ( 關係閉包求法 | 關係圖求閉包 | 關係矩陣求閉包 | 閉包運算與關係性質 | 閉包複合運算 )矩陣
- 閉包是什麼?怎麼形成一個閉包?為什麼使用閉包?
- JavaScript - 閉包JavaScript
- JavaScript 閉包JavaScript
- Golang閉包Golang
- 理解“閉包”
- PHP 閉包PHP
- JavaScript閉包JavaScript
- Swift 閉包Swift
- golang 閉包Golang
- 「閉包」攻略
- 什麼是閉包,閉包的優缺點?
- 【初窺javascript奧秘之閉包】葉大俠病都好了,求不踩了:)JavaScript
- 【學習】你不知道的JavaScript + 忍者祕籍 -- 作用域 +閉包 小結JavaScript
- js閉包及閉包的經典使用場景JS
- [JavaScript閉包]Javascript閉包的判別,作用和示例JavaScript
- 什麼是閉包?閉包的作用是什麼?
- Groovy閉包理解
- 閉包作用域
- 閉包問題
- C#閉包C#
- 筆記:閉包筆記
- 亂談閉包
- 閉包的起源