# 2024-06-28 JavaScript
## 參數和引數的定義
```js
function hi(a, b) { // <=== a, b 屬於參數
}
hi(1, 2); // <=== 1, 2 屬於引數
```
## 回傳值
```js
function add(a, b) {
console.log(a + b); //console.log只是過程,不是結果
return a + b; //真正回傳值需要使用return
}
add(1, 2);
```
[情境一]
```js
function add(a, b) {
return a + b;
}
console.log(add(1, 2));
//最後結果:
// 3
```
[情境二]
```js
function add(a, b) {
console.log(a + b);
}
console.log(add(1, 2));
// 1. add(1,2)會被執行,執行過程印出 3,但是沒有return,所以會回傳undefined
// 2. console.log(add(1,2)) => console.log(undefined)
// 3. 最後印出undefined
//最後結果:
// 3
// undefined
```
[情境三]
```js
function add(a, b) {
return console.log(a + b);
}
console.log(add(1, 2));
// 1. add(1,2)會被執行,遇到console.log(a + b),會得到3
// 2. 因為console.log不會回傳值,所以會得到undefined,最後return會回傳undefined
// 3. console.log(add(1,2)) => console.log(undefined)
// 4. 最後印出undefined
//最後結果:
// 3
// undefined
```
[情境四] Early Return (不寫else相對輕鬆,因為不用處理兩條判斷式)
```js
function is_adult(age) {
if (age >= 18) { // 可以把重點放在這一塊
return true;
}
return false;
}
console.log(is_adult(20));
```
## What 什麼是函數function?
- 輸入值 與 輸出值之間的關係
- 函數名字 = 這個關係的名字
## Why 為什麼要使用函數function?
- 可重複利用
- 給程式碼意義
## 電腦界兩大難題
- 命名 naming (書籍:naming things)
- 快取 cache(暫存) => 不知道什麼時候該放手
## 函數 function
- 什麼是一等公民? 在有階層區分的最低等,最普通
- fn = 一等公民,一級物件(first-class citizen)
- 把 fn 當作和一般物件來看,可以丟來丟去,跟其它 整數,字串..一樣
- 123, "aaa", [], {} 都是一等公民
- fn 與其它人的差異就是,可以被"呼叫",在必要時呼叫
```
※ 函數沒有小括號就是沒有啟動,當作物件來丟
```
[情境一]
```js
function hi(a) {
console.log(a);
}
function hey() {
console.log("hey");
}
hi(hey); // hey是物件 沒有小括號沒有執行
// 因為hey()沒有return,所以會回傳undefined
// 會把結果undefined丟進hi => hi(undefined)
hi(hey());
```

[情境二]
```js
function hi(a) { // a參數會收到 hey 物件
a(); // 把 hey 加上小括號() 表示執行物件a (hey)
}
function hey() {
console.log("hey");
}
hi(hey); // 帶入物件hey ,hey是物件 沒有小括號沒有執行
最後結果: hey
```
[情境三]
```js
function hi(a) {
a();
}
const hey = function () {
console.log("hey");
};
// 會先執行hey()得到hey,但回傳值會是undefined
// 再把undefined帶入hi(),因為對undefined發動,就會出錯
hi(hey());
最後結果: 如下圖
```

[情境四]
```js
function hi(a) {
a();
}
const hey = function () {
console.log("hey");
};
// 會先執行hey()得到hey,但回傳值會是undefined
// 再把undefined帶入hi(),因為對undefined發動,就會出錯
hi(hey());
最後結果: 如下圖
```
[情境五]
```js
function hi(a) {
a();
}
function hey() {
function inner() {
console.log("inner!!");
}
return inner;
}
hi(hey());
// 會先執行hey(),內部因為有return inner,所以會回傳inner物件
// 然後當作hi function的引數帶入 => hi(inner funciton)
// a = inner funciton,然後在hi function內啟動a() => inner()
最後結果: inner!!
```
[情境六]
```js
function hi(a) {
a();
}
function hey() {
return inner; <== 因為變數提升關係,所以會回傳inner function
//第一階段就會變數提升
function inner() {
console.log("inner!!");
}
}
hi(hey());
// 會先執行hey(),內部因為有return inner,所以會回傳inner物件
// 然後當作hi function的引數帶入 => hi(inner funciton)
// a = inner funciton,然後在hi function內啟動a() => inner()
```
[情境七]
```js
function hi(a) {
a();
}
function hey() { // 高階函數
function inner() { // 不是高階函數,因為沒參數,也沒return
console.log("inner!!");
}
return inner;
}
hi(hey); // 高階函數
// 把hey丟入hi funtion,a = hey,然後再啟動a() => hey()
// 啟動hey()因為有return所以會得到inner function,但沒有加上()去啟動
// 但是沒有輸出,所以結果是空白
最後結果: 空白,沒輸出結果
```
## 高階函數 (higher order function)
- 吃別人的function當參數
- 回傳 function
- 只要符合以上兩個條件之一都屬於高階函數
## Callback function (回呼)
- 不用等待,直到他自己做完,自動回傳結果
## 陣列
- 為什麼陣列從 0 開始算?
=> 索引值=偏移數量,索引值就是往旁邊移動幾格,幾格就是偏移數量
[情境一]
```js
const list = [1, 2, 3, 4];
for (let i = 0; i < 4; i++) {
list[i] = list[i] * 2;
}
console.log(list);
// for, [i]
// -> [2, 4, 6, 8]
// 不是好的做法: 是因為會改變原本的陣列內容,可新增一新的陣列來儲存
```
修改寫法
```js
const list = [1, 2, 3, 4];
const newList = [];
for (let i = 0; i < 4; i++) {
const value = list[i] * 2;
newList.push(value);
}
console.log(list);
console.log(newList);
```

### NaN (面試題會問的東西)
```
1. NaN 他是數字 用來表示不是數字
2. 1 / 0 ⇒ Infinity, 0 是一個趨近於 0 的數字
3. Infinity 是一種number型別 typeof Infinity (是一種概念)
4. NaN 是一種number型別 typeof NaN
5. 是根據IEEE754規定
6. NaN === NaN ⇒ false
NaN不會等於任何東西 包括他自己 (IEEE754規定)
```
利用NaN的特性之一 來判斷輸入的數值是不是NaN (使用JS內建,不用自己寫)
```js
function isNaN(value) {
return value !== value; // 利用 NaN 人設,自己不會等於自己
}
console.log(isNaN(NaN));
```
Infinity + Infinity ⇒ Infinity
Infinity - Infinity ⇒ NaN
### 使用map (對現有的東西,做一件事情,然後回傳新陣列)
[情境一]
```js
const list = [1, 2, 3, 4];
const newArray = list.map(function (number) {
return number * 2;
});
console.log(newArray); // [2, 4, 6, 8]
```

[情境二]
```js
const list = [1, 2, 3, 4];
const newArray = list.map(function (number) {
number * 2; // 沒有return
});
console.log(newArray);
```

[情境三]
```js
const list = [1, 2, 3, 4];
// 函數變物件的好處
const double = (x) => x * 2;
const newArray = list.map(double); // 對於map來說 double就是callback function
console.log(newArray);
```
[情境四]
```js
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const even = (n) => {
return n % 2 == 0;
// return false => [false, false, false, false, false, false, false, false, false, false]
// return true = > [true, true, true, true, true, true, true, true, true, true]
};
const newArray = list.map(even); // map判斷真假值,回傳個數一定都會一樣
console.log(newArray);
```

### 使用filter 過濾,回傳新陣列
[情境一]
```js
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// [2, 4, 6, 8, 10]
const even = (n) => {
return n % 2 == 0;
// return false => []
// return true = > [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
};
const newArray = list.filter(even);
console.log(newArray);
```

### 使用reduce (回傳值 => 當作下一次累加值)
[情境一] 有設定預設值0
```js
const list = [1, 2, 3, 4, 5];
// reduce 歸納
// 累加值acc 目前值cv => current value
// 不一定只能是加法(+),也可以進行其它運算
const result = list.reduce(function (acc, cv) {
return acc + cv;
}, 0); // 0 為累加值初始值
console.log(result); // 15
```

[情境二] 有設定預設值0
```js
const list = [1, 2, 3, 4, 5];
const result = list.reduce(function (acc, cv) {
return 1 + cv; <=== cv值會一值被替換,由1..5,最後return 1 + 5
}, 0); // 0 為累加值初始值
console.log(result); // 6
```
[情境三] 沒有設定預設值
```js
const list = [1, 2, 3, 4, 5];
const result = list.reduce(function (acc, cv) {
return acc + cv;
});
// 沒有預設值,會拿陣列第一個元素當累加值,第二個元素當作第一輪目前值
console.log(result); // 15
```

[情境四] 使用reduce求最大值,但是"不要自己寫",拿內建現成函數Math.max
```js
const list = [1, 9, 10, 3, 5];
const result = list.reduce(function (a, b) {
if (a > b) {
return a;
}
return b;
});
console.log(result);
```

```
[面試題] 泡泡排序法 bubble sort (演算法)
```
### 排序sort (使用內建sort()會需要留意用法)
```js
const list = [1, 9, 10, 3, 5];
const newList = list.sort();
console.log(newList); // 會轉換成字串來比較
最後結果: [1, 10, 3, 5] <=== 原因是因為內建sort會先將"數字"轉換成"字串"來比較
```

[綜合練習題]
```js
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 所有奇數的平方和
// const oddList = list.filter(function (number) {
// return number % 2 == 1;
// });
// const squareList = oddList.map(function (number) {
// return number * number;
// });
// const total = squareList.reduce(function (sum, number) {
// return sum + number;
// });
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const total = list
.filter((n) => {
return n % 2 == 1;
})
.map((n) => {
return n * n;
})
.reduce((sum, cv) => {
return sum + cv;
});
console.log(total); // 165
````