---
# System prepended metadata

title: 2024-06-28 JavaScript
tags: [JavaScript]

---

# 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()); 

```

![image](https://hackmd.io/_uploads/SyoqgZhIA.png)


[情境二]
```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());

最後結果: 如下圖

```
![image](https://hackmd.io/_uploads/HJhhfZhL0.png)

[情境四]
```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);
```
![image](https://hackmd.io/_uploads/SkZv_-hLA.png)


### 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]
```
![image](https://hackmd.io/_uploads/HkjTuNhUA.png)


[情境二]
```js
const list = [1, 2, 3, 4];

const newArray = list.map(function (number) {
  number * 2; // 沒有return
});

console.log(newArray);
```
![image](https://hackmd.io/_uploads/Sy__KEnIC.png)


[情境三]
```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);
```
![image](https://hackmd.io/_uploads/BkgCoN38C.png)



### 使用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);
```
![image](https://hackmd.io/_uploads/BJxfiN2UR.png)


### 使用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
```
![image](https://hackmd.io/_uploads/BJdC6Eh8R.png)

[情境二] 有設定預設值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
```
![image](https://hackmd.io/_uploads/B1dSkrhL0.png)

[情境四] 使用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);
```
![image](https://hackmd.io/_uploads/SyhUGB28R.png)

```
[面試題] 泡泡排序法 bubble sort (演算法)
```

### 排序sort (使用內建sort()會需要留意用法)
```js
const list = [1, 9, 10, 3, 5];

const newList = list.sort();
console.log(newList); // 會轉換成字串來比較

最後結果: [1, 10, 3, 5] <=== 原因是因為內建sort會先將"數字"轉換成"字串"來比較
```
![image](https://hackmd.io/_uploads/BJxRXS2IR.png)


[綜合練習題]
```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

````