JavaScript變數儲存淺析(一)

大魔王薩格拉斯發表於2015-11-16

Hello!

  上一篇關於JS中函式傳參(http://www.cnblogs.com/souvenir/p/4969092.html)的介紹中提到了JS的另外一個基本概念:JS變數儲存,

  今天我們就用一個簡單的JS DEMO來開始介紹這個概念。

1 var a = 100;
2  
3 function func(){
4     console.log(a);
5     var a=200;
6     console.log(a);
7 }
8  
9 func();

  相信大家心裡面已經有了各自的答案。

  ....

  來看下實際的執行結果:

  

  納尼!怎麼會醬紫?我們明明定義了一個全域性變數a,按照JS作用域鏈的理論,func應該可以訪問到全部變數a的啊?

  是的,按照作用域鏈的思想,func函式在執行時,在其區域性變數內找不到a變數的話,理應向上在全部作用局中繼續查詢。

  問題就出在函式內部的 var a =200; 這句區域性變數定義。

 

  我們都知道JS變數型別是鬆散型,鬆散型的意思並不是說JS變數就沒有變數型別,而是其變數型別是在執行時才進行確定。

  來看一個DEMO:

1 var str;
2 
3 str=2015;

  第一行我們定義了一個變數str,但是並未賦值,這時候JS並不知道str變數的型別,等到指令碼執行到第3行,我們給str變數賦了一個值:2015.

  這時候JS才知道,哦,原來str的值是2015,這不就是Number型別嗎,這才確定了str的型別。

  

  這讓我想起了JS的另一個概念,叫作函式宣告提升!

  把最開始的DEMO改造下:

 1 var a = 100;
 2 
 3 func();
 4  
 5 function func(){
 6     console.log(a);
 7     var a=200;
 8     console.log(a);
 9 }
10  

  將函式的宣告放在了最後,但是程式碼仍然可以正常執行,並不會出現func未定義的錯誤。

  函式宣告提升就說明JS在執行之前還會經歷另外一個過程:預載入。(有些地方也叫作預編譯)

  在預載入階段,JS主要對全域性作用域、函式的執行環境以及作用域鏈等進行準備,

  這裡的函式執行環境就是指:讀取變數定義並確定其屬於哪個作用域,但不會為其賦值!

  

  到這裡我們終於要開始解釋文章一開始提出的問題了(可憋死寶寶了(づ。◕‿‿◕。)づ):

  我們就來分解一下預載入階段,JS都做了什麼事情:

1 var a = 100;    //定義一個全部變數
2   
3 func();
4 
5 function func(){
6     console.log(a);
7     var a=200;        //定義一個func區域性變數
8     console.log(a);
9 }

  在預載入階段,第一行的時候定義了一個全部變數a,然後到了第7行,又給func定義了一個區域性變數a,

  注意這個時候變數並未賦值,值均為undefined

  到了執行階段:

  第一行給全部變數a賦了值:100,等到執行func函式的時候,

  在第6行,需要使用a變數,JS當然是先查詢func的區域性變數了,沒錯,預載入階段已經為func定義了一個區域性變數a,

  所以JS當然不會繼續往全域性進行查詢了,但是使用的時候才發現居然沒有值,也就是undefined!

  等到第7行JS才給區域性變數a賦值。

 

  小結:

    JS分為預載入和執行期兩個階段,前者只會確定變數的作用域,在執行期才會對齊進行賦值,同時也就確定了變數的具體型別。

  

  

  

   下一篇(http://www.cnblogs.com/souvenir/p/4969565.html)我們將繼續介紹JS中變數的儲存原理,只不過這次我們重點要看的是物件!

  

  

  

  

相關文章