İsNaN (“”) (boşluklu dize) neden false değerine eşit?


160

JavaScript'te neden isNaN(" ")değerlendirilir false, ancak isNaN(" x")değerlendirilirtrue ?

Bir metin giriş alanına sayısal işlemleri gerçekleştirirken ediyorum ve saha ise kontrol ediyorum null, ""ya NaN. Birisi alana bir avuç boşluk yazdığında, doğrulama işlemim her üçünde de başarısız olur ve neden isNaNkontrolü geçtiği konusunda kafam karıştı .


1
Hım ... konunun diğer yarısının nereye gittiğinden pek emin değilim. "JavaScript: isNaN (" ") neden yanlış olarak değerlendiriliyor?"
IVR Avenger

Jes, bu davranış (boş veya boşluk isNaN için yanlış döndürür), ancak bu işlevin tam özelliklerini bulamadım.
Lucero


Bu konularda Javascript voodoo gibi görünüyor! Asla bilemezsiniz ve açıklama her zaman oldukça karmaşıktır. "" == false // trueveisNaN(" ") // false
João Pimentel Ferreira

Yanıtlar:


155

JavaScript boş bir dizeyi 0 olarak yorumlar; bu daha sonra isNAN testini geçemez. Önce boş dizeyi 0'a dönüştürmeyecek dize üzerinde parseInt kullanabilirsiniz. Sonuç daha sonra başarısız olur.


53
Ancak parseInt ("123abcd") 123 döndürür, yani isNaN (parseInt ("123abcd")) true döndürmesi gerekirken false döndürür!
Pawan Nogariya

11
Peki ya (IsNaN (string) || isNaN (parseInt (string)))
mat

5
Sözlü çeviride 2 adım vardır isNaN(arg). 1) Arg değerini sayıya dönüştür, 2) Bu sayının sayısal değer olup olmadığını kontrol edin NaN. Bu daha iyi anlamama yardımcı oldu.
xdhmoore

3
@Antonio_Haley Bir dakika, anlamadım. "JavaScript boş bir dizeyi 0 olarak yorumlar", parseInt ("") neden NaN döndürür?
Jean-François Beauchamp

1
@ Jean-François Doğru, daha doğru ifade "isNaN boş bir dizeyi 0 olarak yorumlar" olur, JavaScript'in kendisi değildir.
Antonio Haley

82

Bunu şaşırtıcı ya da şaşırtıcı bulamazsınız, ancak JavaScript motorunun tuhaflığını gösteren bazı test kodları.

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

yani bu demek oluyor ki

" " == 0 == false

ve

"" == 0 == false

fakat

"" != " "

İyi eğlenceler :)


5
+1 Harika gönderi. Üçlü eşittir (=== ve! ==) operatörünün buraya nasıl uyduğunu ekleyebilir misiniz?
bendewey

2
NaN === NaN veya NaN == NaN ;-) denemeliyim Bütün bunlar javascript motoru wacky veya javascript wacky programcılar için kötü anlamına gelir bilmiyorum.
KooiInc

10
@Kooilnc NaN! = NaN'nin aslında bir kez iyi bir seçim olduğu gerçeği. Fikir şu ki, NaN neredeyse her zaman programlayıcının amaçladığından farklı olan bir hesaplamanın sonucudur ve “yanlış” giden iki hesaplamanın sonuçlarının eşit olduğunu varsaymaktır.
skrebbel

2
@Kooilnc, Javascript'in tuhaflığından bile biraz uzak durmamak için değil, ancak bu NaN'ler sadece IEEE 754 kayan nokta standardına uyuyor. TÜM hakkında her zamanki gibi büyük W'de okuyabilirsiniz: en.wikipedia.org/wiki/NaN
Spike0xff

@NickBerardi F'ing LOL! Bu gönderiyi gördüğüm için çok memnunum. İsNaN işlevinin neden bu kadar geciktirildiğini anlamama yardımcı oldu. Şu anda tam olarak geliştirilmiş olmayan kodumdan çıkaracağım ve muhtemelen bir daha kullanmayacağım. Ben doğrular null, ""ve " "ben. Teşekkürler!
VoidKing

16

Daha iyi anlamak için, lütfen "Dize Türüne Uygulanan ToNumber" sayfa 43 " Ecma-Script spec pdf dosyasını açın.

bir dize, herhangi bir sayıda beyaz boşluk karakteri içerebilecek sayısal bir sözdizimine sahipse, bu sayı Numara türüne dönüştürülebilir. Boş dize 0 olarak değerlendirilir. Ayrıca 'Infinity' dizesi de vermelidir

isNaN('Infinity'); // false

13

Kullanmayı deneyin:

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

Veya

alert(isNaN(parseFloat("    ")));

3
merhaba efendim, isNaN (parseInt ("123a")): 123, döndürür, böylece dize aplha sayısal içeriyorsa, ur çözümünüz çalışmaz
Sajjad Ali Khan

6

Karşılaştığınız MDNsorunun nedeninden

İsNaN işlevinin bağımsız değişkeni Number türünde değilse, değer önce bir Number öğesine zorlanır. Elde edilen değer daha sonra NaN olup olmadığını belirlemek için test edilir.

Eşitlik için NaN karşılaştırmasını da kapsayan aşağıdaki kapsamlı cevabı kontrol etmek isteyebilirsiniz.

JavaScript değişkeninin nasıl test edileceği NaN


5

Ben Javascript'in yazarak nedeniyle olduğunu düşünüyorum: ' 'sıfıra dönüştürülür, oysa 'x'değil:

alert(' ' * 1); // 0
alert('x' * 1); // NaN

4

Doğru bir isNumber işlevi uygulamak istiyorsanız, Javascript: The Good Parts by Douglas Crockford'dan bunu yapmanın bir yolu var [sayfa 105]

var isNumber = function isNumber(value) {
   return typeof value === 'number' && 
   isFinite(value);
}

4
@Xyan, bu durumda OP'nin yapmak istediği görevi yerine getirmek için çok yararlı değil, bu da bir sayının dize temsilini incelemekti ...
ErikE

"sayı" gibi bir dize değişmezine karşı herhangi bir değerde katı eşitlik operatörü kullanmak aptalca,
Bekim Bacaj

4

Tamamen Doğru Olmayan Cevap

Antonio Haley'nin son derece onaylanan ve kabul edilen cevabı , bu işlemin JavaScript'in parseIntişlevinden geçtiğini yanlış bir şekilde varsayıyor :

Dizede parseInt kullanabilirsiniz ... Sonuç isNAN başarısız olmalıdır.

Bu ifadeyi dizeyle kolayca çağırabiliriz "123abc":

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

Bununla, JavaScript parseIntişlevinin "123abc"sayı olarak döndüğünü görebiliriz 123, ancak isNaNişlevi bize bir sayı "123abc" olmadığını söyler .

Doğru cevap

ECMAScript-262, isNaNkontrolün bölüm 18.2.3'te nasıl çalıştığını tanımlar .

18.2.3 isNaN(Sayı)

isNaNFonksiyonudur %isNaN%iç nesne. Ne zaman isNaNfonksiyonu tek argüman numarası ile çağrılır, aşağıdaki adımlar gerçekleştirilir:

  1. Olsun nummu? ToNumber(number).
  2. Eğer numöyleyse NaN, geri dönün true.
  3. Aksi takdirde geri dönün false.

ToNumberİşlev referanslar da tanımlanan ECMAScript 262 bölümü 7.1.3 . Burada, JavaScript'in bu işleve aktarılan Dizeleri nasıl ele aldığı anlatılmaktadır.

Soruda verilen ilk örnek, boşluk karakterlerinden başka bir şey içermeyen bir dizedir. Bu bölüm şunları belirtir:

StringNumericLiteralBoş veya yalnızca beyaz boşluk içeren A'ya dönüştürülür +0.

Bu " "nedenle örnek dize +0, bir sayı olan dönüştürülür .

Aynı bölüm şunları da belirtmektedir:

Dilbilgisi yorumlamak yapamıyorsanız Stringbir genişleme olarak StringNumericLiteral, daha sonra sonucu ToNumberDİR NaN.

Bu bölümde yer alan tüm kontrolleri alıntılamadan " x", soruda verilen örnek, a olarak yorumlanamadığı için yukarıdaki koşula girer StringNumericLiteral. " x"bu nedenle dönüştürülür NaN.


2

Neden olduğundan emin değilim , ancak sorunu çözmek için kontrol etmeden önce boşlukları her zaman kesebilirsiniz. Muhtemelen bunu yine de yapmak istersiniz.


4
kesilmiş boş bir dize de isNaN testinde başarısız olur.
Egemenk

2

İşlev isNaN("")bir String to Number tipi zorlaması gerçekleştirir

ECMAScript 3-5, typeof operatörü için aşağıdaki dönüş değerlerini tanımlar:

  • Tanımsız
  • nesne (null, nesneler, diziler)
  • boole
  • numara
  • sicim
  • fonksiyon

Testimizi bir işlev gövdesine sarmak daha iyidir:

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

Bu işlev, değişken türünü test etmek için tasarlanmamıştır , bunun yerine zorlanmış değeri test eder . Örneğin, boole ve dizeler sayılara zorlanır, bu nedenle belki de bu işlevi şu şekilde adlandırmak isteyebilirsiniz:isNumberCoerced()

dize ve sayı dışındaki türleri test etmeye gerek yoksa , aşağıdaki snippet bazı koşulların bir parçası olarak kullanılabilir:

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

1

Gerçekten bir tamsayı olup olmadığını düzgün kontrol etmek istiyorsanız aşağıdaki işlevi kullanmanızı öneririm:

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

1

Bu isNaN(" ")yanlıştır, isNaNsayısal olmayan bir sayıya sayısal olmayan bir şekilde zorlanması nedeniyle küresel işlevin kafa karıştırıcı davranışının bir parçasıdır .

Gönderen MDN'yi :

isNaNİşlev belirtiminin en eski sürümlerinden bu yana, sayısal olmayan argümanlar için davranışı kafa karıştırıcı olmuştur. isNaNİşlevin bağımsız değişkeni Number türünde olmadığında, değer önce bir Number öğesine zorlanır. Sonuçta elde edilen değer, olup olmadığını belirlemek için test edilir NaN. Bu nedenle, sayısal tipe zorlandığında, geçerli bir NaN olmayan sayısal değerle sonuçlanan sayılar için (özellikle boş dize ve boole ilkelleri, zorlandığında sayısal değerler sıfır veya bir verir), "yanlış" döndürülen değer beklenmedik olabilir; örneğin, boş dize mutlaka "bir sayı değildir".

Ayrıca ECMAScript 6 Number.isNaNile MDN'ye göre şu anda bir yöntem olduğuna dikkat edin:

Global isNaN()işleve kıyasla Number.isNaN(), parametreyi bir sayıya zorla dönüştürme problemi yaşamaz. Bu, normalde dönüştürülecek NaNancak gerçekte aynı değerde olmayan değerleri iletmenin artık güvenli olduğu anlamına gelir NaN. Bu, aynı zamanda yalnızca tip numarası değerlerinin, yani NaNdöndürüleceği anlamına da gelir true.

Maalesef :

ECMAScript 6 Number.isNaNyönteminin bile blog yayınında belirtildiği gibi kendi sorunları var - Çirkin JavaScript ve ES6 NaN sorununu düzeltme .


1

isNaN(Sizin durumunuzda bir dize) başka tür argümanları Number dönüştürülür, böylece işlevi, bağımsız değişkeni olarak Numara beklediği önce gerçek işlevi mantığı gerçekleştirilir. (Farkında olmakNaN Number türünde bir değer olduğunu da unutmayın!)

Btw. bu, tüm yerleşik işlevler için ortaktır - belirli bir türde bağımsız değişken beklerse, gerçek bağımsız değişken standart dönüştürme işlevleri kullanılarak dönüştürülür. Tüm temel türler arasında standart dönüşümler vardır (bool, dize, sayı, nesne, tarih, null, undefined.)

İçin standart dönüşüm Stringiçin Numberbirlikte açık çağrılabilir Number(). Böylece şunu görebiliriz:

  • Number(" ") için değerlendirir 0
  • Number(" x") için değerlendirir NaN

Bu göz önüne alındığında, isNaNişlevin sonucu tamamen mantıklı!

Asıl soru, standart Dize-Sayı dönüşümünün neden olduğu gibi çalışmasıdır. Dize-sayı dönüştürme gerçekten "123" veya "17.5e4" gibi sayısal dizeleri eşdeğer sayılara dönüştürmeyi amaçlamaktadır. Dönüşüm önce ilk boşluk alanını atlar (böylece "123" geçerlidir) ve ardından kalanları sayı olarak ayrıştırmaya çalışır. Bir sayı olarak ayrıştırılamazsa ("x" değil) sonuç NaN olur. Ancak, boş veya yalnızca boşluk olan bir dizenin 0'a dönüştürüldüğü açık özel bir kural vardır. Bu, dönüşümü açıklar.

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


1

Bu sorunu çözmeye yardımcı olmak için bu hızlı küçük işlevi yazdım.

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

Sadece sayısal olmayan (0-9), '-' veya '.' Olmayan ve tanımlanmamış, boş veya boş olmayan karakterleri kontrol eder ve eşleşme yoksa true değerini döndürür. :)


Gecikmiş bunun için teşekkür ederim; Bu sorunumu çok güzel çözdü.
Henry

1

Diğerleri açıklandığı gibi, isNaNişlev, boş dizeyi doğrulamadan önce bir sayıya zorlar, böylece boş bir dizeyi 0 (geçerli bir sayıdır) olarak değiştirir. Ancak, boş bir dize veya yalnızca boşluklu bir dize ayrıştırmaya çalışırken parseIntişlevin döneceğini buldum NaN. Bu nedenle, aşağıdaki kombinasyon iyi çalışıyor gibi görünüyor:

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

Bu kontrol pozitif sayılar, negatif sayılar ve ondalık noktalı sayılar için çalışacaktır, bu yüzden tüm yaygın sayısal durumları kapsadığına inanıyorum.


1

NaN ! == "sayı değil"

NaN Sayı Türünün bir değeridir

Bu ECMAScript bir isNaN () bir tanımıdır

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

Herhangi bir değeri Sayı'ya dönüştürmeye çalışın.

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

Değerin olup olmadığını belirlemek istiyorsanız NaN, önce değeri Sayı değerine dönüştürmeyi denemelisiniz.


0

Bu işlev testlerimde çalışıyor gibi görünüyordu

function isNumber(s) {
    if (s === "" || s === null) {
        return false;
    } else {
        var number = parseInt(s);
        if (number == 'NaN') {
            return false;
        } else {
            return true;
        }
    }
}

2
Tüm fonksiyonunuz yazılabilir:return !(s === "" || s === null || parseInt(s) == 'NaN');
ErikE

0

Ne dersin

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

0

JavaScript yerleşik isNaN fonksiyonu olan - varsayılan olarak beklenmelidir gibi - bir "Dinamik Tip Operatörü". Bu nedenle (DTC işlemi sırasında) basit bir doğru | gibi yanlış "", " ", " 000", NaN olamaz.

Bunun anlamı, argüman verilen ilk olarak geçirecek dönüşüm gibi:

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

Açıklama:

İşlev gövdesinin üst satırında, (ilk olarak) bağımsız değişkeni bir sayı nesnesine başarıyla dönüştürmeye çalışıyoruz. Ve (ikinci), öyleyiz nokta operatörünü kullanarak - hemen kapalı sıyırma - kendi amaçlarımız için ilkel değer yaratılmış nesnenin.

İkinci satırda, bir önceki adımda elde edilen değeri alıyoruz ve NaN'nin evrendeki herhangi bir şeye eşit olmadığı gerçeğinin avantajını kendimiz bile değil, örneğin: NaN == NaN >> falsesonunda (eşitsizlik için) kendisiyle karşılaştırmak .

Fonksiyon geri verecektir Bu şekilde , gerçek , sadece, verilen bağımsız değişken dönüş, eğer çok sayıda nesnenin bir dönüştürme başarısız bir girişimi olduğu zaman, yani, bir not-a-numarası sayı; örneğin, NaN.


isNaNstatic ()

Bununla birlikte, bir Statik Tip Operatörü için - gerekirse ve gerektiğinde - çok daha basit bir fonksiyon yazabiliriz:

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

Ve DTC'den tamamen kaçının, böylece argüman açıkça bir NaN numarası değilse, yanlış döndürür. Bu nedenle, aşağıdakilere karşı testler:

isNaNStatic(" x"); // will return false çünkü hala bir ip.

Ancak: isNaNStatic(1/"x"); // will of course return true.örneğin isNaNStatic(NaN); >> true.

Ama aksine hiç isNaN, isNaNStatic("NaN"); >> falseo (argüman) sıradan bir dize olduğu için.

ps: isNaN'in statik sürümü, modern kodlama senaryolarında çok yararlı olabilir. Ve bunu yayınlamak için zamanımı ayırmamın ana nedenlerinden biri olabilir.

Saygılarımızla.


0

isNAN(<argument>)verilen argümanın yasadışı sayı olup olmadığını söyleyen bir fonksiyondur. isNaNargümanları Number türünde tahmin eder. Argümanın Sayısal olup olmadığını kontrol etmek istiyorsanız? Lütfen $.isNumeric()jQuery işlevini kullanın .

Yani, isNaN (foo) isNaN (Number (foo)) ile eşdeğerdir. Belli nedenlerden ötürü, tüm sayılara sahip sayıları sayı olarak kabul eder. Örn.

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

0

Bunu kullanıyorum

    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


0

Boşluk ile belirli dize değeri olmadığını kontrol veya zaman " "olduğu isNaNbelki dize doğrulama gerçekleştirmek için deneyin örnek:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.