1. 程式人生 > >初步探究ES6之let,const和塊級作用域

初步探究ES6之let,const和塊級作用域

我們知道javascript定義變數的方式是var,但是var有幾個問題。

var

第一個就是作用域的問題,var不是針對一個塊級作用域,而是針對一個函式作用域。舉個例子:

function runTowerExperiment(tower, startTime) {
  var t = startTime;

  tower.on("tick", function () {
    ... code that uses t ...
  });
  ... more code ...
}

這樣是沒什麼問題的,因為回撥函式中可以訪問到變數t,但是如果我們在回撥函式中再次命名了變數t

呢?

function runTowerExperiment(tower, startTime) {
  var t = startTime;

  tower.on("tick", function () {
    ... code that uses t ...
    if (bowlingBall.altitude() <= 0) {
      var t = readTachymeter();
      ...
    }
  });
  ... more code ...
}

後者就會將前者覆蓋

第二個就是迴圈的問題
看下面例子:

var messages = ["Meow!"
, "I'm a talking cat!", "Callbacks are fun!"]; for (var i = 0; i < messages.length; i++) { setTimeout(function () { document.write(messages[i]); },i*1500);

輸出結果是:undefined
因為for迴圈後,i置為3,所以訪問不到其值。

let

為了解決這些問題,ES6提出了let語法。let可以在{},if,for裡宣告,其用法同var,但是作用域限定在塊級。但是javascript中不是沒有塊級作用域嗎?這個我們等會講。還有一點很重要的就是let定義的變數不存在變數提升

變數提升

這裡簡單提一下什麼叫做變數提升

var v='Hello World'; 
(function(){ 
    alert(v); 
    var v='I love you'; 
})()

上面的程式碼輸出結果為:undefined。

為什麼會這樣呢?這就是因為變數提升,變數提升就是把變數的宣告提升到函式頂部,比如:

(function(){ 
    var a='One'; 
    var b='Two'; 
    var c='Three'; 
})()

實際上就是:

(function(){ 
    var a,b,c; 
    a='One'; 
    b='Two'; 
    c='Three'; 
})()

所以我們剛才的例子實際上是:

var v='Hello World'; 
(function(){ 
    var v;
    alert(v); 
    v='I love you'; 
})()

所以就會返回undefined啦。

這也是var的一個問題,而我們使用let就不會出現這個問題。因為它會報語法錯誤:

{     
    console.log( a );   // undefined
    console.log( b );   // ReferenceError!      
    var a;
    let b;     
}

再來看看let的塊級作用域。

function getVal(boo) {
    if (boo) {
        var val = 'red'
        // ...
        return val
    } else {
        // 這裡可以訪問 val
        return null
    }
    // 這裡也可以訪問 val
}

而使用let後:

function getVal(boo) {
    if (boo) {
        let val = 'red'
        // ...
        return val
    } else {
        // 這裡訪問不到 val
        return null
    }
    // 這裡也訪問不到 val
}

同樣的在for迴圈中:

function func(arr) {
    for (var i = 0; i < arr.length; i++) {
        // i ...
    }
    // 這裡訪問得到i
}

使用let後:

function func(arr) {
    for (let i = 0; i < arr.length; i++) {
        // i ...
    }
    // 這裡訪問不到i
}

也就是說,let只能在花括號內部起作用

const

再來說說const,const代表一個值的常量索引。

const aa = 11;
alert(aa) //11
aa = 22;
alert(aa) //11

但是常量的值在垃圾回收前永遠不能改變,所以需要謹慎使用。

還有一條需要注意的就是和其他語言一樣,常量的宣告必須賦予初值。即使我們想要一個undefined的常量,也需要宣告:

const a = undefined;

塊級作用域

最後提一下剛才說到的塊級作用域。

在之前,javascript是沒有塊級作用域的,我們都是通過()來模擬塊級作用域。

(function(){
 //這裡是塊級作用域 
})();

但是在ES6中,{}就可以直接程式碼塊級作用域。所以{}內的內容是不可以在{}外訪問得到的

我們可以看看如下程式碼:

if (true) {
    function foo() {
        document.write( "1" );
    }
}
else {
    function foo() {
        document.write( "2" );
    }
}

foo();      // 2

在我們所認識的javascript裡,這段程式碼的輸出結果為2。這個叫做函式宣告提升,不僅僅提升了函式名,也提升了函式的定義。如果你基礎不紮實的話,可以看看這篇文章:深入理解javascript之IIFE

但是在ES6裡,這段程式碼或丟擲ReferenceErroe錯誤。因為{}的塊級作用域,導致外面訪問不到foo(),也就是說函式宣告和let定義變數一樣,都被限制在塊級作用域中了。