javascript:執行環境與做用域鏈以及函數執行

執行環境定義

定義了變量或者函數有權訪問的其餘數據,每一個執行環境都有一個與之相關聯的變量對象,環境中定義的全部變量和函數都保存在這個對象中。咱們編寫的代碼沒法訪問這個對象,但解析器會在處理數據時在後臺使用它。
執行環境的建立javascript


全局執行環境

在web瀏覽器中,全局執行環境被認爲是window對象,所以全部全局變量和函數都是做爲window對象的屬性和方法建立的。代碼載入瀏覽器時,全局執行環境被建立(當咱們關閉網頁或者瀏覽器時全局執行環境才被銷燬)。前端

局部執行環境

每一個函數都有本身的執行環境,所以局部執行環境爲函數對象。當函數被調用時函數的局部環境被建立(函數內的代碼執行完畢後,該環境被銷燬,同時保存在其中的全部變量和函數定義也隨之被銷燬)。java

這個執行環境以及相關的變量對象是個抽象的概念,解釋以下web

var a = 1;
function fn(num1,num2){
    var b = 2;
    function fnInner(){
        var c = 3;
        alert(a + b + c);
    }
    fnInner();//fnInner調用時局部執行環境建立
}
fn(4,5);//fn調用時局部執行環境建立

圖片描述

圖一

做用域鏈

javascript函數的執行用到了做用域鏈,這個做用域鏈是函數定義的時候建立的,當定義一個函數時,它實際保存一個做用域鏈。當調用這個函數時,它建立一個新的對象來存儲它的局部變量,並將這個對象添加至保存的做用域鏈。做用域鏈的前端始終都是當前執行的代碼所在環境的變量對象。做用域鏈的末端始終都是全局執行環境的變量對象。做用域鏈的用途,是保證對執行環境有權訪問的全部變量和函數的有權訪問瀏覽器

var scope = 'global scope';
function checkscope(){
    var scope = 'local scope';
    function f(){return scope};
    return f;
}
checkscope()();//local scope

理解:當調用checkscope時,函數f被定義並做爲局部變量綁定到了checkscope做用域鏈上,所以函數f不管在哪裏調用,這種綁定依然有效,所以返回值爲local scope。函數

var num1 = 1;
function Outer(){
    var num2 = 2;
    console.log(num1 + num2);//3
    function Inner(){
        //這裏能夠訪問num3,num2,num1
        var num3 = 3;
        console.log(num1 + num2 + num3);//6
        }
    //這裏能夠訪問num2,Inner(),num1但不能訪問num3
    Inner();
}
Outer();
console.log(num1);//1,執行環境
//這裏只能訪問num1

做用域鏈(向上搜索):內部環境能夠經過做用域鏈訪問全部的外部環境,但外部環境不能訪問內部環境中的任何變量和函數。spa

var name = 'Byron';
    function fn(){
        var name = 'Csper';
        console.log(name);//Casper
    }
    fn();

越往內部的環境,變量權重越高。code

注意:沒有帶var關鍵字直接聲明的變量屬於全局變量如直接聲明a = 1,此時的a爲全局變量。對象

javscript引擎在進入做用域時,會對代碼分兩輪處理。第一輪,初始化變量。第二輪,執行代碼圖片

var a = 1;
function prison (a) {
    console.log(a);//1
    var a;
    console.log(a);//1
}
prison(1);

函數執行

函數調用進入執行環境時,首先處理arguments,初始化形參(默認值爲undefined),而後初始化函數內的函數聲明,當代碼一步一步執行時再初始化函數內的變量聲明(進入環境未開始執行代碼時,值爲undefined)。因此函數內的初始化順序爲變量聲明,函數聲明,形參。能夠從上圖圖一看出。下面我來舉個例子(整個全局環境也是函數)。

alert(typeof fn);//function,函數聲明提早
alert(typeof fn0);//undefined,變量聲明提早但未賦值
function fn(){
//函數表達式
}
var fn0 = function(){
//函數定義式
}
alert(typeof fn0);//function,此時變量已被賦值
相關文章
相關標籤/搜索