ใน JavaScript เหตุใด“ 0” จึงเท่ากับเท็จ แต่เมื่อทดสอบโดย 'ถ้า' มันจะไม่เป็นเท็จด้วยตัวเอง


232

ต่อไปนี้แสดงให้เห็นว่า"0"เป็นเท็จใน Javascript:

>>> "0" == false
true

>>> false == "0"
true

ดังนั้นทำไมไม่พิมพ์ต่อไปนี้"ha"?

>>> if ("0") console.log("ha")
ha

47
"0"เป็นสตริงและเนื่องจากไม่ว่างเปล่าจึงประเมินเป็นจริง
เครื่องบินดิจิทัล

8
"0" === false [...] false

3
ตรวจสอบความจริงของบทความของ Angus Croll ใน javascript javascriptweblog.wordpress.com/2011/02/07/…
timrwood

8
'0'==falseแต่ '0' ไม่ใช่ค่าเท็จ (ใช่จาวาสคริปต์สามารถแปลกได้)
Linsey

5
@Linsey: สิ่ง "ลวงตา" และ "ความจริง" ทั้งหมดมีขึ้นเพื่ออธิบายถึงวิธีการแปลงค่าเป็นบูลีน เมื่อคุณเปรียบเทียบสองค่ากับ==พวกเขาจะไม่ถูกแปลงเป็นบูลีนดังนั้นจึงไม่มีผล (กฎสำหรับการแปลงดูเหมือนจะ
เอื้ออำนวย

คำตอบ:


251

เหตุผลก็เพราะเมื่อคุณทำอย่างชัดเจน"0" == falseทั้งสองฝ่ายจะถูกแปลงเป็นตัวเลขแล้วทำการเปรียบเทียบ

เมื่อคุณทำเช่นif ("0") console.log("ha")นี้ค่าสตริงจะถูกทดสอบ สตริงไม่ว่างเปล่าคือในขณะที่เป็นสตริงที่ว่างเปล่าtruefalse

เท่ากับ (==)

หากตัวถูกดำเนินการทั้งสองไม่ใช่ประเภทเดียวกัน JavaScript จะแปลงตัวถูกดำเนินการจากนั้นจึงใช้การเปรียบเทียบอย่างเข้มงวด หากตัวถูกดำเนินการเป็นตัวเลขหรือบูลีนตัวถูกดำเนินการจะถูกแปลงเป็นตัวเลขหากเป็นไปได้ อื่นถ้าตัวถูกดำเนินการอย่างใดอย่างหนึ่งเป็นสตริงตัวถูกดำเนินการอื่นจะถูกแปลงเป็นสตริงถ้าเป็นไปได้ หากตัวถูกดำเนินการทั้งสองเป็นวัตถุ JavaScript จะทำการเปรียบเทียบการอ้างอิงภายในซึ่งเท่ากับเมื่อตัวถูกดำเนินการอ้างถึงวัตถุเดียวกันในหน่วยความจำ

(จากผู้ดำเนินการเปรียบเทียบใน Mozilla Developer Network)


348

ตารางแสดงปัญหา:

ความจริงถ้าคำสั่ง

และ == การเปรียบเทียบความจริงของวัตถุทุกประเภทในจาวาสคริปต์

คุณธรรมของการใช้เรื่องราว === ความเท่าเทียมกันอย่างเข้มงวดแสดงสติ

เครดิตการสร้างตาราง: https://github.com/dorey/JavaScript-Equality-Table


2
มันสมเหตุสมผลมากขึ้นกับการเรียงลำดับของค่าอื่น ๆgist.github.com/kirilloid/8165660
kirilloid

3
จากนี้ไปหากมีคนบอกว่าเขาไม่เคยใช้ตัวเปรียบเทียบที่เข้มงวดฉันจะเผชิญหน้ากับตารางเหล่านี้และทำให้เขาร้องไห้ ยังไม่แน่ใจว่าฉันเข้าใจแนวคิดของเรื่องNaNนี้หรือไม่ ผมหมายถึงtypeof NaN // numberแต่NaN === NaN // falseอืม ...
Justus Romijn

4
เพื่อนของฉันสร้างf.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html - กราฟเดียวกันข้างต้น แต่อ่านง่ายขึ้นเล็กน้อย
Lucy Bain

@JustusRomijn มีหลายค่าที่จะเป็นตัวแทนNaNดังนั้นเมื่อคุณเปรียบเทียบ 2 NaNs พวกเขามีค่าที่แตกต่างกัน (ฉันเดา) อ่านคำพูดแรกที่นี่
cychoi

4
ตารางเหล่านี้มีข้อผิดพลาด ทั้ง==มิได้===ประกอบการสำหรับ[], {}, [[]], [0]และ[1]ค่าไม่ได้ประเมินให้เป็นจริง ฉันหมายถึง[] == []และ[] === []เท็จ
Herbertusz

38

มันเป็นไปตามสเป็ค

12.5 คำแถลง if 
.....

2. ถ้า ToBoolean (GetValue (exprRef)) เป็นจริง 
ส่งคืนผลลัพธ์ของการประเมินคำสั่งแรก
3. อื่น ๆ 
....

ToBoolean ตามสเป็คคือ

การดำเนินการนามธรรม ToBoolean แปลงอาร์กิวเมนต์เป็นค่าประเภทบูลีนตามตารางที่ 11:

และตารางนั้นบอกสิ่งนี้เกี่ยวกับสตริง:

ป้อนคำอธิบายรูปภาพที่นี่

ผลลัพธ์จะเป็นเท็จถ้าอาร์กิวเมนต์เป็นสตริงว่าง (ความยาวของมันคือศูนย์); มิฉะนั้นผลลัพธ์จะเป็นจริง

ตอนนี้เพื่ออธิบายว่าทำไม"0" == falseคุณควรอ่านโอเปอเรเตอร์ความเสมอภาคซึ่งระบุว่ามันได้รับคุณค่าจากการดำเนินการเชิงนามธรรมGetValue(lref)ที่เหมือนกันสำหรับด้านขวา

ซึ่งอธิบายส่วนที่เกี่ยวข้องนี้เป็น:

ถ้า IsPropertyReference (V) แสดงว่า 
ถ้า HasPrimitiveBase (V) เป็นเท็จดังนั้นให้รับเป็น [[รับ]] วิธีการภายในของฐานมิฉะนั้นให้ได้รับ
เป็นวิธีพิเศษภายใน [[รับ]] ที่กำหนดไว้ด้านล่าง 
ข ส่งคืนผลลัพธ์ของการเรียกวิธีรับภายในโดยใช้ฐานเป็นค่านี้และส่งผ่าน
GetReferencedName (V) สำหรับอาร์กิวเมนต์

หรือในคำอื่น ๆ สตริงมีฐานดั้งเดิมซึ่งโทรกลับวิธีรับภายในและจบลงด้วยการมองเท็จ

หากคุณต้องการประเมินสิ่งต่าง ๆ โดยใช้การดำเนินการ GetValue ==หากคุณต้องการประเมินการใช้งานToBooleanให้ใช้===(หรือที่เรียกว่าตัวดำเนินการความเท่าเทียม "เข้มงวด")


"a string has a primitive base, which calls back the internal get method and ends up looking false"สิ่งนี้เป็นจริงสำหรับทุกสายหรือไม่
aziz punjani

@Interstellar_Coder Section 8.12.3: [[Get]] (P)อธิบายวิธีการทำงาน มันจะเป็นจริงสำหรับกรณีที่สตริงเป็น 0 เท่านั้นเนื่องจากจะมีการโทรภายในกลุ่มอื่น ๆ ในที่สุดก็ส่งผลให้GetOwnPropertyเห็นว่า "อะไรก็ตาม" เป็นคุณสมบัติข้อมูลซึ่งจะส่งกลับค่ากลับมาตลอด นี่คือเหตุผลที่ "0" เป็นเท็จและ "blah" เป็นจริง ลองดูวิดีโอของ Douglas Crockford บนโรงละครของนักพัฒนา Yahoo เขาอธิบาย "ความจริง" ใน JavaScript ที่ซับซ้อนน้อยกว่าฉัน หากคุณเข้าใจในสิ่งที่ "ความจริง" และ "เท็จ" หมายความว่าคุณจะเข้าใจคำตอบของ Bobince ทันที
ไม่ระบุตัวตน

1
ฉันจะหาสเป็คได้ที่ไหน
985366

12

มันเป็น PHP ที่สตริง"0"เป็นเท็จ (เท็จเมื่อใช้ในบริบทแบบบูล) ใน JavaScript สตริงที่ไม่ว่างทั้งหมดเป็นความจริง

เคล็ดลับก็คือ==กับบูลีนที่ไม่ได้ประเมินในบริบทบูลีนมันจะแปลงเป็นจำนวนและในกรณีของสตริงที่ทำโดยแยกเป็นทศนิยม ดังนั้นคุณจะได้รับจำนวน0แทนบูลีนความtrueจริง

นี่คือการออกแบบภาษาที่แย่มากและเป็นหนึ่งในเหตุผลที่เราพยายามไม่ใช้==ผู้ดำเนินการที่โชคร้าย ใช้===แทน


7
// I usually do this:

x = "0" ;

if (!!+x) console.log('I am true');
else      console.log('I am false');

// Essentially converting string to integer and then boolean.

4

คำพูดของคุณรอบ ๆ 0ทำให้มันเป็นสตริงซึ่งประเมินว่าเป็นความจริง

ลบคำพูดและมันควรจะทำงาน

if (0) console.log("ha") 

ถูกต้องไม่ใช่เกี่ยวกับวิธี "ทำให้มันทำงานได้" แต่คำถามนั้นเป็นเช่นนั้นมากกว่า "ทำไมมันถึงทำแบบนั้น"
nonopolarity

2

มันเป็นเพราะรายละเอียดของ ECMA ... "0" == falseเนื่องจากกฎที่ระบุไว้ที่นี่http://ecma262-5.com/ELS5_HTML.htm#Section_11.9.3 ... และif ('0')ประเมินผลเป็นจริงเพราะกฎที่ระบุไว้ที่นี่http: / /ecma262-5.com/ELS5_HTML.htm#Section_12.5


ฉันไม่รู้ว่ามีคนส่งสเป็คให้กับเว็บไซต์ ... นั่นยอดเยี่ยมมาก! ไม่มี PDF เพิ่มเติมสำหรับฉัน
ไม่ระบุตัวตน

1

การแสดงออกของ "if" สำหรับการทดสอบความจริงในขณะที่การทดสอบสองเท่าสำหรับการเทียบเท่าประเภทอิสระ สตริงนั้นเป็นจริงเสมอเหมือนที่คนอื่น ๆ ที่นี่ชี้ หากคู่เท่ากับได้รับการทดสอบทั้งสองตัวถูกดำเนินการสำหรับ truthiness ("0" == true) === trueแล้วเปรียบเทียบผลแล้วคุณจะได้รับผลที่คุณสังหรณ์ใจสมมติว่าคือ ดังที่ Doug Crockford กล่าวไว้ในJavaScriptยอดเยี่ยมของเขา: ส่วนที่ดี "กฎที่ [== coerces ประเภทของตัวถูกดำเนินการ] มีความซับซ้อนและไม่สามารถจดจำได้ ... มันพอเพียงที่จะบอกว่าหนึ่งในตัวถูกดำเนินการถูกบังคับประเภทเพื่อให้ตรงกับที่อื่นและที่ "0" จบลงด้วยการถูกตีความว่าเป็นศูนย์ที่เป็นตัวเลข


1

==ตัวดำเนินการความเท่าเทียมกันประเมินอาร์กิวเมนต์หลังจากแปลงเป็นตัวเลข ดังนั้นสตริงศูนย์ "0" จึงถูกแปลงเป็นประเภทข้อมูล Number และบูลีน false จะถูกแปลงเป็นหมายเลข 0 ดังนั้น

"0" == false // true

เช่นเดียวกับ `

false == "0" //true

=== การตรวจสอบความเท่าเทียมกันอย่างเข้มงวดประเมินข้อโต้แย้งด้วยชนิดข้อมูลดั้งเดิม

"0" === false // false, because "0" is a string and false is boolean

เช่นเดียวกับ

false === "0" // false

ใน

if("0") console.log("ha");

สตริง "0" ไม่ได้เปรียบเทียบกับอาร์กิวเมนต์ใด ๆ และสตริงเป็นค่าจริงจนกระทั่งหรือเว้นแต่ว่ามันจะถูกเปรียบเทียบกับอาร์กิวเมนต์ใด ๆ มันเป็นเหมือน

if(true) console.log("ha");

แต่

if (0) console.log("ha"); // empty console line, because 0 is false

`


1

นี่เป็นเพราะ JavaScript ใช้การข่มขู่ประเภทในบริบทบูลีนและรหัสของคุณ

if ("0") 

จะถูกบีบบังคับให้เป็นจริงในบริบทบูลีน

มีค่าความจริงอื่น ๆ ใน Javascript ซึ่งจะถูกข่มขู่เป็นจริงในบริบทบูลีนและดำเนินการบล็อกถ้าเป็น: -

if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)

0
if (x) 

coerces x โดยใช้ toBoolean ภายในของ JavaScript (http://es5.github.com/#x9.2)

x == false

บีบบังคับทั้งสองฝ่ายโดยใช้การข่มขู่ภายใน toNumber (http://es5.github.com/#x9.3) หรือ toPrimitive สำหรับวัตถุ (http://es5.github.com/#x9.1)

สำหรับรายละเอียดทั้งหมดดูได้ที่http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.