# iSpan 4. JavaScript - 上課筆記本 + 整理 >* HTML >定義網頁的內容 >* CSS >定義網頁的外觀(階層樣式表) >* <font color="crimson">JavaScript >定義網頁和使用者的互動</font> w3c的 JavaScript https://www.w3schools.com/js/default.asp <br><br><br><br> JS命名規則可以==英文大小寫(區分大小寫)、數字、$和底線==,但禁止首字為數字 ## <font color="DodgerBlue">JavaScript</font> ### <font color="mistyrose">使用前先了解 . . .</font> * Client 和 Server會互傳資料,js 可以在客戶端先處理好部份資訊或運算,**減少Server端負荷**。 -> 客戶端的JavaScript功能要是關閉,若網頁有使用JavaScript的功能將無法運作。 :::success :book: google瀏覽器的設定 -> 隱私權和安全性 -> 網站設定 -> 下面內容的 JavaScript -> 可以禁止網站使用 JavaScript 。 ::: * 不常更改變動的設定適合使用 Html 撰寫, ==常變動 / 會互動的物件==適合使用 js 撰寫。 * js 在於使用==物件( Object )== ,即==屬性 Proerty==(特徵)和==方法Method==(會動的)的集合 -> 鍵值對 ( key-value ) 的集合,值為基本數據類型為屬性,為函數則為方法。 <br><br> ==HTML DOM 物件==會把HTML檔案轉換成物件,JavaScript就可以對HTML進行變化更改。 >[!IMPORTANT]學習連結: >* [Browser Object Model](https://www.w3schools.com/js/js_window.asp) >* [Document Object Model ( The HTML DOM Tree )](https://www.w3schools.com/js/js_htmldom.asp) 1. DOM tree 是 DOM 的樹狀結構。 2. 根節點為 document,代表整份 html 文件。 3. 其他每個節點代表著元素、屬性、文本。 >* [JavaScript and HTML DOM Reference](https://www.w3schools.com/jsref/default.asp) -> JavaScript / Window / HTML DOM 物件和 Web APIs。 1. **瀏覽器物件模型(Browser Object Model)** 讓 JavaScript 和==瀏覽器對話==以進行操作。 2. **文件物件模型(Document Object Model)** 讓 JavaScript 和==HTML文件對話==以進行操作。 舉 DOM 的一個例子: &emsp;&emsp;`document.write("水箭龜");` &emsp;&emsp;則網頁上就會出現水箭龜三個字,甚至還能賦予 html 標籤,例如: &emsp;&emsp;`document.write("<h1>小火龍</h1>");` &emsp;&emsp;畫面效果就會長這樣,使用 js 對 html 進行操作更改。 ![image](https://hackmd.io/_uploads/S1bj-Shbke.png) <br><br> :::success :book: 三個關於 `<script>` 的補充。 * JavaScript 的使用方式有兩種: 1. 在標籤內直接寫入程式碼。 ![image](https://hackmd.io/_uploads/H1mAzBnZJx.png =70%x) 2. 嵌入外部 JavaScript 檔案。 ![image](https://hackmd.io/_uploads/H1a_mB3-Jg.png) 3. 同時使用。 因為程式碼執行順序,會先執行嵌入的外部檔案,忽略內部文本程式碼且不執行。 * `<script>` 的放置位置妥當,才不會讓使用者覺得網頁讀取時卡頓。 -> ==程式碼執行都是由上至下== 1. 放置在`<head>`區塊內:適合「能夠直接顯示無關運算」的程式碼。 2. 放置在`<body>`區塊尾:適合「需要運算或和 body 內其他元素互動」的程式碼。 * 舊程式碼會看到 `<script type="text/javascript">` 的寫法 -> 舊版需要告訴瀏覽器此段代碼類型為 text/javascript,即 JavaScript 的 MIME 類型。 -> HTML5 後,`<script>` 的 type 默認為 text/javascript。 ::: <br><br> ### <font color="mistyrose">console 主控台</font> 為 BOM 的一個物件。 按下 F12 或是滑鼠右鍵後選擇檢查,主控台就在瀏覽器的開發者工具裡面。 用途為測試、追蹤錯誤、紀錄日記,是工程師開發的重要工具。 * `console.log();` 一般訊息 * `console.error();` 錯誤訊息 * `console.warn();` 警告訊息 * `console.clear();` 清空主控台 * `console.table();` 陣列 * `console.time();` 搭配 `console.timeEnd();` 可以得到包圍程式碼的耗時,比較效能。 * `console.group();` 分組(展開) * `console.groupCollapsed();` 分組(收合) * `console.groupEnd();` 表示分組尾端 ![image](https://hackmd.io/_uploads/r10UgL2-Je.png) <br><br> ### <font color="mistyrose">Document 文件</font> HTML文件在==載入瀏覽器==時,就會變成一份==文件物件==。 文件物件是HTML文件的根結點(root node)。 ![image](https://hackmd.io/_uploads/H18si2eGyx.png) 文件物件也是==window物件的的屬性==。 -> 所以文件物件(document object)==**既是物件也是屬性**==(property)。 -> 使用 `window.document` 或 `document` 皆可。 如果在主控台顯示內容: ![image](https://hackmd.io/_uploads/S1Vy-1-fyg.png) * `document.write("...");` 在html內寫上訊息。 * `document.getElementById("...")` 獲取html內指定某id的元素。 :::info :eyes: document.getElementById("...") 就是需要和 body 內其他元素互動; 若 js 程式碼執行位置在前,則抓取目標就會為 null 。 ![image](https://hackmd.io/_uploads/By7bmkZMJx.png) ::: >[!IMPORTANT]學習連結: >https://www.w3schools.com/jsref/dom_obj_document.asp <br><br><br><br> ## <font color="DodgerBlue"> 變數</font> * 變數==宣告==格式: ==變數類型 變數名;== ->例、變數宣告並賦直 `var x = "小明"; ` * 若未宣告,使用時會跳出錯誤訊息。 * 若未賦值,使用時會跳出關鍵字 undefined。 ![image](https://hackmd.io/_uploads/Hk-lLFzvC.png) <br><br> ### <font color="mistyrose">變數命名</font> 命名規則: 1. 僅限英文大小寫 ( 區分大小寫 )、數字、美元符號、底線(A-Z、a-z、0-9、$、_ )。 2. 禁止首字母為數字。 3. 禁止使用保留字 ( reserved word,也叫關鍵字 keyword )。 4. 命名方式一、底線分隔,例: stu_name_id。 5. 命名方式二、大駝峰 Upper Camel Case:StuNameId。 6. 命名方式三、小駝峰 lower Camel Case:stuNameId。 :::success :book: 害怕使用到保留字,可以在名字前加上my ,例如: myint ::: >[!IMPORTANT]JavaScript 保留字有哪些: >https://www.w3schools.com/js/js_reserved.asp <br><br> ### <font color ="mistyrose">變數類型</font> 1. var,可橫跨block,作用於==函數內==,有==hoisting特性==。 :::success :book: hoisting特性,JavaScript 編譯階段將變數和函式的宣告存入記憶體的概念, 使函數和變量的==宣告==被==提升==到==作用域的頂部==,即使他們的實際定義位置在下面。 例如下圖兩個程式碼,執行上是相同的。 ![image](https://hackmd.io/_uploads/HJYPvYfDA.png) ::: 2. let,block scope ( 區塊作用域 ) 的變數,無法橫跨大括號。 3. const,同let,特點在於==宣告時必須賦值==,之後==無法更改==,適合定義參數如 pi=3.14 等。 :::success :book: 此處的 block 區塊形容大括號包裹的區域,例如迴圈while(){ ... } ::: <br><br><br><br> ## <font color ="DodgerBlue">資料型別</font> 使用==typeof==關鍵字取得資料型態類型 ![image](https://hackmd.io/_uploads/B1GHb6ZMyg.png) <br><br> ### <font color ="mistyrose">String 字串</font> * **雙引號對或單引號對**包覆即是字串。 * 一些特殊字元需要使用跳脫字元反斜線 `"C:\\temp"` -> `"C:\temp"`。 * 算術運算子**加號**遇到字串會變成字串相接的意思 `"小明"+"好帥"` -> `"小明好帥"`。 * ==Template Literalsa 模板字串==,引號改成==反引號==,使用 ==${ }== 讓文字和變數相接,除此之外還可以直接使用多行字串 (單雙引號多行字串需要用反斜線連接)。 ![image](https://hackmd.io/_uploads/Bkws-5GDA.png) ![image](https://hackmd.io/_uploads/S1HFD54_R.png) :::success :book: 常用的跳脫字元 `\'`單引號 `\"`雙引號 `\\`反斜線 `\t`tab `\n`換行 ::: * ==`.length`== 取得字串長度(幾個字元)。 * ==`.indexOf(p)`== 取得第一個特定字串p在字串中的位置,起始位置為0,未找到回傳-1。 * ==`.lastIndexOf(p)`== 取得最後一個特定字串p在字串中的位置,格式上同.indexOf()。 * ==`.split(p1,[p2])`== 根據指定的分隔值p1,將字串切割,回傳一個新字串陣列;p2為保留的切割數量,預設全切。 * ==`.padStart(p1,[p2])`== 把字串的字元數補足到p1個;用p2值取代,預設為空白。 * ==`.substring(p1,[p2])`== 取得字串的其中一部分,回傳為一個新字串。 p1 設定開始位置,p2設定結束位置(==不包含==),預設為字串長度。 編譯時會自動把較小的數字移至p1;負數皆視為0。 * ==`.slice(p1,[p2])`== 同.substring(),但不會編譯時改動p1、p2位置。 負數值 = 字串長度 + 負數值,例、`"abcde.slice(-2) //de"`。 :::success :book: (p1,[p2])被中括號包起來的參數代表可省略。 ::: <br><br> ### <font color ="mistyrose">Number 數值</font> 1. 正數、負數、小數都是數值。 2. 數值運算常見錯誤:Infinity、-Infinity、NaN (Not a number)。 ![image](https://hackmd.io/_uploads/HJnK55fw0.png) 3. 減乘除(- * /)的運算會==強制把字串轉型成數值==,加號例外。 * ==`Number.MAX_SAFE_INTEGER`== 取得安全處理數字最大值。 * ==`isNaN(p)`== 判斷數值是否為NaN。 * ==`parseInt(p)`== 把字串轉換為數值。 * ==`.toString()`== 把數值轉換為字串。 :::success :book: Number 能處理的最大範圍 -2^53到2^53之間(不含兩個端點)。 -> 超過範圍的計算就可能出現錯誤。 ::: <br><br> ### <font color ="mistyrose">Array 陣列</font> 1. 陣列使用時機:相同的資料型態(雖然 JavaScript 可以不需要相同,但還是盡量避免)。 2. 具有==一致的意義==、需要參與同樣的運算。 3. 陣列就像置物櫃一樣,透過index,可以存取物品(元素)。 4. 使用==中括號==表示==宣告陣列== 例、`var temp = [10, 20, 30];`。 5. 存放元素進陣列 `temp[3] = [40];`。 6. 從陣列取得元素 `temp[0]`。 7. ==call by reference (傳址)==。 >[!IMPORTANT]傳址和傳值 >1. call by value (傳值):以變數為參照賦予另一個變數值,電腦會在記憶體中新增(複製)一個新值,讓後來的變數指向新的值。 >2. call by reference (傳址):變數會指向電腦記憶體中同樣的物件,不會有新的物件在記憶體中被創造出來,此時兩個變數的更改會互相影響。 >3. 字串和數值為 call by value; 鎮列為 call by reference。 > >![image](https://hackmd.io/_uploads/rk5jnaXvC.png) :::info :eyes: 列內索引值(index)起始從0開始計算。 ::: :::info :eyes: JavaScript 的陣列不用先宣告長度,甚至可以跳過前面元素,從後面開始設置。 ::: * ==`.length`== 取得陣列長度(幾個元素)。 * ==`.toString()`== 把陣列轉換為字串。 * ==`.join(p)`== 取得陣列轉換的字串,其中,用參數p替代。 * ==`.shift()`== 移除陣列的第一份資料。 * ==`.pop()`== 移除陣列的最後一份資料。 * ==`.unshift(p)`== 增加資料p到陣列第一個位置。 * ==`.push(p)`== 增加資料p到陣列最後一個位置。 <br><br> ### <font color ="mistyrose">Object 物件</font> 1. 物件使用時機:多個屬性和方法都是形容==同一樣東西==。 2. 物件的屬性,定義物件的特性,例如、人類物件有身高、體重等屬性。 3. 物件的方法,定義物件的行為,例如、人類物件有睡眠、進食等方法。 4. 常見的物件中,有的不會定義方法,但幾乎都會定義==屬性==。 5. 使用大括號表示宣告物件 例、 `var score = { name:"小明", math:80, english:95 }`。 6. 物件的大括號內格式為 `{ key1:value1, key2:value2.. }`。 >物件內為**key-value鍵-值對**,設定key值(屬性名/方法名)後冒號,後面放上value值(屬性值或函數(方法)),多個設定要用逗號分隔。 >JavaScript 會自動把==key值判斷為字串類型==。 7. 使用 . 或 [ ] 可以取得或新增物件內的屬性,例、 更改數學屬性的成績 `score.math = 90;`。 新增科學屬性的成績 `score.science = 1000;`。 更改英文屬性的成績 `score["english"] = 90;`。 新增國文屬性的成績 `score["chinese"] = 1000;`。 <br><br> ### <font color ="mistyrose">Boolean 布林值</font> 1. 只會有兩個值:True 或 False。 2. 常見於比較運算後回傳的結果。 3. 轉換成數值則 True為1 , False 為0。 <br><br> ### <font color ="mistyrose">運算子</font> * 算數運算子 常見的加減乘除都在此類,此外還有 1. 取餘數% 例、 `10 % 3 = 1` 、 `15 % 4 = 3`。 2. 變數`++`,變數 = 變數 +1 的意思,例、 ![image](https://hackmd.io/_uploads/S18euKPPC.png) 3. `++`變數,同變數`++`,差異在於若包含在其他式子內,前者會做完式子才+1,後者做之前就+1。 ![image](https://hackmd.io/_uploads/BJmP_twPC.png) * 比較運算子 評估條件,回傳 true 或者 false 值,常見有>、<、>=、<=。 注意程式和數學常見差異。 1. `==` ,等於,單純比值,無視資料型態,字串"10"和數值10==會==視作相等。 2. `===`,等於,不會自動轉型,字串"10"和數值10==不會==視作相等。 3. `!=`,不等於。 :::info :eyes: 因為回傳為布林值,建議不要使用連續比較,例、3>2>1 會回傳 False 因為程式由左至右,(3>2)>1執行後變成 (True)>1 -> (1)>1 -> False ::: * 邏輯運算子 回傳 true 或者 false 值。 1. and (&&) 條件需要同時成立的時候。 2. or (||) 條件擇一成立。 3. 若確定結果程式會直接返回不會繼續判斷,像是 A&&B(A為假) A||B(A為真)。 * 三元運算子 (condition) ? value1:value2,即 (條件|比較) ? 成立執行這段 : 不成立執行這段。 例、`(皮包的錢超過100)? 買一杯手搖 : 回家;` <br><br><br><br> ## <font color="DodgerBlue">內建函數</font> ### <font color="mistyrose">JavaScrip 內建函數</font> 1. Date 日期物件 生成日期物件,隨參數不同有九種生成方式。 ![image](https://hackmd.io/_uploads/HksAiyvfke.png) * ==`d.getFullYear()`== 取得年份 ( yyyy ) 。 * ==`d.getMonth()`== 取得月份 ( 0 - 11 ) 。 * ==`d.getDate()`== 取得日期 ( 1 - 31 ) 。 * ==`d.getDay()`== 取得星期 ( 0 - 6 ) 。 * ==`d.getHours()`== 取得小時 ( 0 - 23 ) 。 * ==`d.getMinutes()`== 取得分鐘 ( 0 - 59 ) 。 * ==`d.setdate( p )`== 設置日期 ( 1 - 31) 。 * ==`d.setMonth( p )`== 設置月份 ( 0 - 11 ) 。 :::info :eyes: 只有日期是從1開始數,所以使用月份要記得+1,星期則是0代表星期日。 ::: :::success :book: 雖然日期限定填入1-31的數字,但0其實會換算成上個月的最後一天。 ::: :::success :book: 日期物件相減可以得到時間差,但單位是毫秒。 ::: >[!IMPORTANT]學習連結: >https://www.w3schools.com/js/js_date_methods.asp 2. Math 數學物件 * ==`Math.random()`== 產生亂數,值為 0~1 ( 不包含1 )。 * ==`Math.ceil(x)`== 數值x無條件進位。 * ==`Math.floor(x)`== 數值x無條件捨去。 * ==`Math.round(x)`== 數值x四捨五入。 >[!IMPORTANT]學習連結: >https://www.w3schools.com/js/js_math.asp <br><br> ### <font color="mistyrose"> Window 內建函數</font> window 在 JavaScript 為全域物件,所以使用屬性和方法==可以省略== window。 > 所以前面 document 章節,才會說 window.document 可以省略為 document。 * ==`window.alert(...);`== 訊息框,內文可以放數值、字串、陣列、變數...等。 ![image](https://hackmd.io/_uploads/B1Oh4CDPR.png) * ==`window.confirm(...) `== 確認框,一樣可以放內文,會返回 True / False。 ![image](https://hackmd.io/_uploads/S10H4AvvA.png) * ==`prompt(...);`== 輸入框,一樣可以放內文,會返回使用者輸入值的==字串==,取消則顯示null。 ![image](https://hackmd.io/_uploads/HJBeSAPD0.png) * ==`setInterval(p1,p2)`== 定義一個==重複計時器==,固定延遲了某段時間之後,才執行對應的程式碼,然後不斷循環。 p1放入函數變數 (無小括號)、函數變數的字串 (有小括號) 或整個函數。 p2放入隔多少毫秒執行一次,注意單位是毫秒。 :::info :eyes: p1不能直接放入 `Hi()` , 函數的==小括號代表立即執行==。 若放入`Hi()`則立即執行,會導致循環時`Hi()`已執行完畢,內容為空,不會重複執行。 ::: * ==`clearInterval(p);`== 清除使用的 setInterval, p 要放上 setInterval()的變數或函數。 * ==`setTimeout(p1,p2)`== 格式和用法同setInterval,不過只做一次,適合跳轉頁面。 :::success :book: 使用document.location.href = "..." 更新網址。 ::: * ==`window.getComputedStyle( p1 ).getPropertyValue( p2 )`== 取得指定元素某項樣式的內容 ( 所有樣式來源皆計算 )。 p1 為HTML元素,p2 為樣式屬性。 >[!IMPORTANT]學習連結: >https://www.w3schools.com/jsref/obj_window.asp <br><br> ### <font color="mistyrose">DOM 文件物件模型的內建函數</font> * ==`document.getElementsByTagName("p")`== 取得所有 p 標籤元素。 * ==`document.getElementsByClassName("p")`== 取得擁有 p class 類別的元素。 * ==`document.getElementById("p")`== 取得 id 為 p 的元素。 :::info :eyes: 前兩個回傳值為HTMLCollection,為類陣列; 而 getElementById 的 element 沒有加 s,回傳為 HTMLElement。 ::: 前三個範例: ![image](https://hackmd.io/_uploads/rkzyNrDG1x.png) * ==`HTMLElement.innerText="..."`== 設定內容,只能純文字。 * ==`HTMLElement.innerHTML="..."`== 設定內容,可以包含標籤變化。 * `HTMLElement.屬性` 設定標籤的屬性,例如 img元素設定 src 屬性; 若為非合法屬性則無效果。 * `HTMLElement.style.樣式屬性` 設定元素的==行內樣式==; 若 CSS 屬性為複合字,需要改成小駝峰形式,例如 font-size 成 fontSize。 ![image](https://hackmd.io/_uploads/SkGxmQdfyl.png) :::success :book: 和`window.getComputedStyle( p1 ).getPropertyValue( p2 )`差異在於 一個為行內樣式,一個為最終樣式。 ::: * ==`document.querySelector("#myId")`== 透過 CSS Selectors 取得一個標籤元素。 * ==`document.querySelectorAll(".myGroup")`== 透過 CSS Selectors 取得全部標籤元素,回傳為 ==NodeList==。 :::info :eyes: 有些方法是針對 ==HTMLElement==,如果取得為 HTMLCollection 或 NodeList ,要指定陣列的哪個元素。 ::: * ==`document.createElement("p")`== 新增p標籤的元素。 * ==`document.createTextNode("...")`== 新增一個文字節點。 * ==`HTMLElement.setAttribute("屬性名稱", "屬性值")`== 對元素設定屬性。 * ==`Node1.appendChild( Node2 );`== 將 Node2 附加到 Node1 上。 * ==`Node1.insertBefore( Node2 , Node3 )`== 在父節點 Node1 下 Node3 節點前插入新節點 Node2。 :::success :book: Node,為 The HTML DOM Tree of Objects 上面的一個節點;常見的節點有 1. 文檔節點:根節點。 2. 元素節點:HTML 元素。 3. 文本節點:純文本內容。 4. 屬性節點:HTML 元素的屬性。 ::: >[!IMPORTANT]學習連結: >https://www.w3schools.com/js/js_htmldom_elements.asp <br><br><br><br> ## <font color="DodgerBlue">流程控制</font> 判斷式內需要為==布林值==。 undefined、null、0、""、NaN 會視為False。 <br><br> ### <font color="mistyrose">if_else判斷</font> 1. 由上而下逐一確認條件,條件符合就進入執行該區域程式。 2. 執行完對應條件的程式後會直接跳出整個if判斷式。 ![image](https://hackmd.io/_uploads/H18iwluDR.png) <br><br> ### <font color="mistyrose">switch_case判斷</font> 1. 找尋 case 名稱中和expression一樣的,執行該區域。 2. 會==判斷資料型態==,注意 expr 和 case 的資料型態,例、 "10"和10。 3. 關鍵字`break` 會跳出迴圈。 ![image](https://hackmd.io/_uploads/SJh3vg_wR.png) :::info :eyes: 若沒有break,則執行完對應區域後會繼續執行下個區域。 所以可以視情況合併條件處理,例如周一到周五上班,周末放假可以寫成如下: ![image](https://hackmd.io/_uploads/BJfrdmdG1x.png) ::: <br><br> ### <font color="mistyrose">while迴圈</font> 1. 當滿足條件時進入迴圈,迴圈結束後會再次確認條件,直至離開迴圈。 2. 離開 while 敘述句的方式:break 或者條件不成立。 ![image](https://hackmd.io/_uploads/SJAcueODC.png) <br><br> ### <font color="mistyrose">for迴圈</font> 1. for ==迴圈執行前==執行 statement 1,為宣告變數給初始值。 2. 執行==每次== for 迴圈==前==執行 statement 2,為結束判斷式。 3. 執行==每次== for 迴圈==後==執行 statement 3,為變數累進。 ![image](https://hackmd.io/_uploads/rklx9euDC.png) :::success :book:不同於`break`是跳出迴圈,關鍵字`continue` 是結束當前迴圈,執行下一輪迴圈 ::: <br><br><br><br> ## <font color="DodgerBlue">function 函數</font> ![image](https://hackmd.io/_uploads/HJrq1WuPC.png) 1. 參數可以為空;若要求複數參數,用,隔開。 2. 給予不對應的參數數量或資料類型,可能會有 undefined、意外結果等等。 3. 回傳值可以為空,若有回傳值則限一,且馬上回傳並終止函數,即`return`以下程式==不會執行==。 4. 函數具有 ==hoisting== 的性質,不同於 var 變數,本身的定義內容也會抬升。 <br><br> ### <font color="mistyrose">函數運算式</font> 1. 宣告函數同時宣告一個變數並賦值。 2. 因為馬上賦值變數,不用再給函數做命名。 3. 失去 hoisting 特性(因為此時為 var的 hoisting ,但尚未賦值)。 ![image](https://hackmd.io/_uploads/S1O4-bOw0.png) <br><br> ### <font color="mistyrose">事件屬性</font> 1. button有一個`onclick`屬性,設定後可以和function做連結,代表按下後執行對應函數。 ![image](https://hackmd.io/_uploads/SJs9R7uG1x.png) 2. 可以在js設定 `HTMLElement.onclick = 函數名稱;`。 3. 或是設定 `HTMLElement.addEventListener('click', 函數名稱);`。 :::success :book: 這裡函數名稱後面不能加上小括號(),因為是點擊才執行,若加上會立即執行。 ::: >[!IMPORTANT]學習連結: >https://www.w3schools.com/js/js_functions.asp >https://www.w3schools.com/js/js_events_examples.asp >寫在標籤內的事件,例如 onclick。 >https://www.w3schools.com/js/js_htmldom_eventlistener.asp >事件監聽器 addEventListener,也是==最推薦==的使用方式。 | | HTML屬性 | 事件監聽器 | | ---------- | ------------------------------ | ---------------------------------- | | 多個事件 | 限定一個,會被覆蓋 | 可以綁定多個事件 | | 事件監聽器 | 寫在HTML標籤內,維護性擴展性差 | 和HTML結構分開,邏輯皆在 js 內處理 | `HTMLElement.onclick = 函數名稱;` 為屬性,所以會覆蓋。 `HTMLElement.addEventListener('click', 函數名稱);` 為函數,不會有覆蓋問題。