# RE:從0開始的JS
*Min*
---
## ECMAScript?
----
ECMAScript 是 JavaScript 的標準,目的是讓不同瀏覽器之間能根據 spec 來實作。當 ECMAScript 發布第三版 (即 ES3) 之後,成為當時所有瀏覽器支援的程式語言。
----
而各家瀏覽器就會依照ECMAScript的標準,去實作JavaScript的runtime(執行環境)。
----
而ECMAScript 會隨著時代演進而更新內容(例如新增語法、功能),所以可能會聽到ES5、ES6之類的,那指的就是ECMAScript的第幾個版本
---
## NodeJS
是一個可以跑在伺服端的Javascript執行環境,可以讓JS直接在電腦上執行,不用透過瀏覽器。
----
### 來下載一下ㄅ
ubuntu
```bash
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs
```
[Windows](https://nodejs.org/en/download/)
[其他的可以看這裡](https://nodejs.org/zh-tw/download/package-manager/)
----
### 順便把yarn也裝一裝ㄅ
```bash=
# ----ubuntu----
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get install yarn
# ----homebrew----
brew install yarn
# ----arch----
pacman -S yarn
```
[Windows](https://classic.yarnpkg.com/lang/en/docs/install/#windows-stable)
----
那該怎麼用呢
----
直接node index.js
----
可以先建一個空白的index.js
然後在裡面輸入console.log("Hello")
接著在終端機下node index.js
---
## 基本語法篇
----
## 先從印出東西開始吧
----
## console.log()
----
```javascript=
console.log("Hello World")
```
---
## 變數與資料型別
----
* var 作用域是「函式(function)」
* let ES6新增的,作用域是「區塊(block)」
* const 用來宣告常數的
----
先試試看ㄅ
```javascript=
var a = 123;
let b = "123"; //盡量用這個
const c = true; //宣告後,就不能再被改了
console.log(a);
console.log(b);
console.log(c);
```
----
變數名稱的限制:
1. 第一個字元必須是字母 (大小寫皆可) 或是底線 (_),之後的字元,可以是數字、字母或底線。
2. 區分大小寫、 var XYZ 並不等於 var xyz。
3. 變數名稱不能用 JavaScript 的保留字。
----
#### 資料型態

----
#### 動態型別
```javascript=
let a = 123;
console.log(typeof a);
a = "123";
console.log(typeof a);
```
----
### 關係運算子

----

----
```javascript=
console.log("123" == 123) //true
console.log("123" === 123) //false
console.log(123 != "123") //false
console.log(123 !== "123") //true
```

---
## if...else
----
#### 語法
```javascript=
if (condition1)
statement1
else if (condition2)
statement2
else if (condition3)
statement3
...
else
statementN
```
----
### 三元運算子
```javascript=
condition ? exprIfTrue : exprIfFalse
```
#### 範例
```javascript=
let a = true ? "apple" : "pineapple";
console.log(a); //apple
```
---
## for and while
----
### for迴圈
```javascript=
for (let i = 0; i < 5; i++) {
console.log(i);
}
```
### while迴圈
```javascript=
let i = 0;
while (i < 5) {
console.log(i);
i++;
}
```
---
## function
----
### 語法
```javascript=
// 第一種
function functionName(parameter1, parameter2, ...) {
// statements
return value;
}
// 第二種
let functionName = function(parameter1, parameter2, ...) {
// statements
return value;
}
```
----
```javascript=
// 箭頭函式
let functionName = (parameter1, parameter2, ...) => {
// statements
return value;
}
// 如果只有一個參數的話
// 括號可以省略
let functionName = x => {
}
```
[延伸閱讀-JS的this](https://blog.techbridge.cc/2019/02/23/javascript-this/)
---
## array
----
### 語法
```javascript=
let a = ["Apple", "Banana", "Pineapple"];
let b = [1, 2, 3];
let c = [4, "Berry", true];
```
----
### 想把東西丟進去?
```javascript=
let a = [1, 2, 3];
// 從尾端
a.push(4) // [1, 2, 3, 4]
// 從開頭
a.unshift(5); // [5, 1, 2, 3, 4]
```
----
### 那想拿出來呢
```javascript=
let a = [1, 2, 3, 4];
// 從尾端
a.pop() // 4
// 從開頭
a.shift(); // 1
```
---
## object
----
### 語法
```javascript=
let obj = {
key1: value1,
key2: value2,
...
};
```
----
```javascript=
let person = {
name: "Min",
country: "Taiwan",
gender: "male",
};
// 取得物件裡的值
person.name
person["name"] // Min
// 修改物件裡的值
person.name = "FKT"
person["name"] = "FKT"
console.log(person.name) //FKT
```
----
```javascript=
// 在物件裡新增屬性
person.department = "資管系"
person["department"] = "資管系"
console.log(person)
// {
// name: "FKT",
// country: "Taiwan",
// gender: "male",
// department: "資管系",
// };
```
---
## 進階篇
----
## 高階函式
----
### forEach
```javascript=
const fruits = ['Apple', 'Pineapple', 'Cherry'];
// forEach
fruits.forEach(function(item) {
console.log(item);
});
// 等於
for (let i = 0; i < fruits.length; i++) {
const item = fruits[i];
console.log(item);
}
```
----
### map
```javascript=
let numList = [1, 2, 3, 4, 5];
// map會回傳一個陣列
let array = numList.map(function (item) {
return item + 1;
});
// [2, 3, 4, 5, 6]
// 等於
let array = [];
for (let i = 0; i < numList.length; i++) {
const item = numList[i];
array.push(item + 1);
}
```
----
### filter
```javascript=
const words = ["spray", "limit", "elite", "exuberant", "destruction", "present", "happy"];
let longWords = words.filter(word => word.length > 6);
// ["exuberant", "destruction", "present"]
// 等於
let longWords = [];
for (let i = 0; i < words.length; i++){
const word = words[i];
if (word.length > 6){
longWords.push(word);
}
}
```
---
## Spread Operator & <br />Rest Operator
----
### Spread Operator
把一個陣列展開成個別的值的速寫語法
```javascript=
const params = [ "hello", true, 7 ]
const other = [ 1, 2, ...params ]
// [ 1, 2, "hello", true, 7 ]
```
```javascript=
function sum(a, b, c) {
return a + b + c
}
const args = [1, 2, 3]
sum(…args) // 6
```
----
### Rest Operator
收集其餘的(剩餘的)這些值,轉變成一個陣列。它會用在函式定義的傳入參數識別名定義(其餘參數, Rest parameters),以及解構賦值時
----
```javascript=
function test(...numbers) {
console.log(numbers)
}
test(1) // [1]
test(1, 2, 3, 4, 5) // [1, 2, 3, 4, 5]
function aFunc(x, ...y){
console.log('x =', x, ', y = ' , y)
}
aFunc(1,2,3) //x = 1, y = [2, 3]
aFunc() //x = undefined, y = []
```
其餘參數在傳入參數定義中,只能位於最後一位,
並且在參數中只能有一個其餘參數。
---
## 解構賦值
----
### 陣列解構
```javascript=
const x = [1, 2, 3, 4, 5];
const [y, z] = x;
console.log(y); // 1
console.log(z); // 2
// 結合rest operator
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]
```
----
### 物件解構
```javascript=
const person = {
name: "Min",
studentID: "B10923012",
skills: {
frontend: ["HTML", "JS", "CSS"],
backend: ["flask", "express", "docker"]
}
};
const { studentID } = person; // "B10923012"
const { skills: { frontend } } = person;
// ["HTML", "JS", "CSS"]
```
---
## 模板語法
----
### 語法
用「\`」括起來,就可以使用 ${...} 來加入變數或函式
```javascript=
let firstName = "John";
let lastName = "Doe";
let text = `Welcome ${firstName}, ${lastName}!`;
```
---
## 補充說明
這部分可以先跳過,有興趣再聽,後面有練習題可以先寫
----
## var && let
前面說過var的作用域是函式(function),而let是區塊(block)。
那作用域到底是什麼呢
----
```javascript=
{ // block
var a = "apple";
let b = "banana";
console.log(a); // apple
console.log(b); // banana
}
console.log(a); // apple
console.log(b); // ReferenceError: b is not defined
```
----
```javascript=
// var
function varTest(){
var i = "Hello World"
console.log(i) // "Hello World"
}
console.log(i); //ReferenceError: i is not defined
// let
function letTest() {
let j = "Hello World"
console.log(j) // "Hello World"
}
console .log(j) //ReferenceError: j is not defined
```
----
### var可以被重複宣告,let會報錯
```javascript=
var a = "123"
var a = "456"
let b = "123"
let b = "456" //SyntaxError: Identifier 'b' has already been declared
```
----
### hoisting(提升)?
----
如果我們試圖對未宣告的變數取值,node會報錯
```javascript=
console.log(a) // ReferenceError: x is not defined
```
----
那如果我們在使用後再宣告呢
```javascript=
console.log(b) //猜猜看結果
var b = 123
console.log(b) //猜猜看結果
```
----
### Answer:
* undefined
* 123
----
在 JavaScript 中,不管你在函數中的哪一行用 var 宣告變數,一律視為在函數的第一行宣告,這個行為就叫做hoisting(提升)。
要注意的是,只有「宣告」這個動作有 hoisting 的特性,賦值 (把值指定給變數) 的動作不會 hoisting。
----
所以剛剛的範例可以看成這樣
```javascript=
var b;
console.log(b);
b = 123;
console.log(b);
```
----
在let裡就有點不一樣了
似乎let不會hoisting...嗎
```javascript=
console.log(b); //ReferenceError: Cannot access 'b' before initialization
let b = 123;
console.log(b);
```
----
### 嗯?
```javascript=
let x = "outer value";
{
console.log(x); //ReferenceError: Cannot access 'x' before initialization
let x = "inner value";
}
```
----
### TDZ(暫時死區)
let/const 中也存在變數提升的,但是他還有另一個概念「暫時死區」,也就是如果在宣告變數之前使用變數,這個變數就是存在「暫時死區」中無法存取!這時候使用它就會報錯 ReferenceError。
----
## 懶人包

---
### 最後ㄉ小練習
[遊戲機制](https://moored-espadrille-379.notion.site/8c99f1cfcdc943d79e3d0b6dff217ab8)
小天玩射擊遊戲,原本積分 7000 分,他想知道經過今天對戰後最後總積分多少,
但是只知道小天今天戰績(名次,擊殺數): (13,1), (1,8), (2,5), (4,3), (1,6)
----
1. 協助小天依照表格(遊戲機制說明),使用 calcScore 函式計算每一場取得的分數
calcScore(13,1) -> 10
calcScore(1,8) -> ?
calcScore(2,5) -> ?
calcScore(4,3) -> ?
calcScore(1,6) -> ?
2. 印出文字 "總共對戰 ... 次,目前總分 ... 分,最後一場排名第 ... 名。"
----
### 附上我寫的範例
```javascript=
let allScore = 7000; //初始分數
// 戰績
let records = [
{ rank: 13, kill: 1 },
{ rank: 1, kill: 8 },
{ rank: 2, kill: 5 },
{ rank: 4, kill: 3 },
{ rank: 1, kill: 6 }
];
function calcScore({ rank, kill }) { //用解構賦值拿出rank跟kill
//如果人數大於6則以6計算
const maxKill = kill > 6 ? 6 : kill;
// 基本的分數加成
let bonus = 10;
if (rank === 1) {
bonus = 25;
} else if (rank === 2 || rank === 3) {
bonus = 20;
} else if (rank === 4 || rank === 5) {
bonus = 15;
} else if (rank >= 6 && rank <= 10) {
bonus = 12;
}
// 算出得分
return maxKill * bonus;
}
for (let i = 0; i < records.length; i++) {
// 計算分數並加上
allScore += calcScore(records[i]);
}
console.log(
`總共對戰 ${records.length} 次,目前總分 ${allScore} 分,最後一場排名第 ${records[records.length - 1]["rank"]} 名。`
);
```
---
## 延伸閱讀
[重新認識 JavaScript](https://ithelp.ithome.com.tw/users/20065504/ironman/1259)
[JS模組化](https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part4/module_system.html)
[NodeJS入門](https://ithelp.ithome.com.tw/users/20103526/ironman/1081)
---
## 結束~~~
記得禮拜五18:00-18:30在茶道教室(GA242)集合ㄛ
{"metaMigratedAt":"2023-06-16T15:52:32.559Z","metaMigratedFrom":"YAML","title":"RE:從0開始的JS","breaks":true,"slideOptions":"{\"transition\":\"slide\"}","contributors":"[{\"id\":\"cfefc38e-571b-4baa-8dd1-9a75490e7f5f\",\"add\":11572,\"del\":1782}]"}