---
# System prepended metadata

title: 周末任務 - 變數宣告、傳值傳參考、undefined及null
tags: [JS 直播班, JavaScript]

---

###### 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]

