《你不知道的javascript(上)》作用域與閉包(二)

在翻閱《你不知道的javascript》這一套書的中上卷目錄之后定躏,發(fā)現(xiàn)書中針對(duì)閉包诸迟、對(duì)象、原型受裹、語法斗这、異步动猬、回調(diào)等等既基礎(chǔ)又重要的
javascript知識(shí)有著針對(duì)性的闡述,于是決定對(duì)這套書的中上卷進(jìn)行學(xué)習(xí)涝影。上卷和中卷各講述了兩大部分知識(shí)枣察,分別是:作用域與閉包、
this和對(duì)象原型燃逻、類型和語法序目、異步和性能。本文是對(duì)作用域與閉包的學(xué)習(xí)總結(jié)伯襟。

對(duì)于作用域及其相關(guān)知識(shí)的理解猿涨,我認(rèn)為主要把握這樣一些東西:js所使用作用域的類型,IIFE以及作用域中的提升姆怪。

1.作用域類型

  作用域分為詞法作用域和動(dòng)態(tài)作用域叛赚,js使用的是詞法作用域。所謂詞法作用域稽揭,指的是在編譯詞法分析階段根據(jù)詞法單元確定下來的作用域俺附,并且在引擎執(zhí)行代碼階段作用域是不變的(大部分情況下),注意括號(hào)里的大部分情況溪掀,因?yàn)樵谕ǔ?duì)語法的學(xué)習(xí)中事镣,只要注意一些不符合常規(guī)情況的狀態(tài),對(duì)語法的把握會(huì)順利許多揪胃。

  一小部分會(huì)在執(zhí)行代碼期間改變作用域的情況(書中稱之為“欺騙”)是兩種:在js中使用了eval()和with()方法(在非嚴(yán)格模式下):

  • eval()可以接受一個(gè)字符串作為參數(shù)璃哟,并且在執(zhí)行代碼期間氛琢,將參數(shù)中可能傳遞的值看作本來就存在于eval()所在位置的代碼;
  • with()主要作用是可以接受一個(gè)對(duì)象随闪,并快捷引用其中的屬性阳似。然而,with()在處理這個(gè)對(duì)象的時(shí)候铐伴,不僅會(huì)形成一個(gè)新的作用域撮奏,
    還可能改變?cè)敬嬖诘脑~法作用域(這個(gè)方法比較復(fù)雜)。

對(duì)eval()舉個(gè)例子:

function foo(str,a) {
  eval(str);
  console.log(a,b);
}
var b = 2;
foo("var b = 3",1);//1,3

在執(zhí)行foo("var b = 3",1)語句時(shí)当宴,在正常情況下挽荡,函數(shù)foo(str,a)執(zhí)行到console.log(a,b)時(shí),查找b會(huì)找到全局變量中的b并得到2即供,但實(shí)際卻得到3,這是因?yàn)閑val()將“var b = 3”看作在函數(shù)foo(str,a)中的代碼于微,相當(dāng)于在函數(shù)中聲明了一個(gè)b作為局部變量逗嫡,于是下一句console.log(a,b)執(zhí)行的時(shí)候先找到局部變量得到值3,就結(jié)束了查找,而全局變量b被屏蔽了株依。

  在嚴(yán)格模式下驱证,eval()有自己的作用域,不會(huì)在其所處函數(shù)中產(chǎn)生屏蔽效應(yīng)恋腕,而with()是被禁用的抹锄。并且,在第一章中講到荠藤,引擎在優(yōu)化性能的時(shí)候伙单,是根據(jù)已經(jīng)確定的作用域和詞法單元來進(jìn)行優(yōu)化的,在使用了eval()和with()后哈肖,使得函數(shù)作用域可能在動(dòng)態(tài)情況下(執(zhí)行代碼期間)發(fā)生變化吻育,而引擎在遇到這個(gè)兩個(gè)方法后就不會(huì)進(jìn)行性能優(yōu)化。所以淤井,在js中使用這兩個(gè)方法會(huì)導(dǎo)致性能下降布疼。

對(duì)于詞法作用域,其中又分成了塊作用域和函數(shù)作用域币狠,js絕大部分情況下使用的是函數(shù)作用域游两,但存在個(gè)別塊作用域的時(shí)候,使用with()和try~catch語句的時(shí)候會(huì)形成塊作用域(又是with()漩绵,在這里贱案,《高程》第三版第4章中也講到了with()會(huì)形成作用域,但《高程》中提到這種情況使得作用域鏈變長了渐行,而with()形成的依然是函數(shù)作用域)轰坊,并且ES6出來之后铸董,也正式承認(rèn)了塊作用域的存在和使用,在{}中使用let和const聲明就能創(chuàng)造塊作用域了肴沫,這為使用循環(huán)語句等提供了很大的便利粟害。

2.IIFE

  IIFE是立即執(zhí)行函數(shù)表達(dá)式。首先應(yīng)該理解什么是函數(shù)表達(dá)式颤芬,非常簡單悲幅,以function單詞作為開頭的是函數(shù)聲明,而帶有function但并非以其開頭的語句就是函數(shù)表達(dá)式站蝠,最典型的情況就是(function(){})汰具。函數(shù)聲明和函數(shù)表達(dá)式相同的地方在于形成了函數(shù)作用域,而不同的地方函數(shù)聲明會(huì)被提升菱魔,而表達(dá)式不會(huì)(顯然不會(huì)留荔,因?yàn)槁暶鞑攀蔷幾g器工作的對(duì)象)。

  函數(shù)表達(dá)式的一個(gè)主要作用是可以使函數(shù)匿名澜倦,這樣就避免了函數(shù)作用域中多出一個(gè)標(biāo)識(shí)符聚蝶。但是并非所有情況下匿名都是最優(yōu)的,例如:當(dāng)函數(shù)不只需要被調(diào)用一次的時(shí)候藻治,就不能匿名了碘勉。

  而函數(shù)表達(dá)式另一個(gè)主要的作用就是作為IIFE的出現(xiàn),既(function(){})()或(function(){}())的形式桩卵,可以立即執(zhí)行函數(shù)验靡,而無需調(diào)用或加載。而IIFE多出來的括號(hào)并不是只使得函數(shù)會(huì)立即執(zhí)行雏节,在括號(hào)中還可以傳遞需要的參數(shù)胜嗓。例如,以(function(a,b){})(c,d)的形式既能將參數(shù)傳遞進(jìn)函數(shù)了矾屯,而簡單的函數(shù)表達(dá)式(function(){})卻沒有這樣的功能兼蕊。

  此外,IIFE還是閉包機(jī)制的一個(gè)最佳實(shí)踐(雖然不是最能體現(xiàn)閉包機(jī)制的方式)件蚕,在第三部分的閉包中會(huì)講到孙技。

3.作用域中的提升

  其實(shí)作用域中的提升非常簡單,只要能夠理解js的編譯原理:在編譯器工作階段排作,會(huì)進(jìn)行聲明牵啦,以及對(duì)其他語句形成引擎執(zhí)行的代碼,因此妄痪,在編寫的代碼中哈雏,不管一個(gè)作用域中的聲明處于哪里,肯定都比賦值等其他句語先完成,而js語句的執(zhí)行是按照從上到下執(zhí)行的裳瘪,這就好比將聲明從下統(tǒng)一提升到了函數(shù)中最上面的地方土浸,這就稱為聲明。

  對(duì)提升需要把握的要點(diǎn)有以下三處:

  • 函數(shù)表達(dá)式不會(huì)提升彭羹;
  • let和const聲明不會(huì)提升黄伊;
  • 函數(shù)聲明會(huì)提升到變量聲明的上方,而在同一個(gè)作用域中聲明了同名函數(shù)時(shí)派殷,后一個(gè)同名函數(shù)在提升時(shí)會(huì)覆蓋前一個(gè)函數(shù)的聲明还最。

Small Star's Blog|小星的博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市毡惜,隨后出現(xiàn)的幾起案子拓轻,更是在濱河造成了極大的恐慌,老刑警劉巖经伙,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扶叉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡帕膜,警方通過查閱死者的電腦和手機(jī)辜梳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泳叠,“玉大人,你說我怎么就攤上這事茶宵∥H遥” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵乌庶,是天一觀的道長种蝶。 經(jīng)常有香客問我,道長瞒大,這世上最難降的妖魔是什么螃征? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮透敌,結(jié)果婚禮上盯滚,老公的妹妹穿的比我還像新娘。我一直安慰自己酗电,他們只是感情好魄藕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著撵术,像睡著了一般背率。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天寝姿,我揣著相機(jī)與錄音交排,去河邊找鬼。 笑死饵筑,一個(gè)胖子當(dāng)著我的面吹牛埃篓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播翻翩,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼都许,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了嫂冻?” 一聲冷哼從身側(cè)響起胶征,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桨仿,沒想到半個(gè)月后睛低,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡服傍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年钱雷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吹零。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡罩抗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灿椅,到底是詐尸還是另有隱情套蒂,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布茫蛹,位于F島的核電站操刀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏婴洼。R本人自食惡果不足惜骨坑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望柬采。 院中可真熱鬧欢唾,春花似錦、人聲如沸粉捻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杀迹。三九已至亡脸,卻和暖如春押搪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浅碾。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工大州, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人垂谢。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓厦画,卻偏偏與公主長得像,于是被迫代替她去往敵國和親滥朱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子根暑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券徙邻,享受所有官網(wǎng)優(yōu)惠排嫌,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 2,396評(píng)論 0 11
  • 《你不知道的JavaScript》真的是一本好書,閱讀這本書缰犁,我有多次“哦淳地,原來是這樣”的感覺,以前自以為理解了(...
    然并阮閱讀 621評(píng)論 2 9
  • 目錄 1.靜態(tài)作用域與動(dòng)態(tài)作用域 2.變量的作用域 3.JavaScript 中變量的作用域 4.JavaScri...
    一縷殤流化隱半邊冰霜閱讀 7,097評(píng)論 37 113
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持帅容,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券颇象,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 2,305評(píng)論 0 21
  • 這個(gè)世界是圓的并徘, 你給出什么遣钳, 總有一天他們都會(huì)回到你的身上來。 你發(fā)出愛心麦乞, 就會(huì)收到愛耍贾; 你發(fā)出智慧, 就會(huì)收...
    千吉change閱讀 247評(píng)論 0 1