Skip to content
This page is a draft. It may be incomplete or contain inaccuracies. If you have any comment, please feel free to leave some feedback!

ลดโค้ดซ้ำซ้อนด้วยฟังก์ชัน

ในตอนนี้เราจะลองเอาฟังก์ชันมาใช้ลดความซ้ำซ้อนของโค้ดครับ

รู้จักกับคำว่า Refactoring

  • เราจะกลับไปแก้ไขโปรเจกต์ก่อน ที่เราเคยทำ ถ้าจำกันได้ ในโปรเจกต์ก่อน จะมีโค้ดบางส่วนที่หน้าตาเหมือน กันค่อนข้างเยอะ เราจะใช้คอนเซปต์ของการสร้างฟังก์ชันมา refactor หรือปรับโครงสร้างโค้ดของเรา ให้มีโค้ดซ้ำซ้อนน้อยลงครับ

  • คำว่า “refactor” หมายถึงการปรับแก้โครงสร้างโค้ด โดยที่โค้ดยังทำงานเหมือนเดิมครับ

Refactor มินิโปรเจกต์ ควิซอย่างง่าย

  • ในมินิโปรเจกต์: ควิซอย่างง่าย เราได้เขียนโค้ดชุดนี้เพื่อกำหนดการทำงานให้กับปุ่มตัวเลือกต่าง

    js
    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
    }
  • จะเห็นว่าในกรณีของปุ่มที่ตรงกับคำตอบไม่ถูกต้อง โค้ดภายในนั้นเหมือน กันหมด เรียกว่าเป็นโค้ดซ้ำซ้อน (duplicated code) ครับ

    js
    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 แล้วนำโค้ดที่ซ้ำซ้อนมาใส่ในฟังก์ชันนี้

    js
    let 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 แทนการเขียนโค้ดซ้ำ ในทุก ปุ่ม

    js
    let 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

    js
    let 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 ของมันเอง แต่จะเห็นว่า ฟังก์ชันเหล่านี้เราสร้างขึ้นมา แค่เพื่อให้มันเรียกใช้งานฟังก์ชันอื่น อีกที

    js
    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()
    }
  • จริง แล้ว เราสามารถกำหนดฟังก์ชันสองฟังก์ชันที่เราสร้างไว้ (handleIncorrectAnswer กับ handleCorrectAnswer) เข้าไปที่ onclick ของแต่ละปุ่มได้เลย เพื่อให้โค้ดกระชับมากขึ้น

    js
    let 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>
    index.html