初步探究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定義變數一樣,都被限制在塊級作用域中了。