Mengapa isNaN (null) == false di JS?

129

Kode ini di JS memberi saya popup yang mengatakan "saya pikir nol adalah angka", yang menurut saya sedikit mengganggu. Apa yang saya lewatkan?

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

Saya menggunakan Firefox 3. Apakah itu bug browser?

Tes lain:

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

Jadi, masalahnya tampaknya bukan perbandingan yang tepat dengan NaN?

Sunting: Sekarang pertanyaan telah dijawab, saya telah membersihkan posting saya untuk memiliki versi yang lebih baik untuk arsip. Namun, ini membuat beberapa komentar dan bahkan beberapa jawaban sedikit tidak bisa dimengerti. Jangan salahkan penulisnya. Di antara hal-hal yang saya ubah adalah:

  • Menghapus sebuah catatan yang mengatakan bahwa saya telah mengacaukan tajuk utama dengan mengembalikan artinya
  • Jawaban sebelumnya menunjukkan bahwa saya tidak menyatakan dengan cukup jelas mengapa saya pikir perilaku itu aneh, jadi saya menambahkan contoh yang memeriksa string dan melakukan perbandingan manual.
Hanno Fietz
sumber
3
bukankah maksud Anda "Mengapa isNaN (null) == false"?
Matt Rogish
Berdasarkan kode Anda, isnan (null) mengembalikan false (null bukan "bukan angka") jika dikatakan "Saya pikir nol adalah angka".
devinmoore

Jawaban:

114

Saya yakin kode itu mencoba bertanya, "apakah xnumerik?" dengan kasus khusus di sini x = null. Fungsi isNaN()ini dapat digunakan untuk menjawab pertanyaan ini, tetapi secara semantik merujuk secara khusus pada nilainya NaN. Dari Wikipedia untuk NaN:

NaN ( N ot a N umber) adalah nilai dari tipe data numerik yang mewakili nilai terdefinisi atau Unrepresentable, terutama dalam perhitungan floating-point.

Dalam kebanyakan kasus, kami pikir jawaban untuk "adalah angka nol?" seharusnya tidak. Namun, isNaN(null) == falsesecara semantik benar, karena nulltidak NaN.

Berikut penjelasan algoritmiknya:

Fungsi isNaN(x)mencoba untuk mengkonversi parameter yang diteruskan ke angka 1 (setara dengan Number(x)) dan kemudian menguji apakah nilainya NaN. Jika parameter tidak dapat dikonversi ke angka, Number(x)akan mengembalikan NaN2 . Oleh karena itu, jika konversi parameter xke hasil angka NaN, itu mengembalikan true; jika tidak, itu mengembalikan false.

Jadi, dalam kasus tertentu x = null, nulldikonversi ke angka 0, (coba evaluasi Number(null)dan perhatikan bahwa ia mengembalikan 0,) dan isNaN(0)mengembalikan false. String yang hanya digit dapat dikonversi ke angka dan isNaN juga mengembalikan false. String (misalnya 'abcd') yang tidak dapat dikonversi ke angka akan menyebabkan isNaN('abcd')true, khususnya karena Number('abcd')return NaN.

Selain kasus tepi nyata ini adalah alasan numerik standar untuk mengembalikan NaN seperti 0/0.

Adapun tes yang tampaknya tidak konsisten untuk kesetaraan yang ditunjukkan dalam pertanyaan, perilaku NaNditentukan sedemikian rupa sehingga perbandingan apa pun x == NaNsalah, terlepas dari operan lainnya, termasuk NaNdirinya sendiri 1 .

Glenn Moss
sumber
8
BTW NaN !== NaN,. Jadi, saya pikir, itu tidak sepenuhnya benar untuk mengatakan Number('abcd') == NaNkarena Number('abcd')itu NaNtetapi tidak sama dengan NaN. Saya suka JavaScript.
nilfalse
Iya. Aku bermaksud untuk menyampaikan bahwa Number('abcd')adalah NaNtapi saya tersirat bahwa tes benar untuk kesetaraan, yang tidak terjadi. Saya akan mengeditnya.
Glenn Moss
Saya bertanya-tanya mengapa isNaNdan Numberdirancang untuk berperilaku seperti itu?
timidboy
1
Konversi nullke 0hanya (setidaknya dalam konteks ini) terjadi di dalam isNaN()fungsi, yang memaksa argumennya.
Glenn Moss
3
Number (null) == 0 but parseInt (null) == NaN love JS
JoshBerke
31

Saya sendiri mengalami masalah ini.

Bagi saya, cara terbaik untuk menggunakan isNaN adalah seperti itu

isNaN(parseInt(myInt))

mengambil contoh phyzome dari atas,

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]

(Saya menyelaraskan hasilnya sesuai dengan input, harap membuatnya lebih mudah dibaca.)

Ini sepertinya lebih baik bagiku.

orang mograbi
sumber
1
Tidak akan berfungsi jika myInt= "123d". parseIntmengkonversi "123d" ke 123, yang kemudian gagal isNaNtes.
divesh premdeep
memang, Jika Anda ingin menangkap skenario itu juga, saya sarankan untuk menggabungkan jawaban saya dan Glenn. yang akan terlihat seperti ini isNaN(parseInt(str,10)) || isNaN(Number()). btw - bagi saya, karena saya harus menjalankan parseIntuntuk menggunakan nilai numerik string, yang memungkinkan "123d" dianggap sebagai nomor yang valid baik-baik saja. Namun saya melihat perlunya mendeteksi skenario itu juga.
cowok mograbi
8

(Komentar saya yang lain mengambil pendekatan praktis. Inilah sisi teoretisnya.)

Saya mencari standar ECMA 262 , yang merupakan implementasi Javascript. Spesifikasi mereka untuk isNan:

Menerapkan ToNumber ke argumennya, lalu mengembalikan true jika hasilnya NaN, dan sebaliknya mengembalikan false.

Bagian 9.3 menentukan perilaku ToNumber(yang bukan merupakan fungsi yang bisa dipanggil, tetapi lebih merupakan komponen dari sistem konversi tipe). Untuk meringkas tabel, tipe input tertentu dapat menghasilkan NaN. Ini adalah tipe undefined, tipe number(tetapi hanya nilai NaN), objek apa pun yang representasi primitifnya NaN, dan apa pun stringyang tidak dapat diuraikan. Daun ini undefined, NaN, new Number(NaN), dan sebagian besar string.

Setiap input yang menghasilkan NaNsebagai output ketika dilewatkan ke ToNumberakan menghasilkan trueketika diumpankan ke isNaN. Karena nulldapat berhasil dikonversi ke angka, itu tidak menghasilkan true.

Dan itu sebabnya.

perlakukan mod Anda dengan baik
sumber
7

Ini memang mengganggu. Berikut ini adalah array nilai yang saya uji:

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

Ini mengevaluasi (di Firebug console) untuk:

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

Ketika saya menelepon x.map(isNaN)(untuk memanggil isNaN pada setiap nilai), saya mendapatkan:

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

Kesimpulannya, isNaNterlihat sangat tidak berguna! ( Sunting : Kecuali ternyata isNaN hanya didefinisikan atas Angka, dalam hal ini berfungsi dengan baik - hanya dengan nama yang menyesatkan.)

Secara kebetulan, ini adalah tipe dari nilai-nilai itu:

x.map(function(n){return typeof n})
-> undefined,number,string,number,object,number,string,number,number,number,number
perlakukan mod Anda dengan baik
sumber
Apa yang Anda bayangkan bahwa seharusnya NaN berarti? Apa yang Anda pikir sangat menyesatkan tentang NaN atau dalam pengujian untuk itu? Kenapa kamu terganggu?
Bekim Bacaj
Yah, ini 8 tahun yang lalu, tetapi sepertinya saya terganggu bahwa 1) memiliki hasil yang tidak konsisten untuk nilai yang bukan dari tipe Number, dan 2) itu pernah mengembalikan true untuk sesuatu yang bukan tipe Number. Karena string sebenarnya bukan NaN. (Juga lihat jawaban saya yang lain, yang menjelaskan mengapa hal ini terjadi.)
perlakukan mod Anda dengan baik
5

Null bukan NaN, juga string bukan NaN. isNaN () hanya menguji jika Anda benar-benar memiliki objek NaN.

alat
sumber
Tapi kemudian setidaknya sebuah string dilemparkan ke objek NaN, seperti isNaN ("text") mengembalikan true.
Hanno Fietz
1

Saya tidak begitu yakin ketika datang ke JS tapi saya telah melihat hal-hal serupa dalam bahasa lain dan biasanya karena fungsinya hanya memeriksa apakah null sama persis dengan NaN (yaitu null === NaN akan salah). Dengan kata lain itu bukan berarti ia berpikir bahwa nol sebenarnya adalah sebuah angka, tetapi itu lebih dari nol itu bukan NaN. Ini mungkin karena keduanya direpresentasikan secara berbeda di JS sehingga mereka tidak akan sama persis, dengan cara yang sama dengan 9! == '9'.

Jason Tennier
sumber
1

Dalam ES5, itu didefinisikan sebagai isNaN (number)mengembalikan true jika argumen memaksa ke NaN, dan sebaliknya mengembalikan false.

Dan lihat tabel konversi ToNumber operasi abstrak . Jadi secara internal mengevaluasi mesin js ToNumber(Null)adalah +0, maka akhirnya isNaN(null)adalahfalse

rab
sumber
0

catatan:

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

Operator == melakukan konversi tipe, sedangkan === tidak.

Situs web Douglas Crockford , sebuah Yahoo! Penginjil JavaScript, adalah sumber yang bagus untuk hal-hal seperti ini.

cllpse
sumber