摘要:塊作用域在中沒有塊作用域也就是說在中聲明的變量會泄露到外面作用域而中新增的可以將變量綁定到所在的任意作用域通常是內部,換句話說,為其聲明的變量隱式的劫持了所在的塊作用域。總結作用域其實是有執行上下文中的變量對象和作用域鏈共同構成的。
執行上下文(也稱執行環境)堆棧
執行上下文是javascript最重要的一個概念,執行上下文定義了變量或函數有權訪問的其他數據,決定了它們各自的行為。而在javascript中有三種執行上下文: 全局執行上下文, 函數執行上下文, eval執行上下文。代碼在其執行上下文中執行。在javascript中只有一個全局執行環境(根據宿主環境的不同,全局執行環境的對象也不一樣)。可以有許多函數和eval執行環境的實例,每次調用一個函數或eval,都會進入對應執行環境執行代碼。注意一個函數可能會產生無限上下文集合,因為每次函數調用自身都會產生一個新的執行上下文
執行上下文可以激活另一個執行上下文,例如函數調用另一個函數(或者全局執行上下文調用全局函數)等等,邏輯上就成了一個堆棧。這被稱為執行上下文堆棧。
當執行流進入一個函數時,函數的上下文就會被推入一個棧中,如果在當前函數中調用另一個函數,當前函數就會暫停執行,并將執行流傳遞給被調用函數(被調用函數同事可能是其他函數的調用者),被調用者被推入堆棧。當被調用者的上下文結束后,將執行流交還給調用者,調用者的繼續運行代碼,直到結束后,棧將上下文彈出。
每個執行上下文可以抽象成一個對象,都包含了一組屬性。
每個執行上下文都有一個與之關聯的變量對象,環境中定義的所有變量和函數都保存在這個對象。但是不包含函數表達式和this(因為他不是一個變量)。
var foo = 10; function bar(){}; (function baz(){}) console.log(baz); //eror
全局上下文的變量對象
如果執行上下文是一個函數,則將其活動對象作為變量對象,除了變量和函數聲明之外,他還存儲形式參數和arguments對象。
function foo(x, y) { var z = 30; function bar() {} (function baz() {}); } foo(10, 20);
我們發現baz不在活動對象里。
作用域鏈本質上就是根據名稱查找變量(標識符名稱)的一套規則。規則非常簡單,在自己的變量對象里找不到變量,就上父級的變量對象查找,當抵達最外層的全局上下文中,無論找到還是沒找到,查找過程都會停止。查找會在找到第一個匹配的變量時停止,被稱為遮蔽效應
var x = 10; (function foo(){ var y = 10; (function bar(){ var z = 10; console.log(x+y+z)![scope-chain.png][6] }) })
如下圖:
詞法作用域就是定義在詞法階段的作用域。換句話說,詞法作用域是由你在寫代碼時將變量和塊作用域寫在哪里決定的,無論函數在哪里被調用,也無論他如何被調用,他的詞法作用域只由函數被聲明位置決定。
在javascript中的eval函數可以接受一個字符串為參數,并將其中的內容視為在書寫時就存在于程序中這個位置的代碼。
function foo(str, a){ eval(str); //欺騙 console.log(a, b); } var b = 2; foo("var b = 3;", 1); //1, 3
函數作用域有兩種方式
//函數聲明 function foo(){ var a = 3; console.log(a); }
//函數表達式 (function foo(){ var a = 2; console.log(a); })
兩者的區別在于它們的名稱標識符會被綁定到何處,第一段代碼中會被綁定到所在作用域中,第二段代碼被綁定在函數表達式自身的函數中而不是所在作用域中。
在javascript中沒有塊作用域,也就是說在{...}中聲明的變量會泄露到外面作用域
if(true){ var foo = "dog" } console.log(foo); //dog function dosomething(i){ console.log(i); } for(var i = 0; i < 10; i++){ dosomething(i); } console.log(i);
而ES6中新增的let可以將變量綁定到所在的任意作用域(通常是{...}內部),換句話說,let為其聲明的變量隱式的劫持了所在的塊作用域。
if(true){ var foo = "dog" } console.log(foo); //dog function dosomething(i){ console.log(i); } for(let i = 0; i < 10; i++){ dosomething(i); } console.log(i); //error總結
作用域其實是有執行上下文中的變量對象和作用域鏈共同構成的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84920.html
摘要:下面我們就羅列閉包的幾個常見問題,從回答問題的角度來理解和定義你們心中的閉包。函數可以通過作用域鏈相互關聯起來,函數內部的變量可以保存在其他函數作用域內,這種特性在計算機科學文獻中稱為閉包。 寫這篇文章之前,我對閉包的概念及原理模糊不清,一直以來都是以通俗的外層函數包裹內層....來欺騙自己。并沒有說這種說法的對與錯,我只是不想擁有從眾心理或者也可以說如果我們說出更好更低層的東西,逼格...
摘要:前言這段時間一直在消化作用域鏈和閉包的相關知識。而作用域鏈則是這套規則這套規則的具體運行。是變量對象的縮寫那這樣放有什么好處呢我們知道作用域鏈保證了當前執行環境對符合訪問權限的變量和函數的有序訪問。 前言:這段時間一直在消化作用域鏈和閉包的相關知識。之前看《JS高程》和一些技術博客,對于這些概念的論述多多少少不太清楚或者不太完整,包括一些大神的技術文章。這也給我的學習上造成了一些困惑,...
摘要:所以覺得把這個執行的詳細過程整理一下,幫助更好的理解。類似的語法報錯的如下圖所示三預編譯階段代碼塊通過語法分析階段之后,語法都正確的下回進入預編譯階段。另開出新文章詳細分析,主要介紹執行階段中的同步任務執行和異步任務執行機制事件循環。 一、概述 js是一種非常靈活的語言,理解js引擎的執行過程對于我們學習js是非常有必要的。看了很多這方便文章,大多數是講的是事件循環(event loo...
閱讀 982·2021-11-23 09:51
閱讀 2695·2021-08-23 09:44
閱讀 656·2019-08-30 15:54
閱讀 1433·2019-08-30 13:53
閱讀 3101·2019-08-29 16:54
閱讀 2527·2019-08-29 16:26
閱讀 1186·2019-08-29 13:04
閱讀 2313·2019-08-26 13:50