---
# System prepended metadata

title: JavaScript（一）
tags: [javaScript]

---

JavaScript（2023/10/16-2023/10/20）
===
> JS / ES6 EcmaScript(ES) 規範 JS 一種ES

# 變數常數資料型態
## 宣告變數(variable)
>不能數字開頭、不能用保留字、變數本身沒有型態
### let
* 有變數提升嗎？
    * JS兩階段運行，let 不會幫忙初始化 TDZ所以感覺像是沒有變數提升 但其實有
* Scope小，若在{...}中宣告，即僅能存在{...}中，不易污染

### var
* 有變數提升
* Scope大，容易污染
* function scope是唯一能夠關住var的
### const
* 又稱常數
* 常數值不能改
* 陣列裡的某項可以改
    * 因為指向陣列，並沒有改變

### var v.s. let
![](https://hackmd.io/_uploads/Sy5rYAnb6.png)


### 宣告準則（建議）
1. const
2. let
3. var

### 範例：
```javascript=
if (true) {
    var a = 1
    let b = 1
    }

console.log(a);
console.log(b);

/*結果：
a = 1
b is not defined(因為let會被{...}關住)*/
```

## 變數提升(variable hoisting)

### Creation Phase
* 註冊名稱
    * `var a = 1` -> 此時 a = undefined
### Execution Phase
* 初始化
    * 賦值 & 執行函數
    * `var a = 1` ->此時 a = 1

### 範例1
```javascript=
console.log(a); 
var a = 1;
/* 結果為undefined */
```
### 範例2
```javascript=
console.log(a);
let a = 2
/* 結果為Cannot access 'a' before initialization */
```

## 全域變數
* 未宣告的東西會放在全域變數
* var 的東西也會放在全域變數
* 範例：
```javascript=
a = 100
console.log(a);

/*結果為100,a被放在全域變數裡*/
```

## 常數補充
>常數（constant）又稱定數，是指一個數值固定不變的數，例如圓周率，與之相反的是變數。
* const一定要初始化(賦值)
* const Array內容可以變長，改變，但不能重複定義
### 範例1：
```JavaScript=
const a;
console.log(a);
/* 結果：Missing initializer in const declaration */
```
### 範例2：
```JavaScript=
const list = ["a","b","c"]
list = ["a","b","c"]
const list = 1
list = 2
    
/* 結果：yntaxError: Identifier 'list' has already been declared */

// const 不能 re-assign
// list[0] = "x"
```

### 範例3:
```JavaScript=
const list = ["a","b","c"]
list.push("d");
console.log(list);
    
/* 結果：[ 'a', 'b', 'c', 'd' ]*/
```


## 資料型態
### 原始型別
* Number
* String
* Boolean
* Null
* Undefined
* Symbol

### 物件型別
* Array
* Function
* Object

### 判斷資料型別

```javascript=
console.log(typeof(n))
```
    

## 補充說明
* 先得到a值 再幫忙+1：
    ```javascript
    a = a + 1
    a += 1
    ```
* 先增加1再幫忙印出來：

    ```javascript
    ++a
    ```

## 錯誤
:::info
* SyntaxError -> 語法錯誤
* ReferenceError: b is not defined -> 未宣告
* annot access 'a' before initialization -> 未初始化
* Missing initializer in const declaration -> 常數未賦值

:::
---

# 流程控制
## 判斷
```JS=
let age = 13
if (age >= 18) {
console.log("已成年")
} else if (age >= 12 && age < 18) {
console.log("青少年")
} else {
console.log("小朋友")
}
```
## 三元
```JS=
age >= 18 ? console.log("已成年") : console.log("未成年")
```

## switch
```javascript!=
let gender = 2

switch (gender) {
    case 1:
        console.log("男");
        break
    case 2:
        console.log("女");
        break

    default:
        console.log("no");
        break
}
```

```javascript!=
let year = 2024

if (year % 4 == 0 && year % 100 !== 0 || year % 400 == 0 ) {
    console.log("閏年");
    
} else {
    console.log("平年");   
}
```

## 代表False
* false
* undefined
* null
* 0
* NaN
    * NaN不等於任何人，包括他自己
    * Not a Number , type = number
    * NaN === NaN
```javascript!=
let a = NaN;

if (isNaN(a)) {
  console.log("is NaN");
} else {
  console.log("not NaN");
}

/* 結果 is NaN */
```

# 內建方法
* Boolean() => 傳出true or false


## 基本符號
* == 等於
* !== 不等於
* = assign
* || or
* && and 
* not
* ** 次方

## 迴圈
### for
```javascript!=
for(var i = 0; i < 5; i++){
    console.log(i);
}
```
可使用`break` & `continue`

#### continue: 跳過這回合
```javascript=
// 印出 2,4,6,8,10

for (var i = 1; i <= 10; i++) {
  if (i % 2 == 1) {
    continue;
  }
  console.log(i);
}

```

### while
>不知道要跑多久，跑到沒有為止
```javascript!=
let a = 0
while (a < 10) {
    console.log(a);
    a ++
}
```

## 範例
```javascript=
/*聖誕樹，使用者輸入幾層，就會出現幾層聖誕樹*/
function createTree(layouts) {
  for (let n = 1; n <= layouts; n++) {
    console.log(" ".repeat(layouts - n) + "*".repeat(n * 2 - 1));
  }
  console.log(" ".repeat(layouts - 1) + "*");
  console.log(" ".repeat(layouts - 1) + "*");
}

createTree(3);

// 輸出：
  *
 ***
*****
  *
  *
```

```javascript=
/* 1加到100 */
let sum = 0;
for (let i = 1; i <= 100; i++) {
  sum = sum + i;
}
console.log(sum);

// 輸出：5050
```
# 函數(Function)
>將複雜的流程用一個名字包起來
>輸入值&輸出值之間的關係
>函數是數學描述對應關係的一種特殊集合
>一等公民（我們都一樣）怎麼處理數字就怎麼處理函數

## 基本介紹
### 參數(parameter),名稱(name),引數(argument)
```javascript=
function name(x) { 
  console.log(3 * x + 2);
}
name(3); 

//輸出 11

// name(x) => x為參數
// name(3) => 3為引數
```
## 參數預設值
```javascript!=
//預設值 y = 0
function add(x, y = 0) {
  console.log(x + y);
}
add(1, 2); // 3
add(2); // 2
add(3); // 3
```
### 函數兩階段運作
* function declaration在第一階段時便已完成 1a + 1b +2
* function declaration能將呼叫函數放在任何地方
* 如果在箭頭、匿名函式裡，將呼叫函示放在不對的地方的錯誤訊息：const => 未初始化 var => 不是個function

#### 範例：
```javascript!=
console.log(add_2(1));

function add_2(m) {
  return m + 3;
}
// 4
```

## 不同函式的寫法
### 匿名函數
沒有名字
```javascript!=
const add_1 = function (m) {
  return m + 1;
};
console.log(add_1(123));
//124
```
### 具名函數
```javascript!=
function add_2(m) {
  return m + 3;
}
console.log(add_2(1));
//4
```

### 箭頭函數
```javascript!=
const add_3 = (m) => {
  return m + 2;
};
console.log(add_3(1));
//3
```

### 箭頭函數精簡版
```javascript!=
const add_4 = (m) => m + 4;
console.log(add_4(1));
//5
```
### function expression
```javascript!=
const add = (m) => {
  return m + 2;
};
```
### function declaration
```javascript!=
function add(m) {
  return m + 3;
}
```




## 回傳值
* console.log(x)沒有回傳值，使用return才有回傳值
* console.log(x)為印出值
* 若在REPL環境下，可以印出結果
* 沒有指定 就預設回傳undefined
* return後，就不會動
* 所有函數都有回傳，沒有return也會得到undefined

### 回傳值範例
```javascript!=
function add(x, y) {
  return x + y;
}
console.log(add(2, 3));
```
```javascript=
//是否成年
function isAdult(age) {
    return age >= 18;
  }
  
  console.log(isAdult(20)); //true
  console.log(isAdult(12)); //false
```

### Early return
>設計多條件判斷的邏輯時，可使用Early return 技巧，讓程式盡可能提早結束，避免去執行到不該執行的部份
```javascript=
function add(x, y) {
  if (y == undefined) {
    return x;
  }
  return x + y;
}
console.log(add(2, 3));
console.log(add(2));

```
### REPL
>「讀取-求值-輸出」循環（英語：Read-Eval-Print Loop，簡稱REPL），也被稱做交互式頂層構件（英語：interactive toplevel）。 -Wiki


## 高階函數
函數包函數就是高階函數
```javascript=
function hello(x) {
  if (typeof x == "function") {
    x();
  } else {
    console.log(x);
  }
}

function a() {
  console.log(`I am function`);
}

hello(1); //1
hello(a); //I am function

//如果打成hello(a())為需要秀出ａ執行後的結果
//會印出 aaaaa & undefined
```


## 範例

```javascript=
// BMI計算機
function BmiCalculator(height, weight) {
    let h = height / 100
    let bmi = weight / (h^2)
    result = bmi.toFixed(2)
    console.log(result)
}

BmiCalculator(height, weight)

```

```javascrip=
// 閏年
function isLeapYear(year) {
    return (year % 4 ===0 && year %100 !== 0) || (year % 400 ===0)
}

console.log(isLeapYear(2020));
```


```javascript=
//奇數還是偶數?
function evenOrOdd(n) {
  if (n % 2 == 0) {
    return "Even";
  }
  return "Odd";
}
console.log(evenOrOdd(-1));

//Even
```


```javascript=
// 加稅前的價格

const VAT = 0.15;
function excludingVatPrice(price) {
  if (price == null) {
    return -1;
  }
  const result = price / (1 + VAT);
  return Number(result.toFixed(2));
}

console.log(excludingVatPrice(230));

//toFixed會變成字串，所以要用Number轉換
```

```javascript=
//加稅前的價格 解法二
const VAT = 0.15;
function round(num, digit) {
  return Number(num.toFixed(digit));
}

function excludingVatPrice(price) {
  if (price == null) {
    return -1;
  }
  const result = price / (1 + VAT);
  return round(result, 2);
}

console.log(excludingVatPrice(230));
```

```javascript=
//取小數點後幾位
function round(num, digit) {
  const ratio = 10 ** digit;
  return Math.round(num * ratio) / ratio;
}

console.log(round(2.333333, 2)); // 2.33
console.log(round(2.333733, 3)); // 2.334
```

## 補充說明
* JavaScript會往外找宣告變數
* undefined = NaN

### 補充1
```javascript=
console.log(1 < 2 < 3); // true
// 1 < 2 = true
// true和3比較時，true會變成1
// 1 < 3
// 答案為true

console.log(3 > 2 > 1); //false
// 3 > 2 = true
// true和1比較時，true會變成1
// 1不>1
//答案為false
```
    


# 陣列
```javascript=
let heros = ["a","b",123,456]
```
## 二維陣列
## 取得第N顆元素
```javascript!=
let hero =["1","3","5","c"]
console.log(hero[2]);
// 印出 5
```

## 最後一個元素索引值
```javascript!=
console.log(hero[hero.length -1])
```
## 增加元素
#### Array.push("") 從陣列最後面增加
```javascript!=
let heroes = ["A", "B", "C", "D"];
heroes.push("E");
console.log(heroes);
//印出[ 'A', 'B', 'C', 'D', 'E' ]
```
#### Array.unshift("") 從陣列的最前面增加
```javascript!=
let heroes = ["A", "B", "C", "D"];
heroes.unshift("E");
console.log(heroes);
//印出['E', 'A', 'B', 'C', 'D' ]
```
### Array.prototype.splice(開始index,砍掉幾個,塞入)

```javascript=
const list = [1, 2, 3, 4];
list.splice(2, 2, "a"); //star:2 ,要砍掉多少個,填充物"a"
console.log(list);//[1,2,'a',3,4]
```

### 針對陣列調整
```javascript=
const list = [1, 2, 3, 4];
list.length = 0;
console.log(list); //[]
```
```javascript=
const list = [1, 2, 3, 4];
list.length = 2;
console.log(list);//2
```
```javascript=
const list = [1, 2, 3, 4];
list[5] = 10;
console.log(list); //[ 1, 2, 3, 4, <1 empty item>, 10 ]
```

## 減少元素
#### Array.pop()從陣列最後面減少
```javascript!=
let heroes = ["A", "B", "C", "D"];
heroes.pop();
console.log(heroes);
//印出 [ 'A', 'B', 'C' ]
```

#### Array.shift() 從陣列最前面減少
```javascript!=
let heroes = ["A", "B", "C", "D"];
heroes.shift("A");
console.log(heroes);
//印出[ 'B', 'C', 'D' ]
````

## 印出被取的元素
```javascript!=
```
## 替換
#### heroes[0] = "Z"
```JavaScript!=
let heroes = ["A", "B", "C", "D"];
heroes[0] = "Z";
console.log(heroes);
//印出[ 'Z', 'B', 'C', 'D' ]
```
## 組裝
#### array1.concat(array2)
```JavaScript!=
let Aheroes = ["A", "B", "C"];
let Bheroes = ["D", "E", "F"];
Cheroes = Aheroes.concat(Bheroes);
console.log(Cheroes);
//印出[ 'A', 'B', 'C', 'D', 'E', 'F' ]
```

## 陣列位置
### Array.prototype.indexOf()
找不到值時拋出-1
```javascript=
let score = [2, 4, 8, 9, 10];
console.log(score.indexOf(2)); //0
console.log(score.indexOf(10)); //4
console.log(score.indexOf(100)); // -1 找不到值時
console.log(score.indexOf(-5)); // -1 找不到值時
```

### Array.prototype.includes()
僅顯示true or false
```javascript=
let score = [2, 4, 8, 9, 10];
console.log(score.includes(2)); // true
console.log(score.includes(10)); // true
console.log(score.includes(100)); // false
console.log(score.includes(-5)); // false
```

## 印出陣列裡的值
### 用for迴圈
```javascript=
let score = [2, 4, 8];
for (var i = 0; i < score.length; i++) {
  console.log(score[i]);
}
//2
//4
//8
```
### 用forEach
把裡面東西一個個丟出來
遍歷 迭代 iteration 每一步再走會把東西丟出來
forEach
```javascript=
//印出陣列裡的值 forEach
const array1 = ["a", "b", "c"];
array1.forEach((element) => console.log(element)); 
//a
//b
//c
```
```javascript=
const list = [1, 2, 3];
list.forEach(function (a) {
  console.log(a * 2 + 1);
});
// 3
// 5
// 7
```
```javascript=
//新陣列

const list = [1, 2, 3, 4, 5];

const result = [];
list.forEach(function (a) {
  result.push(2 * a);
});

console.log(result);
console.log(list);
```
## 找出特定陣列

### 使用Array.propetery.find()
#### 只回傳符合條件的第一個

```javascript=
let heroes = ["AA", "BBBB", "C", "DD"];
let user = heroes.find(function (n) {
  return n.length >= 4;
});
console.log(user);
//BBBB
```
#### 箭頭式
```javascript=
let list = [1, 3, 5, 8, 9];
let result = list.find((n) => n % 2 == 0);
console.log(result);
```
## reverse() 反轉
```javascript
var a = ["one", "two", "three"];
var reversed = a.reverse();

console.log(a); // ['three', 'two', 'one']
console.log(reversed); // ['three', 'two', 'one']
```
## map

對裡面每個元素做某件事情，最後做出新的陣列

### 陣列內的數字放大五倍
```javascript=
let heroes = ["A", "B", "C", "D"];
let result = heroes.map((h) => {
  return h.repeat(5);
});

console.log(result);

//[ 'AAAAA', 'BBBBB', 'CCCCC', 'DDDDD' ]
```

### 每個英雄前面加上超級
```javascript=!
let heroes = ["孫悟空", "魯夫", "宇智波佐助"];
const superHero = heroes.map(function (hero) {
  return "超級" + hero;
});

console.log(superHero);

// [ '超級孫悟空', '超級魯夫', '超級宇智波佐助' ]
```
## Filter
>在陣列裡做判斷，符合條件再收起來
```javascript=!
//判斷名字只有兩個以上
let heroes = ["AAA", "B", "CC", "DDD"];
let result = heroes.filter((n) => {
  return n.length >= 2;
});
console.log(result);

//[ 'AAA', 'CC', 'DDD' ]
```

## 陣列加總
```javascript=
陣列簡單迴圈
let score = [2, 4, 8, 9, 10];
let total = 0;
for (i = 0; i < score.length; i++) {
  total = total + score[i];
}

console.log(total);
```

## 運用reduce加總
* redece接兩個參數＆一個起始值
* acc = 累加值 cv = 每次加的值 
* 如果沒有預設值，會拿元素第一個當預設值，從第二顆開始跑
* acc = 上一輪丟出的cv
```javascript=
let score = [2, 4, 8, 9, 10];
let result = score.reduce((acc, cv) => {
  return acc + cv;
}, 0); 
console.log(result);
```

### 連續技
* 把function拉出來，再簡化
```javascript=
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const result = arr.filter(biggerArr).map(doubleArr);
console.log(result);

function biggerArr(n) {
  return n >= 8;
}

function doubleArr(n) {
  return n * 2;
}
```
* 挑出偶數加總
```javascript=
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const result = arr.filter(even).reduce(sum);
console.log(result);

function even(n) {
  return n % 2 == 0;
}

function sum(x, y) {
  return x + y;
}
```
* 把複雜的字串，整理成只有數字的字串
* type of不是function，是關鍵字
```javascript=
const list = [1, "a", 3, 5, undefined, [], true];
const result = list.filter((n) => typeof n === "number");
console.log(result);
```

#題目觀摩
```javascript=
[1,2,3,4].reduce((x,y) => x+y)
```
---

# 物件
* 物件 =屬性（名詞） + 行為(動詞)
* 陣列就像用數字當索引值的物件

## 建立物件

```javascript=
let buibui = {
  name: "阿肥",
  age: 6,
  attack: function () {
    console.log("喵喵喵");
  },
};

console.log(buibui.age); //6
console.log(buibui.name); //阿肥
console.log(buibui["name"]);//阿肥
buibui.attack();//喵喵喵
```
## 增加物件屬性 
callback
```javascript=
let buibui = {
  name: "阿肥",
  age: 6,
  attack: function () {
    console.log("喵喵喵");
  },
};

buibui.color = "紅色"; //<=增加屬性用這個
console.log(buibui.color); //"紅色"
```
## 刪除物件屬性 delete

```javascript=
let buibui = {
  name: "阿肥",
  age: 6,
  attack: function () {
    console.log("喵喵喵");
  },
};

buibui.color = "紅色";
delete buibui.name;
console.log(buibui);
//{ age: 6, attack: [Function: attack], color: '紅色' }
```


### 範例1:
```javascript=
const a = {
    nn: 123,
    // nn => key
    // 123 => value
    cc: 456,
};
console.log(a["nn"]);
console.log(a.nn);/* 建議*/

/* 結果123 123 */
```