เรารู้จักตัวดำเนินการเปรียบเทียบมากมายจากคณิตศาสตร์
ใน JavaScript พวกเขาเขียนดังนี้:
มากกว่า/น้อยกว่า: a > b
, a < b
มากกว่า/น้อยกว่าหรือเท่ากับ: a >= b
, a <= b
เท่ากับ: a == b
โปรดทราบว่าเครื่องหมายความเท่าเทียมกันสองเท่า ==
หมายถึงการทดสอบความเท่าเทียมกัน ในขณะที่เครื่องหมาย a = b
อันเดียวหมายถึงการมอบหมายงาน
ไม่เท่ากับ: ในคณิตศาสตร์ สัญกรณ์คือ ≠
แต่ใน JavaScript จะเขียนเป็น a != b
ในบทความนี้ เราจะเรียนรู้เพิ่มเติมเกี่ยวกับการเปรียบเทียบประเภทต่างๆ วิธีที่ JavaScript สร้างการเปรียบเทียบ รวมถึงลักษณะเฉพาะที่สำคัญ
ในตอนท้ายคุณจะพบสูตรที่ดีในการหลีกเลี่ยงปัญหาที่เกี่ยวข้องกับ "ลักษณะเฉพาะของ JavaScript"
ตัวดำเนินการเปรียบเทียบทั้งหมดส่งคืนค่าบูลีน:
true
- หมายถึง "ใช่" "ถูกต้อง" หรือ "ความจริง"
false
- หมายถึง "ไม่" "ผิด" หรือ "ไม่เป็นความจริง"
ตัวอย่างเช่น:
การแจ้งเตือน( 2 > 1 ); // จริง (ถูกต้อง) การแจ้งเตือน ( 2 == 1 ); // เท็จ (ผิด) การแจ้งเตือน( 2 != 1 ); // จริง (ถูกต้อง)
ผลลัพธ์การเปรียบเทียบสามารถกำหนดให้กับตัวแปรได้ เช่นเดียวกับค่าใดๆ:
ให้ผลลัพธ์ = 5 > 4; // กำหนดผลลัพธ์ของการเปรียบเทียบ การแจ้งเตือน (ผลลัพธ์); // จริง
หากต้องการดูว่าสตริงมีค่ามากกว่าสตริงอื่นหรือไม่ JavaScript จะใช้ลำดับที่เรียกว่า "พจนานุกรม" หรือ "พจนานุกรม"
กล่าวอีกนัยหนึ่ง สตริงจะถูกเปรียบเทียบทีละตัวอักษร
ตัวอย่างเช่น:
การแจ้งเตือน( 'Z' > 'A' ); // จริง alert( 'เรืองแสง' > 'ยินดี' ); // จริง alert( 'ผึ้ง' > 'เป็น' ); // จริง
อัลกอริทึมในการเปรียบเทียบสองสายนั้นง่าย:
เปรียบเทียบอักขระตัวแรกของทั้งสองสาย
ถ้าอักขระตัวแรกจากสตริงแรกมากกว่า (หรือน้อยกว่า) กว่าสตริงอื่น แสดงว่าสตริงแรกมากกว่า (หรือน้อยกว่า) กว่าอักขระตัวที่สอง เราทำเสร็จแล้ว
มิฉะนั้น หากอักขระตัวแรกของสตริงทั้งสองเหมือนกัน ให้เปรียบเทียบอักขระตัวที่สองในลักษณะเดียวกัน
ทำซ้ำจนกระทั่งสิ้นสุดสายใดสายหนึ่ง
หากทั้งสองสายสิ้นสุดด้วยความยาวเท่ากัน แสดงว่าทั้งสองสายเท่ากัน มิฉะนั้น สตริงที่ยาวกว่าจะยิ่งใหญ่กว่า
ในตัวอย่างแรกด้านบน การเปรียบเทียบ 'Z' > 'A'
จะได้ผลลัพธ์ในขั้นตอนแรก
การเปรียบเทียบครั้งที่สอง 'Glow'
และ 'Glee'
ต้องการขั้นตอนเพิ่มเติมเนื่องจากมีการเปรียบเทียบสตริงแบบอักขระต่ออักขระ:
G
ก็เหมือนกับ G
l
เหมือนกับ l
o
มากกว่า e
หยุดที่นี่ สตริงแรกมีขนาดใหญ่กว่า
ไม่ใช่พจนานุกรมจริง แต่เป็นคำสั่ง Unicode
อัลกอริธึมการเปรียบเทียบที่ให้ไว้ข้างต้นเทียบเท่ากับอัลกอริธึมที่ใช้ในพจนานุกรมหรือสมุดโทรศัพท์โดยประมาณ แต่ก็ไม่เหมือนกันทุกประการ
ยกตัวอย่างเรื่องคดี. ตัวอักษรพิมพ์ใหญ่ "A"
ไม่เท่ากับตัวพิมพ์เล็ก "a"
อันไหนใหญ่กว่ากัน? ตัวพิมพ์เล็ก "a"
ทำไม เนื่องจากอักขระตัวพิมพ์เล็กมีดัชนีที่มากกว่าในตารางการเข้ารหัสภายในที่ JavaScript ใช้ (Unicode) เราจะกลับมาที่รายละเอียดเฉพาะและผลที่ตามมาของสิ่งนี้ในบทที่ Strings
เมื่อเปรียบเทียบค่าประเภทต่างๆ JavaScript จะแปลงค่าเป็นตัวเลข
ตัวอย่างเช่น:
การแจ้งเตือน( '2' > 1 ); // จริง สตริง '2' กลายเป็นตัวเลข 2 การแจ้งเตือน( '01' == 1 ); // จริง สตริง '01' กลายเป็นตัวเลข 1
สำหรับค่าบูลีน true
จะกลายเป็น 1
และ false
กลายเป็น 0
ตัวอย่างเช่น:
การแจ้งเตือน ( จริง == 1 ); // จริง การแจ้งเตือน (เท็จ == 0); // จริง
ผลที่ตามมาตลก
เป็นไปได้ว่าในเวลาเดียวกัน:
สองค่ามีค่าเท่ากัน
หนึ่งในนั้นเป็น true
ในฐานะบูลีน และอีกอันเป็น false
ในฐานะบูลีน
ตัวอย่างเช่น:
ให้ = 0; การแจ้งเตือน ( บูลีน (a) ); // เท็จ ให้ข = "0"; การแจ้งเตือน( บูลีน(b) ); // จริง การแจ้งเตือน (a == b); // จริง!
จากมุมมองของ JavaScript ผลลัพธ์นี้ค่อนข้างปกติ การตรวจสอบความเท่าเทียมกันจะแปลงค่าโดยใช้การแปลงตัวเลข (ดังนั้น "0"
จึงกลายเป็น 0
) ในขณะที่การแปลง Boolean
ที่ชัดเจนใช้กฎอีกชุดหนึ่ง
การตรวจสอบความเท่าเทียมกันเป็นประจำ ==
มีปัญหา ไม่สามารถแยกความแตกต่าง 0
จาก false
:
การแจ้งเตือน ( 0 == เท็จ ); // จริง
สิ่งเดียวกันนี้เกิดขึ้นกับสตริงว่าง:
การแจ้งเตือน( '' == เท็จ ); // จริง
สิ่งนี้เกิดขึ้นเนื่องจากตัวถูกดำเนินการประเภทต่างๆ ถูกแปลงเป็นตัวเลขโดยตัวดำเนินการเท่ากับ ==
สตริงว่าง เช่นเดียวกับ false
จะกลายเป็นศูนย์
จะทำอย่างไรถ้าเราต้องการที่จะแยกความแตกต่าง 0
จาก false
?
ตัวดำเนินการความเสมอภาคที่เข้มงวด ===
ตรวจสอบความเท่าเทียมกันโดยไม่มีการแปลงประเภท
กล่าวอีกนัยหนึ่ง ถ้า a
และ b
เป็นประเภทที่แตกต่างกัน ดังนั้น a === b
จะส่งกลับ false
ทันทีโดยไม่ต้องพยายามแปลงค่าเหล่านั้น
มาลองดูกัน:
การแจ้งเตือน ( 0 === เท็จ ); // เท็จ เนื่องจากประเภทต่างกัน
นอกจากนี้ยังมีตัวดำเนินการ "ไม่เท่าเทียมกันอย่างเข้มงวด" !==
คล้ายกับ !=
ตัวดำเนินการความเท่าเทียมที่เข้มงวดจะใช้เวลาในการเขียนนานกว่าเล็กน้อย แต่จะทำให้ชัดเจนว่าเกิดอะไรขึ้น และทำให้มีพื้นที่สำหรับข้อผิดพลาดน้อยลง
มีพฤติกรรมที่ไม่เป็นไปตามสัญชาตญาณเมื่อมีการเปรียบเทียบ null
หรือ undefined
กับค่าอื่นๆ
สำหรับการตรวจสอบความเท่าเทียมกันอย่างเข้มงวด ===
ค่าเหล่านี้แตกต่างกัน เนื่องจากแต่ละค่าเป็นประเภทที่แตกต่างกัน
การแจ้งเตือน ( null === ไม่ได้กำหนด ); // เท็จ
สำหรับการตรวจสอบแบบไม่เข้มงวด ==
มีกฎพิเศษอยู่ สองคนนี้เป็น "คู่รักที่แสนหวาน": พวกเขาเท่าเทียมกัน (ในความหมายของ ==
) แต่ไม่ใช่คุณค่าอื่นใด
การแจ้งเตือน ( null == ไม่ได้กำหนด ); // จริง
สำหรับคณิตศาสตร์และการเปรียบเทียบอื่นๆ < > <= >=
null/undefined
จะถูกแปลงเป็นตัวเลข: null
กลายเป็น 0
ในขณะที่ undefined
กลายเป็น NaN
ตอนนี้เรามาดูเรื่องตลกๆ ที่เกิดขึ้นเมื่อเราใช้กฎเหล่านี้ และที่สำคัญกว่านั้นคือจะไม่ติดกับดักกับพวกเขาได้อย่างไร
ลองเปรียบเทียบ null
กับศูนย์:
การแจ้งเตือน ( null > 0 ); // (1) เท็จ การแจ้งเตือน ( null == 0 ); // (2) เท็จ การแจ้งเตือน ( null >= 0 ); // (3) จริง
ในทางคณิตศาสตร์มันแปลก ผลลัพธ์สุดท้ายระบุว่า “ null
มากกว่าหรือเท่ากับศูนย์” ดังนั้นในการเปรียบเทียบรายการใดรายการหนึ่งข้างต้นจะต้องเป็น true
แต่เป็นเท็จทั้งคู่
เหตุผลก็คือการตรวจสอบความเท่าเทียมกัน ==
และการเปรียบเทียบ > < >= <=
ทำงานแตกต่างกัน การเปรียบเทียบจะแปลง null
เป็นตัวเลข โดยถือเป็น 0
นั่นเป็นสาเหตุที่ (3) null >= 0
เป็นจริง และ (1) null > 0
เป็นเท็จ
ในทางกลับกัน การตรวจสอบความเท่าเทียมกัน ==
สำหรับ undefined
และ null
ถูกกำหนดไว้ หากไม่มีการแปลงใดๆ การตรวจสอบความเท่าเทียมกันจะเท่ากันและไม่เท่ากับสิ่งอื่นใด นั่นเป็นสาเหตุที่ (2) null == 0
เป็นเท็จ
ไม่ควรเปรียบเทียบค่า undefined
กับค่าอื่นๆ:
การแจ้งเตือน ( ไม่ได้กำหนด > 0 ); // เท็จ (1) การแจ้งเตือน ( ไม่ได้กำหนด < 0 ); // เท็จ (2) การแจ้งเตือน ( ไม่ได้กำหนด == 0 ); // เท็จ (3)
ทำไมมันถึงไม่ชอบศูนย์มากนัก? เท็จเสมอ!
เราได้รับผลลัพธ์เหล่านี้เนื่องจาก:
การเปรียบเทียบ (1)
และ (2)
คืน false
เนื่องจาก undefined
จะถูกแปลงเป็น NaN
และ NaN
เป็นค่าตัวเลขพิเศษที่คืนค่า false
สำหรับการเปรียบเทียบทั้งหมด
การตรวจสอบความเท่าเทียมกัน (3)
ส่งคืน false
เนื่องจาก undefined
จะเท่ากับ null
เท่านั้น undefined
และไม่มีค่าอื่นใด
เหตุใดเราจึงดูตัวอย่างเหล่านี้ เราควรจำลักษณะเฉพาะเหล่านี้ตลอดเวลาหรือไม่? ไม่ใช่จริงๆ จริงๆ แล้ว เรื่องยุ่งยากเหล่านี้จะค่อยๆ คุ้นเคยเมื่อเวลาผ่านไป แต่ก็มีวิธีที่ชัดเจนในการหลีกเลี่ยงปัญหากับสิ่งเหล่านั้น:
ปฏิบัติต่อการเปรียบเทียบใดๆ กับ undefined/null
ยกเว้นความเท่าเทียมกันที่เข้มงวด ===
ด้วยความระมัดระวังเป็นพิเศษ
อย่าใช้การเปรียบเทียบ >= > < <=
กับตัวแปรที่อาจเป็น null/undefined
เว้นแต่คุณจะแน่ใจจริงๆ ว่าคุณกำลังทำอะไรอยู่ หากตัวแปรสามารถมีค่าเหล่านี้ได้ ให้ตรวจสอบแยกกัน
ตัวดำเนินการเปรียบเทียบจะส่งกลับค่าบูลีน
สตริงจะถูกเปรียบเทียบทีละตัวอักษรตามลำดับ "พจนานุกรม"
เมื่อเปรียบเทียบค่าประเภทต่างๆ ค่าเหล่านั้นจะถูกแปลงเป็นตัวเลข (ยกเว้นการตรวจสอบความเท่าเทียมกันที่เข้มงวด)
ค่า null
และ undefined
เท่ากับ ==
ซึ่งกันและกันและไม่เท่ากับค่าอื่นใด
โปรดใช้ความระมัดระวังเมื่อใช้การเปรียบเทียบ เช่น >
หรือ <
กับตัวแปรที่บางครั้งอาจเป็น null/undefined
การตรวจสอบ null/undefined
แยกกันเป็นความคิดที่ดี
ความสำคัญ: 5
สำนวนเหล่านี้จะส่งผลอย่างไร?
5 > 4 "แอปเปิ้ล" > "สับปะรด" "2" > "12" ไม่ได้กำหนด == เป็นโมฆะ ไม่ได้กำหนด === เป็นโมฆะ null == "n0n" null === +"n0n"
5 > 4 → จริง "แอปเปิ้ล" > "สับปะรด" → เท็จ "2" > "12" → จริง ไม่ได้กำหนด == null → จริง ไม่ได้กำหนด === null → false null == "n0n" → เท็จ null === +"n0n" → เท็จ
เหตุผลบางประการ:
เห็นได้ชัดว่าจริง
การเปรียบเทียบพจนานุกรมจึงเป็นเท็จ "a"
มีขนาดเล็กกว่า "p"
อีกครั้ง การเปรียบเทียบพจนานุกรม อักขระตัวแรก "2"
มากกว่าอักขระตัวแรก "1"
ค่า null
และ undefined
จะเท่ากันเท่านั้น
ความเสมอภาคที่เข้มงวดนั้นเข้มงวด ประเภทที่แตกต่างจากทั้งสองฝ่ายทำให้เกิดความเท็จ
คล้ายกับ (4)
, null
เท่ากับ undefined
เท่านั้น
ความเท่าเทียมกันที่เข้มงวดของประเภทต่างๆ