摘要:閉包里面保存的變量只有被方法引用了的變量這個(gè)例子里,閉包里只有并沒(méi)有。那最后來(lái)說(shuō)說(shuō)的問(wèn)題閉包到底是什么閉包是一個(gè)作用域。鑒于在的調(diào)試窗口,是放在下面的那閉包這個(gè)作用域是個(gè)什么范圍被后代方法子方法,孫子方法。。。
首先給js的作用域這個(gè)話題打標(biāo)簽:2,var, 全局變量,局部變量,函數(shù),undefined, 作用域提升,賦值不會(huì)提升,ReferenceError, 同名覆蓋。
打完標(biāo)簽之后,我們來(lái)說(shuō)跟作用域有關(guān)的幾條鐵打的規(guī)則:
1: JS的作用域有2種:全局作用域,函數(shù)作用域。
把作用域想象成一個(gè)房間,而{}是房間的門(mén)。門(mén)上裝了一個(gè)貓眼,所以房間里面可以看清楚外面,但是外面卻看不見(jiàn)里面。 在JAVA或者C里面,大括號(hào)可能會(huì)出現(xiàn)的情況有兩種: 1: 一個(gè)function定義的時(shí)候 2: 一個(gè)塊定義(比如if,for, while)的時(shí)候. 所以此時(shí)的作用域有三種類(lèi)型: 1: 全局作用域, 2: 函數(shù)作用域 3: 塊級(jí)作用域。
但是在JS里面,雖然{}出現(xiàn)的情況也有兩種,但是只有function的{}才起到柵欄的作用。
2: 聲明在全局作用域里的變量是全局變量,聲明在函數(shù)里面的變量是局部變量。
3: 怎么創(chuàng)造一個(gè)全局變量和局部變量?
創(chuàng)造全局變量的方法有兩種:
1: 在全局作用域內(nèi)用var定義: var a; 2: 聲明一個(gè)變量,不帶var(無(wú)論是在全局,在函數(shù)里面還是在一個(gè)塊里面):b
創(chuàng)造局部變量的方法只有一種:
在函數(shù)體里面,帶var聲明一個(gè)變量: function func(){var b;}
3: 使用一個(gè)沒(méi)有聲明過(guò)的變量,會(huì)得到一個(gè)ReferenceError。無(wú)論什么情況下。
4: 不同作用域內(nèi),同名的變量,越小的作用域的變量會(huì)覆蓋越大的作用域的。
4: 作用域提升:變量在聲明之前就可以引用了!
這個(gè)不是和第三點(diǎn)矛盾了嗎?其實(shí)并沒(méi)有。它背后的真正原理是:并不是作用域被提升(我們前面說(shuō)了,一個(gè)變量的作用域會(huì)被框在一對(duì)柵欄{}里面,一旦這個(gè)柵欄確定了,那這個(gè)作用域是不可能變化的),其實(shí)是變量的‘聲明’在其作用域里面被放到任何代碼之前(當(dāng)然包括引用它的代碼之前)??匆欢未a:
var scope = "global"; function func(){ console.log(scope); //輸出‘undefined’,而不是‘global’ var scope = "local"; console.log(scope); //輸出‘local’ }
看到第一個(gè)console,可能以為會(huì)輸出‘global’, 因?yàn)橥ㄟ^(guò)貓眼可以看見(jiàn)外面的變量。但是,一旦我們進(jìn)到一個(gè)函數(shù)體里面,遇到任何的變量的引用,首先要先在當(dāng)前的房間里面找,只有在當(dāng)前的房間里面找不到時(shí),才到父層去找。那為什么是‘undefined呢?其實(shí)以上的代碼等價(jià)于:
var scope = "global"; function func(){ var scope; //變量的聲明會(huì)提升到最前面,但是賦值并不會(huì),所以此刻scope的值還只是undefined. console.log(scope); //輸出‘undefined’,而不是‘global’ scope = "local"; //賦值在這里完成 console.log(scope); //輸出‘local’ }
============閉包的分割線===========
1: 什么是閉包?
我看過(guò)看多不同的書(shū),對(duì)必包的定義都不一樣,而且就算是我知道了閉包的定義,對(duì)我真正理解它的工作原理還是沒(méi)有什么用。所以,我就不去糾結(jié)它到底是什么,我接下來(lái)只關(guān)注它是怎么工作的。
2: 什么時(shí)候會(huì)形成閉包?
以下內(nèi)容非原創(chuàng),這里只是我自己的一個(gè)學(xué)習(xí)筆記。我看了http://www.jianshu.com/p/7312...(在這里感謝作者),跟著文章里面的例子(代碼根據(jù)自己的喜好改了一些)走一遍:
1: When? 閉包出現(xiàn)的時(shí)刻?
function foo() { var a = 2; function baz() { console.log( a ); } return baz; } var fn = foo() fn();//2
在斷點(diǎn)的過(guò)程中,運(yùn)行完第9行代碼的時(shí)候,調(diào)試窗口里并沒(méi)有出現(xiàn)任何閉包;直到我運(yùn)行了第10行代碼,跳到第5行的時(shí)候(也就是baz這個(gè)方法被調(diào)用的時(shí)候),調(diào)試窗口出現(xiàn)了閉包(Closure)。并且可以看到說(shuō)foo是closure, 它包含一個(gè)變量a,值為2。
結(jié)論1:雖然很多書(shū)上說(shuō)閉包跟函數(shù)定義的時(shí)候的作用域有關(guān),跟它執(zhí)行時(shí)候的作用域無(wú)關(guān),但是它在瀏覽器里面出現(xiàn)的時(shí)機(jī)卻是在執(zhí)行的時(shí)候。
2 How? 閉包出現(xiàn)的條件?
function foo() { var a = 2; function baz(m) { console.log(m); } return baz; } var fn = foo() fn(20); //20
很多地方都說(shuō)在方法里面定義方法就會(huì)形成閉包,但是在這里例子里面,我執(zhí)行完第10行的代碼,調(diào)試窗口并沒(méi)有出現(xiàn)任何閉包。和例1的差別在于,baz沒(méi)有引用變量a.
結(jié)論2:一個(gè)方法,一定要引用其父層方法(非自己方法內(nèi)部的變量)的變量才會(huì)形成閉包。
但是閉包的形成是不是一定要執(zhí)行到引用了父層作用域變量的方法才出現(xiàn)呢?看下面一個(gè)例子:
3: 當(dāng)父層方法里有不只一個(gè)方法
function foo() { var a = 10; var b = 30; function fn1() { return a; } function fn2() { return 20; } return fn2; } var fn = foo(); fn();
當(dāng)我執(zhí)行到17行然后跳進(jìn)其方法體(第10行)的時(shí)候,調(diào)試窗口出現(xiàn)了Closure, 并且它有一個(gè)變量a,
值為10。其實(shí)這個(gè)例子說(shuō)明了兩個(gè)事情:
結(jié)論3: 在執(zhí)行一個(gè)定義在方法里面的方法時(shí),即使它的方法體自己沒(méi)有引用父層變量,但是只要有任何兄弟方法引用了,那就會(huì)形成閉包。閉包里面保存的變量只有被方法引用了的變量(這個(gè)例子里,閉包里只有a,并沒(méi)有b)。
4: 當(dāng)不是兄弟方法,而是子方法引用了父級(jí)變量,會(huì)發(fā)生什么情況呢?
function foo() { var a = 10; var b = 30; function fn1() { var c = 20; function fn2(){ return a; } return fn2; } return fn1; } var fn1 = foo(); var fn2 = fn1(); fn2();
fn1方法體內(nèi)沒(méi)有引用任何的父層變量,但是它的子方法fn2引用了變量a。在調(diào)試的過(guò)程中,當(dāng)執(zhí)行到f1的時(shí)候(執(zhí)行到第6行,這時(shí)候可以看到變量c都還是"undefined"),Closure就已經(jīng)出現(xiàn)了,并不像之前那樣一定要等到執(zhí)行fn2.最后看一個(gè)例子:
5: 當(dāng)不是直系子方法,而是侄子方法引用了父級(jí)變量
function foo() { var a = 10; var b = 30; function fn1() { var c = 20; function fn2(){ return a; } return fn2; } function fn3(){ return 40; } return fn3; } var fn3 = foo(); fn3();
當(dāng)執(zhí)行到調(diào)用fn3的時(shí)候,Chosure出現(xiàn)了。所以閉包到底是在什么時(shí)候形成呢?在我們前面的結(jié)論里面有提到說(shuō)方法執(zhí)行的時(shí)候,但是經(jīng)過(guò)后面的這幾個(gè)例子說(shuō)明并不一定非得是執(zhí)行的時(shí)候,而且JavaScript是基于詞法作用域的語(yǔ)言(變量的作用域在其定義的時(shí)候就已經(jīng)確定了,不依賴于執(zhí)行時(shí)的環(huán)境),所以我傾向于閉包(Closure)是在方法定義的時(shí)候就形成了的。那最后來(lái)說(shuō)說(shuō)What的問(wèn)題:閉包到底是什么?
1: 閉包是一個(gè)作用域。(鑒于在Chrome的調(diào)試窗口,Closure是放在Scope下面的)
2: 那閉包這個(gè)作用域是個(gè)什么范圍:被后代方法(子方法,孫子方法。。。)所引用的變量所在的作用域(或者說(shuō)這個(gè)變量所在的方法)。
3: 閉包里面有什么:只包含被后代方法所引用了的變量,并不包含這個(gè)變量的兄弟姐妹。
4: 上面的所有例子都只引用了變量,換成方法,也都是同樣的結(jié)果。
真的是最后一個(gè)例子了:
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/83506.html
摘要:的變量作用域是基于其特有的作用域鏈的。需要注意的是,用創(chuàng)建的函數(shù),其作用域指向全局作用域。所以,有另一種說(shuō)法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。 作用域 定義 在編程語(yǔ)言中,作用域控制著變量與參數(shù)的可見(jiàn)性及生命周期,它能減少名稱(chēng)沖突,而且提供了自動(dòng)內(nèi)存管理 --javascript 語(yǔ)言精粹 我理解的是,一個(gè)變量、函數(shù)或者成員可以在代碼中訪問(wèn)到的范圍。 js的變量作...
摘要:作用域分為詞法作用域和動(dòng)態(tài)作用域。這樣就形成了一個(gè)鏈?zhǔn)降淖饔糜?。一般情況下,當(dāng)函數(shù)執(zhí)行完畢時(shí),里面的變量會(huì)被自動(dòng)銷(xiāo)毀。而能夠訪問(wèn)到這個(gè)在的編譯階段就已經(jīng)定型了詞法作用域。 什么是作用域?在當(dāng)前運(yùn)行環(huán)境下,可以訪問(wèn)的變量或函數(shù)的范圍。作用域分為詞法作用域和動(dòng)態(tài)作用域。詞法作用域是在js代碼編譯階段就確定下來(lái)的; 對(duì)應(yīng)的,with和eval語(yǔ)句會(huì)產(chǎn)生動(dòng)態(tài)作用域。 會(huì)產(chǎn)生新的作用域的情況: ...
摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內(nèi)部,也就是說(shuō)為其聲明的變量隱式的劫持了所在的塊級(jí)作用域。 作用域與閉包 如何用js創(chuàng)建10個(gè)button標(biāo)簽,點(diǎn)擊每個(gè)按鈕時(shí)打印按鈕對(duì)應(yīng)的序號(hào)? 看到上述問(wèn)題,如果你能看出來(lái)這個(gè)問(wèn)題實(shí)質(zhì)上是考對(duì)作用域的理解,那么恭喜你,這篇文章你可以不用看了,說(shuō)明你對(duì)作用域已經(jīng)理解的很透徹了,但是如果你看不出來(lái)這是一道考作用域的題目,...
摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內(nèi)部,也就是說(shuō)為其聲明的變量隱式的劫持了所在的塊級(jí)作用域。 作用域與閉包 如何用js創(chuàng)建10個(gè)button標(biāo)簽,點(diǎn)擊每個(gè)按鈕時(shí)打印按鈕對(duì)應(yīng)的序號(hào)? 看到上述問(wèn)題,如果你能看出來(lái)這個(gè)問(wèn)題實(shí)質(zhì)上是考對(duì)作用域的理解,那么恭喜你,這篇文章你可以不用看了,說(shuō)明你對(duì)作用域已經(jīng)理解的很透徹了,但是如果你看不出來(lái)這是一道考作用域的題目,...
摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內(nèi)部,也就是說(shuō)為其聲明的變量隱式的劫持了所在的塊級(jí)作用域。 作用域與閉包 如何用js創(chuàng)建10個(gè)button標(biāo)簽,點(diǎn)擊每個(gè)按鈕時(shí)打印按鈕對(duì)應(yīng)的序號(hào)? 看到上述問(wèn)題,如果你能看出來(lái)這個(gè)問(wèn)題實(shí)質(zhì)上是考對(duì)作用域的理解,那么恭喜你,這篇文章你可以不用看了,說(shuō)明你對(duì)作用域已經(jīng)理解的很透徹了,但是如果你看不出來(lái)這是一道考作用域的題目,...
閱讀 2084·2021-11-16 11:45
閱讀 582·2021-11-04 16:12
閱讀 1386·2021-10-08 10:22
閱讀 861·2021-09-23 11:52
閱讀 4146·2021-09-22 15:47
閱讀 3523·2021-09-22 15:07
閱讀 494·2021-09-03 10:28
閱讀 1742·2021-09-02 15:21