Ten kod w JS daje mi wyskakujące okienko z napisem „Myślę, że null to liczba”, co wydaje mi się nieco niepokojące. czego mi brakuje?
if (isNaN(null)) {
alert("null is not a number");
} else {
alert("i think null is a number");
}
Używam przeglądarki Firefox 3. Czy to błąd przeglądarki?
Inne testy:
console.log(null == NaN); // false
console.log(isNaN("text")); // true
console.log(NaN == "text"); // false
Więc problem wydaje się nie polegać na dokładnym porównaniu z NaN?
Edycja: Teraz udzielono odpowiedzi na pytanie, wyczyściłem swój post, aby mieć lepszą wersję dla archiwum. Jednak powoduje to, że niektóre komentarze, a nawet odpowiedzi są trochę niezrozumiałe. Nie obwiniaj ich autorów. Zmieniłem między innymi:
- Usunąłem notatkę mówiącą, że schrzaniłem nagłówek, przywracając jego znaczenie
- Wcześniejsze odpowiedzi pokazały, że nie wyjaśniłem wystarczająco jasno, dlaczego uważam, że zachowanie jest dziwne, więc dodałem przykłady, które sprawdzają ciąg i wykonują ręczne porównanie.
javascript
Hanno Fietz
źródło
źródło
Odpowiedzi:
Wydaje mi się, że kod próbuje zapytać „czy jest
x
numeryczny?” z konkretnym przypadkiem tutajx = null
. FunkcjiisNaN()
można użyć, aby odpowiedzieć na to pytanie, ale semantycznie odnosi się ona konkretnie do wartościNaN
. Z Wikipedii dlaNaN
:W większości przypadków uważamy, że odpowiedź na pytanie „czy null numeric?” powinno być nie. Jednak
isNaN(null) == false
jest semantycznie poprawna, ponieważnull
nie jestNaN
.Oto wyjaśnienie algorytmiczne:
Funkcja
isNaN(x)
próbuje przekonwertować przekazany parametr na liczbę 1 (równoważnąNumber(x)
), a następnie sprawdza, czy wartość toNaN
. Jeśli nie można przekonwertować parametru na liczbę,Number(x)
zwróci wartośćNaN
2 . Dlatego, jeślix
wynikiem konwersji parametru na liczbęNaN
jest wartość true; w przeciwnym razie zwraca false.Tak więc w przypadku konkretnego
x = null
,null
jest konwertowana do liczby 0, (próby ocenyNumber(null)
i zobaczyć, że zwraca 0,) iisNaN(0)
zwraca wartość false. Łańcuch, który składa się tylko z cyfr, można przekształcić w liczbę, a isNaN zwraca również wartość false. Łańcuch (np.'abcd'
), Którego nie można przekonwertować na liczbę, spowodujeisNaN('abcd')
zwrócenie wartości true, w szczególności dlatego, żeNumber('abcd')
zwracaNaN
.Oprócz tych pozornych przypadków skrajnych są standardowe numeryczne przyczyny zwracania NaN, takie jak 0/0.
Jeśli chodzi o pozornie niespójne testy równości pokazane w pytaniu, zachowanie
NaN
jest określone w taki sposób, że każde porównaniex == NaN
jest fałszywe, niezależnie od innego operandu, w tymNaN
samego siebie 1 .źródło
NaN !== NaN
. Więc myślę, że nie jest do końca poprawne stwierdzenie,Number('abcd') == NaN
ponieważNumber('abcd')
jest,NaN
ale nie jest równeNaN
. Uwielbiam JavaScript.Number('abcd')
jestNaN
, ale zakłada się, że to prawda testuje równości, co nie jest prawdą. Zmienię to.isNaN
i sąNumber
zaprojektowane tak, aby zachowywać się w ten sposób?null
do0
(przynajmniej w tym kontekście) zachodzi w ramachisNaN()
funkcji, co wymusza jej argument.Właśnie sam napotkałem ten problem.
Dla mnie najlepszym sposobem użycia isNaN jest właśnie taki
isNaN(parseInt(myInt))
biorąc przykład phyzome z góry,
(Wyrównałem wynik zgodnie z danymi wejściowymi, mam nadzieję, że ułatwi to odczytanie.)
Wydaje mi się to lepsze.
źródło
myInt
= „123d”.parseInt
konwertuje „123d” na 123, co następnie nie przechodziisNaN
testu.isNaN(parseInt(str,10)) || isNaN(Number())
. btw - dla mnie, ponieważ muszę biecparseInt
, aby użyć wartości liczbowej ciągu, uznanie „123d” za prawidłową liczbę jest w porządku. Jednak widzę potrzebę wykrycia również tego scenariusza.(Mój drugi komentarz dotyczy podejścia praktycznego. Oto strona teoretyczna).
Sprawdziłem standard ECMA 262 , który implementuje Javascript. Ich specyfikacja dla isNan:
Rozdział 9.3 określa zachowanie
ToNumber
(które nie jest funkcją wywoływalną, ale raczej elementem systemu konwersji typów). Podsumowując tabelę, niektóre typy danych wejściowych mogą generować NaN. Są to typundefined
, typnumber
(ale tylko wartośćNaN
), dowolny obiekt, którego pierwotna reprezentacja toNaN
i każdystring
, którego nie można przeanalizować. Pozostawia toundefined
,NaN
,new Number(NaN)
, a większość struny.Każdy taki wejściowy, który wytwarza
NaN
na wyjściu po przejściu doToNumber
będzie produkowaćtrue
przy zasilaniuisNaN
. Ponieważnull
można z powodzeniem przekonwertować na liczbę, nie tworzytrue
.I dlatego.
źródło
To jest rzeczywiście niepokojące. Oto tablica wartości, które przetestowałem:
Ocenia (w konsoli Firebug) na:
Kiedy dzwonię
x.map(isNaN)
(aby sprawdzić isNaN dla każdej wartości), otrzymuję:Podsumowując,
isNaN
wygląda całkiem bezużytecznie! ( Edycja : z wyjątkiem tego, że okazuje się, że isNaN jest zdefiniowane tylko dla numeru, w którym to przypadku działa dobrze - tylko z wprowadzającą w błąd nazwą.)Nawiasem mówiąc, oto typy tych wartości:
źródło
Null nie jest NaN, podobnie jak łańcuch nie jest NaN. isNaN () po prostu sprawdź, czy naprawdę masz obiekt NaN.
źródło
Nie jestem do końca pewien, jeśli chodzi o JS, ale widziałem podobne rzeczy w innych językach i zwykle dzieje się tak dlatego, że funkcja sprawdza tylko, czy null jest dokładnie równe NaN (tj. Null === NaN byłoby fałszem). Innymi słowy, nie chodzi o to, że myśli, że null jest w rzeczywistości liczbą, ale raczej, że null nie jest NaN. Dzieje się tak prawdopodobnie dlatego, że oba są reprezentowane w JS w różny sposób, więc nie będą dokładnie równe, w taki sam sposób, jak 9! == '9'.
źródło
W ES5 zdefiniowano jako
isNaN (number)
zwraca prawdę, jeśli argument wymusza na NaN, aw przeciwnym razie zwraca fałsz.I zobacz tabelę konwersji operacji abstrakcyjnej ToNumber . Więc wewnętrznie ocena silnika js
ToNumber(Null)
jest+0
, a ostatecznieisNaN(null)
jestfalse
źródło
Uwaga:
Operator == dokonuje konwersji typu, podczas gdy === nie.
Witryna Douglasa Crockforda , Yahoo! Ewangelista JavaScript jest świetnym źródłem informacji o takich rzeczach.
źródło