ตัวดำเนินการทางตรรกศาสตร์
ในตอนนี้เราจะได้รู้จักกับตัวดำเนินการ
!
&&
และ||
ครับตัวดำเนินการ สัญลักษณ์ลอจิกเกต สัญลักษณ์ทางคณิตศาสตร์ !
(Logical NOT)&&
(Logical AND)||
(Logical OR)Logical NOT (
!
) (เปลี่ยนจากtrue
เป็นfalse
, และจากfalse
เป็นtrue
)x
!x
true
false
false
true
Logical AND (
&&
) จะมีค่าเป็นจริงก็ต่อเมื่อทั้งด้านซ้ายและด้านขวา มีค่าเป็นจริงทั้งคู่เท่านั้นa
b
a && b
true
true
true
true
false
false
false
true
false
false
false
false
Logical OR (
||
) จะมีค่าเป็นจริงก็ต่อเมื่อ ด้านซ้าย หรือ ด้านขวา มีค่าเป็นจริงอย่างน้อยหนึ่งด้านa
b
a || b
true
true
true
true
false
true
false
true
true
false
false
false
ตัวอย่างการนำตัวดำเนินการทางตรรกศาสตร์ไปใช้
ยกตัวอย่างแบบฟอร์มลงทะเบียน ฟอร์มเหล่านี้มักจะมีช่องให้ทำเครื่องหมาย (checkbox) เพื่อยอมรับเงื่อนไขการใช้งาน (Terms and Conditions) และนโยบายความเป็นส่วนตัว (Privacy Policy) โดยปุ่มลงทะเบียนจะเปิดใช้งาน ก็ต่อเมื่อทำเครื่องหมายถูกลงในทั้งสองช่องเท่านั้น:
ลองเล่นกับตัวอย่างข้างบนดู
- ตอนแรก ปุ่ม Sign Up จะไม่สามารถกดได้
- ลองทำเครื่องหมายในช่อง Terms and Conditions และ Privacy Policy ดู → ปุ่ม Sign Up จะเปิดให้ใช้งานได้เมื่อทั้งสองช่องถูกติ๊กเท่านั้น
- กดปุ่ม Sign Up ดู → จะมีข้อความแสดงขึ้นมา
- ลองเอาเครื่องหมายออกจากช่องใดช่องหนึ่งดู → ปุ่ม Sign Up จะไม่สามารถกดได้
เริ่มจากโค้ดตั้งต้นนี้:
html<p> <input id="acceptTerms" type="checkbox" /> <label for="acceptTerms">I agree to the Terms and Conditions</label> </p> <p> <input id="acceptPrivacyPolicy" type="checkbox" /> <label for="acceptPrivacyPolicy">I agree to the Privacy Policy</label> </p> <p> <input disabled type="button" id="signUpButton" value="Sign Up" /> </p> <script> let acceptTerms = document.getElementById('acceptTerms') let acceptPrivacyPolicy = document.getElementById('acceptPrivacyPolicy') let signUpButton = document.getElementById('signUpButton') acceptTerms.onchange = () => { // เดี๋ยวมาเขียน } acceptPrivacyPolicy.onchange = () => { // เดี๋ยวมาเขียน } signUpButton.onclick = () => { alert('Sign up button clicked!') } </script>
ในโค้ดนี้ จะมีโค้ด HTML บางอย่างที่เราอาจไม่เคยเจอ
อย่างแรกคือ
<input type="checkbox">
เป็นอินพุตชนิดหนึ่งที่ผู้ใช้งานเลือกทำเครื่องหมายได้ ว่าจะติ๊กหรือไม่ติ๊กอย่างที่สองคือ
<label for="id">
หน้าที่ของมันคือ ทำให้ผู้ใช้งานสามารถคลิกที่ข้อความที่อยู่ข้างใน label แทนการคลิกที่อินพุตได้อย่างที่สามคือ attribute
disabled
ทำให้ element นั้นไม่สามารถใช้งานได้ จะเห็นว่าถ้าปุ่มถูกdisabled
อยู่ เวลาคลิกจะไม่มีอะไรเกิดขึ้นเลย
ส่วนของ JavaScript จะมีเรื่องที่ควรรู้เพิ่มเติมคือ
ชื่ออินพุต.checked
เอาไว้ตรวจสอบว่า อินพุตนั้นถูกติ๊กหรือไม่TIP
ลองสั่ง
acceptTerms.checked
กับacceptPrivacyPolicy.checked
ในคอนโซลดูครับชื่ออินพุต.onchange = () => { /* โค้ด */ }
เอาไว้ใส่โค้ดที่ต้องการให้ทำ เมื่ออินพุตนั้นถูกเปลี่ยนค่าTIP
ลองใส่
console.log
ลงในโค้ด แล้วทดสอบดู จะเห็นว่าเมื่อติ๊กหรือเอาติ๊กออก ก็จะมีข้อความแสดงในคอนโซลjsacceptTerms.onchange = () => { console.log('A') } acceptPrivacyPolicy.onchange = () => { console.log('B') }
ลองทำด้วยความรู้ตอนนี้
เราจะลองใช้ความรู้ที่เราเรียนไปก่อนหน้านี้ มาทำแบบฟอร์มลงทะเบียนให้เปิดใช้งานปุ่ม Sign Up กัน โดยจะยังไม่ใช้ตัวดำเนินการทางตรรกศาสตร์ สามารถเขียนโค้ดได้แบบนี้:
jsacceptTerms.onchange = () => { if (acceptTerms.checked) { if (acceptPrivacyPolicy.checked) { signUpButton.disabled = false } else { signUpButton.disabled = true } } else { signUpButton.disabled = true } } acceptPrivacyPolicy.onchange = () => { if (acceptTerms.checked) { if (acceptPrivacyPolicy.checked) { signUpButton.disabled = false } else { signUpButton.disabled = true } } else { signUpButton.disabled = true } }
หมายเหตุ
โค้ดข้างใน
acceptTerms.onchange
กับacceptPrivacyPolicy.onchange
นั้นเหมือนกัน เพราะเมื่อใดก็ตามที่เราติ๊กถูกหรือเอาติ๊กถูกออกจากกล่องอินพุตอันใดอันหนึ่ง เราต้องการตรวจสอบสถานะของอินพุตทั้งสองอันเสมอจะเห็นว่า โค้ดนี้ค่อนข้างยาว เดี๋ยวเราจะแก้ให้ดีขึ้นกว่านี้
ใช้ &&
เพื่อรวมเงื่อนไขเข้าด้วยกัน
เราสามารถนำตัวดำเนินการทางตรรกศาสตร์มาใช้ เพื่อรวมเงื่อนไขทั้งสองเข้าด้วยกัน และทำให้โค้ดสั้นลงได้
jsacceptTerms.onchange = () => { if (acceptTerms.checked && acceptPrivacyPolicy.checked) { signUpButton.disabled = false } else { signUpButton.disabled = true } } acceptPrivacyPolicy.onchange = () => { if (acceptTerms.checked && acceptPrivacyPolicy.checked) { signUpButton.disabled = false } else { signUpButton.disabled = true } }
ใช้ !
เพื่อกลับเงื่อนไข และจัดรูปให้โค้ดสั้นลงอีก
กรณีที่โค้ดอยู่ในรูปแบบนี้:
jsif (x) { y = true } else { y = false }
สามารถเขียนให้สั้นลงได้เป็น:
jsy = x
ทำไมถึงเขียนให้สั้นลงได้?
ในกรณีที่ x เป็นข้อมูลชนิด boolean จะเห็นพบว่า:
ในกรณีที่
x
เป็นจริง เราสามารถแทนที่y = true
ด้วยy = x
ได้ เพราะว่าx
มีค่าเป็นtrue
อยู่แล้ว:jsif (x) { y = true y = x // เพราะว่าในบล็อกนี้ x มีค่าเป็น true } else { y = false }
ในกรณีที่
x
เป็นเท็จ เราสามารถแทนที่y = false
ด้วยy = x
ได้ เพราะว่าx
มีค่าเป็นfalse
อยู่แล้ว:jsif (x) { y = x // เพราะว่าในบล็อกนี้ x มีค่าเป็น true } else { y = false y = x // เพราะว่าในบล็อกนี้ x มีค่าเป็น false }
เราจะพบว่า ไม่ว่า
x
จะเป็นจริงหรือเท็จ สิ่งที่จะเกิดขึ้นตามมา เหมือนกันทั้งสองกรณี นั่นก็คือy = x
เราจึงสามารถเอาเงื่อนไขออกได้เลยjsy = x
และด้วยเหตุผลเดียวกัน กรณีที่โค้ดอยู่ในรูปแบบนี้:
jsif (x) { y = false } else { y = true }
สามารถเขียนให้สั้นลงได้เป็น:
jsy = !x
ทำไมถึงเขียนให้สั้นลงได้?
เนื่องจาก
false
คือ!true
(เท็จ คือ ไม่จริง) และtrue
คือ!false
(จริง คือ ไม่เท็จ)…โค้ดของเราจึงสามารถเขียนเป็นแบบนี้ได้:
jsif (x) { y = false y = !true } else { y = true y = !false }
และด้วยเหตุผลเดียวกันกับตัวอย่างก่อนหน้า เราสามารถแปลงโค้ดเป็นแบบนี้:
jsif (x) { y = !true y = !x // เพราะว่าในบล็อกนี้ x มีค่าเป็น true, !x มีค่าเป็น false } else { y = !false y = !x // เพราะว่าในบล็อกนี้ x มีค่าเป็น false, !x มีค่าเป็น true }
และสุดท้ายก็ย่อเป็น:
jsy = !x
เนื่องจากโค้ดของโปรแกรมเราอยู่ในรูปแบบหลัง เราจึงสามารถย่อโค้ดให้สั้นลงได้อีกแบบนี้:
jsacceptTerms.onchange = () => { signUpButton.disabled = !(acceptTerms.checked && acceptPrivacyPolicy.checked) } acceptPrivacyPolicy.onchange = () => { signUpButton.disabled = !(acceptTerms.checked && acceptPrivacyPolicy.checked) }
อย่าลืมเครื่องหมายวงเล็บ
ในบรรทัดที่ 2 และ 5 ของโค้ดข้างต้น จะเห็นว่ามีเครื่องหมายวงเล็บครอบอยู่ ซึ่งเป็นเพราะว่า ตัวดำเนินการ
!
มีความสำคัญมากกว่า&&
ดังนั้นเราจึงต้องใส่วงเล็บเข้าไป เพราะหากไม่ใส่วงเล็บ คอมพิวเตอร์จะจัดกลุ่มโค้ดของเราแบบนี้:(!acceptTerms.checked) && acceptPrivacyPolicy.checked
ซึ่งไม่ใช่ที่เราต้องการ
ใช้ De Morgan's law เพื่อกลับเงื่อนไข
กฏของ De Morgan เป็นกฎในวิชาตรรกศาสตร์ที่ระบุไว้ว่า[1]
และ
ซึ่งแปลเป็นภาษา JavaScript ได้ดังนี้:
โค้ดนี้… …มีความหมายเหมือนกับโค้ดนี้ !(p && q)
!p || !q
!(p || q)
!p && !q
เราสามารถนำกฏของ De Morgan มาใช้กับโค้ดของเราได้แบบนี้:
jsacceptTerms.onchange = () => { signUpButton.disabled = !acceptTerms.checked || !acceptPrivacyPolicy.checked } acceptPrivacyPolicy.onchange = () => { signUpButton.disabled = !acceptTerms.checked || !acceptPrivacyPolicy.checked }
สรุป
ในบทนี้เราได้นำตัวดำเนินการทางตรรกศาสตร์ต่างๆ มาใช้งาน เพื่อรวมเงื่อนไขหลายๆ เงื่อนไขเข้าด้วยกัน เพื่อทำให้โค้ดของเราสั้นลงได้
แต่จะเห็นว่าตอนนี้ โค้ดภายใน
acceptTerms.onchange
กับacceptPrivacyPolicy.onchange
นั้นเหมือนกันเลย เพื่อให้อินพุตทั้งสองอันทำงานเหมือนกัน เราจึงเขียนโค้ดที่ซ้ำซ้อนกันขึ้นมา (duplicate code) แต่ในบทต่อไป เราจะเรียนรู้การสร้างฟังก์ชัน เพื่อทำให้โค้ดที่ซ้ำซ้อนนี้หายไปได้jslet recheckSignUpButton = () => { signUpButton.disabled = !acceptTerms.checked || !acceptPrivacyPolicy.checked } acceptTerms.onchange = () => { recheckSignUpButton() } acceptPrivacyPolicy.onchange = () => { recheckSignUpButton() }
ในภาษาอังกฤษ กฏนี้ระบุไว้ว่า "The negation of a conjunction is the disjunction of the negations" และ "The negation of a disjunction is the conjunction of the negations" โดยที่ conjunction หมายถึง
&&
, disjunction หมายถึง||
, และ negation หมายถึง!
↩︎