You-Dont-Know-JS作用域?qū)W習(xí)文檔
引言
You-Dont-Know-JS是github上一個(gè)擁有9000多枚星星的JS教學(xué)文檔,評(píng)價(jià)很高,為了避免和其他翻譯文一樣,容易陷入不宜讀的混亂,也試圖避免原文中過(guò)多數(shù)的術(shù)語(yǔ)導(dǎo)致我露怯,我只提取提取我理解的一些點(diǎn),通俗的講出來(lái)。今天先從第一章作用域開(kāi)始吧:
JS的編譯
js和傳統(tǒng)語(yǔ)言一樣,也需要編譯執(zhí)行,編譯的過(guò)程通常分三步:
- 標(biāo)記+詞法分析 Tokenizing/Lexing:: 把程序語(yǔ)言切成一段一段的片段,稱之為tokens。比如,程序中的 var a = 2;,會(huì)被切成如下tokens:var, a, =, 2, ;。
- 解析 Parsing: 把token流轉(zhuǎn)換成樹(shù),是嵌套元素形式,符合語(yǔ)法結(jié)構(gòu)和規(guī)則,這個(gè)樹(shù)被稱之為"AST" (Abstract Syntax Tree).
- var a = 2;的樹(shù),開(kāi)始于頂層節(jié)點(diǎn) VariableDeclaration, 包含子節(jié)點(diǎn) Identifier (值 a), 另外一個(gè)子節(jié)點(diǎn) AssignmentExpression 包含另外子節(jié)點(diǎn) NumericLiteral (值 2).
- 代碼生成 Code-Generation: 這個(gè)過(guò)程是把AST轉(zhuǎn)換成可執(zhí)行代碼, 這部分各程序語(yǔ)言和個(gè)平臺(tái)之間會(huì)有極大的不同。 所以,刨除細(xì)節(jié),var a = 2;會(huì)被轉(zhuǎn)換成機(jī)器語(yǔ)言,在內(nèi)存中創(chuàng)建一個(gè)變量 a,而后把值儲(chǔ)存其中。
編譯器對(duì)賦值的操作
當(dāng)編譯器遇到var a
,它會(huì)詢問(wèn)域是否存在變量a,如果存在編譯器忽略這個(gè)聲明,如果不存在編譯器要求域聲明一個(gè)新變量a給自己。
編譯器而后為引擎產(chǎn)生可執(zhí)行代碼,處理a = 2
, 引擎首先詢問(wèn)域是否有這個(gè)變量,如果沒(méi)有執(zhí)行其他操作。
兩種引用
LHS(Left-hand Side)引用和 RHS(Right-hand Side)引用,對(duì)于編譯器來(lái)說(shuō),LHS指變量用于賦值,RHS是指變量用于取值。
function foo(a) { console.log( a ); // 2 } foo( 2 );
這里,foo(), 引用(變量)foo
是RHS引用,因?yàn)樗怯糜谌≈档牟僮鳎▽⒑瘮?shù)foo的值取出來(lái)),參數(shù)a被隱含賦值2,a = 2
這里的引用a是LHS引用,因?yàn)樗糜谫x值。console.log(a)
里面的a也是LHS引用,因?yàn)樗糜讷@取a的值。
這里說(shuō)明的是, 代碼里的變量, 對(duì)于編譯器來(lái)說(shuō)有兩種類(lèi)型,用于獲取它值的是一種,本身是用于被賦值的是另外一種。
嵌套域 (Nested Scope)
嵌套域很好理解,如下代碼
function foo(a) { console.log( a + b ); } var b = 2; foo( 2 ); // 4
foo函數(shù)域中沒(méi)有變量b,當(dāng)引用b被調(diào)用的時(shí)候,程序會(huì)逐級(jí)往上查找,直到找到變量b,最頂層為全局變量 (global scope),如下圖所示:
錯(cuò)誤
但是各位有沒(méi)有想過(guò)一個(gè)問(wèn)題,被賦值的引用(LHS)如果本域內(nèi)不存在會(huì)產(chǎn)生什么情況?當(dāng)然,大多數(shù)人都經(jīng)歷過(guò)ReferenceError
,引用錯(cuò)誤。
當(dāng)LHS引用(賦值引用)在域中找不到的時(shí)候,js引擎會(huì)直接拋出錯(cuò)誤,而RHS引用(調(diào)用引用)如果在域中找不到的時(shí)候,js引擎會(huì)向上一級(jí)域中查找,如果依然沒(méi)有,會(huì)直接在全局域中為你自動(dòng)創(chuàng)建一個(gè)(非嚴(yán)格模式下, 嚴(yán)格模式下也會(huì)報(bào)ReferenceError錯(cuò)誤)。
考慮從如下代碼:
function foo(a) { console.log( a + b ); } foo( 2 );
這里的變量b因?yàn)樵诤瘮?shù)域中未定義,所以會(huì)報(bào)錯(cuò)
function foo(a) { b = a; } foo( 2 );
這里的變量b也未定義,但是由于是復(fù)制操作,系統(tǒng)會(huì)為你在外層全局域里自動(dòng)創(chuàng)建一個(gè)。
以上就是You-Dont-Know-JS作用域?qū)W習(xí)文檔的詳細(xì)內(nèi)容,更多關(guān)于JS 作用域的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
element?plus的樣式修改和擴(kuò)展實(shí)例
這篇文章主要為大家介紹了element?plus的樣式修改和擴(kuò)展實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02mini?webpack打包基礎(chǔ)解決包緩存和環(huán)依賴
這篇文章主要為大家介紹了mini?webpack打包基礎(chǔ)解決包緩存和環(huán)依賴示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09JS跨域(Access-Control-Allow-Origin)前后端解決方案詳解
這篇文章主要介紹了瀏覽器跨域(Access-Control-Allow-Origin)解決方案詳解包括了前端跨域,后端跨域,js原生實(shí)現(xiàn)jsonp,jQuery實(shí)現(xiàn)jsonp,vue.js實(shí)現(xiàn)jsonp,需要的朋友可以參考下2022-01-01JS時(shí)間分片技術(shù)解決長(zhǎng)任務(wù)導(dǎo)致的頁(yè)面卡頓
旨在把一個(gè)運(yùn)行時(shí)間比較長(zhǎng)的任務(wù)分解成一塊一塊比較小的任務(wù),分塊去執(zhí)行,因?yàn)槌^(guò) 50ms 的任務(wù)就會(huì)被認(rèn)為是 long task,用戶就能感知到渲染卡頓和交互的卡頓,所以我們可以縮短函數(shù)的連續(xù)執(zhí)行時(shí)間2022-07-07JS開(kāi)發(fā)前端團(tuán)隊(duì)展示控制器來(lái)為成員引流
這篇文章主要為大家介紹了JS開(kāi)發(fā)前端團(tuán)隊(duì)展示控制器實(shí)現(xiàn)為成員引流示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08微信小程序聯(lián)網(wǎng)請(qǐng)求的輪播圖
這篇文章主要介紹了微信小程序聯(lián)網(wǎng)請(qǐng)求的輪播圖的相關(guān)資料,需要的朋友可以參考下2017-07-07JS前端模擬Excel條件格式實(shí)現(xiàn)數(shù)據(jù)條效果
這篇文章主要為大家介紹了JS前端模擬Excel條件格式實(shí)現(xiàn)數(shù)據(jù)條效果,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Astro Islands靜態(tài)頁(yè)面交互式UI組件
這篇文章主要為大家介紹了Astro Islands靜態(tài)頁(yè)面交互式UI組件使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08umi插件開(kāi)發(fā)仿dumi項(xiàng)目自動(dòng)生成導(dǎo)航欄實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了umi插件開(kāi)發(fā)仿dumi項(xiàng)目自動(dòng)生成導(dǎo)航欄實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01