成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

深入解析JavaScript中的作用域

本篇文章帶大家深入理解JavaScript作用域。有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對大家有所幫助。

深入解析JavaScript中的作用域

這篇文章稱為筆記更為合適一些,內(nèi)容來源于 《你不知道的JavaScript(上卷)》第一部分 作用域和閉包。講的很不錯(cuò),非常值得一看。

什么是作用域

作用域是根據(jù)名稱查找變量的一套規(guī)則

理解作用域

先來理解一些基礎(chǔ)概念:

  • 引擎:從頭到尾負(fù)責(zé)整個(gè)JavaScript程序的編譯及執(zhí)行過程。
  • 編譯器:負(fù)責(zé)語法分析和代碼生成。這部分也可以看 JavaScript代碼是如何被執(zhí)行的
  • 作用域:負(fù)責(zé)收集并維護(hù)由所有聲明的標(biāo)識符(變量)組成的一系列查詢,并實(shí)施一套非常嚴(yán)格的規(guī)則,確定當(dāng)前執(zhí)行的代碼對這些標(biāo)識符的訪問權(quán)限。

接下來來看看下面代碼的執(zhí)行過程:

var a = 2;
  • 遇見 var a,編譯器 會(huì)問 作用域 變量a是否存在于同一個(gè)作用域集合中。如果存在,編譯器會(huì)忽略聲明,繼續(xù)編譯;否則,會(huì)要求作用域在當(dāng)前作用域集合中聲明一個(gè)新的變量,并命名為 a

  • 接下來 編譯器 會(huì)為 引擎 生成運(yùn)行時(shí)所需的代碼,用來處理 a = 2 這個(gè)賦值操作。引擎運(yùn)行時(shí)會(huì)先問作用域,當(dāng)前作用域集中是否存在變量a。如果是,引擎就會(huì)使用該變量;如果不存在,引擎會(huì)繼續(xù)查找該變量

  • 如果 引擎 找到了a 變量,就會(huì)將 2 賦值給它,否則引擎就拋出一個(gè)錯(cuò)誤。

總結(jié):變量的賦值操作會(huì)執(zhí)行兩個(gè)動(dòng)作,首先編譯器會(huì)在當(dāng)前作用域中聲明一個(gè)變量,然后在運(yùn)行時(shí)引擎就會(huì)會(huì)作用域中查找該變量,如果能夠找到就對它賦值。

編譯器在編譯過程的第二步中生成了代碼,引擎執(zhí)行它時(shí),會(huì)通過查找變量 a來判斷它是否已聲明過。查找的過程中由作用域進(jìn)行協(xié)助,但是引擎執(zhí)行怎么樣的查找,會(huì)影響最終的查找結(jié)果。

在我們的例子中,引擎會(huì)為變量 a 進(jìn)行 LHS 查詢,另外一個(gè)查找的類型叫做 RHS。 ”L“ 和 "R" 分別代表一個(gè)賦值操作左側(cè)和右側(cè)。當(dāng)變量出現(xiàn)在賦值操作的左側(cè)時(shí)進(jìn)行 LHS 查詢,出現(xiàn)在右側(cè)時(shí)進(jìn)行 RHS 查詢。

LHS:試圖找到變量的容器本身,從而可以對其賦值;RHS: 就是簡單地查找某個(gè)變量的值。

console.log(a);

對 a 的引用是一個(gè) RHS 引用,因?yàn)檫@里 a 并沒有賦予任務(wù)值,相應(yīng)地需要查找并取得 a 的值,這樣才能將值傳遞給 console.log(…)

a = 2;

這里對 a 的引用是 LHS 引用,因?yàn)閷?shí)際上我們并不關(guān)心當(dāng)前的值是什么,只是想要為 = 2這個(gè)賦值操作找到目標(biāo)。

funciton foo(a) {     console.log(a) }  foo(2);
  1. 最后一行 foo 函數(shù)的調(diào)用需要對 foo 進(jìn)行 RHS 引用,去找 foo的值,并把它給我
  2. 代碼中隱式的 a = 2 操作可能很容易被你忽略掉,這操作發(fā)生在 2 被當(dāng)做參數(shù)傳遞給 foo 函數(shù)時(shí),2 會(huì)被分配給參數(shù) a,為了給參數(shù) a (隱式地) 分配值,需要進(jìn)行一次 LHS 查詢。
  3. 這里還有對 a 進(jìn)行的 RHS 引用,并且將得到的值傳給了 console.log(...)console.log(...) 本身也需要一個(gè)引用才能執(zhí)行,因此會(huì)對 console對象進(jìn)行 RHS 查詢,并且檢查得到的值中是否有一個(gè)叫做 log的方法。

RHS查詢在所有嵌套的作用域中遍尋不到所需的變量,引擎就會(huì)拋出 ReferenceError 異常。進(jìn)行RHS查詢找到了一個(gè)變量,但是你嘗試對這個(gè)變量的值進(jìn)行不合理的操作,比如試圖對一個(gè)非函數(shù)類型的值進(jìn)行調(diào)用,后者引用null或 undefined 類型的值中的屬性,那么引擎會(huì)拋出一個(gè)另外一種類型的異常 TypeError。
引擎執(zhí)行 LHS 查詢時(shí)如果找不到該變量,則會(huì)在全局作用域中創(chuàng)建一個(gè)。但是在嚴(yán)格模式下,并不是自動(dòng)創(chuàng)建一個(gè)全局變量,而是會(huì)拋出 ReferenceError 異常

補(bǔ)充JS幾種常見的錯(cuò)誤類型

簡單總結(jié)如下:

作用域是一套規(guī)則,用于確定在哪里找,怎么找到某個(gè)變量。如果查找的目的是對變量進(jìn)行賦值,那么就會(huì)使用 LHS查詢; 如果目的是獲取變量的值,就會(huì)使用 RHS 查詢;
JavaScript 引擎執(zhí)行代碼前會(huì)對其進(jìn)行編譯,這個(gè)過程中,像 var a = 2 這樣的聲明會(huì)被分解成兩個(gè)獨(dú)立的步驟

  • var a 在其作用域中聲明變量,這會(huì)在最開始的階段,也就是代碼執(zhí)行前進(jìn)行

  • 接下來,a = 2 會(huì)查詢 (LHS查詢)變量 a 并對其進(jìn)行賦值。

詞法作用域

詞法作用域是你在寫代碼時(shí)將變量寫在哪里來決定的。編譯的詞法分析階段基本能夠知道全局標(biāo)識符在哪里以及是如何聲明的,從而能夠預(yù)測在執(zhí)行過程中如果對他們查找。

有一些方法可以欺騙詞法作用域,比如 eval, with, 這兩種現(xiàn)在被禁止使用,1是嚴(yán)格模式和非嚴(yán)格模式下表現(xiàn)不同 2是有性能問題, JavaScript引擎在編譯階段會(huì)做很多性能優(yōu)化,而其中很多優(yōu)化手段都依賴于能夠根據(jù)代碼的詞法進(jìn)行靜態(tài)分析,并預(yù)先確定所有變量和函數(shù)的定義位置,才能在執(zhí)行過程中快速找到識別符,eval, with會(huì)改變作用域,所以碰到它們,引擎將無法做優(yōu)化處理。

全局作用域和函數(shù)作用域

全局作用域

  • 在最外層函數(shù)和最外層函數(shù)外面定義的變量擁有全局作用域
var a = 1; function foo() {  }

變量a 和函數(shù)聲明 foo 都是在全局作用域中的。

  • 所有未定義直接賦值的變量自動(dòng)聲明為擁有全局作用域

var a = 1; function foo() {     b = 2; } foo(); console.log(b); // 2
  • 所有 window 對象的屬性擁有全局作用域

函數(shù)作用域

函數(shù)作用域是指在函數(shù)內(nèi)聲明的所有變量在函數(shù)體內(nèi)始終是可見的。外部作用域無法訪問函數(shù)內(nèi)部的任何內(nèi)容。

function foo() {     var a = 1;     console.log(a); // 1 } foo(); console.log(a); // ReferenceError: a is not defined

只有函數(shù)的{}構(gòu)成作用域,對象的{}以及 if(){}都不構(gòu)成作用域;

變量提升

提升是指聲明會(huì)被視為存在與其所出現(xiàn)的作用域的整個(gè)范圍內(nèi)。

JavaScript編譯階段是找到找到所有聲明,并用合適的作用域?qū)⑺麄冴P(guān)聯(lián)起來(詞法作用域核心內(nèi)容),所以就是包含變量和函數(shù)在內(nèi)的所有聲明都會(huì)在任何代碼被執(zhí)行前首先被處理。

每個(gè)作用域都會(huì)進(jìn)行提升操作。

function foo() {     var a;     console.log(a); // undefined     a = 2; } foo();

注意,函數(shù)聲明會(huì)被提升,但是函數(shù)表達(dá)式不會(huì)被提升。

關(guān)于 塊級作用域和變量提升的內(nèi)容之前在 從JS底層理解var、let、const這邊文章中詳細(xì)介紹過,這里不再贅述。

塊級作用域

我們來看下面這段代碼

for(var i = 0; i < 5; i++) {     setTimeout(() => {         console.log(i);     }) } console.log(`當(dāng)前的i為${i}`); // 當(dāng)前的i為5

上面這段代碼我們希望是輸出 0,1, 2, 3, 4 ,但是實(shí)際上輸出的是 5,5, 5, 5, 5。我們在 for 循環(huán)的頭部直接定義了變量 i,通常是因?yàn)橹幌朐?for 循環(huán)內(nèi)部的上下文中使用 i,但是實(shí)際上 此時(shí)的 i 被綁定在外部作用域(函數(shù)或全局)中。

,塊級作用域是指在指定的塊級作用域外無法訪問。在ES6之前是沒有塊級作用域的概念的,ES6引入了 let 和 const。我們可以改寫上面的代碼,使它按照我們想要的方式運(yùn)行。

for(let i = 0; i < 5; i++) {     setTimeout(() => {         console.log(i);     }) } // 0 1 2 3 4 console.log(`當(dāng)前的i為${i}`); // ReferenceError: i is not defined

此時(shí) for 循環(huán)頭部的 let 不僅將 i 綁定到了 for 循環(huán)的迭代中,事實(shí)上將它重新綁定到了循環(huán)的每一個(gè)迭代中,確保使用上一次循環(huán)迭代結(jié)束的值重新進(jìn)行賦值。

let聲明附屬于一個(gè)新的作用域而不是當(dāng)前的函數(shù)作用域(也不屬于全局作用域)。但是其行為是一樣的,可以總結(jié)為:任何聲明在某個(gè)作用域內(nèi)的變量,都將附屬于這個(gè)作用域。
const也是可以用來創(chuàng)建塊級作用域變量,但是創(chuàng)建的是固定值。

作用域鏈

JavaScript是基于詞法作用域的語言,通過變量定義的位置就能知道變量的作用域。全局變量在程序中始終都有都定義的。局部變量在聲明它的函數(shù)體內(nèi)以及其所嵌套的函數(shù)內(nèi)始終是有定義的。

每一段 JavaScript 代碼都有一個(gè)與之關(guān)聯(lián)的作用域鏈(scope chain)。這個(gè)作用域鏈?zhǔn)且粋€(gè)對象列表或者鏈表。當(dāng) JavaScript 需要查找變量 x 的時(shí)候(這個(gè)過程稱為變量解析),它會(huì)從鏈中的第一個(gè)變量開始查找,如果這個(gè)對象上依然沒有一個(gè)名為 x 的屬性,則會(huì)繼續(xù)查找鏈上的下一個(gè)對象,如果第二個(gè)對象依然沒有名為 x 的屬性,javaScript會(huì)繼續(xù)查找下一個(gè)對象,以此類推。如果作用域鏈上沒有任何一個(gè)對象包含屬性 x, 那么就認(rèn)為這段代碼的作用域鏈上不存在 x, 并最終拋出一個(gè)引用錯(cuò)誤 (Reference Error) 異常。

下面作用域中有三個(gè)嵌套的作用域。

function foo(a) {     var b = a * 2;     function bar(c) {         console.log(a, b, c)     }     bar( b * 3); } foo(2);

1.png

氣泡1包含著整個(gè)全局作用域,其中只有一個(gè)標(biāo)識符:foo;
氣泡2包含著foo所創(chuàng)建的作用域,其中有三個(gè)標(biāo)識符:a、bar 和 b;
氣泡3包含著 bar所創(chuàng)建的作用域,其中只有一個(gè)標(biāo)識符:c

執(zhí)行 console.log(...),并查找 a,b,c三個(gè)變量的引用。下面我們來看看查找這幾個(gè)變量的過程.
它首先從最內(nèi)部的作用域,也就是 bar(..) 函數(shù)的作用域氣泡開始找,引擎在這里無法找到 a,因此就會(huì)去上一級到所嵌套的 foo(…)的作用域中繼續(xù)查找。在這里找到了a,因此就使用了這個(gè)引用。對b來說也一樣,而對 c 來說,引擎在 bar(..) 中就找到了它。

如果 a,c都存在于 bar(…) 內(nèi)部,console.log(…)就可以直接使用 bar(…) 中的變量,而無需到外面的 foo(..)中查找。作用域會(huì)在查找都第一個(gè)匹配的標(biāo)識符時(shí)就停止。

在多層的嵌套作用域中可以定義同名的標(biāo)識符,這叫”遮蔽效應(yīng)“。

var a = '外部的a'; function foo() {     var a = 'foo內(nèi)部的a';     console.log(a); // foo內(nèi)部的a } foo();

作用域與執(zhí)行上下文

JavaScript的執(zhí)行分為:解釋和執(zhí)行兩個(gè)階段

解釋階段

  • 詞法分析
  • 語法分析
  • 作用域規(guī)則確定

執(zhí)行階段

  • 創(chuàng)建執(zhí)行上下文
  • 執(zhí)行函數(shù)代碼
  • 垃圾回收

作用域在函數(shù)定義時(shí)就已經(jīng)確定了,而不是在函數(shù)調(diào)用時(shí)確定,但執(zhí)行上下文是函數(shù)執(zhí)行之前創(chuàng)建的。

總結(jié)

  • 作用域就是一套規(guī)則,用于確定在哪里找以及怎么找到某個(gè)變量。

  • 詞法作用域在你寫代碼的時(shí)候就確定了。JavaScript是基于詞法作用域的語言,通過變量定義的位置就能知道變量的作用域。ES6引入的let和const聲明的變量在塊級作用域中。

  • 聲明提升是指聲明會(huì)被視為存在與其所出現(xiàn)的作用域的整個(gè)范圍內(nèi)。

  • 查找變量的時(shí)候會(huì)先從內(nèi)部的作用域開始查找,如果沒找到,就往上一級進(jìn)行查找,依次類推。

  • 作用域在函數(shù)定義時(shí)就已經(jīng)確定了,執(zhí)行上下文是函數(shù)執(zhí)行之前創(chuàng)建的。

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
巨RU麻麻奶水雪白肥美喷| 狠狠色丁香久久婷婷综合蜜芽五月 | 亚洲精品舔Av一| 亚洲AV无码乱码在线观看代蜜桃| 亚洲精品AⅤ无码精品| 又爽又黄无遮挡高潮视频网站 | 亚洲成AV人最新地堂无码| 亚洲欧美中文日韩在线V日本| 玉蒲团之官人我要| 啊灬啊灬啊灬快灬高潮了听书 | 国产AⅤ无码一区二区三区| 国产乱码卡二卡三卡43| 久久精品国产亚洲7777| 欧美成人一区二区三区不卡| 色欲色欲天天天WWW亚洲伊| 性色AV 一区二区三区| 亚洲一二三四2021不卡 | 亚洲男人AV香蕉爽爽爽爽| 在我们寝室当寄吧套子怎么样| 99久热RE在线精品99RE| 国产AⅤ爽AV久久久久成| 精品高朝久久久久9999| 男人桶女人18禁止网站| 视频一区二区三区在线| 亚洲乱码卡1卡2新区3| 99久久亚洲综合精品成人| 女人不怕粗短就怕蘑菇头什么意| 国产美女被遭强高潮网站免费| 在线A级毛片免费视频| 97色伦图片97综合影院| 国产AⅤ精品一区三区| 精产国品一二三产品区别大吗| 免费一对一真人视频APP| 色AV综合AV无码AV网站| 亚洲AV综合色区无码专区桃色 | 久久亚洲AV成人无码国产| 人人爽人人澡人人人人妻| 亚洲AV成人片色在线观看高潮| 中文字幕一区二区人妻| 国产成人精品2021| 久久无码人妻精品一区二区三区| 日本老熟妇VIDEO| 亚洲精品成人网站在线| 宝贝乖女你的奶真大水真多小说| 国内精品自线在拍大学生| 欧美交性一级视频免费播放| 五月天天爽天天狠久久久综合| 在线日产精品一区| 国产精品VA无码免费麻豆| 麻豆久久亚洲AV成人无码电影| 四川少妇BBW搡BBBB槡BB| 亚洲熟妇AV日韩熟妇在线| 成人永久免费高清视频在线观看| 久久WWW色情成人免费观看| 色噜噜亚洲精品中文字幕| 一区二区三区中文字幕| 国产黄A三级三级三级| 麻豆国产在线精品国偷产拍 | 亚洲一区二区三区毛片| 天堂VA视频一区二区| 日韩精品无码人妻免费视频| 欧美性受XXXX88喷潮| 欧美VA久久久噜噜噜久久| 蜜芽VA亚洲VA欧美VA天堂| 久久无码国产专区精品| 狠狠躁夜夜躁青青草原| 国产日韩AⅤ无码一区二区三区| 国产AⅤ无码专区亚洲AV琪琪| 成人作爱Av一级无码| 丰满少妇大力进入| 国精产品999国精产品官网| 国产MV在线天堂MV免费观看| 西西里大但人文艺术~任汾| 小怡的暴露耻辱系列小说| 亚洲嫩模喷白浆在线观看| 无码熟熟妇丰满人妻PORN| 人人妻人人狠人人爽天天综合网| 欧美人妻少妇精品视频专区| 欧美日韩在线视频一区二区| 欧美熟妇与小伙性欧美交| 欧美精品久久久久久久自慰| 永久免费看啪啪网址入口| 欧美爽到高潮漏水大喷视频| 欧美极品少妇XXXXⅩO69| 亚洲AV永久无码精品秋霞电影影院| 国产精品成人嫩草影院| 强制高潮18XXXXHD日韩| 永久AV狼友网站在线观看| 娇喘潮喷抽搐高潮在线视频| 我的娇妻QUEEN| 粗大的内捧猛烈进出动态图| 欧美成人A猛片在线观看| 野花社区免费观看高清在线1日本| 国产精品亚洲专区无码蜜芽| 日日摸日日碰夜夜爽97| JEANASIS日本| 欧美成人AA久久狼窝五月丁香| 又大又粗又硬又爽黄毛少妇| 精品人妻一区二区三区免费| 亚洲 日韩 欧美 成人 在线观| 国产AV无码专区亚洲AWWW| 人人超碰人人超级碰国| A∨无码天堂AV| 免费看人妻丰满熟妇AV无码片| 亚洲色偷拍一区二区三区| 黑人巨大粗物挺进了少妇| 性色欲情网站IWWW九文堂| 国产成人无码AV麻豆| 色视频综合无码一区二区三区| AV色欲无码人妻中文字幕| 老司机67194精品线观看| 色YEYE香蕉凹凸视频在线观看| 鲁一鲁AV2019在线| 亚洲人色婷婷成人网站在线观看| 国产最新AV在线播放不卡| AV鲁丝一区鲁丝二区鲁丝三区| 久久99精品久久只有精品| 色狠狠AV一区二区三区| FREEMOVIES性中国| 久久国产精品99国产精| 无码人妻精品一区二区三 | 在厨房被C到高潮A毛片奶水| 污污网站18禁在线永久免费观看 | 91精品人妻一区二区| 绿帽娇妻在卧室疯狂的呻吟 | 麻花传媒剧国产MV在线看| 曰本真人性做爰ⅩXX| 人妻少妇AV中文字幕乱码| AV优选天堂污污污成人亚洲| 嫩草欧美曰韩国产大片| 91人妻超碰亚洲| 欧美成人国产精品视频| 99精品久久久久中文字幕| 年轻漂亮的人妻被公侵犯BD免费版| 中日韩人妻中文字幕视频在线 | 97色伦图片97综合影院| 欧美熟妇搡BBBB搡BBBB| А天堂最新版中文网| 人人玩人人添人人澡 | 色妞色视频一区二区三区四区| 久久亚洲精品无码观看| 2019四虎影视最新在线| 老熟女HDXXXX国产喷水| 中文字幕久久久人妻无码| 女人被狂躁c到高潮视频| 啊灬啊灬快点灬用力岳| 少妇无码AV无码专区线Y| 国产精品免费久久久久影院仙踪林| 午夜.DJ高清在线播放视频| 狠狠人妻熟妇Av又粗又大| 亚洲综合色婷婷七月丁香| 男女体裸下00动态视频| 被老头一个晚上做了6次| 他的舌头探入蜜源毛毛虫说说| 国产农村妇女毛片精品久久 | 国产一区二区三区在线电影| 亚洲乱码在线卡一卡二卡新区| 久久婷婷成人综合色综合| 99精品国产在热久久无码| 日本亚欧乱色视频免费观看| 国产精品成人一区二区三区视频| 亚洲AV永久无码精品网址| 老师黑色双开真丝旗袍| 宝宝才两根手指就疼哭了怎么回事 | CHINESE国产AVVIDE| 日韩成人无码中文字幕| 国产免费一区二区三区免费视频| 亚洲日本VA一区二区三区| 奶酥1V2双C高| 大J8黑人W巨大888A片| 亚洲AV纯肉无码精品动漫| 久久亚洲SM情趣捆绑调教| av一区二区三区| 婷婷俺也去俺也去官网| 精品无人码麻豆乱码1区2区| 99国产精品国产精品九九| 熟妇无码乱子成人精品| 狠狠综合久久AV一区二区| 人人人人人人一摸| 亚洲一区在线日韩在线尤物| 欧美国产日本高清不卡| 公和我做好爽添厨房| 亚洲欧美偷拍综合图区| 欧美午夜性春猛交ⅩXXX男| 国产精品国产免费无码专区蜜桃 | 激情欧美成人久久综合| 1000部拍拍拍18勿入免费视| 少妇下蹲露大唇无遮挡| 久久国产精品无码一区二区三区| WWW.色五月.COM| 亚洲AV涩涩涩成人网站| 男友把舌头都伸进我的嘴巴里了| 国产SM主人调教女M视频| 西方14147大但人文艺术| 久久久精品人妻一区亚美研究所 | 同性男男黄G片免费网站 | 亚洲人妻免费视频| 日本三级欧美三级人妇视频黑白配| 国内永久免费CRM系统Z在线| FREEFR性中国少妇性HD|