Mengapa isNaN ("") (string dengan spasi) sama dengan false?

160

Dalam JavaScript, mengapa isNaN(" ")mengevaluasi false, tetapi isNaN(" x")mengevaluasi true?

Saya melakukan operasi numerik pada kolom input teks, dan saya memeriksa apakah lapangan adalah null, "", atau NaN. Ketika seseorang mengetikkan beberapa spasi di bidang, validasi saya gagal pada ketiganya, dan saya bingung mengapa itu bisa melewati isNaNpemeriksaan.

Pembalas IVR
sumber
1
Hm ... tidak yakin ke mana separuh subjek lainnya pergi. Seharusnya membaca, "JavaScript: Mengapa isNaN (" ") dievaluasi menjadi false?"
IVR Avenger
Jes, itulah perilaku (ruang kosong atau kosong salah untuk isNaN), tapi saya tidak menemukan spesifikasi persis dari fungsi ini.
Lucero
Berikut pertanyaan yang menjawab ini: http://stackoverflow.com/questions/115548/why-is-isnannull-false-in-js
Lucero
Javascript pada masalah ini sepertinya voodoo! Anda tidak pernah tahu dan penjelasannya selalu cukup kompleks. "" == false // truedanisNaN(" ") // false
João Pimentel Ferreira

Jawaban:

155

JavaScript mengartikan string kosong sebagai 0, yang kemudian gagal dalam tes isNAN. Anda dapat menggunakan parseInt pada string terlebih dahulu yang tidak akan mengkonversi string kosong ke 0. Hasilnya kemudian gagal adalahNAN.

Antonio Haley
sumber
53
Tetapi parseInt ("123abcd") mengembalikan 123, yang berarti isNaN (parseInt ("123abcd")) akan mengembalikan false sementara itu harus kembali benar!
Pawan Nogariya
11
Jadi bagaimana dengan (IsNaN (string) || isNaN (parseInt (string)))
matt
5
Ada 2 langkah dalam menafsirkan isNaN(arg). 1) Konversi nomor arg ke, 2) Periksa apakah nomor itu adalah nilai numerik NaN. Itu membantu saya memahaminya dengan lebih baik.
xdhmoore
3
@Antonio_Haley Tunggu sebentar, saya tidak mengerti. Jika "JavaScript mengartikan string kosong sebagai 0", mengapa parseInt ("") mengembalikan NaN?
Jean-François Beauchamp
1
@ Jean-François Anda benar, pernyataan yang lebih benar adalah "isNaN mengartikan string kosong sebagai 0", bukan JavaScript itu sendiri.
Antonio Haley
82

Anda mungkin menemukan ini mengejutkan atau mungkin tidak, tetapi di sini ada beberapa kode uji untuk menunjukkan kepada Anda keanehan dari mesin JavaScript.

document.write(isNaN("")) // false
document.write(isNaN(" "))  // false
document.write(isNaN(0))  // false
document.write(isNaN(null)) // false
document.write(isNaN(false))  // false
document.write("" == false)  // true
document.write("" == 0)  // true
document.write(" " == 0)  // true
document.write(" " == false)  // true
document.write(0 == false) // true
document.write(" " == "") // false

jadi ini artinya

" " == 0 == false

dan

"" == 0 == false

tapi

"" != " "

Selamat bersenang-senang :)

Nick Berardi
sumber
5
+1 Pos luar biasa. Bisakah Anda menambahkan bagaimana triple sama dengan (=== dan! ==) cocok di sini?
bendewey
2
Anda harus mencoba NaN === NaN atau NaN == NaN ;-) Saya tidak tahu apakah semua ini berarti mesin javascript aneh atau bahwa javascript buruk untuk programmer aneh sekalipun.
KooiInc
10
@ Kooilnc fakta bahwa NaN! = NaN, sebenarnya, adalah pilihan yang bagus untuk sekali. Idenya adalah bahwa NaN hampir selalu merupakan hasil dari perhitungan yang berjalan berbeda dari yang dimaksudkan oleh programmer, dan untuk menganggap bahwa hasil dari dua perhitungan yang "salah" adalah sama adalah cukup berbahaya, kataku.
skrebbel
2
@ Kooilnc tidak untuk mengambil bahkan sedikit dari keanehan javascript, tetapi NaNs ini hanya mematuhi standar floating point IEEE 754. Anda dapat membaca SEMUA tentang hal itu seperti biasa di W besar: en.wikipedia.org/wiki/NaN
Spike0xff
@NickBerardi F'ing LOL! Saya sangat senang melihat posting ini. Membantu saya mencari tahu mengapa fungsi isNaN terbelakang. Saya akan menghapusnya dari kode saya yang belum sepenuhnya dikembangkan saat ini, dan kemungkinan tidak akan pernah menggunakannya lagi. Saya akan memvalidasi untuk null, "", dan " "saya sendiri. Terima kasih!
VoidKing
16

Untuk memahaminya dengan lebih baik, silakan buka Ecma-Script spec pdf di halaman 43 "ToNumber Diterapkan ke Tipe String"

jika sebuah string memiliki sintaks numerik, yang dapat berisi sejumlah karakter spasi-putih, string dapat dikonversi ke tipe angka. Empty string dievaluasi menjadi 0. Juga string yang 'Infinity' harus berikan

isNaN('Infinity'); // false
Rafael
sumber
13

Coba gunakan:

alert(isNaN(parseInt("   ")));

Atau

alert(isNaN(parseFloat("    ")));
bendewey
sumber
3
hai pak, isNaN (parseInt ("123a")): akan mengembalikan 123 sehingga solusi Anda tidak akan berfungsi, jika string berisi aplha numeric
Sajjad Ali Khan
6

Dari MDNalasan masalah yang Anda hadapi

Ketika argumen ke fungsi isNaN bukan dari tipe Number, nilainya pertama kali dipaksa ke Number. Nilai yang dihasilkan kemudian diuji untuk menentukan apakah itu NaN.

Anda mungkin ingin memeriksa jawaban komprehensif berikut yang mencakup perbandingan NaN untuk kesetaraan juga.

Cara menguji apakah variabel JavaScript adalah NaN

dopeddude
sumber
5

Saya pikir itu karena pengetikan Javascript: ' 'dikonversi menjadi nol, sedangkan 'x'bukan:

alert(' ' * 1); // 0
alert('x' * 1); // NaN
Greg
sumber
4

Jika Anda ingin menerapkan fungsi isNumber yang akurat, berikut adalah salah satu cara untuk melakukannya dari Javascript: The Good Parts oleh Douglas Crockford [halaman 105]

var isNumber = function isNumber(value) {
   return typeof value === 'number' && 
   isFinite(value);
}
Brian Grinstead
sumber
4
@Xyan dalam hal ini fungsi ini tidak sangat membantu untuk melakukan tugas yang diminta OP, yaitu untuk memeriksa representasi string dari angka ...
ErikE
menggunakan apa yang disebut operator kesetaraan ketat nilai apa pun terhadap string literal seperti "angka" itu bodoh,
Bekim Bacaj
4

Jawaban Tidak Sepenuhnya Benar

Jawaban Antonio Haley yang sangat tervotasikan dan diterima di sini membuat asumsi yang salah bahwa proses ini berjalan melalui parseIntfungsi JavaScript :

Anda dapat menggunakan parseInt pada string ... Hasilnya seharusnya gagal adalah NAN.

Kami dapat dengan mudah menyangkal pernyataan ini dengan string "123abc":

parseInt("123abc")    // 123     (a number...
isNaN("123abc")       // true     ...which is not a number)

Dengan ini, kita dapat melihat bahwa parseIntfungsi JavaScript kembali "123abc"sebagai angka 123, namun isNaNfungsinya memberi tahu kita bahwa "123abc" itu bukan angka.

Jawaban yang benar

ECMAScript-262 mendefinisikan cara kerja isNaNcek di bagian 18.2.3 .

18.2.3 isNaN(Jumlah)

The isNaNFungsi adalah %isNaN%objek intrinsik. Ketika isNaNfungsi dipanggil dengan satu nomor argumen, langkah-langkah berikut diambil:

  1. Biarkan begitu num? ToNumber(number).
  2. Jika numadalah NaN, kembali true.
  3. Kalau tidak, kembalilah false.

The ToNumberreferensi fungsi itu juga didefinisikan dalam ECMAScript-262 ini bagian 7.1.3 . Di sini, kita diberitahu bagaimana JavaScript menangani Strings yang diteruskan ke fungsi ini.

Contoh pertama yang diberikan dalam pertanyaan adalah string yang hanya berisi karakter spasi putih. Bagian ini menyatakan bahwa:

A StringNumericLiteralyang kosong atau hanya berisi ruang putih yang dikonversi +0.

The " "contoh String Oleh karena itu dikonversi menjadi +0, yang merupakan nomor.

Bagian yang sama juga menyatakan:

Jika tata bahasa tidak dapat menafsirkan Stringsebagai perluasan StringNumericLiteral, maka hasilnya ToNumberadalah NaN.

Tanpa mengutip semua cek yang terkandung dalam bagian itu, " x"contoh yang diberikan dalam pertanyaan jatuh ke dalam kondisi di atas karena tidak dapat diartikan sebagai a StringNumericLiteral. " x"Oleh karena itu dikonversi ke NaN.

James Donnelly
sumber
2

Saya tidak yakin mengapa , tetapi untuk mengatasi masalah ini Anda selalu bisa memotong spasi sebelum memeriksa. Anda mungkin ingin tetap melakukannya.

Joel Coehoorn
sumber
4
string kosong yang dipangkas juga gagal dalam tes isNaN.
Egemenk
2

Fungsi isNaN("")melakukan pemaksaan tipe String to Number

ECMAScript 3-5 menetapkan nilai pengembalian berikut untuk typeof operator:

  • tidak terdefinisi
  • objek (null, objek, array)
  • boolean
  • jumlah
  • tali
  • fungsi

Lebih baik untuk membungkus tes kami di badan fungsi:

function isNumber (s) {
    return typeof s == 'number'? true
           : typeof s == 'string'? (s.trim() === ''? false : !isNaN(s))
           : (typeof s).match(/object|function/)? false
           : !isNaN(s)
}

Fungsi ini tidak dimaksudkan untuk menguji tipe variabel , melainkan menguji nilai yang dipaksakan . Sebagai contoh, booleans dan string dipaksa ke angka, jadi mungkin Anda ingin memanggil fungsi ini sebagaiisNumberCoerced()

jika tidak perlu menguji jenis selain string dan angka , maka cuplikan berikut ini dapat digunakan sebagai bagian dari beberapa kondisi:

if (!isNaN(s) && s.toString().trim()!='') // 's' can be boolean, number or string
    alert("s is a number")
Steven Pribilinskiy
sumber
1

Saya menyarankan Anda untuk menggunakan fungsi berikut jika Anda benar-benar ingin memeriksa apakah itu bilangan bulat:

function isInteger(s)
{
   return Math.ceil(s) == Math.floor(s);
}
Bat_Programmer
sumber
1

Yang isNaN(" ")salah adalah bagian dari perilaku membingungkan dari isNaNfungsi global karena paksaan non-angka ke tipe numerik.

Dari MDN :

Karena versi paling awal dari isNaNspesifikasi fungsi, perilakunya untuk argumen non-numerik membingungkan. Ketika argumen ke isNaNfungsi bukan dari tipe Number, nilainya pertama kali dipaksa ke Number. Nilai yang dihasilkan kemudian diuji untuk menentukan apakah itu NaN. Jadi untuk non-angka bahwa ketika dipaksa ke tipe numerik menghasilkan nilai numerik non-NaN yang valid (terutama string kosong dan boolean primitif, yang ketika dipaksa memberikan nilai numerik nol atau satu), nilai yang dikembalikan "false" mungkin tidak terduga; string kosong, misalnya, tentunya "bukan angka."

Perhatikan juga bahwa dengan ECMAScript 6, sekarang juga ada Number.isNaNmetode, yang menurut MDN:

Dibandingkan dengan isNaN()fungsi global , Number.isNaN()tidak mengalami masalah dengan paksa mengubah parameter ke angka. Ini berarti sekarang aman untuk meneruskan nilai yang biasanya dikonversi NaN, tetapi sebenarnya bukan nilai yang sama NaN. Ini juga berarti bahwa hanya nilai-nilai nomor jenis, yang juga NaN, kembali true.

Sayangnya :

Bahkan metode ECMAScript 6 Number.isNaNmemiliki masalah sendiri, seperti diuraikan dalam posting blog - Memperbaiki masalah JavaScript dan ES6 NaN yang jelek .

lucono
sumber
1

The isNaNFungsi mengharapkan Nomor sebagai argumen, sehingga argumen dari jenis lain (dalam kasus Anda string) akan dikonversi ke Nomor sebelum logika fungsi yang sebenarnya dilakukan. (Ketahuilah bahwa NaNini juga merupakan nilai dari tipe Number!)

Btw. ini umum untuk semua fungsi bawaan - jika mereka mengharapkan argumen tipe tertentu, argumen aktual akan dikonversi menggunakan fungsi konversi standar. Ada konversi standar antara semua tipe dasar (bool, string, number, object, date, null, undefined.)

Konversi standar untuk Stringke Numberdapat dipanggil secara eksplisit dengan Number(). Jadi kita dapat melihat bahwa:

  • Number(" ") mengevaluasi ke 0
  • Number(" x") mengevaluasi ke NaN

Mengingat ini, hasil dari isNaNfungsi ini sepenuhnya logis!

Pertanyaan sebenarnya adalah mengapa konversi String-to-Number standar berfungsi seperti itu. Konversi string-ke-angka benar-benar dimaksudkan untuk mengkonversi string numerik seperti "123" atau "17.5e4" ke angka yang setara. Konversi pertama melompati spasi putih awal (jadi "123" valid) dan kemudian mencoba untuk menguraikan sisanya sebagai angka. Jika itu tidak dapat diuraikan sebagai angka ("x" tidak) maka hasilnya adalah NaN. Tetapi ada aturan khusus yang eksplisit bahwa string yang kosong atau hanya spasi kosong dikonversi ke 0. Jadi ini menjelaskan konversi.

Referensi: http://www.ecma-international.org/ecma-262/5.1/#sec-9.3.1

JacquesB
sumber
1

Saya menulis fungsi kecil cepat ini untuk membantu menyelesaikan masalah ini.

function isNumber(val) {
     return (val != undefined && val != null && val.toString().length > 0 && val.toString().match(/[^0-9\.\-]/g) == null);
};

Ini hanya memeriksa setiap karakter yang bukan numerik (0-9), yang bukan '-' atau '.', Dan yang tidak terdefinisi, nol atau kosong dan mengembalikan true jika tidak ada kecocokan. :)

Kesederhanaan Xtra
sumber
Terimakasih terima kasih untuk ini; ini memecahkan masalah saya dengan sangat baik.
Henry
1

Seperti yang dijelaskan lainnya, isNaNfungsi akan memaksa string kosong menjadi angka sebelum memvalidasinya, sehingga mengubah string kosong menjadi 0 (yang merupakan angka yang valid). Namun, saya menemukan bahwa parseIntfungsi akan kembali NaNketika mencoba mengurai string kosong atau string dengan spasi saja. Dengan demikian kombinasi berikut tampaknya berfungsi dengan baik:

if ( isNaN(string) || isNaN(parseInt(string)) ) console.log('Not a number!');

Pemeriksaan ini akan berfungsi untuk angka positif, angka negatif dan angka dengan titik desimal, jadi saya percaya ini mencakup semua kasus angka umum.

Nadav
sumber
1

NaN ! == "bukan angka"

NaN adalah nilai dari Tipe Angka

ini adalah definisi isNaN () dalam ECMAScript

1. Let num be ToNumber(number).
2. ReturnIfAbrupt(num).
3. If num is NaN, return true.
4. Otherwise, return false.

Cobalah untuk mengubah nilai apa pun menjadi Angka.

Number(" ") // 0
Number("x") // NaN
Number(null) // 0

Jika Anda ingin menentukan apakah nilainya NaN, Anda harus mencoba mengubahnya menjadi nilai angka terlebih dahulu.

bitfishxyz
sumber
0

Fungsi ini sepertinya berfungsi dalam pengujian saya

function isNumber(s) {
    if (s === "" || s === null) {
        return false;
    } else {
        var number = parseInt(s);
        if (number == 'NaN') {
            return false;
        } else {
            return true;
        }
    }
}
bruno negrao
sumber
2
Seluruh fungsi Anda dapat ditulis:return !(s === "" || s === null || parseInt(s) == 'NaN');
ErikE
0

Bagaimana dengan

function isNumberRegex(value) {        
    var pattern = /^[-+]?\d*\.?\d*$/i;
    var match = value.match(pattern);
    return value.length > 0 && match != null;
}
Alexander Schmidt
sumber
0

The JavaScript built-in Isnan fungsi, adalah - seperti yang harus diharapkan secara default - sebuah "Dynamic Type Operator". Oleh karena itu semua nilai yang (selama proses DTC) dapat menghasilkan true | salah seperti"", " ", " 000" , tidak bisa NaN.

Berarti argumen yang diberikan akan terlebih dahulu menjalani konversi seperti pada:

function isNaNDemo(arg){
   var x = new Number(arg).valueOf();
   return x != x;
}

Penjelasan:

Di baris atas badan fungsi, kami (pertama) berusaha untuk berhasil mengubah argumen menjadi objek angka. Dan (kedua), menggunakan operator titik kita - untuk kenyamanan kita sendiri - segera menanggalkan, yang primitif nilai dari objek yang dibuat.

Pada baris kedua, kita mengambil nilai yang diperoleh pada langkah sebelumnya, dan keuntungan dari kenyataan bahwa NaN tidak sama dengan apa pun di alam semesta, bahkan dengan dirinya sendiri, misalnya:NaN == NaN >> false untuk akhirnya membandingkannya (untuk ketidaksetaraan) dengan dirinya sendiri .

Dengan cara ini fungsi kembali akan menghasilkan true hanya ketika, dan hanya jika, pengembalian argumen yang disediakan, adalah upaya gagal konversi ke objek nomor, yaitu, nomor bukan-angka; misalnya, NaN.


isNaNstatic ()

Namun, untuk Operator Tipe Statis - jika diperlukan dan saat dibutuhkan - kita dapat menulis fungsi yang jauh lebih sederhana seperti:

function isNaNstatic(x){   
   return x != x;
}

Dan hindari DTC sama sekali sehingga jika argumen tidak secara eksplisit nomor NaN, itu akan mengembalikan false. Karenanya, pengujian terhadap hal-hal berikut:

isNaNStatic(" x"); // will return false karena masih string.

Namun: isNaNStatic(1/"x"); // will of course return true.seperti akan misalnya isNaNStatic(NaN); >> true.

Tetapi bertentangan dengan isNaN, isNaNStatic("NaN"); >> falsekarena itu (argumen) adalah string biasa.

ps: Versi isNaN statis bisa sangat berguna dalam skenario pengkodean modern. Dan itu mungkin salah satu alasan utama saya meluangkan waktu untuk memposting ini.

Salam.

Bekim Bacaj
sumber
0

isNAN(<argument>)adalah fungsi untuk mengetahui apakah argumen yang diberikan adalah angka ilegal. isNaNtypecasts argumen menjadi tipe Number. Jika Anda ingin memeriksa apakah argumennya Numeric atau tidak? Silakan gunakan $.isNumeric()fungsi di jQuery.

Yaitu, isNaN (foo) setara dengan isNaN (Number (foo)). Ia menerima string apa pun yang memiliki semua angka sebagai angka karena alasan yang jelas. Misalnya

isNaN(123) //false
isNaN(-1.23) //false
isNaN(5-2) //false
isNaN(0) //false
isNaN('123') //false
isNaN('Hello') //true
isNaN('2005/12/12') //true
isNaN('') //false
isNaN(true) //false
isNaN(undefined) //true
isNaN('NaN') //true
isNaN(NaN) //true
isNaN(0 / 0) //true
Om Sao
sumber
0

Saya menggunakan ini

    function isNotANumeric(val) {
    	if(val.trim && val.trim() == "") {
         return true;
      } else {
      	 return isNaN(parseFloat(val * 1));
      }
    }
    
    alert(isNotANumeric("100"));  // false
    alert(isNotANumeric("1a"));   // true
    alert(isNotANumeric(""));     // true
    alert(isNotANumeric("   "));  // true

kiranvj
sumber
0

Ketika memeriksa apakah nilai string tertentu dengan spasi atau " "yang isNaNmungkin mencoba untuk melakukan validasi string misalnya:

// value = "123 " if (value.match(/\s/) || isNaN(value)) { // do something }

Channox
sumber