- JS全書:JavaScript Web前端開發(fā)指南
- 高鵬
- 754字
- 2020-09-18 10:29:20
4.5 閉包
在講閉包之前,先了解一下什么是自由變量。
自由變量是指在函數(shù)中使用的,但既不是函數(shù)參數(shù)也不是函數(shù)的局部變量的變量。
示例代碼:

上述代碼中,對(duì)于函數(shù)foo來說,a既不是函數(shù)參數(shù)也不是函數(shù)的局部變量的變量,因此a屬于自由變量。
4.5.1 什么是閉包
在ECMAScript中,閉包(Closure)是指能夠訪問自由變量的函數(shù)。
按照以上的概念,我們可以說所有的函數(shù)都是閉包,因?yàn)樗鼈兌荚趧?chuàng)建的時(shí)候就保存了上層上下文的作用域鏈,觀察如下代碼。

ECMAScript使用的是詞法作用域(Lexical scoping,又稱“靜態(tài)作用域”),即在函數(shù)創(chuàng)建時(shí),就保存上層上下文的作用域鏈。上述代碼中,在foo函數(shù)創(chuàng)建時(shí),其所使用的變量a是已經(jīng)在上下文中靜態(tài)保存好的,因此,在執(zhí)行foo()時(shí)a的值為1。
而任何函數(shù),在其創(chuàng)建時(shí)保存的上層上下文的作用域中都有全局的自由變量global(在瀏覽器中,global為window),因此說,所有函數(shù)都是閉包。
4.5.2 實(shí)踐中的閉包
上面說的是理論上的閉包,但在實(shí)踐中,閉包不僅只是能夠訪問自由變量的函數(shù),閉包還是指引用了自由變量的,并且被引用的自由變量將和這個(gè)函數(shù)一同存在的函數(shù),在創(chuàng)建該函數(shù)的上下文已經(jīng)銷毀時(shí),該函數(shù)仍然存在。
示例代碼:

上述代碼中,foo函數(shù)執(zhí)行后返回了一個(gè)匿名函數(shù),該函數(shù)引用了自由變量a,而在foo()執(zhí)行完畢后,創(chuàng)建該函數(shù)的環(huán)境已經(jīng)銷毀,但該函數(shù)并沒有被銷毀,因此foo()的返回值就是一個(gè)閉包。
閉包會(huì)使引用的自由變量不能被清除,這就使閉包比其他函數(shù)占用的內(nèi)存更多,但這也是閉包的強(qiáng)大之處,以下是一個(gè)使用閉包的示例。

再來看一個(gè)面試中經(jīng)常遇到的題目。

這3個(gè)函數(shù)創(chuàng)建時(shí)均使用的是已經(jīng)在上下文中靜態(tài)保存好的變量i,而在for循環(huán)結(jié)束時(shí),變量i的值為3,當(dāng)data0執(zhí)行時(shí),其所引用的自由變量i的值為3,因此輸出3。
我們的目標(biāo)是輸出0、1、2,上面的示例顯然無法實(shí)現(xiàn)這個(gè)需求,利用閉包可以很輕松地解決這個(gè)問題,示例如下。

練習(xí)
- 嘗試使用閉包。
- JavaScript從入門到精通(微視頻精編版)
- Python數(shù)據(jù)分析入門與實(shí)戰(zhàn)
- Getting started with Google Guava
- SQL學(xué)習(xí)指南(第3版)
- Ceph Cookbook
- ASP.NET動(dòng)態(tài)網(wǎng)頁設(shè)計(jì)教程(第三版)
- Java面向?qū)ο蟪绦蜷_發(fā)及實(shí)戰(zhàn)
- 零基礎(chǔ)學(xué)Java(第4版)
- Full-Stack Vue.js 2 and Laravel 5
- CKA/CKAD應(yīng)試教程:從Docker到Kubernetes完全攻略
- Java程序設(shè)計(jì)
- Learning Concurrency in Kotlin
- HTML5開發(fā)精要與實(shí)例詳解
- 大學(xué)計(jì)算機(jī)基礎(chǔ)
- C++從入門到精通(第6版)