首先要理解作用域
- 在JavaScript中,作用域通常是指代碼的上下文(context)尽爆。能夠定義全局或者局部作用域谣旁。
- 函數(shù)作用域:JavaScript 中函數(shù)域?yàn)樽钚∮蚍秶芈or與while循環(huán)或者if和switch都不能構(gòu)建作用域惠呼。規(guī)則就是导俘,新函數(shù)新域。
- 詞匯作用域:當(dāng)遇到一個(gè)函數(shù)嵌套到另一函數(shù)中剔蹋,內(nèi)部函數(shù)能夠訪問外部函數(shù)的作用域旅薄,那么這種方式叫做詞匯作用域(Lexical Socpe)或者閉包,也稱為成為靜態(tài)作用域泣崩。
- 任何父作用域中定義的變量少梁、對(duì)象和函數(shù)在其域作用鏈中都可以使用
- 作用域鏈:函數(shù)的作用域由作用域鏈構(gòu)成。我們知道矫付,每個(gè)函數(shù)可以定義嵌套的作用域凯沪,任何內(nèi)嵌函數(shù)都有一個(gè)局部作用域連接外部函數(shù)。這種嵌套關(guān)系我們可以稱為鏈买优。域一般由代碼中的位置決定妨马。當(dāng)解釋(resolving)一個(gè)變量,通常從作用域鏈的最里層開始杀赢,向外搜索烘跺,直到發(fā)現(xiàn)要尋找的變量、對(duì)象或者函數(shù)脂崔。作用域鏈的用途是保證對(duì)執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問滤淳。作用域鏈包含了在環(huán)境棧中的每個(gè)執(zhí)行環(huán)境對(duì)應(yīng)的變量對(duì)象。通過作用域鏈砌左,可以決定變量的訪問和標(biāo)識(shí)符的解析脖咐。全局執(zhí)行環(huán)境的變量對(duì)象始終都是作用域鏈的最后一個(gè)對(duì)象。
閉包
特性:
- 函數(shù)嵌套函數(shù)
- 函數(shù)內(nèi)部可以引用外部的參數(shù)和變量
- 參數(shù)和變量不會(huì)被垃圾回收機(jī)制回收
作用:創(chuàng)建私有變量模仿塊級(jí)作用域
閉包是指有權(quán)訪問另一函數(shù)作用域中的變量的函數(shù)汇歹。換句話說文搂,在函數(shù)內(nèi)定義一個(gè)嵌套的函數(shù)時(shí),就構(gòu)成了一個(gè)閉包秤朗,它允許嵌套函數(shù)訪問外層函數(shù)的變量煤蹭。通過返回嵌套函數(shù),允許你維護(hù)對(duì)外部函數(shù)中局部變量取视、參數(shù)硝皂、和內(nèi)函數(shù)聲明的訪問。這種封裝允許你在外部作用域中隱藏和保護(hù)執(zhí)行環(huán)境作谭,并且暴露公共接口稽物,進(jìn)而通過公共接口執(zhí)行進(jìn)一步的操作。
閉包和詞法域( Lexical Scope)很像折欠。返回函數(shù)引用贝或,這種實(shí)際應(yīng)用吼过,是一個(gè)可以用來解釋閉包工作原理的好例子。在我們的域內(nèi)部咪奖,我們可以返回對(duì)象盗忱,能夠被父域使用
閉包使得我們的內(nèi)部域無法被公共域訪問到。單獨(dú)調(diào)用函數(shù)并不作任何操作羊赵,因?yàn)槠鋯渭兊姆祷匾粋€(gè)函數(shù)趟佃。閉包并不一定需要返回函數(shù)。單純?cè)谥虚g詞匯域量的范圍外簡(jiǎn)單訪問變量就創(chuàng)造了一個(gè)閉包昧捷。
閉包的應(yīng)用
模塊化:模塊類似于一個(gè)單例對(duì)象闲昭。由于在上面的代碼中我們利用了(function() { ... })();的匿名函數(shù)形式,因此當(dāng)編譯器解析它的時(shí)候會(huì)立即執(zhí)行靡挥。在閉包的執(zhí)行上下文的外部唯一可以訪問的對(duì)象是位于返回對(duì)象中的公共方法和屬性序矩。然而,因?yàn)閳?zhí)行上下文被保存的緣故跋破,所有的私有屬性和方法將一直存在于應(yīng)用的整個(gè)生命周期簸淀,這意味著我們只有通過公共方法才可以與它們交互。
立即執(zhí)行的函數(shù)表達(dá)式(IIFE): 是一個(gè)在全局環(huán)境中自執(zhí)行的匿名函數(shù),護(hù)全局命名空間免受變量污染,它通過構(gòu)建函數(shù)作用域的形式將變量與全局命名空間隔離幔烛,并通過閉包的形式讓它們存在于整個(gè)運(yùn)行時(shí)(runtime)啃擦。在很多的應(yīng)用和框架中,這種封裝源代碼的方式用處非常的流行饿悬,通常都是通過暴露一個(gè)單一的全局接口的方式與外部進(jìn)行交互令蛉。