---
# System prepended metadata

title: JavaScript
tags: [Class]

---

JavaScript
===

變數 variable
===
### 命名法
1. camelCase（myHeroName）
2. snake_case（my_hero_name）


## Hoisting 變數提升（二階段運作）

宣告變數 或 函式宣告都會產生hoisting，只是兩者有些微的不同；而宣告變數區分成var || const/let也有所不同。


```JavaScript=
b();
console.log(a);

var a = 5 ;

function b() {
console.log("Hello")
}

// Hello
// undefined
```
#### 宣告變項：
1. var a =1
    console.log(a)
    * 建立期 a.找名字 b.初始化(給初始值)
    * 執行期 a.執行函數 b.賦值
2. let b =1
    console.log(b)
    * 建立期 a.找名字 ~~b.初始化~~
      TDZ(Temporal Dead Zone暫時死區) 將變數蓋起來
    * 執行期 a.執行函數(將變數的蓋子拿開) b.給值

    ==let是在執行時賦值==
    
#### 函式宣告：
函式建立時，JS會把函式宣告移到作用域頂部，並且可以直接使用。
龍哥：函式在第一階段初始化+給值一起完成。

所以：

```JavaScript=
b();

function b(){
console.log("Hello")
}

// 即便開頭先呼叫b函式，結果一樣是Hello
```


## 流程控制

判斷式可以搭配強制轉型(coercion)的特性；用Boolean()判斷true or false。但要特別留意的地方是 0 也會被強制轉換成false，所以帶入的引數要確定不是 0，不然一樣無法順利執行。

補充：『undefined』 『null』 『+-0』 『''』經過Boolean皆為flase
## if...else...
```javascript
 if("判斷式"){
     console.log( )
 }if else( ){
     console.log( )
 }else( ){
     console.log( )
 }
```
## switch case 
```javascript
 switch( ){
    case 1 :
        console.log( )
    break
    case 2 :
        console.log( )
    break
    default :
        console.log( )
    break
  }
```

### NaN
#### NaN=Not A Number
    如何判斷某個值是NaN

    let a = NaN

    ---JS內建語法--
    if(Number.isNaN(a)){
    console.log("它是NaN")
    }else{
    console.log("它不是NaN")
    }
    // 原isNaN(a)會強制轉換成數字，以Number.isNaN代替
    // 如果瀏覽器不支援的情況下，使用--魔法用法--

    ---魔法用法---
    if(a !== a){
    ==console.log("它是NaN")
    }else{
    console.log("它不是NaN")
    }

## 布林值Boolen (只有 true or false)
#### Js中的 Falsey Value (只會被當false)
- 0 ; -0
- '' ; ""
- NaN
- undefined
- null
- false


## 型別轉換
#### 轉換成‘數字’
    - parseInt( )
    - Number( ) / +( )
#### 轉換成‘文字’
    - toString( )

### == vs === 
: 兩者都會檢查型別
*    console.log(123 == "123"); //ture 鬆散，且會做型別轉換
*    console.log(123 === "123"); //false 嚴格

==使用時機->
皆以三個等號為主;如你知曉兩個值在雙等號時是相同的,則可使用雙等號==
>For Example：
```
let a = undefined
```
>**// 已知undefined 和 null 都是空值，所以可以使用 ==**
  
```
if(a ==null){
    console.log("沒有值")
   } 
```
```
if(a ===undefined || a ===null){
    console.log("沒有值")
   }
```
```
let age = 18
if(age==18){
    console.log("18歲")
}else{
    console.log("不是18歲")
}
```
==一個等號是'指定'，雙等號才是等於==

### ||-> 或者or
### &&->而且and
    邏輯短路 
     x()=10秒 || y()=30秒 
      如x成立，則y有無成立都output
     x()=10秒 && y()=30秒
      除了x成立外，y也得成立才output
 ---     
     可以用來代替if...else...（但新手通常都把|| &&放在判斷式中）
     
    - 當data為空值時
      let data = null
      if(!data){
        console.log("沒有data")
      }
      data || console.log("沒有data") 
      //如data有值則印出data值，反之則印出console.log
      
    - 當data有值時
      let data = 12345
      if(data){
        console.log(data)
      }
      data && console.log(data) 
      //印出12345

### 課堂實作：請輸入年齡
```JS
1 const age = prompt ("How old are you?")
2 console.log ("You are ${age} year-old")
  // 這邊會出現錯誤的地方
  // a. 沒寫，取消->null
  // b. 有寫，空白->''
  // c. 亂寫     ->1~150
```
=更完整寫法=
```Js
1 const age = prompt("How old are you?")
2 const ageNumber = parseInt(age)
3 if(ageNumber > 0 && ageNumber <= 150){
4   console.log("You are ${ageNumber} year-old")
5 }else{
7   console.log("NG")
8 }
```
### REPL=Read-Eval-Print-Loop
讀你的指令-評估後-印出來-再讓你繼續下指令

like：直接在瀏覽器中打1+2 會主動印出3，即便你沒有打console.log

### 三元運算子 ( ) ? XXX : YYY
- if...else...寫法
```javascript
let age=20

if(age>=18){
    console.log("isAdult")
    } else {
        console.log("notAdult")
    }
```
- 三元運算子寫法
```javascript
let age=20
age>=18 ? console.log("isAdult"):console.log("notAdult")

// 如果age大於等於18的話，output"isAdult"否則output"notAdult"
```
迴圈 (for / while)
===
### for 迴圈(起始狀態;結束條件;每回合做的事)
```javascript=
for(let i = 0; i > 10; i++){
    //迴圈中要做的事
}   
```
### while 迴圈
```javascript=
let i = 0  //預設值

while( i < 10 ){  //做到哪
    //迴圈中要做的事
    
    i = i + 1  //增加多少到下一局
}
```

### continue
1. 跳過這回合不執行後面
```javascript
for(let i=0 ;i<10 ;i++){
    
    if(i==5){
        continue
	}
    console.log(i)
} 
// 當遇到i=5的回合時跳過不執行，所以output:0.1.2.3.4.6.7.8.9
```
2. 放最後沒意義
```javascript
for(let i=0; i<10; i++){
    console.log(i)
    if(i % 2 == 1){
        continue
    }
//因為他是用來跳過這個執行,結果你又不寫東西給他，很沒意義
```
### break
1. 舉例一
```javascript
for(let i=0; i<10; i++){
    if(i==5){
        break
    }
    console.log(i)
}
// 遇到5的part停止 output:0.1.2.3.4
```
2. 舉例二
```javascript
for(let i=0; i<10; i++){
    console.log(i)
    if(i==5){
        break
    }
}
// 印完5的part後面都停止不做 output:0.1.2.3.4.5
```
### 總結
```
1. continue視為pass這回合
2. break視為終止執行
3. 兩者都需要在迴圈中使用
```
函數 function
===
### 一般寫法
```javascript
function hi(a){
    console.log(a)
}
hi(a)
```
### 匿名函數 anonymous function
```javascript
const hi = function(){
    console.log(123)
}
hi(a)
```
### 箭頭函數 arrow function
```javascript
const hi = ()=>{
    console.log(123)
}
```
備註
```
以一般寫法來看：
在function中定義的a稱為『參數』
console.log(a)中的a稱為『變數』
而hi(a)中的a稱為『引數』
```
### function會遇到的情況
情況一
```javascript
let a =123
function hi(){
    let a = 456
}
hi()
console.log(a)

// 123 
// 因為let a=456 只會在block中執行，並不會影響到function外的宣告
```
情況二
```javascript
let a=123
function hi(){
  a=666
}
hi()
console.log(a)  

// 666
// 切記！不能亂指定！
// 此情況在function中的a=666執行後，污染到了function外的宣告，因此output:666
```
情況三 （let不能重複宣告,var可以）
```javascript
function hi(a){ //函式已經有a了
  let a=456     //又重複宣告a
  console.log(a)
}
hi(123)

//因為在function中重複宣告了a 所以出現以下錯誤
//Identifier 'a' has already been declared
```
以情況三來看，如果改成
```javascript
let a=123
function hi(a){
  a=456
  console.log(a)
}
hi(123)
console.log(a)

// 456
// 123
```
function中參數為a，所以在行為內的a=456是指，我把行爲中的a都指定為456去計算，所以並不會影響function外的a

### 回傳值 retrun value
> 回傳值：完成函數後所得到的結果
1. 舉例一
```javascript
function hi(){
  console.log(123) //console.log本來就會印出123
 //return undefined,沒有寫回傳值(代表此函數沒結果)
}
console.log(hi())
// 123
//undefined
```
2. 舉例二
```javascript
function hi(){
  return console.log(123)
    //印出123是console.log本來就會做的事 
    //undefined是console.log函數沒有回傳值
}
console.log(hi())
//123
//undefined
```
3. 舉例三
```javascript
//寫法1
function isAdult(age){
  if(age>=18){
    return "ture"
  }else{
    return "false"
  }
}
console.log(isAdult(20))
//ture

//寫法2
function isAdult(age){
  return (age>=18) //使用到布林值ture,false
}
console.log(isAdult(20))
//ture
```

### Scope範圍（要去哪找？）
> const,let = bolck scope 活不出{ }
> var = function scope 活不出函數
1. 舉例一
```javascript
for(let i=0; i<10; i++){
  var a=456 //可執行，block無法關注var
}
console.log(a)
//456

for(let i=0; i<10; i++){
  let a=456 //let活不出{ }
}
console.log(a)
//a is not defined
```
2. 舉例二
```javascript
           //flag通常是用來表示一個布林型的值
function run(flag){
  if(flag){
    let message = "yes" //let活不出block
  }else{
    let message = "no" //let活不出block
  } 
    //上面皆可略過
    console.log(message)
            //沒有message給他印出
}
run(true)
//Message is not defined at run


function run(flag) {
    let message = "No"
    
    if (flag) {
    let message = "YES"; //活不出block
    } 
    
    //直接跳上去看 let message = "No"
    console.log(message);
    //有東西給他印了
}
run(true);
//No


function run(flag) {
  var message = "No" //var活不出function
  if (flag) {
  let message = "YES"; //let活不出block
  } 
}
console.log(message); //沒有message給他去印
run(true);
//message is not defined


function hi(flag){
  var uu=456
    function ha(){
    var message=123 //var活不出function
  }
}
hi()
console.log(message); //沒有message給他去印
//message is not defined
```

### 結合 變數提升概念(往前看note)

**Function Statements隨時呼叫都可以；
Function Expressions不行。如下：**

```javascript
abc()
var abc=function(){
  console.log(123);
}
//因為變數提升 var回傳undefined
//undefined() 不是函式
//TypeError: abc is not a function


abc()
let abc=function(){
    console.log(123);
}
//abc is not defined
//有變數提升  TDZ
//未初始化


abc()
const abc=function(){
    console.log(123);
}
// Cannot access 'abc' before initializatio

```

### 全域變數 window
> 絕對〖 不要 〗不宣告，會污染全域變數

### 嚴格模式 strict mode
> 以字串的形式出現。（因為有些舊系統可能不支援）

陣列Array
===
```javascript=
let a = ["a","b","c"]
    如要抓取"a"值-> console.log(a[0])
    // 0->index索引值(偏移值)
        *參考goodnote筆記page5的圖*
```
  
## 陣列取值
**動態寫法，chars陣列可能會長大**
```javascript
let chars = ["a","b","c","d"]
-> console.log(chars[chars.length-1])
```

## function是“物件”
函數等同變數，只是可被呼叫

> 高級函數(Higher-Order Function,HOF)中的函數可以是匿名函數
> 再想一次函數寫法：
> 1. 一般寫法 function 函數名(參數){return ...}
> 2. 匿名函數 const 名字 = function(參數){return...}
> 3. 箭頭函數 const 名字 = (參數)=>{return...}

### .forEach(function( ))
> 1. 沒有回傳值
> 2. 只幫忙做事，不收結果

舉例
```javascript=
const nums = [1, 2, 3, 4, 5];
// output:[1, 3, 5]
const num = [ ]

nums.forEach((n)=>{
    if(n % 2 !== 0)
        num.push(n) //.forEach()要自己丟進去
    })
console.log(num)
```

### .push(元素1, 元素2..., 元素n)
> 1. 從陣列後面塞進新元素

舉例
```javascript=
const nums = [1, 2, 3, 4, 5];
// output:[1, 3, 5]
const num = [ ]

nums.forEach((n)=>{
    if(n % 2 !== 0)
        num.push(n) //.forEach()要自己丟進去
    })
console.log(num)
```

## .map(function(原陣列的元素, 索引值, 呼叫map方法的陣列 ))
> 1. 收集成新陣列
> 2. 丟進去幾個，就會回傳幾個
> 3. return

舉例
```javascript=
const numbers = [1, 2, 3, 4, 5]
// 每個元素乘以2

const double = numbers.map((n)=>{
   return n * 2  //.map()會直接收集並且回傳
})
console.log(double)

// [2, 4, 6, 8, 10]
```

## .filter(function( ))
> 1. 過濾出要的東西，並組成一個新陣列
> 2. 只做過濾，不改變值

舉例
```javascript=
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 找出奇數
const odd = numbers.filter((n) => {
  return n % 2 !== 0 //如果是ture就留下那個數回傳
})
console.log(odd)

// [1, 3, 5, 7, 9]
```

## .reduce(function(acc, cv) => { } ,0)
> 1. 做規劃、整理
> 2. acc = 累加值 ; cv = 目前值
> 
舉例
```javascript=
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
//加總
const sum = numbers.reduce((acc , cv)=>{
    return acc + cv //第一次的acc+cv會是第二次的acc
 },0) //0為初始值，如不寫則少一跑一圈，但結果不會有變化
console.log(sum)
```
## [.sort( a, b )](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) 對陣列進行排序(由小到大)
> 1. 對陣列進行排列(只會有原陣列中的元素)
> 2. 會帶入compareFn比較回傳值
```javascript=
arr.sort((a, b) => {
  return a - b;  //sort是一個比較函數
})
// a-b>0 ; a大於b -> [b, a]
// a-b<0 ; a小於b -> [a, b]
// a-b=0 ; a,b相等
```
> 3. 如沒有帶入compareFn，則將陣列內的元素轉為字串，並以Unicode進行比較
> 4. undefined會排在非undefined元素前面

## .join( )
> 1. 將所有元素轉為**字串**
> 2. 回傳最終的字串，如arr.length為0，則傳回空字串
> 3. ( )內可以放『 , 』可將最終回傳的字串分開
 
四種不同的方式連接集群：
```javascript=
const a = ["Wind", "Water", "Fire"];

a.join();  //'Wind,Water,Fire'
a.join(", ");  //'Wind, Water, Fire'
a.join(" + ");  //'Wind + Water + Fire'
a.join("");  //'WindWaterFire'
```

## .indexOf( 要找的元素, 從第幾個索引值開始找 )
> 只會回傳第一個找到的位置，如沒有找到變回傳-1

```javascript=
const arr = [1, 2, 3, 4, 5, 3, 2]

const result = arr.indexOf(3)
console.log(result)

// 2
```

## .lastIndexOf( 要找的元素, 從第幾個索引值開始找)
> 只會回傳要找的元素最後的位置，如沒有找到變回傳-1

```javascript=
const arr = [1, 3, 4, 5, 3, 4, 3]

const result = arr.lastIndexOf(3)
console.log(result)

//6
```

## .slice( 開始擷取的索引值, 結束的索引值)
> 擷取陣列中，[start索引值]到[end索引值]之前(不包括end的值)的元素

例：
```javascript=
var str = "Hello, world!";
var slicedStr = str.slice(0, 5);
//擷取從索引 0 到索引 5（不包括索引 5）的子字串

console.log(slicedStr); // 印出 "Hello"
```

DOM Document Object Model
(文件物件模擬)
===

例：
HTML中
```htmlembedded=
<div id="doll-1" class="doll">Doll 1</div>

<div d="doll-2" class="doll">Doll 2</div>
```

## JS [DOM](https://ithelp.ithome.com.tw/articles/10202689) 拿HTML的東西
> JS沒辦法拿到HTML的東西，而是透過Runtime(俗稱瀏覽器)作為媒介取得。瀏覽器會將HTML的標籤結構，解析且變成物件(DOM tree)後給JS使用。

1.  document.getElementById(" ")
```javascript=
const d1 = document.getElementById("doll-1")
console.log(d1)

//<div id="doll-1" class="doll">Doll 1</div>
```

2. document..querySelector("# ")
>- 即便HTML文件中有一樣名稱的元素，也**只會抓一個**(由上往下)，且**抓第一個出現的**
>- 可以運用CSS的選取器的方式來選，例如，"h1:nth-child(3)" 選取第三個h1
```javascript=
const d2 = document.querySelector("#doll-1")

console.log(d2)
//<div id="doll-1" class="doll">Doll 1</div>
```

3. 一口氣抓兩個娃娃
```javascript=
const d3 = document.getElemensByClassName("doll")
console.log(d3)

//HTMLCollection
//<div id="doll-1" class="doll">Doll 1</div> 
//<div d="doll-2" class="doll">Doll 2</div>
```
這邊會抓出一個元素集合(不是陣列，是物件)。
集合中的每一個都是一個元素。
會動態更新集合裡的元素。

4.
```javascript=
const d3 = document.querySelectorAll(".doll")
console.log(d3)

//NodeList
//<div id="doll-1" class="doll">Doll 1</div> 
//<div d="doll-2" class="doll">Doll 2</div>
```
括號中要使用CSS選取器用法。
這邊的集合中每一個都是一個節點(不是陣列，是物件)。

總結：HTMLCollection V.S. NodeList 都不是陣列，兩者差別在於能執行的行為不同。

## 監聽 .addEventListener( ___,( ) =>{  } )
### DOMContentLoaded 
先監聽完整份文件後，再進行其他事，才不會輸出null

舉例
```javascript=
document.addEventListener(DOMContentLoaded,()=>{
    comst el = document.querySelector("h1")
    consolr.log(el)
})

//先讀取完整份文件後再執行querySelector的行為
```

或者，你也可以
< script **defer** src="app.js">< /script> 在這邊加上**defer**(意為延遲解析) 

### defer 、 async 、  type=“module”
```javascript=
<script src=“”my.js” type=“module”> //same as defer
```
type=“module”   defer   則一使用

```javascript=
<script src=“”my.js” type=“module” async>
```
type=“module”   async   可以搭配使用


### type=“module”
> 
情境一
```javascript=
<script src=“a.js”>
<script src=“a.js”>

// 載入兩次a.js
```

情境二
```javascript=
<script src=“b.js” type=“module”>
<script src=“b.js” type=“module”>

// 只會載入一次b.js cuz type=“module”會判別檔名，不會重複執行
```

情境三
```javascript=
<script src=“c.js.1” type=“module”>
<script src=“c.js.2” type=“module”>

// 兩個都會載入
```

### 預設行為
例如：超連結 < a href="">...< /a>，按了後跳出網頁為其的預設行為。

擋掉預設行為作法：
```javascript=
const link = document.querySelector("a") //呼叫超連結物件

link.addEventListener("click", (e)=>{
    e.preventDefault //擋掉超連結的預設行為
    console.log(go)
})
```

### Set（集合）
> Set(集合)中的元素都是獨一無二，不會重複

ES6語法
===
### 物件簡寫(key與value一樣時)
```javascript=
const name = "cc"
conast age = "18"

const hero = {
    name: name
    age: age   //如果key與value一樣可以簡寫
}
簡寫成 -> const hero = { name, age }
```

## 解構 （ 重要！）可以把物件簡化，也能一個一個拆開看
情況一：物件的解構
```javascript=
const hero = { name: "kk", age: 18, power: 100 }

const name = hero.name;
const age = hero.age;

//解構
-> const { name, age } = hero //大括號內的順序不重要
```

情況二：陣列的解構
```javascript=
const nums = [1, 3, 5, 7]

const first = nums[0]
const last = nums[nums.length - 1 ]

//解構
const [first, second, third, fourth] = nums
console.log(first, fourth) //1,7
```
情況三：函數的解構
```javascript=
function bmi(user){
原寫法->//const height = user.height;
       //const weight = user.weight;    
解構後-> const { height, weight } = user
    
    return height * weight * 2;
}

const me = {height: 100, weight: 200}
console.log(bmi(me))
```
也可在**參數**中直接解構，如下
```javascript=
function bmi({ height, weight }){
    return height * weight * 2;
}

const me = {height: 100, weight: 200}
console.log(bmi(me))
```

# [...a, ...b] 展開或收集成陣列
陣列展開
```javascript=
const a = [1, 2, 3]
const b = [4, 5, 6]

//console.log(a.concat(b)) 合併兩陣列原方法
//展開
const c = [...a, ...b]
console.log(c);
```
```javascript=
function hi(a, b, c){
    console.log(a, b, c);
}
const data [1, 2, 3]
hi(...data)

// 1,2,3
```

收集陣列
```javascript=
const nums = [1, 2, 3, 4, 5]

//收集
const c = [first,...second]
console.log(c);

//1
//[2,3,4,5]
```
展開 v.s. 收集
```javascript=
function hi(a, b, c, ...others){
    console.log(a, b, c); //1,2,3
    console.log(others); //4,5
}
const data [1, 2, 3, 4, 5]; //收集給console.log(others)
hi(...data); //展開帶進console.log(a, b, c)
```

### 多維陣列 -> 一維陣列 .flat( )

```javascript=
 function log(...params) {
  if (params.length == 0) {
    console.log("");
    return;
  }
  console.log(...params.flat()); //用flat攤平再用...陣列展開
}

log();
log([1, 2, 3])  // 1, 2, 3
```

# fetch( ) ：拿回來
> 因為會回傳promise，所以需要使用then來解（但也有其他的方式）。

舉例：
```javascript=
const userList = " 網址 ";

const result = fetch(userList);
console.log(result)
// promise (保證會回來但不知道什麼時候回來)
```
印出要的東西->用then解，如下
```javascript=
const userList = " 網址 ";
                             //用then解
const result = fetch(userList).then(() => {
    console.log("ok")
})
// ok
```
網址：
URL 
API = Application Programming Interface（存取網址的介面）= 應用程式介面
```javascript=
const userList = " 網址 ";
                             //用then解
const result = fetch(userList).then((resp) => {
    return resp.json()
})
// promise
```
.json( )=JavaScript Object Notation 物件表示法
>將text經過json轉換成能在JS中使用的物件(類似DOM tree作用)
```javascript=
const userList = " 網址 ";
                             
const result = 
fetch(userList)
    .then((resp) => {
        return resp.json(); //放到resp裡做回傳resp.json()的動作
    })
    .then((data) => {  //解構，原d.name
        data.forEach(({ name } => {
           console.log(name) 
        });
    })
// 輸出網址中的所有名字
```

#### 拿東西
如果HTML的標籤:< div id="xyz" data-ccc="123" data-a"432">...< /div>

const x = docuent.querySelector("#xyz")
console.log(x.dataSet)

# 遞迴 （費式數列）

>費式：
F(0)=0
F(1)=1
F(n)=F(n-1) + (n-2)

```javascript=
function fib(n) {
    if(n < 2){
        return n
    }
    return fib(n-1) + fib(n-2)
}

//在函式中呼叫自己會有堆疊液出的問題，這邊不會
//可以改用迴圈的方式寫看看
```

# for in / for of
**for in**
找key用的

舉例：
```javascript=
const hero = { name:123, age: 456, power: 789 }
for(let h in hero){
    console.log(h) //namm, age, power
    console.log(hero[h]) //123, 456, 789
}
```

**for of**
找值(value)
==用於可迭代的對象，例如陣列、字符串、Map、Set...==
物件不可迭代，所以上面for in的舉例就不能使用for of來執行。

舉例：
```javascript=
const arr = [1, 2, 3];
for (let elem of arr) {
  console.log(elem); // 输出 1, 2, 3
}
//陣列可以迭代

const str = 'hello';
for (let char of str) {
  console.log(char); // 输出 'h', 'e', 'l', 'l', 'o'
}
//字串可以迭代
```

# by value v.s by reference

### by value
在 JavaScript 中 primitive type（Boolean, String, Number, null, undefined）都屬於 By Value

例如：
```javascript=
var a = 10 ;

var b ;
b = a ;
a = 5 ;

console.log(a)  // 10
console.log(b)  // 5
```
![image](https://hackmd.io/_uploads/HJAM2TkxA.png)

想像a和b分別存在不同的記憶體中，所以改變b的值時，不會影響到a，這樣的情況就是by value。

### by reference
在 JavaScript 中 Objects（Object, Array, Function）都屬於 By Reference。

例如：
```javascript=
var c = { greeting: 'Hello' };

var d;
d = c;
d.greeting = 'Hola';

console.log(c) //'Hola'
console.log(d) //'Hola'
```
![image](https://hackmd.io/_uploads/S1S1Ca1eC.png)

by reference中，想像c和d存在同一個記憶體中，所以不管是改變c或d的內容，兩者都會一起改變。




# jQuary
> JQuary是JavsScript延伸出來的套件

## localStorage


# shallow copy : 淺層複製
> 如果遇到多維陣列，只會複製到第一層陣列

# module 模組系統
## inport

## export

## [setTimeout](https://developer.mozilla.org/zh-CN/docs/Web/API/setTimeout)(未執行的function, 要延遲多久時間)
> 第一個參數=> callback function


0325 JavaScript Note

# Regular Expression (REGEX) 常規表示法
[REGEX符號運用](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Regular_expressions)
> '.' => 任何字
> '+' => 1個以上
> '?' => 0個 || 1個
> 可以用反斜線區隔同樣符號不同功能

eq:
判斷是否為email //xx@gmil.com

REGEX:
.+@.+\..+
翻譯成中文 =>（很多個任何字＠很多個任何字.很多個任何字）

```JavaScript=
function isValidEmail(mail) {
    const pattern = / .+@.+\..+ /

    if (mail.match(pattern)){   
        return true;
    }
    return false;
}

const m = "xxg@gmil.com.tw";
console.log(isValidEmail(m))
```

```JavaScript=
function isValidEmail(mail) {
    const pattern = /.+@.+\..+/  
                //記得用/ /把正規表示法包起來，不能留空！！！

    //return Boolean(mail.match(pattern))
    return !!mail.match(pattern) //可以用‘兩個驚嘆號’代替Boolean()，來轉換回傳的值(要回傳布林值)
}

const m = "xxg@gmil.com.tw";
console.log(isValidEmail(m))
```

# this 
> 通用
> 跟寫在哪無關，只跟怎麼被呼叫有關

### this規則
#### 1. 誰呼叫誰就是this , 無人呼叫this＝global 全域物件(window)

呼叫的前面有人：
```JavaScript=
const hero = {
    name:"kk"
    attack: function(){
        console.log(this);
    },
};
hero.attack() //前面有hero，所以this=hero
```

呼叫的前面沒人：
```JavaScript=
function cc(){
    console.log(this)
}
cc() //印出windows，因為cc()前面沒人
```

兩層function時
```JavaScript=
function cc() {
    function aa() {
        console.log(this) //印出window
    }
    aa();
}

cc();
```

#### 2. 確認是否有使用箭頭函數（箭頭函數沒有自己的this，所以會印出window）

箭頭函數沒有argument：
```JavaScript=
const hi = () => {
    console.log(argument) //argument是ES6前用來印出不固定數的引數的方法，現在都用...(展開陣列)
}

hi(1, 2, 3, 4, 5) //output壞掉，因為箭頭函數沒有自己的argument
```

箭頭函數沒有this：
```JavaScript=
const hi = () => {
    console.log(this)
}

hi(1, 2, 3, 4, 5) //output 全域物件，因為箭頭函數沒有自己的this，this會往外成找
```

比較一般函數 及 箭頭函數 使用this時：
```JavaScript=
const hero = {
    name: "kk",
    a: () => {
        console.log(this);
    },
    b: function() {
        console.log(this);
    },
};

hero.a() // 印出window
hero.b() // 印出hero
```

#### 3. 是否有使用 new (有 new 走物件導向的流程) // {}

舉例：
```JavaScript=
function a() {
    console.log(this);
}

new a() //a{}
```

#### 4. 是否有用call || apply (兩者用法皆是把this轉向)，bind(先把h帶入成this，產出新function)

call || apply舉例：
```JavaScript=
function a(){
    console.log(this.name); //要印出 kk
}

const h = { name: "kk" };

a.call(h);
a.apply(h)   //兩種方式都能把h帶入 function 當作 this (注意!!不是把h當參數，而是把 h 當作 this!!)
```

如果，也想把引數帶進參數的話：
```JavaScript=
function a(x, y){
    consolr.log(this.name)
}

const h = { name: "kk" }

const data = [1, 2] //apply用法

a.call(h, 1, 2)  //引數一個一個帶進去
ca.apply(h, data) //引數一整包 data 帶進去
```

call || apply 使用情況：
```JavaScript=
const hero = {
    hp: 100,
    mp: 30,
    attack: function() {
        console.log("ATTACK!!");
    }
};

const mage = {
    hp: 60,
    mp: 100,
    attack: function() {
        console.log("attack~~~");
    },
    heal: function() {
        this.hp+ = 30
    }
}

mage.heal() //這裡的法師只能幫自己補血

console.log(hero.hp);  //印出100
mage.heal.apply(hero); //用 apply 把 hero 帶入成 this，讓法師也能幫英雄補血
console.log(hero.hp)   //印出130，因為已經補完血了
```

bind(一定要呼叫，才會有結果)舉例；
```JAvaScript=
function a() {
    consolr.log(this);
}

const h = { name: "kk" }

const f = a.bind(h);  //把 h 帶入成 this，然後 產出一個新的 function
f();   //啟動由 bind 產出的新 function，如果想帶引數進去，從這邊帶

conaole.log(f) //
```

bind 使用時機：
```Javascript=
function ass(a, b) {
    return a + b
}

//partial function(局部函數)
const add5 = add.bind(null, 5);  //這邊的null是帶入成this，所以跟函數內要回傳的算式沒關係。這邊b都還沒有被帶入任何引數。

console.log(add5(10));  //15，這邊把10帶入給b
console.log(add5(3));   //8，這邊把3帶入給b
console.log(add5(8));   //13，這邊把8帶入給b
console.log(add5(100)); //105，這邊把100帶入給b
```

#### 5. 是否有開啟 strict mode (嚴格模式)

```JavaScript=
"use strict"

function a() {
    console.log(this)
}

```

> 總結this的五點規則：
> 1. 是否有開起 strict mode
> 2. 是否有使用 new
> 3. 是否有使用箭頭函數
> 4. 是否有用 call , apply , bind
> 5. 誰呼叫，誰就是 this ; 無人呼叫 this = global 全域物件

# 閉包 clousure 
    閉包只是一種手法，因稍後延遲發生某事，若不先存取就無法帶入當下的資料。不等於 閉包是逃避的做法。

```JavaScript
allBtn.forEach((btn) => {
    btn.addEventListener("click", function() {
        var that = this  //閉包，把this變成that帶走做事(逃避的作法)
        const handler = function() {
        console.log(that)
        };
    })
})
```

比較使用bind：
```JavaScript
allBtn.forEach((btn) => {
    btn.addEventListener("click", function() {
        const handler = function() {
            console.log(this);
        };
        const nowHandler = handler.bind(this);  //bind 會先把 this 收著，
        newHandler();               //這邊是在呼叫 bind 生成的新 function，
        setTimeout(newHandler, 1000);                  //在1秒後執行。
    })
})
```
    以上兩個方法都有閉包的發生，只是 var that=tihs 是逃避的做法,而使用 bind 是對 this 掌握度較好

比較使用var(全域污染) 及 let(閉包)：
```JavaScript=
for(var i = 0; i < 3; i++){
    setTimeout(()=> console.log(i))
}
// 印出 3 3 3
// 因為 var 會污染全域變數，所以在此函數中 setTimeout 執行完從 Q 要回 stack 時，i 已經變成3了

for(let i = 0; i < 3; i++){
    setTimeout(()=> console.log(i))
}
// 印出 0 1 2
// let 只能存在 block scope，因而產生閉包。等 setTimeout 完成回到 stack 後 i 就找不到了，所以要帶著 i。
```

# IIFE (Immediately Invoke Function)：定義完馬上執行的function
> 在IIFE裡的東西不會流到外面去 => function scope
> jQuery就是一個IIFE

```JavaScript=
for(var i = 0; i < 3; i++) {
    setTimeout(((y) => { 
        console.log(y); 
    })(i), 0);
}
```

0408 JS Note

# lexical scope || dynamic scope(動態執行)

- scope : 在哪找東西
- lexical：跟寫在哪有關，跟怎麼執行無關
- dynamic：跟怎麼執行有關 like : this

舉例：
```JavaScript
let abc = 456

function a(){
    let abc = 123
    console.log(abc);
}
// 123
```
# pass by value || pass by reference
要把東西傳進去才會有這兩種差別產生
舉例： （要把o還是c傳入這個hi的function裡）
```JavaScript
function hi(data){

}

const o = {name: 'cc'} ;
const c = 123 ;

hi(c) //? 傳常數進去，本來就不能改，所以-> by value
hi(o) 
```
//! 比較  data = 123 和 data['xx'] = "aa" 差別 

# AJAX 非同步：
JS在瀏覽器是單執行序(環境給他的)，一次只能執行一件事，透過非同步，讓執行效能增加。
like : setTimeOut(), fetch()...

# tagged function
//FIXME 思考這題 ： 
```JavaScript
function getPersonInfo(str, ...params) {
  const result = str.map((s, i) => {
                        //s->str的元素，i是索引值，把i給params用
    return [s, params[i]];
  });

  console.log(result.flat().join(""));
}
```

今日課堂內容：
# target v.s currentTarget

# try / catch

# 測試
測試 = 自動話測試 ＝ 寫一段程式碼，測試某功能是否正確運作
like:
```JavaScript
function add (a, b) {
    return a + b ;
}
if (add(1, 2) == 3) {
    console.log("OK");
} else {
    console.log("ng")
}
```

## TDD(Test Driven Development)測試驅動開發
```JavaScript
//先寫 if ... else ...

//? 規格、測試(一開始一定會壞，因為function還沒寫)
if (add(1, 2) == 3) {
    console.log("OK");
} else {
    console.log("ng")
}

//? 實作
function () {...}
```

## 測試套件 jest
```JavaScript
it("測試的描述", () => {
    expect(true).toBe(true);
    //要做的事
});
```





