==, === ไม่ได้ต่างกันแค่จำนวนของ = นะ

Withusiri Rodsomboon
InsightEra
Published in
4 min readDec 31, 2019

สวัสดีครับผู้อ่านทุกท่าน วันนี้เรื่องที่เราจะมาพูดถึงกันเป็นเรื่องที่หลายๆ คนที่ใช้ javascript ต้องเคยพบเจอ (รวมไปถึงคนในอนาคตที่จะมาใช้งานด้วยต้องเจอแน่ๆ) ซึ่งเรื่องนั้นก็ไม่ใช่เรื่องไกลตัวที่ไหนเลยเป็นเรื่องของเจ้า == และ === ว่ามันทำงานต่างกันอย่างไรนั่นเอง

== และ === คืออะไรกัน

ก่อนอื่นต้องขอแนะนำชื่อให้ทุกคนรู้จักเจ้าสองตัวนี้กันก่อน
ตัวแรก == (สองเท่ากับ) หรือมีชื่ออื่นๆ ว่า loose equality, double equals
ตัวที่สอง === (สามเท่ากับ) ซึ่งชื่ออื่นๆ ของเจ้าตัวนี้ก็คือ strict equality, triple equals
สองตัวนี้คือ Operators (comparison operators) ใน javascript นั่นเองครับ ซึ่งหน้าที่ของตัว == และ === ก็คือใช้ในการเปรียบเทียบค่าสองค่า (เทียบว่าค่าสองค่านี้เท่ากันหรือไม่) แล้วคืนผลลัพธ์ของการเปรียบเทียบกลับมา

แล้วเจ้า == กับ === ต่างกันอย่างไรนะ

ความแตกต่างระหว่าง == และ === ถ้าพูดแบบรวบรัดเพื่อให้เข้าใจง่ายๆ ก็คือ (ในกรณีนี้ขอยกตัวอย่างเป็น if ( x == y) )

== จะทำการแปลง type ของตัวใดตัวหนึ่งหรือทั้งสองตัวเมื่อ type ของ x และ y ไม่เหมือนกัน จากนั้นจึงค่อยทำการเทียบ value ของ x และ y=== จะไม่ทำการแปลง type ของทั้ง x และ y ซึ่งในกรณีที่ type ของ x และ y ไม่เหมือนกันจะส่งผลให้ได้ค่า False กลับมาทันที ถ้า type เหมือนกันก็จะทำการเทียบ value ของ x และ y ต่อ

แต่ถ้าจะพูดถึงการทำงานของ == และ === ให้ละเอียดมากกว่านี้ สิ่งที่เราต้องรู้สองสิ่งก็คือ

“The Abstract Equality Comparison Algorithm” ( == )
และ
“The Strict Equality Comparison Algorithm” ( === )

สองตัวนี้เปรียบเสมือนเงื่อนไขขั้นตอนการทำงานของ == และ === กล่าวคือมันจะเป็นตัวกำหนดเงื่อนไขการเปรียบเทียบและผลลัพธ์ที่จะได้จากการเปรียบเทียบระหว่าง x และ y เราลองไปอ่าน “The Abstract Equality Comparison Algorithm (สำหรับ ==)” กันดีกว่า ว่ามันกำหนดอะไรไว้อย่างไรบ้าง

1. If Type(x) is the same as Type(y), then
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- If Type(x) is Number, then
- If x is NaN, return false.
- If y is NaN, return false.
- If x is the same Number value as y, return true.
- If x is +0 and y is −0, return true.
- If x is −0 and y is +0, return true.
- Return false.
- If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.
- If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
- Return true if x and y refer to the same object. Otherwise, return false.
2. If x is null and y is undefined, return true.3. If x is undefined and y is null, return true.4. If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y).
5. If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
6. If Type(x) is Boolean and Type (y) is Non-Boolean, return the result of the comparison ToNumber(x) == y.7. If Type(y) is Boolean and Type (x) is Non-Boolean, return the result of the comparison x == ToNumber(y).8. If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).
9. If Type(x) is Object and Type(y) is either String or Number,
return the result of the comparison ToPrimitive(x) == y.
10. Return false.

ความรู้สึกแรกหลังอ่านจบเป็นยังไงครับ T-T อะไรเนี่ยใครจะจำได้ ดูพิลึกซับซ้อนวุ่นวายมากๆ แล้วอันนี้ยังเป็นแค่ของ “The Abstract Equality Comparison Algorithm” นะครับ ยังมีอีกตัวอีกนะ !! แต่อย่าพึ่งเศร้าครับ ตอนนี้ 2019 จะ 2020 อยู่แล้วเรามีเครื่องมือช่วยเหลือเราแน่นอน ซึ่งเดี๋ยวผมจะบอกตอนท้ายบทความครับ (สำหรับใครที่อยากอ่านตามไปที่นี่ได้เลยครับ https://www.ecma-international.org/ecma-262/5.1/ ที่ section 11.9.3 และ 11.9.6 ครับ)

เรามาดูกันต่อจากหลักการทำงานของ == ที่พึ่งเอ่ยถึงไปเมื่อสักครู่ เราจะเห็นสิ่งนึงในข้อที่ 4 ครับ

return the result of the comparison x == ToNumber(y)

เอ๋ ? อะไรคือ ToNumber(y) ตอนเราเทียบ เราเทียบ x == y นี่ทำไมถึงมี method อะไรแบบนั้นโผล่ออกมา !
อย่างที่เกริ่นไปตั้งแต่ตอนต้นว่าการเทียบ x == y ถ้า type ไม่เหมือนกัน javascript จะพยายามแปลง type ให้เป็น type เดียวกันก่อนที่จะทำการเทียบ value ซึ่งในกรณีของข้อที่ 4 นั้นเป็นการเทียบระหว่าง x(number) == y(string) เราจะเห็นว่า type ไม่เหมือนกัน javascript เลยทำการแปลง y(string) ให้กลายเป็น y(number) จากนั้นจึงทำการเทียบค่าระหว่าง x(number) กับ y(number) แล้วจึงได้ผลลัพธ์ออกมาครับ

ในทำนองเดียวกันครับกับข้อ 8 เราจะเห็นสิ่งนี้

return the result of the comparison x == ToPrimitive(y)

ตัว ToPrimitive(y) จะทำงานต่างจาก ToNumber() ตรงที่ว่าตัว ToPrimitive() เอาไว้สำหรับแปลง Object ให้เป็น Primitive value ของ Object นั้นๆ ซึ่งการเรียกใช้ ToPrimitive() นั้นจะมีการเรียกการใช้งาน valueOf และ toString ซึ่งโดยปกติ javascript จะใช้ valueOf ก่อนถ้าสามารถแปลงเป็น Primitive value ได้ ก็จะทำการ return กลับมา แต่ถ้าไม่ได้ก็จะใช้ toString ต่อ แล้วถ้าได้ค่า Primitive value ก็จะ return กลับมาเหมือนกันครับ

มาดู case การเปรียบเทียบที่น่าสนใจและชวนสับสน

if ( [] == [] ) {
// this block won't be execute
}
if ( {} == {} ) {
// this block won't be execute
}
if ( null == undefined ) {
// this block will be execute
}

ในกรณีแรกกับกรณีที่สองเป็นกรณีที่หลายๆ คนอาจจะงงว่าทำไมมันถึงได้ False ทั้งๆ ที่ทั้ง x และ y ก็ตัวเดียวกันนี่ (ขอเรียกส่วนข้างหน้าว่า x และส่วนข้างหลังว่า y นะครับ) ซึ่งสาเหตุที่ได้ False กลับมาเป็นเพราะว่าในโลกของ javascript นั้น Array และ Object เป็นตัวแปรแบบ Reference type โดยที่ตัวแปรประเภทนี้จะเก็บ reference เอาไว้แทน ไม่ได้เก็บ value ไว้กับตัวมันเองจริงๆ ส่งผลให้การเทียบกันระหว่าง [], [] หรือ {}, {} นั้นได้ผลลัพธ์เป็น False เพราะมัน reference ไปที่คนละจุดนั่นเองครับ
ส่วนในกรณีที่สามนั้นจะอ้างอิงจากเงื่อนไขข้อที่ 2 และข้อที่ 3 จาก “The Abstract Equality Comparison Algorithm” ว่าถ้า x หรือ y ตัวใดตัวหนึ่งเป็น null และอีกตัวเป็น undefined จะทำให้ได้ผลลัพธ์ออกมาเป็น true เสมอครับ ไม่มีการแปลง type ใดๆ เกิดขึ้นครับประหนึ่งว่าเป็นกฎเอาไว้เลย

แล้วเราควรใช้อะไรดีระหว่าง == กับ ===

หลายๆ คนที่อ่านมาถึงจุดนี้คงเริ่มรู้สึกว่า แล้วเราจะใช้อะไรดีระหว่าง == กับ === สำหรับผู้อ่านที่ใช้ IDE ที่ค่อนข้างฉลาด เวลาเราเขียน if ( x == y ) จะเห็นได้ว่า IDE บางตัวจะแนะนำให้เราเปลี่ยนไปใช้ === แทน ซึ่งผมก็แนะนำว่าเราก็ควรใช้ === มากกว่า == เพราะ
1. การใช้ === ในการเปรียบเทียบระหว่าง x กับ y เราจะมั่นใจได้แน่นอนว่า x และ y นั้นเท่ากันจริงๆ (ทั้งในแง่ของ type และ value)
2. การใช้ === จะเร็วกว่าในกรณีที่ type ของ x กับ y ไม่เหมือนกันเพราะจะได้ False กลับไปทันที ส่วนในกรณีที่ type ของ x กับ y เหมือนกันนั้นประสิทธิภาพแทบจะไม่ต่างกันเลย (เพราะเป็นการเทียบ value เหมือนกัน)

ถ้าถามว่าในการทำงานของผมมีใช้ == บ้างไหม ผมก็ตอบเลยว่ามีครับ เพียงแต่การที่เราจะใช้ == นั้น เราควรมีเหตุผลที่หนักแน่นพอว่าทำไมเราถึงต้องใช้มัน แทนที่จะใช้ === ที่รัดกุมกว่าครับ

แล้วถ้ากรณี if (x) เฉยๆ ล่ะ !

สำหรับในกรณีที่เราสงสัยว่าถ้าเราใช้แค่ if (x) ล่ะ javascript จะทำอย่างไร คำตอบก็คือ javascript จะแปลง x ให้กลายเป็น Boolean ครับแล้วจากนั้นจึงจะดูว่าเป็น True หรือ False ซึ่งใน javascript สิ่งที่จะให้ค่า True นั้นมีเยอะมากครับ แต่ False จะมีอยู่ไม่กี่ตัวนั่นก็คือ

null
undefined
"" (empty string)
NaN
false

ที่กล่าวไปข้างต้นนี้ เมื่อแปลงเป็น Boolean ล้วนแล้วแต่ให้ค่า False ทั้งสิ้น ซึ่งเราจะเรียกกลุ่มเหล่านี้ว่า falsy ครับ ส่วนที่นอกเหนือไปจากนี้จะได้ค่า True และเราเรียกกลุ่มนั้นว่า truthy ครับ

ตัวช่วย ! ของพวกเรา

ตามที่ผมได้บอกเอาไว้ในตอนที่อธิบายขั้นตอนการเปรียบเทียบของ == ว่าเราไม่ต้องนั่งจำตรงนั้นเองแล้วเพราะว่าในปัจจุบันมีเครื่องมือเข้ามาช่วยเหลือเราให้สะดวกสบายมากยิ่งขึ้น ซึ่งสิ่งนั้นก็คือ … https://dorey.github.io/JavaScript-Equality-Table/ นั่นเอง ซึ่งตารางนี้จะช่วยบอกเราเองครับว่าถ้าเราใช้ ==, === หรือ if() ในการเปรียบเทียบอะไร แล้วจะได้ค่า True หรือ False ครับ

JS Comparision Table (==)

ซึ่งการที่เราจะอ่านตารางนี้ก็ง่ายมากครับ แถวด้านซ้ายกับด้านบนคือตัวแทนของคู่ x และ y ส่วนสี่เหลี่ยมช่องไหนที่เป็นสีเขียวนั่นหมายถึงว่ามีค่าเป็น True ครับ ยกตัวอย่างเช่น ด้านซ้ายเราเป็น [] และด้านบนเราเป็น 0 ก็จะเทียบเท่าได้กับ

if ( [] == 0 ) {}

ซึ่งเมื่อเราดูในตารางตรงจุดที่ตัดกันระหว่างสองตัวนี้จะเห็นว่าเป็นสีเขียว นั่นหมายความว่า [] == 0 จะได้ค่าออกมาเป็น True นั่นเองครับ ส่วนในกรณีของ === หรือ if() เราสามารถกดเปลี่ยนเมนูด้านบนเพื่อไปดูข้อมูลของสองอันนั้นได้เลยครับ

เป็นอย่างไรกันบ้างครับ หวังว่าบทความนี้จะมีประโยชน์ไม่มากก็น้อยสำหรับผู้อ่านทุกท่าน ถ้าใครมีความคิดเห็นเพิ่มเติม หรือคำแนะนำสามารถ comment มาได้เลยนะครับ ขอบคุณครับ

อ้างอิง

--

--