# 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); } }); ```