ลดโค้ดซ้ำซ้อนด้วยฟังก์ชัน
ในตอนนี้เราจะลองเอาฟังก์ชันมาใช้ลดความซ้ำซ้อนของโค้ดครับ
รู้จักกับคำว่า Refactoring
เราจะกลับไปแก้ไขโปรเจกต์ก่อนๆ ที่เราเคยทำ ถ้าจำกันได้ ในโปรเจกต์ก่อนๆ จะมีโค้ดบางส่วนที่หน้าตาเหมือนๆ กันค่อนข้างเยอะ เราจะใช้คอนเซปต์ของการสร้างฟังก์ชันมา refactor หรือปรับโครงสร้างโค้ดของเรา ให้มีโค้ดซ้ำซ้อนน้อยลงครับ
คำว่า “refactor” หมายถึงการปรับแก้โครงสร้างโค้ด โดยที่โค้ดยังทำงานเหมือนเดิมครับ
Refactor มินิโปรเจกต์ ควิซอย่างง่าย
ในมินิโปรเจกต์: ควิซอย่างง่าย เราได้เขียนโค้ดชุดนี้เพื่อกำหนดการทำงานให้กับปุ่มตัวเลือกต่างๆ
jschoiceA.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceB.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceC.onclick = () => { beforeAnswer.hidden = true correctFeedback.hidden = false } choiceD.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false }
จะเห็นว่าในกรณีของปุ่มที่ตรงกับคำตอบไม่ถูกต้อง โค้ดภายในนั้นเหมือนๆ กันหมด เรียกว่าเป็นโค้ดซ้ำซ้อน (duplicated code) ครับ
jschoiceA.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceB.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceC.onclick = () => { beforeAnswer.hidden = true correctFeedback.hidden = false } choiceD.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false }
เราสามารถสร้างเป็นฟังก์ชันเพื่อรับมือการกดปุ่มที่ตรงกับคำตอบที่ผิดได้ ผมจะตั้งชื่อว่า
handleIncorrectAnswer
แล้วนำโค้ดที่ซ้ำซ้อนมาใส่ในฟังก์ชันนี้jslet handleIncorrectAnswer = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceA.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceB.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceC.onclick = () => { beforeAnswer.hidden = true correctFeedback.hidden = false } choiceD.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false }
จากนั้นเราก็จะทำให้โค้ดเรียกใช้ฟังก์ชัน
handleIncorrectAnswer
แทนการเขียนโค้ดซ้ำๆ ในทุกๆ ปุ่มjslet handleIncorrectAnswer = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceA.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false handleIncorrectAnswer() } choiceB.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false handleIncorrectAnswer() } choiceC.onclick = () => { beforeAnswer.hidden = true correctFeedback.hidden = false } choiceD.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false handleIncorrectAnswer() }
นี่คือท่าการรีแฟคเตอร์ที่เรียกว่า Extract Function (บางภาษาเรียกว่า Extract Method) เป็นการแกะโค้ดภายในฟังก์ชัน แยกออกมาเป็นฟังก์ชันใหม่
เพื่อความสม่ำเสมอในโค้ดทั้งสองกรณี (คำตอบถูกและคำตอบผิด) ผมจะแยกโค้ดการทำงานของปุ่มคำตอบที่ถูกต้องออกมาด้วย เป็นฟังก์ชันที่ชื่อ
handleCorrectAnswer
jslet handleIncorrectAnswer = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } let handleCorrectAnswer = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceA.onclick = () => { handleIncorrectAnswer() } choiceB.onclick = () => { handleIncorrectAnswer() } choiceC.onclick = () => { beforeAnswer.hidden = true correctFeedback.hidden = false handleCorrectAnswer() } choiceD.onclick = () => { handleIncorrectAnswer() }
กำหนดฟังก์ชันให้กับปุ่มตัวเลือกตรงๆ
ในตอนนี้ เราได้กำหนดฟังก์ชัน onclick ให้ปุ่มต่างๆ โดยแต่ละปุ่มจะมีฟังก์ชัน onclick ของมันเอง แต่จะเห็นว่า ฟังก์ชันเหล่านี้เราสร้างขึ้นมา แค่เพื่อให้มันเรียกใช้งานฟังก์ชันอื่นๆ อีกที
jslet handleIncorrectAnswer = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } let handleCorrectAnswer = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceA.onclick = () => { handleIncorrectAnswer() } choiceB.onclick = () => { handleIncorrectAnswer() } choiceC.onclick = () => { handleCorrectAnswer() } choiceD.onclick = () => { handleIncorrectAnswer() }
จริงๆ แล้ว เราสามารถกำหนดฟังก์ชันสองฟังก์ชันที่เราสร้างไว้ (
handleIncorrectAnswer
กับhandleCorrectAnswer
) เข้าไปที่ onclick ของแต่ละปุ่มได้เลย เพื่อให้โค้ดกระชับมากขึ้นjslet handleIncorrectAnswer = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } let handleCorrectAnswer = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceA.onclick = () => { handleIncorrectAnswer() } choiceA.onclick = handleIncorrectAnswer choiceB.onclick = () => { handleIncorrectAnswer() } choiceB.onclick = handleIncorrectAnswer choiceC.onclick = () => { handleCorrectAnswer() } choiceC.onclick = handleCorrectAnswer choiceD.onclick = () => { handleIncorrectAnswer() } choiceD.onclick = handleIncorrectAnswer
สุดท้ายแล้วโค้ดของโปรเจกต์เราจึงเหลือแค่นี้:
ดูโค้ด (ก่อน)
html<!doctype html> <html> <head> <title>Simple Quiz</title> </head> <body> <h1>Simple Quiz</h1> <div id="beforeAnswer"> <p id="question"><b>คำถาม:</b> JavaScript ถูกสร้างเมื่อปีไหน</p> <input id="choiceA" type="button" value="(A) 1993"> <input id="choiceB" type="button" value="(B) 1994"> <input id="choiceC" type="button" value="(C) 1995"> <input id="choiceD" type="button" value="(D) 1996"> </div> <p id="correctFeedback" hidden> <b>ถูกต้อง!</b> 🎉 </p> <div id="incorrectFeedback" hidden> <p> <b>ยังไม่ถูก</b> </p> <input id="tryAgain" type="button" value="ลองอีกครั้ง"> </div> <script> let beforeAnswer = document.getElementById('beforeAnswer') let correctFeedback = document.getElementById('correctFeedback') let incorrectFeedback = document.getElementById('incorrectFeedback') let tryAgain = document.getElementById('tryAgain') let question = document.getElementById('question') let choiceA = document.getElementById('choiceA') let choiceB = document.getElementById('choiceB') let choiceC = document.getElementById('choiceC') let choiceD = document.getElementById('choiceD') choiceA.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceB.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceC.onclick = () => { beforeAnswer.hidden = true correctFeedback.hidden = false } choiceD.onclick = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } tryAgain.onclick = () => { incorrectFeedback.hidden = true beforeAnswer.hidden = false } </script> </body> </html>
ดูโค้ด (หลัง)
html<!doctype html> <html> <head> <title>Simple Quiz (v2)</title> </head> <body> <h1>Simple Quiz</h1> <div id="beforeAnswer"> <p id="question"><b>คำถาม:</b> JavaScript ถูกสร้างเมื่อปีไหน</p> <input id="choiceA" type="button" value="(A) 1993"> <input id="choiceB" type="button" value="(B) 1994"> <input id="choiceC" type="button" value="(C) 1995"> <input id="choiceD" type="button" value="(D) 1996"> </div> <p id="correctFeedback" hidden> <b>ถูกต้อง!</b> 🎉 </p> <div id="incorrectFeedback" hidden> <p> <b>ยังไม่ถูก</b> </p> <input id="tryAgain" type="button" value="ลองอีกครั้ง"> </div> <script> let beforeAnswer = document.getElementById('beforeAnswer') let correctFeedback = document.getElementById('correctFeedback') let incorrectFeedback = document.getElementById('incorrectFeedback') let tryAgain = document.getElementById('tryAgain') let question = document.getElementById('question') let choiceA = document.getElementById('choiceA') let choiceB = document.getElementById('choiceB') let choiceC = document.getElementById('choiceC') let choiceD = document.getElementById('choiceD') let handleIncorrectAnswer = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } let handleCorrectAnswer = () => { beforeAnswer.hidden = true incorrectFeedback.hidden = false } choiceA.onclick = handleIncorrectAnswer choiceB.onclick = handleIncorrectAnswer choiceC.onclick = handleCorrectAnswer choiceD.onclick = handleIncorrectAnswer tryAgain.onclick = () => { incorrectFeedback.hidden = true beforeAnswer.hidden = false } </script> </body> </html>