iT邦幫忙

1

ES6 學習筆記_02(作用域)

什麼是作用域?

作用域就是一個變數的生存範圍,一旦超出了這麼範圍就無法存取到這個變數。

在ES6之前,Javascript只擁有函數作用域和全域作用域,函式作用域也就是說每一個函數都有自己的作用域,在作用域外面無法存取到函數內定義的變數,全域作用域代表global任何地方都能存取到,而ES6引入的let與const,多了塊狀作用域的概念,

作用域式分層的,內層作用域可以取得外層作用域的變數,反之則不行。

全域作用域(global)

全域作用域式全局性的,也就是說在整個Javascript程式中到處都可以使用,所有window物件都屬於全域作用域中,全局作用域有個缺點,如果我們定義了很多變數、函示但卻沒有使用那麼它們就全部都在全局作用域中,會污染全局命名空間, 容易引起命名衝突。

var global = 123;
test = () => {
    console.log(global); //123
};
test();

值得注意的是,尚未定義且直接賦值的變數都會自動宣告為全局作用域這點在寫成式的時候會常常造成錯誤。

test = () => {
    var func = 123;
    global = 456;
    console.log(func); //123
};
test();

console.log(func); //ReferenceError: func is not defined
console.log(global); //456 雖然global在函示內被賦值,但卻沒有定義型態,所以被自動歸類為全局作用域 

函式作用域

函式作用域只有在函數內可以被訪問到,所以在函數內所宣告的變數不會洩漏到全域中造成全域汙染,而函式作用域可以訪問父層作用域的變數,但自身作用域的變數層級較高。

test = () => {
    var a = 10;
};
console.log(a); //ReferenceError: a is not defined
var global = 123;
test = () => {
    var global = 456;
    console.log(global); //456
}

test();

塊級作用域

在ES6中引入了let與const兩個變量宣告,新增了塊級作用域的概念。

為什麼需要塊級作用域?

由於ES5只有全局作用域與函數作用域,所以常常會造成一些想像不到的錯誤。

var tmp = new Date();

test = () => {
    console.log(tmp);
    if(false){
        var tmp = "hello world";
    }
};

test(); //undefined

在上面的程式中,雖然function可以讀取到全域的tmp變數,但是由於變量提升(hoisting)的關係導致輸出為undefined。

var tmp = new Date();

test = () => {
    var tmp; //hoisting
    console.log(tmp); //undefined
    if(false){
        tmp = "hello world";
    }
};

test(); //undefined

而ES6新增了塊級作用域搭配上let,const不會hoisting的情況,可以避免常數的不確定性。

test = () => {
    let n = 5;
    if(true){
        let n = 10;
    }
    //由於let n=5與console屬於同級塊狀作用域,而let n=10屬於下一層級的塊狀作用域,所以不會互相影響
    console.log(n); //5 
};

還有值得注意的地方,ES6的塊級作用域必須有大括號,若沒有JavaScript則認為不存在塊級作用域。

//Error
if (true) let x = 1;

if (true) {
  let x = 1;
}

參考資料 :
ECMAScript 6 入门
深入理解JavaScript作用域和作用域鏈
所有的函式都是閉包:談 JS 中的作用域與 Closure


尚未有邦友留言

立即登入留言