JavaScript-變量提高(AO、GO)編譯、閉包

JavaScript是一個解釋型語言

MDN上明確的說,JavaScript是一個輕量級的、解釋型的、面向對象的、將函數視爲一級公民的語言。
那麼,既然js是一個解釋型語言,那它就是在運行時把代碼轉換成機器能夠識別的語言。哪它又爲何會存在變量提高呢?
下面這篇文章給出瞭解釋,在此也特別感謝做者的分享!
https://mp.weixin.qq.com/s/ne...數組

變量提高、預編譯過程

function fn(c){
    console.log(c);  //true
    var c = false;
    console.log(a);  //function a(){}
    var a = 1;
    console.log(a);  //1
    function a(){
        
    };
    console.log(a);  //1
    b();             //函數聲明
    var b = function(){
        console.log("函數表達式");
    }
    function b(){    
        console.log( "函數聲明" )
    }
    b();             //函數表達式
    var d = 4;
}
fn(true);

上面這個fn方法很簡單,相信不少人都能過作出來,但確定也不少人不理解結果爲何是這樣!
那麼這個過程是怎樣執行的呢:
首先,js在執行前會產生一個GO(Global Object),也就是咱們常說的全局做用域。當一個方法被調用的時候會造成一個局部做用域AO(Activation Object)。
全局代碼在執行的時候,先是變量提高,在全局做用域內添加屬性,而後是函數(以函數聲明建立的函數)提高,再是代碼執行。
函數在被調用的時候,以上面的fn這個方法爲例,進入函數上下文,可是在執行代碼以前,經歷的階段:
第一階段:首先建立一個AO,幷包含下列屬性:閉包

AO : {
    arguments: <ArgO>,  //函數內部參數的類數組對象
    c: true,            //傳入的參數,若是沒有傳遞實參,那麼值就是undefined
}

第二階段:函數內部的函數(以函數聲明建立的函數)提高函數

AO : {
    arguments: <ArgO>,
    c: true,
    a: function a(){},
    b: function b(){ console.log( "函數聲明" ) }
}

第三階段:函數內部的變量提高code

AO : {
    arguments: <ArgO>,
    c: true,
    a: function a(){},
    b: function b(){ console.log( "函數聲明" ) },
    d: undefined
}

函數內部又定義了變量 var c和var a,當變量提高時,發現AO中已經存在a和c屬性,若是變量名稱跟已經聲明的形參或函數相同,則變量聲明不會干擾已經存在的這類屬性。若是不相同切不存在,那就會放到AO中,值爲undefined。對象

當上面的這些準備工做作完以後,纔會開始執行函數內部的代碼,這樣就很好明白,函數內部的變量,在什麼階段分別表明什麼樣的值!ip

閉包解析

在JavaScript高級程序3中,對閉包的描述是這樣的,閉包是指有權訪問另外一個函數做用域中的變量的函數。那麼,很顯然,閉包其實就是一個函數。
那麼咱們怎樣經過GO、AO理解閉包呢:作用域

function foo(){
    var a = 1;
    function fnSon(){
        a++;
        console.log(a);
    }
    return fnSon;
}
var fnTest = foo();
fnTest();   //2
fnTest();   //3

當foo這個方法被調用的時候,建立一個AO,當函數執行完以後AO裏面包含了變量a、函數fnSonget

AO:{
    a:1,
    fnSon: function(){}
}

此時的fnSon被賦值給了fnTest,那麼foo方法的AO在執行完以後就沒辦法被銷燬,當fnTest被調用的時候,代碼執行完以後,foo的AO對象中的a變成了2,再次調用fnTest的時候就變成3。io

相關文章
相關標籤/搜索