詳解js變量聲明提升


之前一直覺會認為javascript代碼執行是由上到下一行行執行的。自從看了《你不知道的JS》后發現這個觀點並不完全正確。先來給大家舉一個書本上的的例子:

  var a='hello world';
  var a;
  console.log(a); 

 

一開始我覺得輸出的是undefined。但是真正的結果是hello world。帶着疑問再看另外一段代碼:

console.log(a);
var a='hello world';

 

 

借鑒與上面的例子會認為會輸出一個hello world,或者是拋出一個沒有聲明的異常錯誤,然而發現這兩種想法也是錯誤。輸出的結果是‘undefined’。這書非常人性化的總結出了結論是:

引擎解釋javascript代碼的之前會對其進行編譯。在編譯過程中會查找所有聲明,並用合適作用域將他們關聯起來。換句話說,在代碼執行之前,會對作用域鏈中所有變量和函數聲明先處理完先。所以,當遇到var a='hello world'中是 var a是先在編譯階段執行,然后在執行a='hello world'。所以,第一段代碼實質上是:

var a;
a='hello world';
console.log(a);

 

 

所以輸出的就就是helloworld。總結一句話就是:只有聲明被提升,而賦值或其他運算會留在原地。所以第二段代碼實際上就是:

var a;
console.log(a);
a='hello world';

 

 

介紹完這兩個經典例子是時候來看看一下這個例子了:

var name = "world";
(function () {
if (typeof name == 'undefined') {
var name = 'yang';
console.log('Hello ' + name)
} else {
console.log('Hello ' + name)
}
})()

 

根據javascript的運行機制和javascript沒有塊作用域這個特點,可以得出,變量name會聲明提升移至作用域 scope (全局域或者當前函數作用域) 頂部的。所以上述代碼就相當於:

var name = "world";
(function () {
var name;
if (typeof name == 'undefined') {
var name = 'yang';
console.log('Hello ' + name)
} else {
console.log('Hello ' + name)
}
})()

 

 

因此,if判斷的時候typeof name == 'undefined'是true。所以會執行條件為true里面的代碼。輸出就是Hello yang。
那么如果想實現上面的函數,我們該如何實現?答案非常簡單那就創建塊作用域了。如何最簡單的創建塊作用域呢?那當然是采用es6的新特性let關鍵字。let關鍵字可以將變量綁定到所在的任意區域中通常在{...}中。換句話說。let為其聲明變量隱性劫持到所在區域中。下列例子中:let就綁定到if (typeof name == 'undefined') {...}中。所以name不會被提升,所以判斷就為假,於是就可以輸出我們期待已久的‘helloworld’。

var name = "world";
(function () {
if (typeof name == 'undefined') {
let name = 'yang';

console.log('Hello ' + name)
} else {
console.log('Hello ' + name)
}
})()

 

注意點:let所在的塊級作用域,在聲明代碼被運行前,是不會像var那樣會被查找到,提前聲明,而是運行到了該代碼才會被聲明執行。下面例子很好說明這個問題:

 
(function (){
    console.log(b);
    let b=2;
})()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM