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

### 宣告準則(建議)
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())為需要秀出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 */
```