執行環境
執行環境定義了變數或函式有權訪問的其他資料,決定了它們各自的行為。變數物件
每個執行環境都有與之關聯的變數物件,環境中定義的所有變數和函式都儲存在這個物件中。雖然我們在編寫程式時,無法訪問這個物件,但是解析器在處理資料時會在後台使用它。
全域性執行環境是最外層的乙個執行環境。根據ecmascript實現所在的宿主環境的不同,表示執行環境的物件也不同。在web瀏覽中,全域性執行環境被認為是window物件,因此所有的全域性變數和函式都是作為window物件的屬性和方法建立的。當乙個執行環境中的所有**執行完畢後,該環境就會被銷毀,環境內的變數和函式也就不復存在了。對於全域性執行環境來說,只有應用程式退出時才會被銷毀。
每個函式也有自己的執行環境。當執行流進入乙個函式時,該函式的執行環境就會被推進乙個環境棧中,當函式執行完畢後,該函式的執行環境被彈出,把控制權還給之前的執行環境。
作用域就是變數和函式的可訪問範圍。若學過c語言,則可知道以下**中c的作用域就是這個if語句範圍內。
if(a>b)
當**在乙個執行環境中執行時,會建立乙個基於變數物件的作用域鏈。作用域鏈的用途是保證對執行環境有權訪問的變數和函式的有序訪問。作用域鏈的最前端是當前執行環境的變數物件。如果這個環境是函式,那麼其變數物件就是其活動物件。活動物件在最開始時只包含乙個變數,即arguments物件(全域性環境中不存在,這是因為arguments是儲存函式傳入資料的物件)作用域鏈是乙個鏈式結構,那麼其下乙個變數物件來自包含環境,再下乙個來自下乙個包含環境 , … … 直到全域性執行環境。因此,全域性執行環境的變數物件位於作用域鏈的末尾。
識別符號解析是沿著作用域鏈一級一級地搜尋識別符號的過程。從作用域鏈的前端開始,逐級往上搜尋,直到找到識別符號或找不到識別符號而產生錯誤。為什麼是基於變數物件的作用域鏈生成作用域鏈的目的是為了找到相應的識別符號,而對於每個執行環境來說,環境內定義的所有變數和函式均儲存在與執行環境相關聯的變數物件中。因此,作用域鏈中儲存的是各個執行環境中的環境物件。
接下來看乙個示例:
我們來分析一下,全域性環境中有乙個變數color和乙個函式changecolor。changecolor()的區域性變數中有乙個變數anothercolor和函式swapcolors(),在這個區域性環境中,可以訪問到全域性環境中的color變數。swapcolors()的區域性環境中,有乙個變數tempcolor, 且通過**我們可以看到,在這個區域性環境中可以訪問到changecolor()區域性環境和全域性環境中的變數,這是因為這兩個環境是swapcolors()環境的父執行環境。關係圖如上。
內部環境可以通過作用域鏈訪問到所有的外部環境,但是外部環境不能訪問到內部環境的任何變數和函式。乙個簡單的理解方式作用域鏈是有著先後關係的,我們把處於作用域前端的想象成古代地位高的人,全域性環境由於具有普遍性,即每個內部環境都能訪問全域性環境中的變數和函式,所以就把全域性環境當作古代平民,那麼,作用域鏈最前端的則代表帝王,帝王可以隨便拿大臣的,百姓的東西。大臣只能隨便拿平民的,不能隨便拿帝王的。同樣,平民只能拿他自己的,不能隨便拿大臣的,帝王的東西。
這些環境之間的關係是線性的,有次序的。每個環境都可以向上搜尋作用域鏈,以查詢變數和函式名,但任何變數不能向下查詢。函式引數也被當作變數來對待,因此其訪問規則與執行環境中的其他變數相同。有些語句可以在作用域鏈的前端臨時增加乙個變數物件,該變數物件會在**執行後被移除。try-catch語句中的catch塊
with語句
這兩個語句都會在作用域鏈的前端加上乙個變數物件。with語句是新增指定的物件,而catch語句則是建立乙個新的變數物件,其中包含的是被丟擲的錯誤物件的宣告。我們以紅寶書上的例子:
function buildurl()
return url;
}
with語句接收的是location物件,因此其變數物件中就包含了location物件的所有屬性和方法,而這個變數物件被新增到作用域鏈的前端。用with從物件中建立出的作用域僅在with宣告中而非外部作用域有效with語句塊中作用域的『變數物件』是唯讀的,不能儲存識別符號,只能儲存在其上一層。因此,url就成了函式執行環境中的一部分。
意思是說,在with內部,我們不能新增新的變數到with關聯的物件中。即 with的物件變數是唯讀的,不能新增變數,但是可以修改或刪除關聯物件的屬性。上面的**中,當執行到with語句時,作用域鏈為:
with的變數物件就是location 物件在類c的語言中,由花括號括起來的**塊一般都有塊級作用域(類似於ecmascript中的執行環境),但是在ecmascript中,卻沒有這種概念。
if(a)
在if條件語句之外,也是可以訪問到b的。
宣告變數
查詢識別符號
前面也說過了,查詢識別符號時,是沿著作用域鏈逐級向上的。首先會在當前執行環境的變數物件中查詢,若找到,則停止查詢,不管父環境中是不是也有同乙個識別符號。若沒找到,則繼續沿著作用域鏈向上查詢,直到找到識別符號或者找不到,瀏覽器報錯。
js 執行環境及作用域
執行環境定義了變數或函式有權訪問的其他資料,決定了他們各自的行為。每個執行環境都有乙個與之關聯的變數物件,環境中定義的所有變數和函式都儲存在這個物件中。每個函式都有自己的執行環境。當執行流進入乙個函式時,函式的環境會被推入乙個環境棧中。而在函式執行之後,棧將其環境彈出,把控制權返回給之前的執行環境。...
JS中的執行環境和作用域
window 是最大最外圍的執行環境,然後每個函式都有自己的執行環境。js 是從上到下執行的,單純的用語言描述可能會有點繞,而且不大直觀。我們看著 來 console.log global begin i var i 1foo 1 function foo i console.log foo beg...
js的執行環境與作用域
var person lisa console.log window.person lisa const person2 lily console.log window.person2 error 報錯var color blue function changecolor else changeco...