一段代碼引發的思考
1 var laterDeclaredVar = 'I am a global variable ...'; 2 (function(){ 3 console.log(laterDeclaredVar); //會輸出什么? 4 laterDeclaredFunction(); //能否被正常執行? 5 6 var laterDeclaredVar = 'I am a variable which is defined later...'; 7 function laterDeclaredFunction () { 8 console.log('I can be called any where though I am declared later...'); 9 // 上面打印的話翻譯一下是:雖然我被晚一些定義了,但是我可以在函數的任何地方被訪問 10 // I can be called any where even though I am declared later 11 // 后者則被翻譯為:即使我被晚一些定義了,我可以在函數的任何地方被訪問 12 // 這里需要補充一個知識點是though和even though的區別: 13 // though和even though都引導讓步狀語從句,但是though和even意為“雖然” 14 // though引導的句子所說的是事實 15 // 而even though(=even if),意為“即使” 16 // 有退一步設想的意味,所說的不一定是事實。 17 // 為了寫這個打印專門復習了一下英文,查了一下這個句式該怎么寫,都是知識點,快快拿小本記好! 18 } 19 })()
這段代碼需要我們思考的是第三行會在控制台輸出什么?第四行對laterDeclaredFunction()的調用能否成功呢?
答案是醬紫的:
我們都有一個共識是js語言執行順序是自上而下的,那么已經在第一行聲明了定義了變量laterDeclaredVar,在第三行卻打印出undefined呢?為什么laterDeclaredFunction是在第七行聲明的,第四行的調用卻能成功呢? 為什么會是這樣呢?
這一切都和變量對象有關!!
先回到執行上下文生命周期部分溫習一下。
....溫習完畢!
什么是變量對象?
我們在寫程序的時候會定義很多變量和函數,而上面的問題的本質實際是對於解釋器來說,是如何以及從哪里找到這些變量和函數的?
變量對象是與執行上下文對應的概念,定義着執行上下文下的所有變量、函數以及當前執行上下文函數的參數列表。也就是說變量對象定義着一個函數內定義的參數列表、內部變量和內部函數。
數據結構上來說,它是這樣的:
變量對象的創建過程?
以下面代碼作為例子來看outerFun() 變量對象的創建過程。
1 function outerFun (arg1, arg2) { 2 var outerV1 = 1 3 var outerV2 = 2 4 function innerFun1 () { 5 var innerV1 = 3; 6 var innerV2 = 4; 7 console.log('i am innerFun1...') 8 } 9 function innerFun2 () { 10 console.log('i am innerFun2...') 11 } 12 function outerV2 () { 13 return 'i am outerV2' 14 } 15 } 16 outerFun()
它的變量對象創建過程是這樣的:
變量對象是在函數被調用,但是函數尚未執行的時刻被創建的,這個創建變量對象的過程實際就是函數內數據(函數參數、內部變量、內部函數)初始化的過程。
什么是活動對象?
未進入執行階段之前,變量對象中的屬性都不能訪問!但是進入執行階段之后,變量對象轉變為了活動對象,里面的屬性都能被訪問了,然后開始進行執行階段的操作。所以活動對象實際就是變量對象在真正執行時的另一種形式。
全局變量對象
我們上面說的都是函數上下文中的變量對象,是根據執行上下文中的數據(參數、變量、函數)確定其內容的,全局上下文中的變量對象則有所不同。以瀏覽器為例,全局變量對象是window對象,全局上下文在執行前的初始化階段,全局變量、函數都是被掛載倒window上的。
至此,用變量對象的知識去解釋文章開頭代碼的執行結果,就已經打通了任督二脈。這里不再做具體分析。
同樣至此,執行上下文生命周期中的變量對象和活動對象部分梳理完畢,接下來的事情接下來再說!
我是Han,我的終極夢想不是世界和平,而是不勞而獲!thx!