ทำไม isNaN (null) == false ใน JS?


130

โค้ดนี้ใน JS ทำให้ฉันมีป๊อปอัปขึ้นมาว่า "ฉันคิดว่าโมฆะเป็นตัวเลข" ซึ่งฉันรู้สึกว่ารบกวนเล็กน้อย ฉันขาดอะไรไป?

if (isNaN(null)) {
  alert("null is not a number");
} else {
  alert("i think null is a number");
}

ฉันใช้ Firefox 3 นั่นเป็นบั๊กของเบราว์เซอร์หรือไม่?

การทดสอบอื่น ๆ :

console.log(null == NaN);   // false
console.log(isNaN("text")); // true
console.log(NaN == "text"); // false

ดังนั้นปัญหาดูเหมือนจะไม่ใช่การเปรียบเทียบกับ NaN อย่างแน่นอน?

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

  • ลบข้อความที่บอกว่าฉันคาดคั้นพาดหัวข่าวตั้งแต่แรกโดยการเปลี่ยนความหมายใหม่
  • คำตอบก่อนหน้านี้แสดงให้เห็นว่าฉันไม่ได้ระบุอย่างชัดเจนเพียงพอว่าเหตุใดฉันจึงคิดว่าพฤติกรรมแปลก ๆ ดังนั้นฉันจึงเพิ่มตัวอย่างที่ตรวจสอบสตริงและทำการเปรียบเทียบด้วยตนเอง

3
คุณไม่ได้หมายถึง "ทำไม isNaN (null) == false"
Matt Rogish

ตามรหัสของคุณ isnan (null) ส่งคืนเท็จ (null ไม่ใช่ "ไม่ใช่ตัวเลข") หากมีข้อความว่า "ฉันคิดว่าค่าว่างเป็นตัวเลข"
devinmoore

คำตอบ:


114

ฉันเชื่อว่ารหัสพยายามถามว่า "เป็นxตัวเลขหรือไม่" x = nullกับกรณีเฉพาะของที่นี่ ฟังก์ชั่นisNaN()สามารถใช้ในการตอบคำถามนี้ NaNแต่ความหมายมันหมายเฉพาะค่า จาก Wikipedia สำหรับNaN:

NaN ( N ot a N umber) เป็นค่าของชนิดข้อมูลตัวเลขที่แสดงถึงค่าที่ไม่ได้กำหนดหรือไม่สามารถแสดงได้โดยเฉพาะอย่างยิ่งในการคำนวณจุดลอยตัว

ในกรณีส่วนใหญ่เราคิดว่าคำตอบของ "เป็นตัวเลขว่าง?" ควรจะไม่ใช่ แต่isNaN(null) == falseถูกต้องความหมายเพราะไม่ได้เป็นnullNaN

นี่คือคำอธิบายอัลกอริทึม:

ฟังก์ชันisNaN(x)จะพยายามแปลงพารามิเตอร์ที่ผ่านไปเป็นตัวเลข1 (เทียบเท่าNumber(x)) จากนั้นทดสอบว่าค่าเป็นNaNหรือไม่ ถ้าพารามิเตอร์ไม่สามารถแปลงเป็นตัวเลขNumber(x)จะกลับ2NaN ดังนั้นหากxผลลัพธ์การแปลงพารามิเตอร์เป็นตัวเลขNaNจะส่งกลับจริง มิฉะนั้นจะส่งกลับเท็จ

ดังนั้นในกรณีที่เฉพาะเจาะจงx = null, nullจะถูกแปลงเป็นตัวเลข 0, (ลองประเมินNumber(null)และเห็นว่ามันกลับ 0) และisNaN(0)ผลตอบแทนที่เป็นเท็จ สตริงที่เป็นตัวเลขเท่านั้นสามารถแปลงเป็นตัวเลขได้และ isNaN ยังส่งคืนค่าเท็จ สตริง (เช่น'abcd') ที่ไม่สามารถแปลงไปยังหมายเลขที่จะทำให้isNaN('abcd')การกลับจริงโดยเฉพาะเพราะผลตอบแทนNumber('abcd')NaN

นอกเหนือจากกรณีขอบที่ชัดเจนเหล่านี้แล้วยังมีเหตุผลเชิงตัวเลขมาตรฐานในการส่งคืน NaN เช่น 0/0

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


8
NaN !== NaNBTW, ดังนั้นผมคิดว่ามันเป็นไปไม่ได้โดยสิ้นเชิงที่ถูกต้องที่จะพูดNumber('abcd') == NaNเพราะNumber('abcd')เป็นแต่ไม่เท่ากับNaN NaNฉันชื่นชอบ JavaScript
nilfalse

ใช่. ฉันตั้งใจจะสื่อว่านั่นNumber('abcd')คือNaNแต่ฉันบอกเป็นนัยว่ามันทดสอบความเท่าเทียมกันจริงซึ่งไม่ใช่อย่างนั้น ฉันจะแก้ไขมัน
Glenn Moss

ผมสงสัยว่าทำไมมีisNaNและNumberออกแบบมาเพื่อทำงานในลักษณะที่?
timidboy

1
การแปลงnullเป็น0เท่านั้น (อย่างน้อยในบริบทนี้) เกิดขึ้นภายในisNaN()ฟังก์ชันซึ่งบังคับให้อาร์กิวเมนต์
Glenn Moss

3
Number (null) == 0 แต่ parseInt (null) == NaN love JS
JoshBerke

31

ฉันเพิ่งพบปัญหานี้ด้วยตัวเอง

สำหรับฉันวิธีที่ดีที่สุดในการใช้ isNaN ก็เป็นเช่นนั้น

isNaN(parseInt(myInt))

ยกตัวอย่างของไฟโซมจากด้านบน

var x = [undefined, NaN,     'blah', 0/0,  null, 0,     '0',   1,     1/0, -1/0,  Number(5)]
x.map( function(n){ return isNaN(parseInt(n))})
        [true,      true,    true,   true, true, false, false, false, true, true, false]

(ฉันจัดเรียงผลลัพธ์ตามอินพุตหวังว่าจะช่วยให้อ่านง่ายขึ้น)

ดูเหมือนจะดีกว่าสำหรับฉัน


1
จะไม่ทำงานถ้าmyInt= "123d" parseIntแปลง "123d" เป็น 123 ซึ่งจะไม่ผ่านการisNaNทดสอบ
divesh premdeep

ถ้าคุณต้องการจับสถานการณ์นั้นด้วยฉันขอแนะนำให้รวมคำตอบของฉันกับของเกล็น isNaN(parseInt(str,10)) || isNaN(Number())ซึ่งจะมีลักษณะเช่นนี้ btw - สำหรับฉันเนื่องจากฉันต้องเรียกใช้parseIntเพื่อใช้ค่าตัวเลขของสตริงการปล่อยให้ "123d" ถือเป็นตัวเลขที่ถูกต้องนั้นใช้ได้ อย่างไรก็ตามฉันเห็นความจำเป็นในการตรวจจับสถานการณ์นั้นเช่นกัน
guy mograbi

8

(ความคิดเห็นอื่นของฉันใช้แนวทางปฏิบัตินี่คือด้านทฤษฎี)

ฉันค้นหามาตรฐาน ECMA 262ซึ่งเป็นสิ่งที่ Javascript ใช้ ข้อกำหนดสำหรับ isNan:

นำ ToNumber ไปใช้กับอาร์กิวเมนต์จากนั้นส่งกลับค่าจริงหากผลลัพธ์เป็น NaN มิฉะนั้นจะส่งกลับเท็จ

ส่วน 9.3 ระบุลักษณะการทำงานของToNumber(ซึ่งไม่ใช่ฟังก์ชันที่เรียกได้ แต่เป็นส่วนประกอบของระบบการแปลงประเภท) เพื่อสรุปตารางอินพุตบางประเภทสามารถสร้าง NaN ได้ สิ่งเหล่านี้คือประเภทundefinedประเภทnumber(แต่มีเพียงค่าเท่านั้นNaN) วัตถุใด ๆ ที่มีการแทนค่าดั้งเดิมNaNและสิ่งstringที่ไม่สามารถแยกวิเคราะห์ได้ ใบนี้undefined, NaN, new Number(NaN)และสตริงมากที่สุด

การป้อนข้อมูลใด ๆ ดังกล่าวที่ผลิตNaNเป็นผลผลิตเมื่อผ่านไปToNumberจะผลิตเมื่อเลี้ยงไปtrue isNaNเนื่องจากสามารถประสบความสำเร็จได้รับการแปลงเป็นตัวเลขก็ไม่ได้ผลิตnulltrue

และนั่นคือเหตุผลที่


7

นี่เป็นการรบกวนอย่างแท้จริง นี่คืออาร์เรย์ของค่าที่ฉันทดสอบ:

var x = [undefined, NaN, 'blah', 0/0, null, 0, '0', 1, 1/0, -1/0, Number(5)]

จะประเมิน (ในคอนโซล Firebug) เพื่อ:

,NaN,blah,NaN,,0,0,1,Infinity,-Infinity,5

เมื่อฉันโทรx.map(isNaN)(เพื่อเรียก isNaN ในแต่ละค่า) ฉันจะได้รับ:

true,true,true,true,false,false,false,false,false,false,false

สรุปisNaNดูสวยไร้ประโยชน์! ( แก้ไข : ยกเว้นปรากฎว่า isNaN ถูกกำหนดไว้เหนือ Number เท่านั้นซึ่งในกรณีนี้ใช้งานได้ดี - เพียงแค่ใช้ชื่อที่ทำให้เข้าใจผิด)

อนึ่งนี่คือประเภทของค่าเหล่านี้:

x.map(function(n){return typeof n})
-> undefined,number,string,number,object,number,string,number,number,number,number

คุณคิดว่า NaN ควรหมายถึงอะไร? คุณคิดว่าอะไรที่ทำให้เข้าใจผิดเกี่ยวกับ NaN หรือในการทดสอบ? จะรบกวนทำไม
Bekim Bacaj

นี่คือเมื่อ 8 ปีที่แล้ว แต่ดูเหมือนว่าฉันจะถูกรบกวนที่ 1) มีผลลัพธ์ที่ไม่สอดคล้องกันสำหรับค่าที่ไม่ใช่ประเภท Number และ 2) มันจะคืนค่าจริงสำหรับบางสิ่งที่ไม่ใช่ประเภท Number เนื่องจากสตริงไม่ได้เป็น NaN (ดูคำตอบอื่นของฉันด้วยซึ่งจะอธิบายว่าเหตุใดจึงเกิดขึ้น)
ปฏิบัติต่อ mods ของคุณให้ดีใน

5

Null ไม่ใช่ NaN และสตริงไม่ใช่ NaN isNaN () เพียงทดสอบว่าคุณมีวัตถุ NaN จริงๆหรือไม่


แต่อย่างน้อยสตริงก็ถูกโยนลงในวัตถุ NaN เนื่องจาก isNaN ("text") ส่งกลับค่าจริง
Hanno Fietz

1

ฉันไม่แน่ใจว่าพูดถึง JS แต่ฉันเคยเห็นสิ่งที่คล้ายกันในภาษาอื่นและโดยปกติแล้วเป็นเพราะฟังก์ชันกำลังตรวจสอบว่า null เท่ากับ NaN หรือไม่ (เช่น null === NaN จะเป็นเท็จ) กล่าวอีกนัยหนึ่งไม่ใช่ว่ามันคิดว่าโมฆะเป็นจำนวนจริง แต่เป็นโมฆะไม่ใช่ NaN อาจเป็นเพราะทั้งสองแสดงต่างกันใน JS ดังนั้นจึงไม่เท่ากันทุกประการในลักษณะเดียวกับที่ 9! == '9'


1

ใน ES5 กำหนดให้เป็นisNaN (number)ผลตอบแทนจริงหากอาร์กิวเมนต์บังคับให้เป็น NaN และส่งกลับเท็จ

  • ถ้าToNumber (ตัวเลข)เป็น NaN ให้ส่งคืนจริง
  • มิฉะนั้นให้ส่งคืนเท็จ

และเห็นการดำเนินการที่เป็นนามธรรมตาราง ToNumber แปลง ดังนั้นจึงเป็นเครื่องมือ js ภายในประเมินToNumber(Null)เป็น+0ที่สุดก็isNaN(null)คือfalse


0

บันทึก:

"1" == 1 // true
"1" === 1 // false

ตัวดำเนินการ == ทำการแปลงประเภทในขณะที่ === ไม่ทำ

เว็บไซต์ของ Douglas Crockfordซึ่งเป็น Yahoo! ผู้เผยแพร่ศาสนา JavaScript เป็นแหล่งข้อมูลที่ยอดเยี่ยมสำหรับสิ่งต่างๆเช่นนี้

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