2018-05-18 補充,參考這位印度人的講解,超級厲害,把scope觀念講得超明寮,雖然英文很有雷。Youtube系列影音。
http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/
http://www.w3schools.com/js/js_hoisting.asp
Javascript的變數範疇又差點破壞我對PHP變數的理解 (= =)
global vs local:跟PHP一樣的是local變數僅能運作在local範圍,global範圍是不能存取。好詭異的差異在,居然在local範疇(函數)可以存取到global變數。
- local變數:函數(function)裡面,使用var定義的為local,不是用var定義的變數表示來自global。
- global變數:函數以外使用var定義,或者不須用var定義。
var a = 100; //global
b = 1000; //global
function foo() {
var c; //local
a++; //來自global的a
}
console.log(foo()); //101
console.log(foo()); //102
2018-05-18 印度人補充:javascript雖然是直譯式語言,但它其實還是有分兩個階段執行,Compilation 與 Interpretation。
var a = 10;
function myFn() {
var b = 10;
var c = b;
console.log(a + b);
}
myFn();
compilatation階段,只是註冊變數(包含函數),把它歸到正確的scope。所以上面的code總共有四個變數要註冊。var a 與 myFn 註冊成global變數、var b 與 var c 註冊成 myFn scope 的變數。指派值與console.log() 與 myFn() 在這個階段會被跳過。
interpretation階段,開始指派值與執行。a = 10,在global找到了a變數,所以把10指派給a; 接著的function myFn()會被跳過,因為它不是執行。而是最後一行的myFn()才去執行。b = 10 在myFn scope找到b變數,所以把10指派給b、c = b 在myFn scope找到c變數也找到b變數,把找到的b值指派給c。最後把console.log()執行。
hoisting(提升):JS引擎運作時會自動把宣告(定義)的變數拉提到該範疇的最上方,初始化變數不算是宣告喔,用例子看比較清楚。
//global範疇
x = 5;
console.log(x); //5
var x; //定義變數x, 會被提升至第1行(x=5)之前
//先宣告再給值(等同上方code)
var x;
x = 5;
//local範疇
var name = 'nicole';
function getName() {
//依據第一段定義,它應該是global的name(nicole)。
//但是因為底下有var name,會被移置到函數內容第一行,所以它是local變數。
console.log(name); //undefined
var name;
name = 'Amuro';
}
getName();
//合成底下兩行變一行也是undefined
//因為JS引擎只會提升宣告,初始化值並不會被提升。
var name;
name = 'Amuro';
var name = 'Amuro';
所以養成在各個範疇就宣告(定義)變數的好習慣,才不容易造成bug。