九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
前端基本知識:JS的閉包理解

JS閉包的理解

一、變量的作用域

二、如何從外部讀取局部變量

三、什么是閉包

四、深入理解閉包

五、閉包的用途

六、使用閉包注意情況

七、JavaScript的垃圾回收機制

八、一些思考題

一、變量作用域

1、要理解閉包,我們先來看一下JavaScript的特殊的變量作用域。

變量的作用域無非是兩種,全局變量和局部變量。

JavaScript語言的獨特之處是:函數(shù)內(nèi)部可以讀取所有的全局變量。

var n=999; function f1{ alert(n); } f1; // 999

函數(shù)外部無法讀取函數(shù)內(nèi)部的局部變量。

function f1{ var n=999; } alert(n); // error

這里有一個地方需要注意,函數(shù)內(nèi)部聲明變量的時候,一定要使用var命令。如果不用的話,你實際上聲明了一個全局變量!

再來看一個例子,理解一下變量作用域

注意:函數(shù)名只是一個標(biāo)識(指向函數(shù)的指針),而才是執(zhí)行函數(shù)

二、如何從外部讀取局部變量

從局部變量讀取外部全局變量是JavaScript語言的特點,但是有時我們需要從外部讀取函數(shù)內(nèi)部的局部變量,那怎么辦呢?解決辦法:在函數(shù)內(nèi)部定義一個函數(shù)。

函數(shù)f1中定義一個f2函數(shù)。上述代碼中,函數(shù)f2倍包括早函數(shù)f1內(nèi)部,這時候,f1的內(nèi)部局部變量f2都可見,反過來,f2的布局變量,f1不可見。這個就是JavaScript語言特有的“鏈?zhǔn)阶饔糜颉钡慕Y(jié)構(gòu)---子對象會一級級的向上尋找所有的父對象的變量(即,所有的父對象的變量,子對象都是可見的)。

既然f2可以讀取f1中的局部變量,那么只要把f2作為返回值,我們就可以在f1的外部就可以讀取f1內(nèi)部變量了。

三、什么是閉包

閉包就是可以讀取其他函數(shù)內(nèi)部的變量。

由于,JavaScript語言中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,也可以說,閉包就是“定義在一個函數(shù)內(nèi)部的函數(shù)”。

所以,本質(zhì)上說,閉包就是講函數(shù)內(nèi)部很函數(shù)外部連接起來的一座橋梁。

JavaScript中所有的function都是一個閉包。不過一般來說,嵌套的function所產(chǎn)生的閉包更為強大,也是大部分時候我們所謂的“閉包”??聪旅孢@段代碼:

這段代碼有個特點:

1、函數(shù)b嵌套在函數(shù)a內(nèi)部

2、函數(shù)a返回函數(shù)b

執(zhí)行代碼c=a;實際c指向函數(shù)b

再執(zhí)行c;就會彈出一個窗口顯示 i 的值(第一次為1)。

這段代碼其實就是創(chuàng)建了一個閉包,因為函數(shù)a外的變量c引用了函數(shù)a內(nèi)的函數(shù)b,

當(dāng)函數(shù)a 的 內(nèi)部函數(shù)b 被 函數(shù)a 外的 一個變量引用的時候,就創(chuàng)建了一個閉包。

四、深入理解閉包

如果要深入理解閉包和嵌套函數(shù)b的關(guān)系,我們需要引入:函數(shù)的執(zhí)行環(huán)境(excution context)、活動對象c(call object)、作用域(scope)、作用域鏈(scope chain),以函數(shù)a為例,從定義到執(zhí)行過程

1、當(dāng)定義函數(shù)a的時候,js解釋器會將函數(shù)a的作用域鏈(scope chain)設(shè)置成 定義a時a所在的環(huán)境,如果a是一個全局函數(shù),則作用域鏈(scope chain)中只用window對象。

2、當(dāng)執(zhí)行函數(shù)a的時候,a會進(jìn)入到相應(yīng)的執(zhí)行環(huán)境(excution context)。

3、在創(chuàng)建執(zhí)行環(huán)境的過程中,首先會為a添加一個scope屬性,即a的作用域,其值為第1步的作用域鏈(scope chain)。即a.scope=a的作用域鏈。

4、然后執(zhí)行環(huán)境會創(chuàng)建一個活動對象(call object)?;顒訉ο笠彩且粋€擁有屬性的對象,但它不具有原型,而且不能通過JavaScript代碼直接訪問。創(chuàng)建完活動對象后,把活動對象添加到a的作用域鏈的最頂端。此時a的作用域鏈包含了兩個對象:a的活動的對象和window對象。

5、下一步是在活動對象上添加一個arguments屬性,它保存著調(diào)用函數(shù)a時所傳遞的參數(shù)。

6、最后把所有的函數(shù)a的形參和內(nèi)部函數(shù)b的引用也添加到a的活動對象上。這一步中,完成了函數(shù)b的定義,因此,如同第3步,函數(shù)b的作用域鏈被設(shè)置成b所定義的環(huán)境,即a的作用域

到此,整個函數(shù)a從定義到執(zhí)行的步驟就完成了。此時a返回函數(shù)b的引用給c,又函數(shù)b的作用域鏈包含鏈包含了對函數(shù)a的活動對象的引用,也就是說b可以訪問a中的定義的所有變量和函數(shù)。函數(shù)b被c引用,函數(shù)b依賴函數(shù)a,一次函數(shù)a在返回后不會被gc回收。

當(dāng)函數(shù)b執(zhí)行的時候也會像以上步驟一樣。因此,執(zhí)行時b的作用域鏈包含3個對象:b的活動對象,a的活動對象和window對象,如下圖所示:

如圖所示,在當(dāng)函數(shù)b中訪問一個變量的時候,搜索順序是:

1、先搜索自身的活動對象,如果存在則返回,如果不存在將繼續(xù)搜索函數(shù)a的活動對象,依次查找,直到找到為止。

2、如果函數(shù)b存在prototype原型對象,則在查找完自身的活動對象后先查找自身的原型對象,再繼續(xù)查找。這就是JavaScript中的變量查找機制。

3、如果整個作用域鏈都無法找到,則返回undefined。

本節(jié)小結(jié),上文提到兩個重要的詞語:函數(shù)的定義與執(zhí)行。文中提到函數(shù)的作用域是在定義函數(shù)時確定的,而不是在執(zhí)行的時候確定的(參看步驟1和3),用一段代碼來說明這個:

這段代碼中,變量h指向了 f 中的那個匿名函數(shù)(由g返回)。

1、假設(shè)函數(shù)h的作用域是在執(zhí)行alert(h)確定的,那么此時h的作用域鏈?zhǔn)牵篽的活動對象-》alert活動對象-》window對象。

2、假設(shè)函數(shù)h的作用域是在定義時候確定的就是說h指向的那個匿名函數(shù)在定義的時候就已經(jīng)確定確定了作用域。那么在執(zhí)行的時候,h的作用域鏈為:h的活動對象-》f的活動對象-》window活動對象。

如果第一種假設(shè)成立,anemia輸出值就是undefined;如果第二種假設(shè)成立,則輸出值為1.

運行結(jié)果證明了第二個假設(shè)是正確的,說明函數(shù)的作用域確實在定義這個函數(shù)的時候就已經(jīng)確定了

五、閉包的用途

接上個例子,

閉包的作用就是在a執(zhí)行完并返回后,閉包使得Javascript的垃圾回收機制GC不會收回a所占用的資源,因為a的內(nèi)部函數(shù)b的執(zhí)行需要依賴a中的變量。由于閉包的存在使得函數(shù)a返回后,a中的i始終存在,這樣每次執(zhí)行c,i都是自加1后alert出i的值。

閉包有很多用途,最大的兩個好處:

(一)讀取函數(shù)內(nèi)部的變量

(二)讓這些變量始終保存在內(nèi)存中。

理解“(二)讓這些變量始終保存在內(nèi)存中”這句話,看一下下面的額代碼。

這段代碼中,result實際上是閉包f2函數(shù)。result一共運行了兩次,第一次是999,第二次是1000.

這說明,函數(shù)f1中的局部變量n一直保存在內(nèi)存中,并沒有在f1調(diào)用后進(jìn)行自動清除。

原因:f1是f2的父函數(shù),而f2被賦給一個全局變量,這導(dǎo)致f2一直在內(nèi)存中,f2依賴于f1,因此f1始終在內(nèi)存中,不會再調(diào)用結(jié)束之后,被垃圾回收機制回收。

注意:nAdd=function{n+=1}這個函數(shù),首先這個函數(shù)沒有用var關(guān)鍵字,因此nAdd是一個全局變量,而不是局部變量。其次,nAdd的值是一個匿名函數(shù),這個匿名函數(shù)本身就是一個閉包,可以在函數(shù)外部對函數(shù)的內(nèi)部今次進(jìn)行操作。

六、使用閉包的注意情況

(1)閉包會是的函數(shù)中的變量倍保存在內(nèi)存中,內(nèi)存消耗大,所以不能濫用閉包。否則會造成網(wǎng)頁性能問題,在IE中可能存在內(nèi)存泄漏,解決辦法,在函數(shù)退出之前,將不使用的局部變量全部刪除。

(2)閉包會在父函數(shù)的外部,改變父函數(shù)變量內(nèi)部的值。所以你把父函數(shù)當(dāng)做對象object使用,把閉包當(dāng)做她的公用方法,把內(nèi)部變量當(dāng)做他的私有屬性,不要隨便改變父函數(shù)內(nèi)部變量的值。

JavaScript中,如果一個對象不再被引用,那么這個對象就會被GC回收。如果兩個對象相互引用,而不再被第三者所引用,那么這兩個相互引用的對象就會被回收。因為函數(shù)a被b引用,b又被a外的c引用,這就是為什么函數(shù)a執(zhí)行后不會被回收的原因。

八、一些思考題

1、使用對象的閉包使用

2、直接調(diào)用函數(shù)內(nèi)部的函數(shù),報錯,需要使用閉包。

上面的代碼是錯誤的.innerFun的作用域在outerFun內(nèi)部,所在outerFun外部調(diào)用它是錯誤的.

改成下面,就可行了

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
javascript深入理解js閉包
JavaScript權(quán)威指南
深入理解JavaScript的變量作用域
Web性能優(yōu)化系列:10個JavaScript性能提升的技巧
javascript權(quán)威指南 學(xué)習(xí)筆記之變量作用域分享
JavaScript作用域
更多類似文章 >>
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服