0%

008重新認識JS-Day02-筆記3

變數的有效範圍

在ES6之前,JS變數有效範圍的最小單位是以function做分界。
在ES6之後,有了letconst分別定義了「變數」和「常數」,他們與var不從的地方在於,
他們是用大括號{}來切分的,而且let不能重複宣告變數。

ex:

1
2
3
4
5
6
7
8
9
10
11
12
var x = 10;
var doSomething = function(){
var x = 100;
return x + y;
}

console.log(doSomething(5)); // 105
console.log(x); // 10

上面這個例子,在doSomething的函式中,有再一次用var來定義變數x,故這個變數x的動範圍是再doSomething的函式範圍中,跟外面那個全域變數x是不同人!!!
所以,倒數最二行印出來的結果,是x=100這個區域變數,加總出來的結果
倒數第一行印出來的結果,就是x=10這個全域變數的結果

提升(Hoisting)

在變數宣告的部分,編譯器會自動地將’宣告’的那部分,提升到該變數被定義的範圍的最上方。
注意!!是只有’宣告’的部分被提升喔,被定義的部分是會保留在原地的。
ex:

1
2
3
4
5
6
7
8
9
var x = 1;
var doSomething = function(y){
console.log(x); // ???

var x = 100;
return x + y;
}
console.log(doSomething(50)); // 150
console.log(x); // 1

Question1. ??? 的結果是undefined !!
Question2. 倒數第二行印出來的結果,居然是150 !!!

讓我們來解析一下上面這行程式碼
首先,先記得上面講的變數的’宣告’,會先被提升到該變數被宣告範圍的最上方
ex:

1
2
3
4
5
6
7
8
9
10
var x = 1;
var doSomething = function(y){
var x; // x 被提升了
console.log(x); // undefined

x = 100; // 賦值部分被留在原地
return x + y;
}
console.log(doSomething(50)); // 150
console.log(x); // 1

Ans1:
由上面的例子可以看出來在doSomething的變數x被宣告的部分,被提升函數中的最上方位置,但是,此時,x還沒有被賦值,所以,
下面console的結果才會是undefined

Ans2:
一樣是因為在domSomething的函式中的變數x是區域變數,它跟外面的全域變數x是不同人,所以,在doSomething調用的x,是區域變數x,故其值為100,
也因為是這樣,100 + 50 = 150,結果才會是150。

let/const 宣告的暫時性死區(Temporal Dead Zone, TDZ)

首先,要知道let宣告是無法重複宣告的,而且,let宣告是沒有提升的特性的。
也因為let沒有提升的特性,也造成它有死區的狀況出現。
ex:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---var宣告---
var doSomething = function(y){
console.log(x); // undefined
var x = 10;

return x + y;
}

---let宣告---
var doSomething = function(y){
console.log(x); // ReferenceError
let x = 10;

return x + y;
}

由上面個範例可以看的出來,在var宣告的範例中,因為,var有提升的特性,只是賦值得那部分會留在原地,所以,在console印出的結果是undefined
而由let宣告的那個範例,因為,let沒有提升的特性,所以,console那段,編譯器根本就不知道變數x是誰, 而這段就是let的死區,所以,才會報出ReferenceError的錯誤。

函式的提升特性

注意!! 「函式宣告」 方式定義的函式有提升的特性。 而用「函式運算式」方式定義的函式式沒有提升的特性。
ex:

1
2
3
4
5
6
7
8
9
10
11
---函式宣告---
console.log(square(2)); // 4
function square(num){
return num * num;
}

---函式運算式---
console.log(square(2)); // squre is not a function
var square = funtion(num){
return num * num;
}

另外,變數提升的部分只有”宣告的部分被提升”。
而函式宣告提升的部分”整個函式定義的內容都被提升”。

全域變數 和 區域變數

在JavaScript中,「全域變數」精確地來講是指「全域物件的屬性」。

「全域物件」是什麼?

以瀏覽器來講,「全域物件」指的是window。

ex:

1
2
var a = 10;  // 全域變數
console.log(window.a); // 10 (可看出來a是window的屬性)

ex2:

1
2
3
4
5
6
function func(num){
b = 10; // 這個變數b,沒有透過var或let來宣告,他會直接變成全域變數,也就是會變成window的其中一個屬性
return num + b;
}
func(10)
console.log(window.b); // 10,因為,它變成window的屬性了