---
# System prepended metadata

title: JavaScript Basics
tags: [code]

---

# CH5 JS Basics
javascript最初創建的目的是為了**讓網頁活起來**，這種語言的程序稱為腳本(script)。javascript可以直接被寫在html，並在頁面加載時自動運行。

Vanilla JavaScript: 純javascript，而不需要任何而外的library(eg. jQuery)或框架。
每個瀏覽器有自己的js引擎，用來讀取並編譯js程式碼，若要確認某個瀏覽器的js引擎是否有支援某種功能，可參考 https://caniuse.com

## `<script>`放哪裡?
通常放在html的最下方，與CSS`<link>`不同，因為將js放在HTML正文的底部時，他會在任何js之前讓html, CSS有時間加載。`<script>`被放在HTML最下方所以是最後才會被加載。

先讓瀏覽器加載HTML, CSS，用戶不用等JS被解析完成，即可在網頁中看到某些內容，比較容易將使用者留下。

## 常見javascript函數
`console.log()` -- 將message輸出到控制台
`window.alert()` -- 提醒框
`window.prompt()` -- 有輸入格的提醒框
```javascript
let user_name=window.prompt("type your name");
window.alert("hihi" + user_name);
```
## Lexical Structure
自然語言(Natural Language): 
1. 語法/文法grammar
2. vocab

程式語言(Programming Language)
1. 語法syntax
2. 保留字reserved word

Lexical Structure是一組基本規則(syntax)。
1. Case Sensitive: js的大小寫有差別
2. 空白、換行會被忽略: minification(刪除空白鍵、換行鍵)
3. 註解: ```// 單行註解```、`/*多行註解*/`
4. 變數名稱需要由文字、underscore`_`、dollar sign`$`當開頭
5. js內部有關鍵字(reserved word, keyword)不能當變數名稱
6. js使用Unicode字元集合，所以string內部可由任何Unicode文字組成
7. Semicolons`;`用來分隔程式語句，在js中可用可不用

## 變數與賦值
* 變數varible
* 賦值assignment

PS. 語法糖syntax sugar支援x=x+1更改為x+=1

### 宣告變數declare varible
1. 若數值的值會變動，使用`let`宣告
2. 若數值不會驗動，則使用`const`(constants常數)來宣告變數
3. 不要使用var宣告變數

需注意的規則: 
1. 用const宣告變數，一定要馬上給予初始值(initializer)。若用let宣告變數但還沒賦值，則變數的值是`undefined`
2. 用const, let宣告的變數不能重複宣告(redeclaration)
3. const不能重複賦值(reassignment)

PS.JS引擎中有一個稱為garbage collector的後台程式，來監視所有物件並刪除那些變得無法訪問的object

## 數據(資料)類型data type
==7種基本數據類型(primitive data type)==
1. Number -- 整數與帶小數點的數字
2. BigInt -- 任意長度的整數
3. String -- 字符串
4. Boolean -- true, false
5. null -- 用來代表某個故意不存在的值
6. undefined -- 未被賦值的變數
7. symbol -- unique identifier

PS.第八種數據類型為object，屬於non-primitive data type，可能為array, object, function...

### Number
允許精確地表示介於2^(-253)和2^(253)之間的所有整數。如果使用大於此的整數值，可能會丟失數字的精度。
> JS處理有小數值的方式是採用double-precision 64bit binary format IEEE754 encoding

支援的運算符號: `+`,`-`,`*`,`/`,remainder(餘數) operator`%`(mod),exponentiation(指數) operator`**`,`++`,`--`,`+=`,`-=`,`/=`,`*=`
[x++, ++x差異](https://dev.to/yubo0826/x-x-chai-bie-yu-qi-zhong-de-han-yi-3e21)
### String
1. 在JS中可使用單引號或雙引號。
2. 兩個string的串接(concatenation)由`+`所完成的。
3. 不能做`-`,`*`,`/`的運算，若嘗試此類運算，因JS還是會嘗試算出某個值的結果，但兩個operand的值都不是數字，無法算出一個數字結果，結果會是`NaN`(Not a Number)。
4. `\n`換行

js是弱型別語言，會在背地裡將該變數轉換成可以被執行的資料型態，強行去執行。
```javascript
20+30+'string' //output: 50string
20+30+'string'+10+15 //output: 50string1015
```

### Number Methods
* `toString()` -- return一個數字的string
```javascript
//x is a number(x is an object)
let x = 27;

//對x來說，toString()是一個method or function
console.log(x.toString()+27); //output: 2727
console.log(typeof x); //number
```
* `toFixd(n)` -- return被轉換的數字，到小數第n位數
```javascript
let pi = 3.141592653589;
console.log(pi.toFixed(2)); //output: 3.14
console.log(typeof pi); //number
```
二進制不能精確地表示所有小數，這可能會導致意外結果，eg. `0.1+0.2 === 0.3` return false

#### String Attrubutes and Methods
[string](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/String)
* `length` -- return string長度(string的屬性)
* `[n]` -- return index第n項的字(index從0開始計算)，`str.length-1`為最後一個字的index
* `slice(indexStart[, indexEnd])` -- 提取字串的一部分作為新的string返回，而不修改原始的字串，indexStart是inclusive(會被包含)，indexEnd可不填，exclusive(不會被包含)
* `indexOf(substring)` -- return substring的第一個index位置，若找不到則return -1
* `toUpperCase()` -- return轉換為大寫的string，不會影響到string本身
* `toLowerCase()` -- return轉換為小寫的string，不會影響到string本身
* `splite(pattern)` -- return 透過搜索將一個字串以pattern分成一個有序的array，pattern可以是regular expression(正規表達式)
* `startsWith(s)` -- 確定string是否以指定字串s開頭，根據需要回傳true或false
* `endsWith(s)` -- 與`startsWith(s)`同，但確認結尾
* `includes(str)` -- return true如果string內部包含str
* `charCodeAt(n)` -- return int between 0 and 65535，表示給定index的UTF-16 code unit
常見編碼方式: ASCII

### Boolean
true, false
Unary(單一) operator`!`可以將boolean的值反轉

### Undefined & Null
#### undefined
1. 已宣告變數，卻沒有賦予initializer時，會出現undefined。
2. functions預設的return value為undefined。
#### Null
用來代表某個故意不存在的值

## JavaScript operators
運算元(operand)、運算符(operator)，eg. a+b, `a` `b` are operands, `+` is an operator
* assignment operator
* comparison operator
* logical operator
* typeof operator(unary)
* negation operator `!`
* increment operator `x++`, `x--`
* bitwise operator
* srithmetic operator `+`,`+=`,`-=`, ...

### Comparison Operators
js的comparuison operators的運算元是兩個任意資料型態，運算結果為boolean值
* `==` -- return true if operands are equal
* `!=`
* `===` -- return true if operands are equal and of the same data type
* `!==`
* `>`, ...

### Logical Operators
operands為任意資料型態，且運算結果為boolean

![image](https://hackmd.io/_uploads/HkSNT-xUa.png)

### Bitwise Operators
在decimal系統中，可用的數字集合是`{0,1,2,3,4,5,6,7,8,9}`，由於在9之後就沒有數字可用了，因此使用2位數來標記下一個數字。
在binary系統中，可用的數字集合是`{0,1}`，在1之後則需要進位來代表下一個數字 => 0,1,10,11,100,101,110,111,...

|binary |0|1|10|11|100|101|110|111|1000|
|-------|-|-|- |- | - | - | - | - | -- |
|decimal|0|1|2 |3 | 4 | 5 | 6 | 7 | 8  |

若要把二進制的數字轉換成十進制，公式為: (數學歸納法)
![image](https://hackmd.io/_uploads/H1P-yflL6.png)
[binary to decimal](https://www.rapidtables.com/convert/number/binary-to-decimal.html)

js的bitwise(每兩個bit) operators將數字operand視為32bits的數字(binary)，並且對每個bit進行運算。
bit -- binary digit
`
let a = 10, b = 9;`
* `a&b` -- 在兩個operand的對應位都是1的位置返回一個1 (AND)
```javascript
console.log(a&b); // 8
a=1010
b=1001
> 1000
```
* `a|b` -- 在兩個operand的對應位都是0的位置返回一個0 (OR)
```javascript
console.log(a&b); // 11
a=1010
b=1001
> 1011
```
* `a^b` -- 在兩個operand的對應位相同的每個位置返回0 (XOR)
```javascript
console.log(a&b); // 3
a=1010
b=1001
> 0011
```
* `~a` -- 反轉operand的每個bit
```javascript
console.log(~a); // 5, js顯示-11是因為tools component?的問題(學CPU才會知道，可忽略)
a=1010
> 0101
```
* `a<<b` -- 將二進制表示中的a向**左**移動b位制，丟棄任何被移出的bit
```javascript
console.log(a<<1); //20
a=1010 所有都向左移動一格，右邊補0
> 10100
```
* `a>>b` -- 將二進制表示中的a向**右**移動b位制，丟棄任何被移出的bit
```javascript
console.log(a>>1); //5
a=1010 所有都向右移動一格，最後的0丟棄
> 101
```

#### 何時會用到Bitwise Operators?
:::info
* 編碼運算
* 資料傳出，sockets programming, ports
* 資料加密、SHA函數
* 作業系統、CPU
* Finite State Machine
* Graphics(eg. 影像處理、人工智能)
:::
## if statement
if是最簡單的決策語句
`if(condition)statement;`
```javascript
if(condition 1){
    statement 1;
}esle if(condition 2){
    statement 2;
}esle{
    statement 3;
}
```

### Tyuthy and Falsy Values
在javaScript中，每個值(data type)在boolean context之下，都可以被視為true或false。在boolean context之下，js會自動做type coercion，常見的boolean context:
1. if statement
2. logical operators運算
3. others

js中的Falsy Values:
* false
* 0, -0, 0n(BitInt)
* "", '', `` ("".length=0)
* null
* undefined
* NaN
除此之外的都是Truthy Values，包含[] empty array, {} empty object...等

## ==Coding Convention(習慣) and Restrictions==
### coding convention:
1. 變數與函數的名稱全部小寫，若由2個以上的單字組成，則使用camelCase或用underline
[常見重點整理 - 命名慣例 & 開發時注意事項](https://hackmd.io/@Heidi-Liu/note-common)
2. operators前後加空白鍵
3. 用分號結束一個簡單的statement
4. Constants都使用大寫
5. Class由大寫字母開頭

### coding restrictions:
1. 變數、函數名稱不可由數字開頭
2. 變數、函數名稱不可包含Hyphen`-`
3. 變數、函數名稱不可使用reserved words

# CH6 JS Basics 2
## function 函式(method 方法)
### 數學函數
函數應該只返回一個值
`f(x)=3x+6`，x為參數(parameter)
`f(5)`，5為自變數(argument)

### javascript function
[Functions](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Functions)
declare a function
```javascript
// declaration, definition
function FuncName(para){
    statements
    return result;
}

//function exection, Invoke a function, function invocation, call a function
//調用function
FuncName();
```

若無return語句，則return undefined(js的function默認的return value)
```javascript
undefined + undefined //NaN
```
```javascript
function convertor(c){
    return c * 1.8 + 32;
}
let input = Number(prompt("請輸入溫度(C)"));
let result = convertor(input);
alert("換算後的溫度為" + result + "F");
```
每個js function實際上都是一個object(有instance properties, instance methods)

## Array 陣列
array不是primitive data type，可儲存用途或性質相近的資料
`let arr = []`
1. js array可以調整大小，且可包含不同資料型態 `srr = [1, 'A']`
2. js array中的元素必須使用非負整數作為index
3. js array的第一個元素為0，最後一個為array.length-1
4. js array會複製reference
```javascript
let friends = ['gracr', 'mike', 'spencer'];
let anotherVar = friends; // 複製reference
anotherVar[0] = 'michael';

console.log('friends arr: ');
console.log(friends) // 'michael', 'mike', 'spencer'
console.log('anotherVar arr: ');
console.log(anotherVar); // 'michael', 'mike', 'spencer'
```
### Array Instance Properties
* `.length`
### 常見的Array Instance Methods
* `push(element)` -- 將一個或多個元素添加到array的末尾，並return array的新長度
* `pop()` -- 從array中刪除最後一個元素並return該刪除的元素
* `shift()` -- 從array中刪除第一個元素並return該刪除的元素
* `unshift(element)` -- 將一個或多個元素添加到array的開頭，並return array的新長度

當array內部的元素還有array時，稱為array of arrays
```javascript
let myArr = [['name', 'address', 'age'], ['mike', 'taiwan', 35], ['john', 'us', 26]];
console.log(myArr[1][0]); // mike
```

## <補充>==primitive data type vs. reference data type==
> RAM(Random-access memory, 記憶體)
### primitive data type
copy by value
```javascript
let deposit = 500; //在RAM找到一個位置存取deposit=500
let anotherDeposit = deposit; //找到另一個位置存取anotherDeposit
anotherDeposit = 600; // anotherDeposit = 600
console.log('deposit: ' + deposit + ', anotherDeposit: '+anotherDeposit); 
// deposit: 500, anotherDeposit: 600
```
### reference data type
copy by reference，for 減少記憶體占用, OOP(物件導向程式設計)

```javascript
let friends = ['a', 'b', 'c']; // 將friends指向a, b, c的位置
let another = friends; // 將friensds的位置給another
another[0] = 'd'; // 將'a'位置的值改成'd'
```

### `==` 差異
```javascript
let x = 10;
let y = 10;
// x, y各指向不同的RAM位置且值=10
// 因為x, y是primitive data type，因此比較時js會比較指向RAM位置的值
console.log(x == y); // true
```

```javascript
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
// arr1, arr2分別指向RAM不同位置的[1, 2, 3]
// 因為arr1, arr2是reference data type，因此比較時js會比較指向的RAM位置
console.log(arr1 == arr2); // false
```

## Function的時間複雜度
在CS中演算法的時間複雜度(Time complexity)可以描述該演算法執行時間，常用`O`(Big O Notation)表示，不包括函式的低階項和首項係數。
* 橫軸(x)為參數大小，縱軸(y)為執行時間
* `f(n)=5n^3 + 3n` -> 不包括函式的低階項(`3n`)和首項係數(`5`) -> 時間複雜度=`O(n^3)`

為了計算時間複雜度，通常會估計演算法的操作單元數量，每個單元執行的時間都是相同的。

時間複雜度: 在參數逐漸變大的形況下，function執行完畢所需要的時間的成長速度。

### Function的時間複雜度
js陣列常見Method的時間複雜度:
* `push` -- O(1) (參數的成長和所需完成的時間無關)
* `pop` -- O(1)
* `shift` -- O(n) (把前面的元素去掉，後面所有的元素往前移一格)
* `unshift` -- O(n)

每個js引擎內部對於陣列的實現方法略有差異，對於不同大小的陣列，可能會使用其他更好的資料結構，eg. double-linked list, binary search tree(BST)。

### Big O Notation Formal Definition
![image](https://hackmd.io/_uploads/HJsG8qILa.png)

## Object 物件
1. 每個js的物件都有properties, method
2. 屬於物件的function被稱為method
3. 物件的屬性與相對應的值是一種key-value repair
4. 獲取物件的方式可以透過dot notation或`[]`
5. js object是一種hashtable雜湊表(O(1))
```javascript
let obj = {
    first_name: "Wilson",
    last_name: "Ren",
    age: 26,
    is_married: true,
    spouse: "Grace",

    sayHi() {
        console.log(this.first_name + " says Hi");
    },

    walk() {
        console.log(this.first_name + " is walking...");
    },

    speak(words) {
        console.log(this.first_name + " says " + words);
    },
};

console.log(obj.first_name); // dot notation
console.log(obj["first_name"]); // []
obj.sayHi();
obj.speak("Happy");
```
6. `this`指的是調用該方法的物件，若某個function沒有調用該function的物件，則`this`是指向global物件(在瀏覽器中指的是window物件)
```javascript
function hello() {
    console.log("hello");
    console.log(this);
}
hello();
```
7. 在js中function, array都是object (special type of objects)
```javascript
function hello() {
    console.log("hello");
}
console.log(typeof hello); // function
console.log(typeof [1, 2, 3]); // object -> bug
```
[Array.isArray()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)

## Loop 迴圈
重複做某件事，`while loop`, `do while loop`, `for loop`，若把`return`放到loop內部，循環會馬上停止。

### for loop
1. initialization: declare循環開始前的計數器變數
2. final expression: 每次循環迭代結束時要執行的程式碼，一般用於更新或遞增計數器變數
```javascript
// initialization: declare循環開始前的計數器變數
for(initialization; condition; final expression){
    ...
};
```
### while loop
若忘記加計數器而導致while loop無限循環，電腦CPU可能會癱瘓
* 適合不知道loop要執行幾次的時候
```javascript
while (condition){
    ...
};
```
### do while loop
該循環指定的statement，直到條件=false
* 先執行語句後再評估條件
```javascript
do{
    ...
} while();
```

### Nested Loop 巢狀迴圈
在loop內部還有另一個loop的情況

### break, continue
* `break` -- 終止迴圈，如果在Nested Loop中使用，只會終止使用包含`break`的loop，若需要終止Nested loop，則需要使用`return`
* `continue` -- 跳過`continue`之後的循環內code，強制執行循環的下一次迭代

### loop跑array
```javascript
let arr = ["Mike", "Grace", "Json"];

for(let i = 0; i < arr.length; i++){
    console.log(arr[i] + " is my friend.");
}
```

## 練習
### 終極密碼
```javascript
let ans, startNum, endNum, isFlag = true;

function init() {
    // 0 <= Math.random < 1
    // 0 <= Math.floor(Math.random * 100) < 1
    ans = Math.floor(Math.random() * 100);
    startNum = 0;
    endNum = 99;
}

while (isFlag) {
    init();
    while (true) {
        let yourNum = prompt("請輸入你的猜測(" + startNum.toString() + "~" + endNum.toString() + ")");
        if (yourNum < startNum || yourNum > endNum) {
            alert("無效猜測，請重新猜測一個數字");
            continue;
        }
        if (yourNum == ans) {
            isFlag = confirm("猜對了，秘密數字是" + yourNum + "! 還要繼續嗎?");
            break;
        } else if (yourNum < ans) {
            startNum = yourNum;
        } else {
            endNum = yourNum;
        }
    }
}
```

### 反轉陣列
將一個array內部的所有元素反過來!
(禁止使用Array.prototype.reverse()。另外，考慮時間複雜度，需要在O(n)內，不能是O(n^2))
例如:
`const friends = ["Harry", "Ron", "Snap", "Mike", "Grace"];`
會變成
`["Grace", "Mike", "Snap","Ron","Harry"];`

```javascript
const friends = ["Harry", "Ron", "Snap", "Mike", "Grace"];
let a = 0, b = friends.length - 1;
 
while (a < b) {
    let tmp;
    tmp = friends[a];
    friends[a] = friends[b];
    friends[b] = tmp;
    a++;
    b--;
}
console.log(friends)
```
```javascript
const friends = ["Harry", "Ron", "Snap", "Mike", "Grace"];
const reversed_friends = [];

for (let i = friends.length - 1; i >= 0; i--) {
    reversed_friends.push(friends[i]);
}
```
### 找出最大值
在這個coding練習裡面，你要寫一個函式，他可以接受一個parameter，參數是一個array of numbers。這個函式要return一個值，也就是Array當中最大的數! 若是 input是一個 empty array，則return undefined。例如：
```javascript
findBiggest([15, 20, 22, 16, 7]); // return 22
findBiggest([1, 2, 3, 4, 5, 999]); // return 999
findBiggest([-11, 0, -3, -4, -5, -999]); // return 0
findBiggest([]); // return undefined
```

```javascript
function findBiggest(arr) {
    console.log('start:' + arr)
    if (arr.length == 0) {
        return undefined;
    }
    let max = arr[0];
    for (let i = 0; i < arr.length; i++) {
        console.log("compare(max, arr[i]): " + "(" + max + "," + arr[i] + ")")
        if (max < arr[i]) {
            console.log('change: max' + arr[i])
            max = arr[i];
        }
    }
    return max;
}
```
### 數值加總
addUpTo() 這個函式有大於0的參數 n，n為一個正整數。 addUpTo() 要 return 1 + 2 + 3 + ..... + n 的值。
例如:
```javascript
// addUpTo(5) = 1 + 2 + 3 + 4+ 5 = 15
// addUpTo(100) = 1 + 2 + 3 + 4 + 5 + ....... + 100 = 5050

addUpTo(5); // 15
addUpTo(100); // 5050
addUpTo(5000); // 12502500
addUpTo(100000); // 5000050000
```
```javascript
function addUpTo(num) {
    let sum = 0;
    for (let i = 1; i <= num; i++) {
        sum += i;
    }
    return sum;
}
```

# 程式練習題
[題目連結](https://www.notion.so/yuhsien/179caa9730284da48b0a6df66886a447)

# CH7 Document Object Model (DOM)
## DOM & Window Object
文件物件模型(DOM)是HTML的程式介面，允許在JS當中操作HTML元素。
* DOM提供了一個文件的結構化(Tree)表示法，讓程式可以存取並改變文件架構、風和、內容。
* DOM提供了文件已擁有屬性與函式的節點與物件組成的結構化表示。
    * 節點可以附加事件處理程序，一旦樹發事件就會執行處理程序。
* 本質上，他將網頁與腳本或程式語言連在一起。

### Window Object
`this` -- 1. JS物件method 2. window object

`window.alert()` -- alert function is a method of window object
`window.prompt()`
`window.addEventListen()` -- 將事件監聽程式碼附加到window object
`window.setInterval()` -- 每次經過給定的毫秒數時安排一個函數執行
`window.clearInterval()` -- 將`setInterval()`所重複執行的程式暫停
> window object用的時候可以省略window
```javascript
function sayHelloToUser() {
    alert("3秒過了...")
}

let interval = window.setInterval(sayHelloToUser, 30000);
window.clearInterval(interval);
```

> 物件導向程式概念: 一個object可以是另一個object的attribute。
```javascript
let Grace = {
    name: "Grace",
    age: 20
};
let Wilson = {
    name: "Wilson",
    age: 25,
    spouse: Grace
};
console.log(Wilson.spouse.age); // 20
```

Window Object可使用的常見properties: 
* `window.console` -- retun一個concole object，可以對瀏覽器的debugging console進行控制與訪問。常用的method為`log()`, `error()`
* `window.document` -- return window包含的文檔(HTML document object)，也就是html文件
* `window.localStorage` -- return一個local stage物件
* `window.sessionStorage` -- return一個session stage物件

### Document Object Model
從DOM可知HTML也被視為是個物件。這個架構被稱之為是Model。
1. doucument是一個object，是window object的一個屬性
2. doucument是指HTML doucument
3. 這個模型意味著所有doucument內部的HTML元素都是object (每個HTM tag都有其屬性和方法)

每個點都是一個節點(node)
![image](https://hackmd.io/_uploads/BJ7pQ5FIp.png)

## get element by id or class
在DOM這棵樹上，每個點被稱為節點(nodes)，分為三種: 
1. HTML元素節點(element nodes or element object)
2. 文字節點(text node)
3. 註解節點(comment node)

DOM提供2種節點集合(not array): 
1. HTML collection (only element nodes)
2. NodeList (所有3種nodes)

## Document object
Document object指的是`window.document`下的屬性，常見的method: 
> 注意回傳的data type
* `window.document.addEventListener()`
* `window.document.createElement(tagName)`
* `window.document.getElementById(id)` -- return第一個id相符合的element object
* `window.document.getElementByClassName(className)` -- return一個動態的HTML collection，內部元素包含所有給定className的元素
* `querySelector(selectors)` -- return document第一個符合特定選擇器群組的element object，採用深度優先搜尋演算法
    * 深度優先搜尋演算法: 走得越深越好，逐一走過每個tag去尋找
* `querySelectorAll(selectors)` -- return一個靜態(not live) NodeList，表示與指定選擇器組匹配的元素列表

> querySelector在現在的專案中比較常使用，使用CSS的selector
> CSS selector: id - `#id`, class - `.class`

### HTML collection & NodeList
注意: HTML collection, NodeList are not array (cannot use `pop`, ...)

#### HTML collection
是一種array-like object
[HTMLCollection](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection) -- 動態 dynamtic，會因為DOM改變而length會跟著改變
#### NodeList
[NodeList](https://developer.mozilla.org/zh-TW/docs/Web/API/NodeList) -- 靜態 static，不會因為DOM改變而length會跟著改變，改變DOM之後再重新取得一次

### 差別比較
#### ==childNodes & children==
Element Object是三種節點的其中一種
* 每個節點Node有`childNodes`屬性，return type為NodeList，包含了此節點在DOM Tree之下的第一層的所有節點
* 每個Element Object有`children`屬性，return type為HTML collection，包含了此節點在DOM Tree之下的第一層的所有HTML Object

Element Object這種node可以使用`childNodes`&`children`屬性，但另外兩種nodes(text, comment)只有能夠使用`childNodes`，若使用`children`則return `undefined`。

#### JS取得html元素方法
| Methods                      | return type                              |
| ---------------------------- |:---------------------------------------- |
| getElementById(id)           | Element object                           |
| getElementByClassName(class) | HTMLCollection(內部元素為Element object) |
| querySelect(selector)        | Element object                           |
| querySelectAll(selector)     | NodeList(內部元素為Nodes)                |

#### NodeList vs HTMLCollection
![image](https://hackmd.io/_uploads/SJRSNjFU6.png)

```javascript
let hellos = document.querySelectorAll(".hello");
hellos.forEach((hello) => {
    console.log(hello);
})

let helloss = document.getElementsByClassName("hello");
helloss.forEach((hello) => {
    console.log(hello); // Uncaught TypeError: helloss.forEach is not a function
})
```

## Function Declaration & Expression
在JS中定義function有兩種方式: 
* Declaration -- `function funcName (para){}`
* Expression -- `function (para){}`，省略function name來創建匿名函數

### Function Expression用途
* 定義沒有名稱的函數放入變數中，讓程式碼更有彈性。PS.與Declaration幾乎沒有區別，但若使用Declaration，可在定義函數前使用該function
```javascript
let Wilson = {
    name: "Wilson",
    greet() {
        console.log(this.name + "打招呼")
    },
    walk: function () {
        console.log(this.name + "正在走路")
    }
};
console.log(Wilson.walk()); //Function Expression
console.log(Wilson.greet());
```

* 作為higher order function的callback function使用，ex. forEach, addEventListener
> higher order function: 在function中放入function，A(B)，A: higher order function

優點: 
1. 若程式碼有許多callback function都是使用function declaration，命名變數時都需要避開function declaration
2. callback function名稱其實沒有意義
3. 程式碼變乾淨
```javascript
function react() {
    alert("有人正在點擊畫面");
}
// parameter 1: 是哪個event
// parameter 2: 事件發生後，我們要執行的function
// addEventListener 本身是一個higher order function
// react是一個callback function
window.addEventListener("click", react);

// Function Expression
window.addEventListener("click", function () {
    alert("有人正在點擊畫面");
});
```

* 使用IIFE(Immediately Involied Function Expression)的功能

在伺服器的程式碼可以使用(打開後就立即要執行)
```javascript
(function (a, b) {
    console.log(a + b);
})(10, 5);
```

### Arrow Function Expression
JS中的函數是first-class object(一等公民)，可以: 
1. 將function分配給變數: `let hello = function(){};`
2. 將function當作argument傳給其他function(=數學的composite function)。higher order function的argument被稱為callback function。

在許多情況下，若要把function當作argument傳給其他function，那麼對此函數命名則變的沒有意義，建議使用function expression。JA中Arrow Function Expression是function expression的簡化語法。

* `() => ...`
```javascript
() => {
    console.log("hello");
}
let Wilson = {
    name: "Wilson",
    greet() {
        console.log(this.name + "打招呼")
    },
    // arrow function express沒有this keyword綁定
    walk: () => {
        console.log(this); // {} 空物件
        console.log(this.name); // undefined
        console.log("Wilson is walking....");
    }
};
```
* `param => ...`
* `(param1, param2, ...) => ...`

#### 總結 
1. 若有一個參數，則不需要加括號；若有0或2 up的參數，則需要加括號
2. ...(expression)無加大括號(curly brackets)，會自動return (only一個計算式)
```javascript
let num1 = () => 15; // 15
let num2 = () => { 15 }; // undefined
let num3 = () => { return 15 }; // 15

let addition1 = (a, b) => a + b;
console.log(addition1(10, 30)); // 30

let addition2 = (a, b) => {
    let pi = 3.14;
    return a * b * pi;

};
console.log(addition2(10, 30)); // 30
```
3. **Arrow Function Expression沒有this關鍵字綁定，不應該用作objects的method**

### forEach() Method
forEach()為higher order function，與arrow function expression協作為: 
* `forEach(element => ...)`
* `forEach(callbackFn)`
* `forEach((element, index) => ...)`
```javascript
let myLuckyNumbers = [1, 2, 3, 4, 5, 6, 7];

// 1. for迴圈
for (let i = 0; i < myLuckyNumbers.length; i++) {
    console(myLuckyNumbers[i] + 3);
}

2. 使用funciton declaration
function plus3(n) {
    console(n + 3);
}
myLuckyNumbers.forEach(plus3);

// 3. 使用function expression創建匿名函數
myLuckyNumbers.forEach(function (n) {
    console(n + 3);
});

// 4. arrow function expression
myLuckyNumbers.forEach((n) => {
    console(n + 3);
});

// 搭配index
myLuckyNumbers.forEach((n, index) => {
    console(n + " is at index " + index);
});
```

## Element objects
在DOM Tree中，每個HTML元素可能有自己獨特的properties和methods，eg. `<video>`, `<h1>`...。
除了各自的properties, methods外，也有共用的properties, methods:
* `addEventListener(event, callbackFn)`
```javascript
let myBtn = document.querySelector("#my-btn");
myBtn.addEventListener("click", () => {
    alert("你點了btn");
})
```
* `appendChild(element)`
```javascript
let body = document.querySelector("body");
let myH1 = document.createElement("h1");
body.appendChild(myH1);
```
* `innerHTML`
* `innerText`
```javascript
let body = document.querySelector("body");
let myH1 = document.createElement("h1");
//innerHTML: 會被當作HTML的程式理解，可以插入tag, innerText: 只會被當作文字
myH1.innerText = "<a>這是我的h1</a>";
myH1.innerHTML = "<a href='https://www.google.com'>這是我的h1</a>";
body.appendChild(myH1);
```
* `children` -- return HTMLcollection
* `childNodes` -- return NodeList
* `parentElement` -- 選取父元素
* `classList` -- element class的列表，可以用的method有`add()`, `remove()`, `toggle()`, `contains()`
    * `toggle()` -- 有屬性的話刪除，沒有的話則加入
    * `contains()` -- 檢查是否有指定的class
* `getAttribute(attributeName)` -- 獲得一個屬性，eg. href
```javascript
<a title="到google首頁" href="https://www.google.com"></a>

let a = document.querySelector("a");
a.getAttribute("title");
a.getAttribute("href");
```
* `querySelector(selector)` -- document object也可以用，但element object使用只找element底下的
* `querySelectorAll(selector)` -- document object也可以用，但element object使用只找element底下的
* `remove()` -- 直接移除此tag (not hidden)
```javascript
<button>讓anchor tag消失</button>
<a title="到google首頁" href="https://www.google.com"></a>

let button = document.querySelector("button");
button.addEventListener("click", ()=>{
    let a = document.querySelector("a");
    a.remove();
})
```
* `style` -- 可以用來改變element object的inline style，因為js中不能使用hyphen`-`，因此JS中的CSS屬性都被更改為cameCase
```javascript
let button = document.querySelector("button");
button.style.backgroundColor = "green";
button.style.color = "white";
button.style = "background-color: green; color: white;";
```

## Inheritance 繼承
可以將attribute, methods從一個class繼承到另一個class。
* subclass(子類), child class -- 從一個class繼承的class
* superclass(父類) -- 繼承自的class
> object B -> object A: B為subclass, A為superclass

優點:
1. 減少code, RAM下降, 提升速度
2. 較好維護

所有的html元素都從element object繼承了peoperties, methods，其中某些HTML元素有自己獨特的peoperties, methods。
![image](https://hackmd.io/_uploads/HywTauWwT.png)

## JavaScript Events
表示一個在DOM物件所發生的事件，事件通常由使用者的操作行為所產生(ex: 調整螢幕大小、點滑鼠、敲鍵盤...)。

`addEventListener(type, listener)` - 等待事件發生，去執行被賦予的func。
* `type`: 事件類型，eg. click, resize...
* `listener`: callback function，被執行時，js會把event object (`e`)當作argument，放進listener執行

```javascript
let button = document.querySelector("button");
button.addEventListener("click", (e)=>{
    console.log(e);
})
```
### JS Event繼承關係
![image](https://hackmd.io/_uploads/B17GrwGPa.png)
[Event reference list MDN](https://developer.mozilla.org/zh-TW/docs/Web/Events#%E4%BA%8B%E4%BB%B6%E5%88%86%E9%A1%9E)
```javascript
window.addEventListener("keydown", (e) => {
    console.log(e); // keycode: 按的鍵
})
```
### event object常用屬性、方法
* `target` -- 指向最初觸發事件的DOM物件
* `preventDefault()` -- 取消事件的預設行為，但部會影響事件的傳遞，事件仍會繼續傳遞
* `stopPropagation()` -- 可以防止event bubbling進一步傳播當前事件
```javascript
<input type="text" />
<input type="number" min="0" max="10" />
<button>交出表單</button>

let button = document.querySelector("button");
button.addEventListener("submit", (e) => {
    e.preventDefault(); // 取消交出表單的預設行為
})
```
## Event Bubbling 冒泡事件
當一個事件發生在一個元素上時，他首先在其上運其event handler，然後運行其parent element的event handler，然後一職網上運行其他祖先的event handler。
> In programming, an event handler is a callback routine that operates asynchronously once an event takes place.

```javascript
<style>
  .a {
    width: 300px;
    height: 300px;
    background-color: red;
  }
  .b {
    width: 150px;
    height: 150px;
    background-color: blue;
  }
</style>
<div class="a">
    <div class="b"></div>
</div>

let a = document.querySelector("a");
let b = document.querySelector("b");

a.addEventListener("click", () => {
    alert("紅色框的事件監聽器正在被執行");
})

b.addEventListener("click", () => {
    e.stopPropagation(); // 防止冒泡事件
    alert("藍色框的事件監聽器正在被執行");
})
```

## Local Storage & Session Storage
Storage是瀏覽器儲存數據的地方，並非database。在Storage內部儲存的數值都是key-value pair，且key, value都會被轉為string。
* Local Storage: 沒有過期的時效
* Session Storage: 用戶關閉瀏覽器後，sessionStorage就會被銷毀

localStorage和sessionStorage使用的methods是一樣的: 
* `setItem(key, value)` -- 當傳遞一個key和value時，會將該key-value pair加到給定的storage，或是該key的值已存在，則更新key的value
* `getItem(key)` -- 給定key取得value，若值不存在，則return `null`
```javascript
localStorage.setItem("name", "wilson");
localStorage.setItem("age", 26);

let myAge = localStorage.getItem("age");
console.log(myAge);
```
* `removeItem(key)` -- 從給定的storage中刪除該key-value pair
* `clear()` -- 清除儲存在給定storage中的所有key-value pair

Storage bind 網址
![image](https://hackmd.io/_uploads/BJBxdOzvT.png)

### JSON
JSON(JavaScript Object Notation)，是一種交換資料的格式。JSON Object有兩個method:
* `JSON.stringify(value)` -- 將value換成JSON String
* `JSON.parse(text)` -- 解析JSON String，製作出JSON String描述的JavaScript值或是Object

array -> JSON.stringify => JSON String
JSON String -> JSON.parse => array
![image](https://hackmd.io/_uploads/HJhn9uMwa.png)
```javascript
let myLuckyNumbers = [1, 2, 3];
localStorage.setItem("myLuckyNumbers", JSON.stringify(myLuckyNumbers));
let myNumber = JSON.parse(localStorage.getItem("myLuckyNumbers"));

console.log(typeof myNumber);
myNumber.forEach(n => {
    console.log(n)
});
```