iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 3
0
自我挑戰組

學JS的心路歷程系列 第 3

學JS的心路歷程 Day3-範圍 Scope 和 提升(Hoisting)

在上一篇提到了JS有三種宣告變數的方式,分別是varconstletvarconst let 最大區別就是範圍(scope)的限制。所以在這一篇我們會詳談何謂範圍鏈及他們的覆寫優先順序。

範圍 Scope

我們先來看一個例子:

var globalVar = 'global';

function scopeFun(){
    globalVar = "change in scopeFun";
    console.log("1.",globalVar);//1. change in scopeFun
    var funVar = 'Im in fun';
    console.log("2.",funVar);//2. Im in fun
}

scopeFun();
console.log("3.",globalVar);//3. change in scopeFun
console.log("4.",funVar);//funVar is not defined

在function中所宣告的var在全域是沒辦法作呼叫的,但是在全域宣告的在function中卻可以用。
這邊我們可以確定兩件事情:

  1. var 是 函數級作用域(function-level scope)由function的{}所區隔。
  2. 變數會由內往外尋找直到全域,我們稱這行為為範圍鏈(Scope Chain)。

那我們再來看ES6新增的 letconst的範圍:

let globalLet = true;

function scopeFun(){
    if(globalLet){
        let localLet = "local let";
        const localConst = "local const";
        console.log(localLet,localConst);
    }
    console.log(localLet,localConst);
}

scopeFun();

由這個例子我們可以得知:
letconst的是區塊作用域(Blocak-level scope)由 {}所區隔。

提升(Hoisting)

在講解變數覆寫優先順序前,我們還需要先了解什麼是 Hoisting:
在執行程式碼前,JS會把函式宣告放進記憶體裡面,可以在程式碼宣告該函式之前使用它。

function myName(name){
    console.log("my name is "+name);
}

myName("John");//my name is John

一般在撰寫一個函式時候都會這樣作,但我們前面有提到說 可以在宣告該函式之前使用它,所以我們也可以這樣作:

myName("John");//my name is John

function myName(name){
    console.log("my name is "+name);
}

當然 提升 也適用於 變數,但是跟函式就有很大的區別了。
如果我們在宣告前就先給初始化的話,是可以正常使用的:

price = 10;
price +=1;
console.log(price);//11
var price = 20;

但是如果在宣告後才初始化,則前面使用將會得到undefined:

console.log(price);//undefined
var price = 20;

這段程式碼可以理解成這樣:

var price;
console.log(price);//undefined
var price = 20;

這邊要注意的是,ES6提供的變數宣告letconst是無法做到的,會回報錯誤:

console.log(price);//ReferenceError: price is not defined
let price= 20;

那如果我們用變數宣告函式的話,會發生什麼事情呢:

console.log(price);//undefined
price(20);//TypeError: price is not a function
var price = function (amount){
    console.log(20*amount);
}

可以看到只有變數被提升到最上面且是undefined,所以無法當成函式使用。

總結:

  1. var 是 函數級作用域(function-level scope)由function的{}所區隔。
  2. letconst的是區塊作用域(Blocak-level scope)由 {}所區隔。
  3. 變數會由內往外尋找直到全域,我們稱這行為為範圍鏈(Scope Chain)。
  4. 可以在宣告該函式之前使用它,這行為稱為 提升(Hoisting)。
  5. 變數var也有提升,但如果使用時沒有初始化將會得到undefined
  6. var宣告函式無法在之前使用,因為var提升是undefined

參考資料:
https://developer.mozilla.org/zh-TW/docs/Glossary/Hoisting

https://ithelp.ithome.com.tw/articles/10198485


上一篇
學JS的心路歷程 Day2- 宣告
下一篇
學JS的心路歷程 Day4 - 參數的傳遞方式(上)
系列文
學JS的心路歷程30

尚未有邦友留言

立即登入留言