久久精品五月,日韩不卡视频在线观看,国产精品videossex久久发布 ,久久av综合

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

深入解析JavaScript中的作用域

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

深入解析JavaScript中的作用域

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

什么是作用域

作用域是根據名稱查找變量的一套規則。

理解作用域

先來理解一些基礎概念:

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

接下來來看看下面代碼的執行過程:

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

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

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

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

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

在我們的例子中,引擎會為變量 a 進行 LHS 查詢,另外一個查找的類型叫做 RHS。 ”L“ 和 "R" 分別代表一個賦值操作左側和右側。當變量出現在賦值操作的左側時進行 LHS 查詢,出現在右側時進行 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 函數的調用需要對 foo 進行 RHS 引用,去找 foo的值,并把它給我
  2. 代碼中隱式的 a = 2 操作可能很容易被你忽略掉,這操作發生在 2 被當做參數傳遞給 foo 函數時,2 會被分配給參數 a,為了給參數 a (隱式地) 分配值,需要進行一次 LHS 查詢。
  3. 這里還有對 a 進行的 RHS 引用,并且將得到的值傳給了 console.log(...)console.log(...) 本身也需要一個引用才能執行,因此會對 console對象進行 RHS 查詢,并且檢查得到的值中是否有一個叫做 log的方法。

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

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

簡單總結如下:

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

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

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

詞法作用域

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

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

全局作用域和函數作用域

全局作用域

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

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

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

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

函數作用域

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

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

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

變量提升

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

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

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

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

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

關于 塊級作用域和變量提升的內容之前在 從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 循環的頭部直接定義了變量 i,通常是因為只想在 for 循環內部的上下文中使用 i,但是實際上 此時的 i 被綁定在外部作用域(函數或全局)中。

,塊級作用域是指在指定的塊級作用域外無法訪問。在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 循環頭部的 let 不僅將 i 綁定到了 for 循環的迭代中,事實上將它重新綁定到了循環的每一個迭代中,確保使用上一次循環迭代結束的值重新進行賦值。

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

作用域鏈

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

每一段 JavaScript 代碼都有一個與之關聯的作用域鏈(scope chain)。這個作用域鏈是一個對象列表或者鏈表。當 JavaScript 需要查找變量 x 的時候(這個過程稱為變量解析),它會從鏈中的第一個變量開始查找,如果這個對象上依然沒有一個名為 x 的屬性,則會繼續查找鏈上的下一個對象,如果第二個對象依然沒有名為 x 的屬性,javaScript會繼續查找下一個對象,以此類推。如果作用域鏈上沒有任何一個對象包含屬性 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所創建的作用域,其中有三個標識符:a、bar 和 b;
氣泡3包含著 bar所創建的作用域,其中只有一個標識符:c

執行 console.log(...),并查找 a,b,c三個變量的引用。下面我們來看看查找這幾個變量的過程.
它首先從最內部的作用域,也就是 bar(..) 函數的作用域氣泡開始找,引擎在這里無法找到 a,因此就會去上一級到所嵌套的 foo(…)的作用域中繼續查找。在這里找到了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();

作用域與執行上下文

JavaScript的執行分為:解釋和執行兩個階段

解釋階段

  • 詞法分析
  • 語法分析
  • 作用域規則確定

執行階段

  • 創建執行上下文
  • 執行函數代碼
  • 垃圾回收

作用域在函數定義時就已經確定了,而不是在函數調用時確定,但執行上下文是函數執行之前創建的。

總結

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

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

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

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

  • 作用域在函數定義時就已經確定了,執行上下文是函數執行之前創建的。

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
久久精品五月,日韩不卡视频在线观看,国产精品videossex久久发布 ,久久av综合
91精品久久久久久久久久不卡| 日韩av电影一区| 精品一区二区三区免费看| 午夜在线一区| 久久福利影视| 三级欧美在线一区| 亚洲综合中文| 91精品丝袜国产高跟在线| 国产亚洲久久| 麻豆精品久久久| 国产传媒在线| 久久中文字幕二区| 国产亚洲毛片| 日韩国产欧美视频| 久久精品一区二区国产| 91日韩欧美| 久久久久免费av| 午夜欧美精品| 亚洲在线网站| 亚洲精品麻豆| 国产精品永久| 在线天堂中文资源最新版| 亚洲无线一线二线三线区别av| 波多野结衣一区| 亚洲毛片在线| 美女久久久精品| 四虎4545www国产精品 | 欧美韩一区二区| 精品国产乱码久久久| 国产激情在线播放| 影视先锋久久| 先锋影音久久久| 欧美久久久网站| 麻豆成全视频免费观看在线看| av一区二区高清| 日本少妇精品亚洲第一区| 国产一区二区三区国产精品| 伊人久久成人| 欧美在线91| 黑人精品一区| 丝袜美腿一区二区三区| 欧美一区免费| 日韩一区自拍| 性一交一乱一区二区洋洋av| 国产精品调教视频| 久久一区二区三区电影| 只有精品亚洲| 精品国产一区二区三区噜噜噜| 亚洲国内欧美| 国产精品美女久久久久久不卡| 久久久9色精品国产一区二区三区| 视频精品一区二区| 久久麻豆视频| 婷婷丁香综合| 国产精品亚洲欧美一级在线| 欧美+亚洲+精品+三区| 欧美精品影院| 免费av一区二区三区四区| 欧美在线91| 免费不卡中文字幕在线| 石原莉奈在线亚洲二区| 精品伊人久久| 六月婷婷一区| 樱桃视频成人在线观看| 日本不卡视频在线观看| 色偷偷色偷偷色偷偷在线视频| 蜜臀久久99精品久久久久久9 | 你懂的国产精品永久在线| 午夜电影亚洲| 福利视频一区| 日韩中文字幕一区二区高清99| 日韩毛片视频| 国产精品羞羞答答在线观看| 亚洲精品小说| 久久亚洲精品中文字幕| 亚洲欧美日韩在线观看a三区| 精品一区二区男人吃奶| 视频精品一区| 亚洲精品网址| 黄色aa久久| 久久精品99国产精品日本| 99riav国产精品| 久久久久久久欧美精品| 亚洲高清激情| 国产精品嫩草影院在线看| 99久久视频| 欧美激情一区| 日韩av资源网| 视频一区国产视频| 美女久久久久| 欧美黄色网页| 日韩综合一区| 欧美精品二区| 日韩黄色在线观看| 玖玖玖国产精品| 亚洲一级影院| 97精品国产| 久久精品二区亚洲w码| 91伊人久久| 五月天久久久| av亚洲一区二区三区| 精品国产欧美日韩一区二区三区| 日本在线一区二区三区| 亚洲欧美日韩一区在线观看| 国产一区亚洲| 欧美日韩免费观看视频| 精品欧美日韩精品| 国产精品1区在线| 日本免费新一区视频| 国产农村妇女精品一二区| 亚洲精品午夜av福利久久蜜桃| 日韩电影免费网址| www在线观看黄色| 精品国产乱码久久久| 777久久精品| 日韩高清三区| 日韩国产在线不卡视频| 日韩一区二区三区精品| 亚洲精品乱码| 日本不卡高清| 日韩免费精品| 日本99精品| 日韩国产高清在线| 69堂免费精品视频在线播放| 欧美日韩午夜电影网| 国产欧美三级| 国产精品porn| 精品国产鲁一鲁****| 国产成人久久精品麻豆二区 | 免费av一区| 99re国产精品| 首页国产欧美久久| 蜜桃91丨九色丨蝌蚪91桃色| 美女日韩在线中文字幕| 日韩中文字幕一区二区三区| 日韩精品一二三四| 在线视频亚洲欧美中文| 日韩一区二区三区精品视频第3页| 亚洲尤物av| 日韩av中文字幕一区二区| 欧美日韩91| 另类综合日韩欧美亚洲| 国产传媒在线| 国产精品88久久久久久| 中文在线一区| 中文字幕av亚洲精品一部二部| 日韩av字幕| 精品三级在线| 亲子伦视频一区二区三区| 不卡中文一二三区| 日韩影片在线观看| 久久99久久久精品欧美| 日韩精品中文字幕第1页| 国产一区日韩一区| 亚洲欧美日本日韩| 日韩精品视频网站| 国产极品模特精品一二 | 久久精品国产999大香线蕉| 日韩欧美1区| 三级欧美韩日大片在线看| 日本欧美在线| 国产一区二区三区黄网站| 国内精品99| 日韩精品亚洲专区| 久久亚州av| 欧美日韩第一| 青青青国产精品| caoporn视频在线| 神马日本精品| 亚洲午夜免费| 日产精品一区二区| 日韩午夜av| 久久99影视| 99久久婷婷| 国产日韩一区| 激情久久婷婷| 91欧美极品| 亚洲91久久| 日本h片久久| 久久精品国产68国产精品亚洲| 亚洲精品亚洲人成在线观看| av资源中文在线| 综合欧美精品| 国产+成+人+亚洲欧洲在线| 欧美日韩高清| 欧美黑人做爰爽爽爽| 99国产成+人+综合+亚洲欧美| 欧美日韩亚洲一区在线观看| 久久国产中文字幕| 91麻豆精品激情在线观看最新| 成人看片网站| 69堂免费精品视频在线播放| 99精品网站| 欧美国产日本| 久久电影一区| 国产自产自拍视频在线观看| 综合激情网...| 成人va天堂| 欧美一级二级三级视频| 亚洲天堂1区|