1. 程式人生 > >JS的解析與執行過程—全局預處理階段之命名沖突的處理策略

JS的解析與執行過程—全局預處理階段之命名沖突的處理策略

bsp env 函數表 nvi body 相同 class pre 優先級

有如下代碼:

 1 <body>
 2     <script>
 3         alert(f);
 4         
 5         function f() {
 6             console.log("fff");
 7         }
 8         var f = 5;
 9     </script>
10 </body>

不論var f 與function f 的先後順序如何,該代碼執行的結果總是彈出function f 的字符串,為什麽呢?像這種函數與變量命名沖突時JS的處理原則又是什麽?

在掃描函數聲明與變量聲明的時候,是先掃描函數聲明(function fn()),後掃描變量聲明(var a)的;

  • 處理函數聲明有沖突,會覆蓋;
  • 處理變量聲明有沖突,會忽略;

上面代碼中,由於先掃描函數聲明,所以LexicalEnviroment對象中先存在了 f 指向函數的引用,然後掃描到變量的時候發現變量名沖突,忽略這個變量,所以總是彈出函數字符串。

也就是說,在JS中函數的優先級是高於變量的。相同優先級以後面的為準,不同優先級以級別高的為準。

然後當存在兩個同名函數時,會覆蓋,所以總是指向後一個函數的,這點就像聲明兩個同名變量一樣。

總結:有如下代碼:

 1     <
script> 2 alert(a); 3 // alert(b); 4 alert(f); 5 alert(g); 6 7 var a = 5; 8 b = 6; 9 alert(b); 10 function f() { 11 console.log("fff"); 12 } 13 var g = function() { 14 console.log(
"ggg"); 15 } 16 alert(g); 17 </script>

這段代碼在預處理階段,分別掃描函數聲明和變量聲明,加入到全局對象window中:

1 window = {
2             f: 函數引用,
3             a: undefined,
4             g: undefined
5         }

註意,由於函數 g 是以函數表達式的方式聲明的,所以在預處理時會當作一個變量,其值為undefined,所以上面代碼執行結果為彈出undefined, f 的字符串表示, undefined

然後走過了var a = 5; b = 6;之後window對象變為:

1 window = {
2             f: 函數引用,
3             a: 5,
4             b: 6,
5             g: undefined
6         }

所以此時alert(b)彈出6;

因為在JS中不用var聲明,直接寫的變量默認為全局變量(window的),此時直接不用預處理而直接一步加到全局對象中,預處理的undefined被賦值。

然後走過函數f與函數g的表達式,此時g也指向函數,所以最後alert(g)彈出g的字符串。

JS的解析與執行過程—全局預處理階段之命名沖突的處理策略