###### tags: `JavaScript` `JS 直播班`
# 周末任務 - 變數宣告、傳值傳參考、undefined及null
:::info
📕 **筆記大綱介紹**
- var、let、const 的差異
- by reference (傳參考)、by value(傳值)概念
- undefined 與 null 的差異
:::
## var、let、const 的差異
### 為什麼要宣告變數?
變數在程式運行中扮演很重要的角色,我們可以將資料存放進變數內,並在需要的時候引用。
### JS 三種宣告變數方式
1. var
2. const
3. let
### var : 時代的眼淚
- var 的問題:能夠被重複宣告
var 可以被重複宣告,而且不會出錯!想要天下大亂是逆?!!
```javascript=
var weather = "天氣晴";
function fn() {
var weather = "下大豪雨";
console.log(weather); // output: 下大豪雨
}
fn();
console.log(weather); // output: 天氣晴
```
- var 的問題2:作用域的汙染
在for迴圈上體驗凡響!!!
```javascript=
for (var i = 0; i < 3; i++) {
console.log(i); // output: 0,1,2
}
console.log("i", i); // output: 3
```
### let、const : ES6推出的解決方法
ES6 推出可以使用範圍寫法的概念。
### let 解決 var 缺點的瑰寶
- 不能被重複宣告 : 會幫你噴錯除錯喇!
Identifier 'a' has already been **declared** :arrow_right: 已經被宣告過啦!
```
let a = 1;
let a = 2; // output: Uncaught SyntaxError: Identifier 'a' has already been declared
```
- 可以區分作用域 : 沒有問題的喇!
```javascript=
var teacher = "血汗校長"; // 全域變數
function changeTeacher(){
let teacher = "漂釀老師"; // 區域變數
teacher = "帥氣工友";
console.log(teacher); // output: 帥氣工友
}
changeTeacher();
console.log(teacher); // output: 血汗校長
```
- 改善for迴圈的汙染
i is not defined :arrow_right: 還沒定義過喇!
```javascript=
for (let i = 0; i < 3; i++) {
console.log(i);
}
console.log(i); // Uncaught ReferenceError: i is not defined
```
### const : 定義常數就用我
> 常數 : 不能被變更的變數。
- 重新宣告會出錯窩~
Identifier 'pi' has already been declared :arrow_right: 已經被宣告過啦! (還想改圓周率阿(誤XD
```javascript=
const pi = 3.14159265359;
console.log(pi); // output: 3.14159265359
pi = 3;
console.log(pi); // output: Uncaught SyntaxError: Identifier 'pi' has already been declared
```
- 有個例外:常數裡的陣列,想不到吧~
因為陣列存放記憶體的方式是指向記憶體位置,所以想要修改裡面的內容,是可以的!
```javascript=
const family = {
dadName: 'David',
momName: 'Amy'
};
family.dadName = 'Yappy';
console.log(family); // output: {dadName: 'Yappy', momName: 'Amy'}
```
#### Object.freeze()
:thinking_face: 可以解決嗎? YES! 來試試看 `Object.freeze()` JS的內建語法吧~
Identifier 'objUrl' has already been declared :arrow_right: 已經被宣告過啦!
```javascript=
const objUrl = {
urlIndex: "https://www.google.com/",
};
// 使用 freeze 就不能修正了
Object.freeze(objUrl);
objUrl.urlIndex = "https://tw.yahoo.com";
console.log(objUrl.urlIndex); // output: Uncaught SyntaxError: Identifier 'objUrl' has already been declared
```
## by value(傳值)、by reference (傳參考)
### JS 的型別,主要有兩種
了解傳值還是傳參考前,得先知道型別有哪些~
- Primitive type : 原始型別處理值
- Object types : 物件處理參考
### Primitive 的成員
- String
- Number
- Boolean
- Null
- Undefined
### Object
- Object
- Function
- Array
- Set
### by value(傳值)
:writing_hand: 舉例來說...
1. 我先創造了變數a,並且賦值 "Hello world!"
2. 這是在電腦記憶體內創造了型別為字串的記憶體空間,並存放 "Hello world!" 進去
3. 再將變數a指向剛剛設定的記憶體空間 (目前進度只有到 `let a = "Hello world!";` 喔~)
4. 第二階段: 創造b變數
5. **另開一個記憶體**並將a記憶體空間內的值複製
6. 將b變數指向這個複製人(值: "Hello world!")
7. 第三階段: a指向新的記憶體空間: "JS is FUN!"
8. 查看大家的結果啦~
:star: 最大的重點就是,a、b的值是不會互相被影響,**賦值完**你我就是陌生人囉!
```javascript=
let a = "Hello world!";
let b = a;
a = "JS is FUN!";
console.log("a", a); console.log("b", b);
// output: a JS is FUN!
// output: b Hello world!
```
### by reference (傳參考)
>在JavaScript裡,物件、陣列、函式都是call by reference。
:star: 我本身就是個記憶體空間,不管你怎麼指都會指到同個位址啦!
```javascript=
let people = { greeting : '安安!' };
let minions = people;
minions.greeting = 'Bello~';
console.log("people", people);
console.log("minions", minions);
//output: people {greeting: 'Bello~'}
//output: minions {greeting: 'Bello~'}
```
挖!全部都變成小小兵LA~~
這就是**傳址**,一修改記憶體內容,有指向的全部都被更改了> <
## undefined && null
### undefined (不明確的)
代表一種型態,變數宣告了,但目前還沒有值。
1. 一般變數
```javascript=
let a;
console.log(a); //output: undefined
```
2. 物件沒有這個**屬性**
```javascript=
var family = {
dad: "David",
mom: "Annie",
son: "Sowut"
};
console.log(family.daughter); //output: undefined
```
3. 函式沒有回傳值你硬要調用捏 :face_with_raised_eyebrow:
```javascript=
function calc() {}
console.log(calc()); //output: undefined
```
4. 函式有傳入值就任性不給(?
```javascript=
function payMoney(dollar) {
console.log(dollar); //output: undefined 員工QQ
}
payMoney();
```
:santa: 補充: is not defined :arrow_right: 這個變數還沒被宣告喇!
```javascript=
console.log(b) //output: b is not defined
```
### null 空值
- 硬是被給的,刻意使變數為空值
- 若想要利用js抓取節點(dom),如果沒有這個值會返回空給你看(阿人家就沒有~)
```javascript=
const elTitle = document.getElementById('jsTitle');
console.log(elTitle); // output: null
```
### 比較一下
#### 型別差很多耶~
- undefined : 原始型別就有我本人 undefined
- NaN : 無法計算的數字型別 number
- null : 一種物件型態
```javascript=
typeof undefined //output: 'undefined'
typeof NaN //output: 'number'
typeof null //output: 'object'
```
#### 真假值
如果使用寬鬆比較(兩個==),會為真,因為兩個false去比較。但如果我們用更嚴謹的比較方法(三個===),他有協助我們去比較型態,就會是相反的結果了。
```javascript=
console.log(undefined == null); // output: true
console.log(undefined === null); // output: false
```
## 📚 參考閱讀資源
>**1. [語法與型別](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types)**
>[name=MDN WEB Docs]
>**2. [ECMAScript6 入門:var、let、const 差異](https://w3c.hexschool.com/blog/530adff5)**
>[name=Sealman]
>**3. [var、let、const 的差異?](https://hackmd.io/m7wJAmCUSsqUDFjFefY1Vw?view)**
>[name=guitimliu]
>**4. [JavaScript 的「傳值」與「傳址」](https://hackmd.io/@chupai/B13YRDJJB)**
>[name=竹白]
>**5. [JavaScript null、undefined 與 undeclared](https://kim85326.github.io/2019/09/09/JavaScript-null-undefined-%E8%88%87-undeclared/)**
>[name=Elaine's Blog]