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
```

想像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'
```

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);
//要做的事
});
```