摘要:詞法作用域定義在詞法階段的作用域由你在寫(xiě)代碼時(shí)將變量和塊作用域?qū)懺谀膩?lái)決定的,因此當(dāng)詞法分析器處理代碼時(shí)會(huì)保持作用域不變。欺騙詞法作用域在詞法分析器處理過(guò)后依然可以修改作用域。
你不知道的JS(上卷)筆記
你不知道的 JavaScript
JavaScript 既是一門(mén)充滿(mǎn)吸引力、簡(jiǎn)單易用的語(yǔ)言,又是一門(mén)具有許多復(fù)雜微妙技術(shù)的語(yǔ)言,即使是經(jīng)驗(yàn)豐富的 JavaScript 開(kāi)發(fā)者,如果沒(méi)有認(rèn)真學(xué)習(xí)的話(huà)也無(wú)法真正理解它們.
上卷包括倆節(jié):
作用域和閉包
this 和對(duì)象原型
作用域和閉包希望 Kyle 對(duì) JavaScript 工作原理每一個(gè)細(xì)節(jié)的批判性思 考會(huì)滲透到你的思考過(guò)程和日常工作中。知其然,也要知其所以然。
詞法作用域作用域共有倆種主要的工作模型: 詞法作用域和動(dòng)態(tài)作用域。
詞法階段詞法化:大部分標(biāo)準(zhǔn)語(yǔ)言編譯器的第一個(gè)工作階段叫作詞法化(也叫單詞化)。
詞法化的過(guò)程會(huì)對(duì)源代碼中的字符進(jìn)行檢查,如果是有狀態(tài)的解析過(guò)程,還會(huì)賦 予單詞語(yǔ)義。
詞法作用域
定義在詞法階段的作用域
由你在寫(xiě)代碼時(shí)將變量和塊作用域?qū)懺谀膩?lái)決定的,因此當(dāng)詞法分析器處理代碼時(shí)會(huì)保持作用域不變。
欺騙詞法作用域: 在詞法分析器處理過(guò)后依然可以修改作用域。
事實(shí)上,讓詞法作用域根據(jù)詞法關(guān)系保持書(shū)寫(xiě)時(shí)的自然關(guān)系不變是一個(gè)非常好的最佳實(shí)踐。
“作用域氣泡法” 劃分作用域
查找作用域氣泡的結(jié)構(gòu)和互相之間的位置關(guān)系給引擎提供了足夠的位置信息,引擎用這些信息來(lái)查找標(biāo)識(shí)符的位置。
作用域查找始終從運(yùn)行時(shí)所處的最內(nèi)部作用域開(kāi)始,逐級(jí)向外或者向上進(jìn)行。
作用域查找會(huì)在找到第一個(gè)匹配的標(biāo)識(shí)符時(shí)停止,或者直至找到最后一個(gè)全局作用域處。
window.a的方式可以訪(fǎng)問(wèn)那些被同名變量遮蔽了的全局變量,但非全局變量如果被遮蔽,就無(wú)法訪(fǎng)問(wèn)到了
遮蔽效應(yīng): 在多層的嵌套作用域中可以定義同名的標(biāo)識(shí)符。
欺騙詞法倆種欺騙手段:eval和with;
社區(qū)認(rèn)為使用這倆種機(jī)制并不是什么好主意,因?yàn)槭褂眠@倆種機(jī)制會(huì)導(dǎo)致性能下降
另外一個(gè)不推薦使用 eval(..) 和 with 的原因是會(huì)被嚴(yán)格模式所影響(限 制)。with 被完全禁止,而在保留核心功能的前提下,間接或非安全地使用 eval(..) 也被禁止了。
JavaScript 中的 eval(..) 函數(shù)可以接受一個(gè)字符串為參數(shù),并將其中的內(nèi)容視為好像在書(shū) 寫(xiě)時(shí)就存在于程序中這個(gè)位置的代碼。換句話(huà)說(shuō),可以在你寫(xiě)的代碼中用程序生成代碼并 運(yùn)行,就好像代碼是寫(xiě)在那個(gè)位置的一樣。
function foo(str, a) { eval( str ); // 欺騙! console.log( a, b ); } var b = 2; foo( "var b = 3;", 1 ); // 1, 3
eval通常被用來(lái)執(zhí)行動(dòng)態(tài)創(chuàng)建的代碼
在這個(gè)例子中,為了展示的方便和簡(jiǎn)潔,我們傳遞進(jìn)去的“代碼”字符串是 固定不變的。而在實(shí)際情況中,可以非常容易地根據(jù)程序邏輯動(dòng)態(tài)地將字符 拼接在一起之后再傳遞進(jìn)去。eval(..) 通常被用來(lái)執(zhí)行動(dòng)態(tài)創(chuàng)建的代碼,因 為像例子中這樣動(dòng)態(tài)地執(zhí)行一段固定字符所組成的代碼,并沒(méi)有比直接將代 碼寫(xiě)在那里更有好處。
在嚴(yán)格模式的程序中,eval(..) 在運(yùn)行時(shí)有其自己的詞法作用域,意味著其 中的聲明無(wú)法修改所在的作用域。
類(lèi)似:setTimeout的第一個(gè)參數(shù)為字符串時(shí);new Function的最后一個(gè)字符串參數(shù);等都不提倡,不要使用。
withwith 通常被當(dāng)作重復(fù)引用同一個(gè)對(duì)象中的多個(gè)屬性的快捷方式,可以不需要重復(fù)引用對(duì)象 本身。
例如:
var obj = { a: 1, b: 2, c: 3 }; // 單調(diào)乏味的重復(fù) "obj" obj.a = 2; obj.b = 3; obj.c = 4; // 簡(jiǎn)單的快捷方式 with (obj) { a = 3; b = 4; c = 5; } // 但實(shí)際上這不僅僅是為了方便地訪(fǎng)問(wèn)對(duì)象屬性。考慮如下代碼: function foo(obj) { with (obj) { a = 2; } } var o1 = { a: 3 }; var o2 = { b: 3 }; foo( o1 ); console.log( o1.a ); // 2 foo( o2 ); console.log( o2.a ); // undefined console.log( a ); // 2——不好,a 被泄漏到全局作用域上了!
可以注意到一個(gè)奇怪的副作用,實(shí)際上 a = 2 賦值操作創(chuàng)建了一個(gè)全局的變量 a。這 是怎么回事?
with 可以將一個(gè)沒(méi)有或有多個(gè)屬性的對(duì)象處理為一個(gè)完全隔離的詞法作用域,因此這個(gè)對(duì) 象的屬性也會(huì)被處理為定義在這個(gè)作用域中的詞法標(biāo)識(shí)符。
盡管 with 塊可以將一個(gè)對(duì)象處理為詞法作用域,但是這個(gè)塊內(nèi)部正常的 var 聲明并不會(huì)被限制在這個(gè)塊的作用域中,而是被添加到 with 所處的函數(shù)作 用域中。
with 這種將對(duì)象及其屬性放進(jìn)一個(gè)作用域并同時(shí)分配標(biāo)識(shí)符的行為很讓人費(fèi)解。
性能JavaScript 引擎會(huì)在編譯階段進(jìn)行數(shù)項(xiàng)的性能優(yōu)化。其中有些優(yōu)化依賴(lài)于能夠根據(jù)代碼的 詞法進(jìn)行靜態(tài)分析,并預(yù)先確定所有變量和函數(shù)的定義位置,才能在執(zhí)行過(guò)程中快速找到 標(biāo)識(shí)符。
小結(jié)詞法作用域意味著作用域是由書(shū)寫(xiě)代碼時(shí)函數(shù)聲明的位置來(lái)決定的。編譯的詞法分析階段 基本能夠知道全部標(biāo)識(shí)符在哪里以及是如何聲明的,從而能夠預(yù)測(cè)在執(zhí)行過(guò)程中如何對(duì)它 們進(jìn)行查找。
JavaScript 中有兩個(gè)機(jī)制可以“欺騙”詞法作用域:eval(..) 和 with。前者可以對(duì)一段包 含一個(gè)或多個(gè)聲明的“代碼”字符串進(jìn)行演算,并借此來(lái)修改已經(jīng)存在的詞法作用域(在 運(yùn)行時(shí))。后者本質(zhì)上是通過(guò)將一個(gè)對(duì)象的引用當(dāng)作作用域來(lái)處理,將對(duì)象的屬性當(dāng)作作 用域中的標(biāo)識(shí)符來(lái)處理,從而創(chuàng)建了一個(gè)新的詞法作用域(同樣是在運(yùn)行時(shí))。
這兩個(gè)機(jī)制的副作用是引擎無(wú)法在編譯時(shí)對(duì)作用域查找進(jìn)行優(yōu)化,因?yàn)橐嬷荒苤?jǐn)慎地認(rèn) 為這樣的優(yōu)化是無(wú)效的。使用這其中任何一個(gè)機(jī)制都將導(dǎo)致代碼運(yùn)行變慢。不要使用它們。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/108971.html
摘要:如果提升改變了代碼執(zhí)行的順序,會(huì)造成非常嚴(yán)重的破壞。聲明本身會(huì)被提升,而包括函數(shù)表達(dá)式的賦值在內(nèi)的賦值操作并不會(huì)提升。要注意避免重復(fù)聲明,特別是當(dāng)普通的聲明和函數(shù)聲明混合在一起的時(shí)候,否則會(huì)引起很多危險(xiǎn)的問(wèn)題 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門(mén)充滿(mǎn)吸引力、簡(jiǎn)單易用的語(yǔ)言,又是一門(mén)具有許多復(fù)雜微妙技術(shù)的語(yǔ)言,即使是經(jīng)驗(yàn)豐富的 Ja...
摘要:詞法作用域的查找規(guī)則是閉包的一部分。因此的確同閉包息息相關(guān),即使本身并不會(huì)真的使用閉包。而上面的創(chuàng)建一個(gè)閉包,本質(zhì)上這是將一個(gè)塊轉(zhuǎn)換成一個(gè)可以被關(guān)閉的作用域。結(jié)合塊級(jí)作用域與閉包模塊這個(gè)模式在中被稱(chēng)為模塊。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門(mén)充滿(mǎn)吸引力、簡(jiǎn)單易用的語(yǔ)言,又是一門(mén)具有許多復(fù)雜微妙技術(shù)的語(yǔ)言,即使是經(jīng)驗(yàn)豐富的 Jav...
摘要:如果是聲明中的第一個(gè)詞,那么就是一個(gè)函數(shù)聲明,否則就是一個(gè)函數(shù)表達(dá)式。給函數(shù)表達(dá)式指定一個(gè)函數(shù)名可以有效的解決以上問(wèn)題。始終給函數(shù)表達(dá)式命名是一個(gè)最佳實(shí)踐。也有開(kāi)發(fā)者干脆關(guān)閉了靜態(tài)檢查工具對(duì)重復(fù)變量名的檢查。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門(mén)充滿(mǎn)吸引力、簡(jiǎn)單易用的語(yǔ)言,又是一門(mén)具有許多復(fù)雜微妙技術(shù)的語(yǔ)言,即使是經(jīng)驗(yàn)豐富的 Ja...
摘要:的抽象語(yǔ)法樹(shù)中可能會(huì)有一個(gè)叫作的頂級(jí)節(jié)點(diǎn),接下來(lái)是一個(gè)叫作它的值是的子節(jié)點(diǎn),以及一個(gè)叫作的子節(jié)點(diǎn)。值得注意的是,是非常重要的異常類(lèi)型。嚴(yán)格模式下,未聲明的和倆者行為相同,都會(huì)是。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門(mén)充滿(mǎn)吸引力、簡(jiǎn)單易用的語(yǔ)言,又是一門(mén)具有許多復(fù)雜微妙技術(shù)的語(yǔ)言,即使是經(jīng)驗(yàn)豐富的 JavaScript 開(kāi)發(fā)者,如果...
iKcamp官網(wǎng):http://www.ikcamp.com 訪(fǎng)問(wèn)官網(wǎng)更快閱讀全部免費(fèi)分享課程:《iKcamp出品|全網(wǎng)最新|微信小程序|基于最新版1.0開(kāi)發(fā)者工具之初中級(jí)培訓(xùn)教程分享》。包含:文章、視頻、源代碼 showImg(https://segmentfault.com/img/remote/1460000011522427?w=1626&h=1242); 第二章:小程序中級(jí)實(shí)戰(zhàn)教程之預(yù)...
閱讀 787·2019-08-30 15:55
閱讀 1530·2019-08-30 15:52
閱讀 2695·2019-08-30 15:44
閱讀 2105·2019-08-30 11:14
閱讀 2621·2019-08-29 13:59
閱讀 1817·2019-08-29 13:45
閱讀 1012·2019-08-29 13:21
閱讀 3374·2019-08-26 13:31