閉包是JavaScript的重點(diǎn)也是難點(diǎn)之一,由于涉及多重知識(shí)點(diǎn),對(duì)初學(xué)者來(lái)說(shuō)比較難理解。本文將閉包相關(guān)的知識(shí)點(diǎn)進(jìn)行梳理,幫助大家更好的理解閉包。下面從4個(gè)部分進(jìn)行說(shuō)明:即作用域、執(zhí)行上下文、閉包和內(nèi)存管理。
文章重點(diǎn)內(nèi)容如圖所示:
1、作用域
作用域其實(shí)就是定義了一套規(guī)則用來(lái)查找變量,控制著變量與函數(shù)的可見性和生命周期。在JavaScript中,有全局作用域和函數(shù)作用域,隨著es6的發(fā)展,引入了塊級(jí)作用域。
- 全局作用域
在代碼中任何地方都能訪問(wèn)到的對(duì)象擁有全局作用域,一般來(lái)說(shuō)以下幾種情形擁有全局作用域:
(1)最外層函數(shù)和在最外層函數(shù)外面定義的變量擁有全局作用域
(2)所有末定義直接賦值的變量自動(dòng)聲明為擁有全局作用域
(3)所有window對(duì)象的屬性擁有全局作用域
- 函數(shù)作用域
在函數(shù)內(nèi)聲明的變量,在當(dāng)前函數(shù)可訪問(wèn)。
- 塊級(jí)作用域
Es6增加了let和const聲明變量,也使得作用域更加豐富,增加了塊級(jí)作用域。
總結(jié):在JavaScript執(zhí)行函數(shù)時(shí),遇到變量,先按照“就近”原則在函數(shù)內(nèi)部找該變量的聲明或者賦值。若沒(méi)有找到,則繼續(xù)向上個(gè)函數(shù)作用域查找,直到最頂層作用域。整個(gè)查找過(guò)程層層遞進(jìn),形成一個(gè)鏈就是作用域鏈。
2、執(zhí)行上下文和調(diào)用棧
- 執(zhí)行上下文
執(zhí)行上下文是當(dāng)前代碼的執(zhí)行環(huán)境/作用域。每個(gè)執(zhí)行環(huán)境都有一個(gè)與之關(guān)聯(lián)的變量對(duì)象(VO),執(zhí)行環(huán)境中定義的所有變量和函數(shù)都會(huì)保存在這個(gè)對(duì)象中,解析器在處理數(shù)據(jù)時(shí)就會(huì)訪問(wèn)這個(gè)內(nèi)部對(duì)象。
JavaScript執(zhí)行主要分為兩個(gè)階段:代碼預(yù)編譯和代碼執(zhí)行階段。
代碼預(yù)編譯是編譯器將JavaScript代碼編譯成可執(zhí)行的代碼,同時(shí)對(duì)變量的內(nèi)存空間進(jìn)行分配(變量提升過(guò)程再此階段完成),作用域也在該階段確定。
執(zhí)行階段主要任務(wù)是執(zhí)行代碼,執(zhí)行上下文在這個(gè)階段全部創(chuàng)建完成。包括:變量對(duì)象、作用域鏈及this的指向
- 調(diào)用棧
在執(zhí)行一個(gè)函數(shù)時(shí),如果這個(gè)函數(shù)又調(diào)用了另外一個(gè)函數(shù),而這個(gè)“另外一個(gè)函數(shù)”也調(diào)用了“另外一個(gè)函數(shù)”,便形成了一系列的調(diào)用棧。
3、閉包
- 什么是閉包?
比較容易理解的版本定義如下:
函數(shù)嵌套函數(shù)時(shí),內(nèi)層函數(shù)引用了外層函數(shù)作用域下的變量,并且內(nèi)層函數(shù)在全局環(huán)境下可訪問(wèn),就形成了閉包
- 為什么會(huì)有閉包
由于JavaScript的作用域只能向上層函數(shù)訪問(wèn),內(nèi)部函數(shù)的變量外部函數(shù)無(wú)法訪問(wèn)(執(zhí)行完上下文被銷毀),為了解決這個(gè)問(wèn)題,出現(xiàn)了閉包。這樣外界可以通過(guò)這個(gè)返回的函數(shù)獲取原函數(shù)內(nèi)部的變量值。
- 閉包有哪些優(yōu)點(diǎn)
簡(jiǎn)單來(lái)說(shuō)閉包為訪問(wèn)函數(shù)內(nèi)部變量提供了途徑和便利。這樣可以實(shí)現(xiàn)“模塊化”
- 閉包的缺點(diǎn)
由于閉包使得變量常駐內(nèi)存,濫用閉包會(huì)導(dǎo)致內(nèi)存的大量消耗,導(dǎo)致內(nèi)存泄漏問(wèn)題。
4、內(nèi)存管理
- 基本概念
內(nèi)存管理都是指對(duì)內(nèi)存生命周期的管理,包括分配內(nèi)存空間、讀寫內(nèi)存和釋放內(nèi)存空間。
- 內(nèi)存空間分為:
棧空間:由操作系統(tǒng)自動(dòng)分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等
堆空間:一般由開發(fā)者分配釋放,要考慮垃圾回收的問(wèn)題
一般情況下基本數(shù)據(jù)類型存放在棧內(nèi)存中,引用類型保存在堆內(nèi)存當(dāng)中
- 內(nèi)存泄漏
內(nèi)存泄漏是指內(nèi)存空間明明已經(jīng)不再被使用,但由于某種原因并沒(méi)有被釋放的現(xiàn)象
- 瀏覽器垃圾回收
兩種算法實(shí)現(xiàn)主動(dòng)垃圾回收:標(biāo)記清楚法和引用計(jì)數(shù)法
垃圾回收優(yōu)質(zhì)文章參考:
本文講解了閉包相關(guān)的基本知識(shí),有了這些知識(shí)再通過(guò)實(shí)例練習(xí),相信聰明的你一定可以掌握閉包了。