執行環境(也就是常說的上下文)和做用域是js中很基礎也很重要的概念, 但在不少時候,特別是看其餘的文檔的時候,卻容易混淆概念,這篇文章試着梳理下執行環境和做用域的概念。javascript
一、執行環境前端
執行環境定義了變量或函數有權訪問的其餘數據,決定了它們各自的行爲。每一個執行環境都有一個相關聯的變量對象,這個對象裏面保存了環境中定義的全部變量和函數。這個變量對象在編寫代碼是不能訪問的(除了最外層的window對象),只有解析器在後臺處理才能使用。java
執行環境能夠分紅兩種:全局執行環境和函數執行環境。在執行js代碼以前,默認都會建立一個全局的執行環境,與之關聯的是window對象,裏面保存了全部全局變量和函數,直到頁面關閉時才銷燬。而當執行某個函數時,會建立一個活動對象,並把這個對象做爲與該函數的執行環境關聯的變量對象,從而建立出函數的執行環境。函數的執行環境在函數執行完以後,就會被銷燬。編程
另外,須要提一句的是:在活動對象剛被建立時,對象中只有arguments對象一個屬性。微信
二、做用域函數
瞭解執行環境,就能夠來講做用域了。ui
在js中,執行環境是用環境棧來管理的。最底層的是全局執行環境,當執行到一個函數, 函數的執行環境就會被推入到環境棧中。若是在函數中繼續執行函數,那麼內部函數的執行環境就繼續被推入環境棧。例以下面的代碼:spa
var name = 'window';
outer();
function outer(){
var name = 'outer';
inner();
//函數內部的函數
function inner(){
var name = 'inner';
console.log(name);
}
}複製代碼
對應的環境棧以下:code
環境棧中的變量對象,從上到下就組成一條做用域鏈, 用來保證對執行環境有權訪問的全部變量和函數的有序訪問。解析標識符時,就沿着做用域鏈一級一級地搜索,也就在環境棧中從上向下一個個對象搜索,直到找到標識符,就返回,不然就報錯。例如,上面的代碼,執行後會輸出‘inner’,當把inner函數中的定義變量語句註釋以後就輸出‘outer’。cdn
二、延長做用域鏈
在兩種狀況下,雖然不是在執行函數,但也會在做用域鏈的前端臨時增長一個變量對象:
在執行with 語句時,會將指定的對象添加到做用域鏈中。例如:
function getHost() {
var res = '';
with(location){
res = host;
}
return res;
}複製代碼
在上面的代碼中,執行with語句時,做用域鏈的最頂端是臨時添加的location對象,所以能夠直接訪問location對象的host屬性獲取值。
在執行catch語句時,會建立一個新的變量對象(該對象中包含被拋出的錯誤對象),並添加到做用域鏈的頂端。正由於這個緣由,在js的編程中,若是不是必要的,不建議在代碼中使用try-catch語句塊。
備註:
在第一個例子中,咱們把inner函數定義在outer函數的內部,若是是定義在outer函數外部呢?會不會有什麼不一樣?緣由是什麼?
寫在最後:
若是以爲我寫的文章對你有幫助,歡迎掃碼關注個人公衆號:海痕筆記
微信號:haihenbiji