fbpx

上集聊完 DOM 基本概念和 JS 如何與 DOM 互動之後

Ex: innerHTML() , createElement() , appendChild() 等等

這集要來和大家介紹新手朋友看到就頭痛的「Callback function 回呼函式」,大家準備好了嗎?

 

看過第一、二集學習日記的朋友們應該都清楚:凡是在 JS 中所見即「物件」。所以,當我說函式 (function) 也是物件時,你應該覺得跟呼吸一樣自然🤙

但是,你有想過函式也能如同數值一般,作爲參數 (argument) 被傳遞到另一個函式中嗎?

如果沒有,小白介紹給你知道😍  這個看似很酷(被傳來傳去)的函式就是鼎鼎大名的 –– 「回呼函式 (callback function)」!

 

如果以上沒聽懂,就讓以下範例來讓你對回呼函式有深刻的認識吧~ Go go!

 

這是一般的函式的標準長相:

function functionName(param1, param2) {

   // 其中放入待執行程式碼 或是 return 返回值

}

🦦 小複習:function 可以擁有名字,也可為匿名函式。除此之外,傳入函式的參數 (argument/ parameter) 如果超過一項,需以逗號分隔,同時注意參數的排列具順序、對應性。

 

但如果今天有兩個函式需要運行… 情況會是如何?

第一個函式:

function firstFunc(x) {

    alert(x+1);

}

 

第二個函式:

function secondFunc(y, z) {

   …  // 一些功能

 

若小白🙆‍♀️想先運行第二個函式後執行第一個,小白可以使用回呼這樣寫~ 

function firstFunc(x) {

    alert(x+1);

}




function secondFunc(y, callback) {

   callback(y);

} 




secondFunc(1, firstFunc);     // 呼叫 secondFunc 函式

運作方式: 🔑 務必行行理解,並能說出每一行的用途與先後順序

現在想像你是電腦(由上而下、由左而右掃視)

  1. 第一眼你看到了兩個函式 >> 你心理有數知道要幹嘛了
  2. 再瞥了一眼 secondFunc(1, firstFunc);  ,你瞬間接收到 secondFunc 要被執行的訊號,這時你開始執行 secondFunc  
  3. 仔細把 secondFunc 的參數看過後,發現裡頭有一個 callback function,也就是我們的 firstFunc
  4. 將secondFunc 中傳入的值依順序帶入參數,這時我們會發現到:callback(y); 意同 callback(1); 也等同 firstFunc(1)
  5. 經以上解析後,你轉而執行 alert(1+1); 並跳出內容為 “2” 的對話視窗

用 Codepen 操作會有以上結果👆

小結:回呼函式 (callback function) 本質上與一般函式相同,差別僅在於「被呼叫執行的時機」。更精確地說,回呼函式為「在一支函式執行後,才開始執行的函式」

 

常見的回呼函式有 2 種:

第一種為用於控制時間與製作計時器的函式 

  1. setTimeout

顧名思義:set (設定)timeout (「時間到」),意即:設定何時時間到

  • 功能:延遲了某段時間後,才去執行的指定的程式碼

👉 第一個參數為時間到時要執行的程式,第二個參數為延遲時間(單位:毫秒)

  • 特性:程式僅執行一次、不重複(若要重複請見以下 setInterval)
  • 時間單位:毫秒 (milliseconds)   

🦦 補: 1 秒 = 1000 毫秒

  • 清除:可用 clearTimeout() 來取消還未執行的 setTimeout() 功能

註:setTimeout() 中回傳的 ID 必須作為 clearTimeout() 的參數才能終止 setTimeout()  的設定

 

範例:

<button onclick="irisGreeting()">Interact with Iris!</button>

<script>

function irisGreeting() {

  setTimeout(function() { alert("Hola"); }, 3000);

}

</script>

解說:點擊 button 後三秒電腦會自動彈出寫有「Hola」 對話視窗,視窗關閉後不再顯示

 

  1. setInterval 

顧名思義:set (設定)interval (間隔),意即:設定時間的間隔

  • 功能:延遲固定某段時間後,不斷執行指定的程式碼

👉 第一個參數為時間到時要重複執行的程式,第二個參數為延遲時間(單位:毫秒)

  • 特性:間隔一段時間重複進行
  • 時間單位:毫秒 (milliseconds)  
  • 清除:當還未使用 clearInterval() 之前,setInterval() 中的指定程式都會不斷重複執行

註:若要使用 clearInterval(),需事先把 interval 擺入變數中,其後若要終止執行時再將該變數帶入 clearInterval 中作為參數即可

 

範例:

<button onclick="irisGreeting()">Interact with Iris!</button>

<script>

function irisGreeting() {

  setInterval(function() { alert("Hola"); }, 3000);

}

</script>

解說:點擊 button 後三秒電腦會自動彈出寫有「Hola」 對話視窗,視窗關閉後三秒後又會跳出,不斷循環(寫 setInterval 務必小心~ 如果沒有搭配 clearInterval 容易當機唷)

第二種為事件監聽

什麼是事件監聽?

概念很簡單,就是監聽一個事件(有講等於沒講嘛!?😂)別急著罵我,先動動腦想想在我們使用電腦或是觸控設備(手機、平板)時,有哪些行為? 

對~沒錯👍  答案有太多 說都說不完,姑且讓我簡單說幾個:滑鼠點擊、游標滑動、按下按鈕、切換頁面… 太多太多

 

我們統稱「滑鼠點擊、游標滑動、按下按鈕、切換頁面…」這些行為「事件」。因此,監聽事件就是觀察使用者的一舉一動,當使用者作出某些行為時,電腦方執行相對應的操作。

 

事件監聽對象有… element、document 和 window 

事件監聽的寫法範例:document.addEventListener(event, function, useCapture)

🦦  解說:第一個參數為一個事件(譬如 “click” 點擊);第二個參數為「當出現指定事件後要執行的函式」;第三個參數為布林值可選擇要加與否  [這部分較深入詳細請見其他大大網站]

 

如上所述,事件分多種,以下列出常見的分類

  1. 滑鼠 mouse events

例如:click 點擊, mouseover 游標滑過、dbclick 點擊兩次、contextmenu 滑鼠右鍵展開選單

  1. 觸碰 touch events (手機、平板才有)

例如:touchmove 手指移動、touchstart 手指觸碰到螢幕 

  1. 鍵盤 keyboard events

例如:

  1. 滾輪 wheel events

例如:wheel 滾動滑鼠

 

事件監聽範例:

<button id="button">

  我是程式小白

</button>

<br>

<h5 id=heading>

  猜猜我是誰

</h5>




<script>

document.getElementById("button").addEventListener("click", function () { 

  document.getElementById("heading").innerHTML= "我是你的程式學習好朋友!";                

});

</script>

按鈕下方字串因「點擊」事件被觸發而變動(如下二圖)

若仔細觀察以上程式碼,不難察覺小白在 addEventListener 的參數中加入了「函式」,這樣的寫法為回呼函式的內嵌,你也可以寫成以下:

function showWhoIsIris() { 

  document.getElementById("heading").innerHTML= "我是你的程式學習好朋友!";

}

  

  document.getElementById("button").addEventListener("click", showWhoIsIris);

說了這麼多,為什麼要用回呼函式?回呼函式又有哪些優點呢?

 

  1. Why use callback functions? 
  • 突破 JS 中同步(程式碼由上而下讀取)和 single-thread 單執行緒的限制,使特定事件能夠優先或按一定先後次序執行
  • 假如沒有回呼的設定,程式碼需要按原先撰寫次序運行,雖然在一般狀況下沒有問題,但當一個事件拖太久無法執行時就會造成程式碼阻塞 (blocking) 的情形
  • 補充:事件循環 (event loop) 概念 (stack、heap、queue 等)

 

講到這… 就會不免牽扯到「同步」和「非同步」的問題了

👉 同步 (Synchronous) 指的是程式必須等待前面的程式執行完才能執行。

👉 非同步(Asynchronous) 是指程式不須等待前面的程式執行完就能執行,使瀏覽器能同時執行多個任務而不會產生以上所述頁面阻塞的情形

 

非同步的概念也能應用於 AJAX (Asynchronous Javascript and XML) 在串接第三方 API 時請求遠端伺服器  (server) 回應之上  這部分有興趣延伸的朋友可以上網爬爬文

 

  1. What are the pros (and cons) of callback functions? 回呼函式優缺總匯

優 (Pros)

  • 增加重複使用 (reusability) 性
  • 程式碼更易讀、易維護

 

缺 (Cons)

  • callback hell:回呼中有回呼終有回呼,以此巢狀方式不斷包裹交織,最後成為一個非常複雜的結構
  • 解決以上地獄結構,你可以…

(1) 把程式碼分段拆開減少巢狀寫法重複次數

(2) 使用 ES6 Promise 和 async/ await 等工具

 

呼🥱  一次吸收這麼多 你應該也跟我一樣快知識爆炸了🤦‍♀️

最後再複習一次這集日記重點就收工嘍

 

  1. Callback function 介紹
  2. 常見的兩種 Callback function 
  3. Callback function 優缺與改良

 

最後~ 如果你想繼續追蹤我的 JS 系列筆記 歡迎加入程式小白群😍  和我&其他程式學習朋友們一起討論切磋 JS 和 Python 唷! 

 

參考資料 References:

  1. https://ithelp.ithome.com.tw/articles/10191970
  2. https://matthung0807.blogspot.com/2019/04/javascript.html
  3. https://medium.com/%E9%A6%AC%E6%A0%BC%E8%95%BE%E7%89%B9%E7%9A%84%E5%86%92%E9%9A%AA%E8%80%85%E6%97%A5%E8%AA%8C/js-%E4%BA%8B%E4%BB%B6%E7%AD%86%E8%A8%98-%E4%B8%8A-5377a572be51
  4. https://matthung0807.blogspot.com/2019/05/javascript-callback-callback-function.html
  5. https://kuro.tw/posts/2019/02/23/%E8%AB%87%E8%AB%87-JavaScript-%E7%9A%84-setTimeout-%E8%88%87-setInterval/
  6. https://www.w3schools.com/JSREF/obj_keyboardevent.asp
  7. https://www.freecodecamp.org/news/javascript-callback-functions-what-are-callbacks-in-js-and-how-to-use-them/
  8. https://dev.to/marek/are-callbacks-always-asynchronous-bah
  9. https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part4/callback.html
  10. https://www.sitepoint.com/demystifying-javascript-closures-callbacks-iifes/
  11. https://zellwk.com/blog/callbacks/
  12. https://www.youtube.com/watch?v=8aGhZQkoFbQ&feature=emb_logo&ab_channel=JSConf
  13. https://www.dashingd3js.com/lessons/javascript-callback-functions

 

iris

iris

我是踏踏實實的程式小白🙆‍♀ 今年開始學習 JS 和 React~ 這邊專放我學習時的筆記和心得📒 如果喜歡我的文章不妨加入我一起學習💪 營造有趣學習程式大圈圈

Leave a Reply