gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長資訊網
最全最豐富的資訊網站

深入解析JavaScript中的作用域

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

深入解析JavaScript中的作用域

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

什么是作用域

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

理解作用域

先來理解一些基礎概念:

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

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

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

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

  • 如果 引擎 找到了a 變量,就會將 2 賦值給它,否則引擎就拋出一個錯誤。

總結:變量的賦值操作會執(zhí)行兩個動作,首先編譯器會在當前作用域中聲明一個變量,然后在運行時引擎就會會作用域中查找該變量,如果能夠找到就對它賦值。

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

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

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

console.log(a);

對 a 的引用是一個 RHS 引用,因為這里 a 并沒有賦予任務值,相應地需要查找并取得 a 的值,這樣才能將值傳遞給 console.log(…)

a = 2;

這里對 a 的引用是 LHS 引用,因為實際上我們并不關心當前的值是什么,只是想要為 = 2這個賦值操作找到目標。

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

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

補充JS幾種常見的錯誤類型

簡單總結如下:

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

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

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

詞法作用域

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

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

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

全局作用域

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

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

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

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

函數(shù)作用域

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

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

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

變量提升

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

JavaScript編譯階段是找到找到所有聲明,并用合適的作用域將他們關聯(lián)起來(詞法作用域核心內容),所以就是包含變量和函數(shù)在內的所有聲明都會在任何代碼被執(zhí)行前首先被處理。

每個作用域都會進行提升操作。

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

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

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

塊級作用域

我們來看下面這段代碼

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

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

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

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

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

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

作用域鏈

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

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

下面作用域中有三個嵌套的作用域。

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

1.png

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

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

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

在多層的嵌套作用域中可以定義同名的標識符,這叫”遮蔽效應“。

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

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

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

解釋階段

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

執(zhí)行階段

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

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

總結

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

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

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

  • 查找變量的時候會先從內部的作用域開始查找,如果沒找到,就往上一級進行查找,依次類推。

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

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
黄色高清无遮挡| www.亚洲高清| 一区二区久久精品| 日韩中文字幕免费在线| 人体内射精一区二区三区| 手机成人av在线| 亚洲av无日韩毛片久久| 91亚洲精品久久久蜜桃借种| 国产成人av影视| 37pao成人国产永久免费视频| 国产一二三四五| 97精品国产97久久久久久粉红| 思思久久精品视频| 欧美日韩怡红院| 欧美国产日韩另类 | 可以看毛片的网址| 特级西西444| 女人被男人躁得好爽免费视频 | jizzjizzxxxx| 99999精品视频| 亚洲一级免费在线观看| 红桃视频 国产| 妞干网在线播放| 日日碰狠狠添天天爽超碰97| 麻豆av免费在线| 欧美一级视频在线| 奇米777四色影视在线看| 丰满女人性猛交| 免费看日本毛片| 国产精品久久久毛片| 成年人网站av| 青青草原av在线播放| 午夜啪啪小视频| 成人免费毛片网| 亚洲精品免费一区亚洲精品免费精品一区| 免费看黄在线看| 91传媒久久久| 91社在线播放| 337p粉嫩大胆噜噜噜鲁| 超碰在线超碰在线| 青青视频在线播放| 国产91在线亚洲| 亚洲这里只有精品| 青春草国产视频| 亚洲精品mv在线观看| 欧美日韩中文在线视频| 精品综合久久久久| 久草综合在线观看| 18禁裸男晨勃露j毛免费观看| 亚洲欧美日韩三级| 欧美性猛交内射兽交老熟妇| 成年人视频在线免费| 欧美黄色免费网址| 牛夜精品久久久久久久| 黄色大片在线免费看| 欧美 亚洲 视频| 9999在线观看| 天天综合网久久| chinese少妇国语对白| xxxx18hd亚洲hd捆绑| 久久福利一区二区| 在线成人免费av| 欧美h视频在线观看| mm131亚洲精品| 国产精品天天av精麻传媒| 91精品91久久久中77777老牛| 国产在线观看福利| 免费在线黄网站| 欧美a级免费视频| 少妇一晚三次一区二区三区| 五月天国产视频| 国产性生活一级片| 国产 porn| 亚洲精品综合在线观看| 亚洲 中文字幕 日韩 无码| 99热成人精品热久久66| 妞干网在线免费视频| 精品一区二区中文字幕| 成人小视频在线看| 手机在线成人免费视频| 日本久久久久久久久久久久| 亚洲一区二区福利视频| 欧美日韩中文不卡| 欧美日韩亚洲国产成人| 欧美无砖专区免费| 337p粉嫩大胆噜噜噜鲁| 亚洲一级片免费| 99精品视频网站| www.夜夜爱| 亚洲免费av一区二区三区| 精品久久久99| av 日韩 人妻 黑人 综合 无码| 精品中文字幕av| 99re精彩视频| a天堂资源在线观看| 国产成人精品无码播放| 自拍偷拍21p| 日韩国产小视频| 成人在线看视频| www亚洲国产| 草草久久久无码国产专区| 国产九九在线视频| 国产免费裸体视频| 欧美亚洲日本在线观看| 天堂网成人在线| aa免费在线观看| 波多野结衣 作品| 成人中文字幕av| 欧美高清中文字幕| 亚洲午夜激情影院| 日本中文字幕片| www.18av.com| 国产福利精品一区二区三区| 亚洲熟妇av一区二区三区漫画| 91黄色在线看| 亚欧精品在线视频| 日本在线观看免费视频| 欧美一级片免费播放| 高清一区在线观看| 欧美一区二区三区爽大粗免费| 国产精品视频网站在线观看| 日本男人操女人| 黄色动漫网站入口| av片在线免费| 992tv快乐视频| 三级网在线观看| 97超碰成人在线| 别急慢慢来1978如如2| 国产最新免费视频| 国产中文字幕二区| 国产真实老熟女无套内射| 欧美美女黄色网| 91免费国产精品| 日韩极品视频在线观看| 亚洲精品国产suv一区88| 9999在线观看| 国产香蕉一区二区三区| 国产一级片中文字幕| 熟女少妇精品一区二区| 欧美成人免费高清视频| 成人黄色一区二区| 视频在线观看免费高清| 蜜臀av免费观看| 在线无限看免费粉色视频| 免费看av软件| 国产av熟女一区二区三区| 国产自产在线视频| 女人扒开屁股爽桶30分钟| 久久久久久香蕉| 涩多多在线观看| 真人做人试看60分钟免费| 欧美成人精品免费| 自慰无码一区二区三区| 中文久久久久久| 好吊色这里只有精品| 九一免费在线观看| 精品中文字幕av| 国产原创精品在线| 国产亚洲精品久久久久久久| 亚洲午夜无码av毛片久久| 色诱视频在线观看| 日韩在线不卡一区| 毛片在线视频播放| 国产又猛又黄的视频| 老司机午夜免费福利视频| 自拍日韩亚洲一区在线| 亚洲无吗一区二区三区| 中国黄色录像片| 美女网站免费观看视频| avove在线观看| 天堂在线资源视频| 东北少妇不带套对白| 国产一级特黄a大片免费| 欧美日韩午夜爽爽| 不卡的av中文字幕| 18禁网站免费无遮挡无码中文| 欧美少妇一区二区三区| 91专区在线观看| 日本中文字幕在线不卡| 国产男女激情视频| 精品国产av无码一区二区三区| 18视频在线观看娇喘| 北条麻妃视频在线| 999在线观看视频| 只有这里有精品| 777视频在线| av免费播放网址| 霍思燕三级露全乳照| 性鲍视频在线观看| 国产成人手机视频| 日韩精品视频一区二区在线观看| 国产911在线观看| 粗暴91大变态调教| 国产无套内射久久久国产| 国产日韩av网站| 国产 日韩 亚洲 欧美| 国产 欧美 日韩 一区| 国产精品久久久影院| 天天成人综合网| a级片一区二区|