# DOM相關
DOM:文件物件模式
### querySelector
querySelector():只會return第一個滿足css selector的html element
eg.
```
let secondH1 = document.querySelector(".second");
```
### querySelectorAll
querySelectorAll():
eg. HTML的code可能為
```
<h1 class = "second">
<p class = "second">
<p class = "second">
```
裡面有很多element的class都是second,若要全部取出,則需要用querySelectorAll()來幫忙:
```
let seconds = document.querySelectorAll(".second");
console.log(seconds);
```
若僅需要特定的second,可以透過index number來決定要抓取哪個second。
eg. 抓取第二個second
```
console.log(seconds[1]);
```
看起來很像array,但是並非array!而是NodeList!!!
### Arrow Function Expression
* Arrow Function Expression是用來定義(製作)function的方法。
* 跟function Declaration不同,但運作十分類似。
* 不同點在於:
1. 語法不同
2. 關鍵字「this」
先來比較語法:
```
// function declaration
function sayHi() {
console.log("Hi");
}
// arrow function expression
let sayHi = () => {
colsole.log("Hi");
};
```
let sayHi = ():告知JavaScript sayHi是一個方法;後面箭頭(=>)要接大括號{};
當然也可以在小括號內寫一些value:
```
let sayHi = (name) => {
colsole.log("Hi" + name);
};
sayHi("Jimmy");
```
一般而言,JavaScript的特性是「由上往下執行」,也就是先跑的要先寫;function declaration的特性是允許先執行方法(寫在上面),再把方法宣告出來(寫在下面),像是這樣:
```
sayHi(); <-先執行方法
function sayHi() { <-再宣告方法
console.log("Hi");
}
```
當然反過來寫,先宣告再執行也OK。
但在Arrow Function Expression中無法使用這招,會出現「Uncaught ReferenceError」,要求要先初始化(initialize,意即creat an object)才能使用。
簡言之就是,在我們定義sayHi這個function以前,我們不能去使用他。所以程式碼只能這樣處理:
```
let sayHi = () => {
console.log("Hi");
};
sayHi();
```
#### this keyword:念書要看上下文
在function declaration中,this一般而言是指他所在的object;但在arrow function expression中,this會指向「他上一層的thi̍s」;若他上一層沒東西,則會指向window object,如下所示:
```
let Wilson = {
name: "Wilson Ren",
//function declaration
greeting() {
console.log(this); <-這裡的this指Wilson這個object
console.log("Hi, my name is " + this.name + ".");
},
//arrow function expression
walk: () => {
console.log(this); <-這裡的this指Window object
console.log(this.name + " is walking on the street.");
}
}
Wilson.greeting();
Wilson.walk();
```
this指向上層的this的範例:
```
function Person(){ <-我就是傳說中的上一層
this.age = 0;
setInterval(() => {
this.age++; <-this去抓了上層Person建構式所建立的物件
}, 1000);
}
var p = new Person();
```
##### 小小結:
* arrow function expression沒有屬於自己的this變數,在使用this的時候,會看自己所在的位置的上一層function有沒有其他this可以對照;若無,則最終指向window function(感覺window function跟Java「大家的老爸」object父類別有點像!?)
* 一般而言,在object裡面不太會使用arrow function expression,但寫DOM時會大量使用。
* arrow function expression在使用前需要先給一個變數,例如:
```
let sayHi = () => {}
```
參考資料:(中文的喔~)
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/Arrow_functions
### forEach Function
另一種跑迴圈的方式。(Another way to loop through an array.)
forEach function會以其設定的條件,對陣列中每個元素都跑一次,例如下列程式:
```
let luckyNumbers = [7, 15, 23, 66, 91, 10, 13];
luckyNumbers.forEach(function checkNum(n) {
if (n > 20) {
console.log(n);
}
});
```
這意味著forEach function從第一個元素比對到最後一個元素,並透過console.log會把陣列內>20的元素列印出來。
其實整個程式碼與下面「for loop」的程式碼是一樣的:
```
for (let i = 0; i < luckyNumbers.length; i++) {
if (luckyNumbers[i] > 20) {
console.log(luckyNumbers[i]);
}
}
```
forEach function也可以這樣寫:
```
let luckyNumbers = [7, 15, 23, 66, 91, 10, 13];
luckyNumbers.forEach(checkNum());
function checkNum(n) {
if (n > 20) {
console.log(n);
}
}
```
欸那個,checkNum那麼多,好像可以合併在一起吼:
```
let luckyNumbers = [7, 15, 23, 66, 91, 10, 13];
luckyNumbers.forEach(function checkNum(n) {
if (n > 20) {
console.log(n);
}
});
```
一般而言,我們幫function取名字的目的是為了要在之後執行他,但forEach function卻是「當下」就自動執行,在當下就執行完畢的情況下,幫function取名這個行為就變得十分雞肋。故checkNum這個名字可以直接刪掉,讓forEach function沒有名字的情況下仍然可以執行,也就是所謂的「匿名函式」(anonymous function)。
用匿名函式的寫法,可以把程式碼再簡化:
```
let luckyNumbers = [7, 15, 23, 66, 91, 10, 13];
luckyNumbers.forEach(function(n) {
if (n > 20) {
console.log(n);
}
});
```
匿名函式算是一種function declaration。
既然function declaration都出現了,那他的宿敵----arror function expression當然也要參戰囉!
首先我們把程式碼刪光光,僅留下這樣:
```
let luckyNumbers = [7, 15, 23, 66, 91, 10, 13];
luckyNumbers.forEach();
```
在forEach()中間塞一個小括號,小括號內寫上n,並在小括號後面畫個箭頭:
```
let luckyNumbers = [7, 15, 23, 66, 91, 10, 13];
luckyNumbers.forEach((n) =>);
```
在箭頭後面填上大括號,在大括號內部寫判斷式:
```
let luckyNumbers = [7, 15, 23, 66, 91, 10, 13];
luckyNumbers.forEach((n) => {
if (n > 20) {
console.log(n);
}
});
```
以上就是在forEach function裡加入arror function expression的方式。
另外更誇張的是,其實forEach((n)),那個包在n外面的小括號也可以不用寫......
### CallBack function
延續剛剛forEach function與其程式碼:
```
let luckyNumbers = [7, 15, 23, 66, 91, 10, 13];
luckyNumbers.forEach(
n => { <-從n開始
if (n > 20) { <-這一整段
console.log(n); <-就是
} <-所謂的
} <-CallBack function
);
```
CallBack有「打回來」的意思,在forEach function中顧名思義,每執行一次就會執行CallBack function,打回來再執行下一個元素。
CallBack function可執行的有:
* currenValue
* index(可加可不加)
* array(可加可不加)
* thisArg(可加可不加)
```
let luckyNumbers = [7, 15, 23, 66, 91, 10, 13];
luckyNumbers.forEach((n, index, arr) => {
if (n > 20) {
console.log(n);
console.lon(n + " is at index number " + index);
console.log(arr);
}
});
```