ferrante.pl

  • blog
  • nauka, kurs javascript, kurs jquery
  • o mnie

Falsy values i operatory porównania

  • JavaScript
  • Vademecum
data publikacji:

05/09

liczba komentarzy:
22

Jest coś takiego w JavaScript, co się zowie jak powyżej. Niestety, bardzo często jest to temat niezrozumiały. Miałem okazję uczestniczyć bądź po prostu układać pytania do kilku rekrutacji na JavaScript developera w dużych firmach i muszę stwierdzić, że czasem bywa wręcz z falsy values dramatycznie.

O co takiego chodzi? Falsy values1 to nic innego, jak zbiór wartości, które dają fałsz. Coś w ten deseń:

if (!value) {
	console.log('Jedną z falsy values jest: '+ value);
}

Pytanie, jakie są to wartości? Oto one:

  • “” – pusta zmienna typu String
  • 0 – typu Number
  • false typu Boolean
  • undefined
  • null
  • NaN typu Number

Czyli:

if (!NaN) {
	console.log('Jedną z falsy values jest: '+ NaN);
}
if (!null) {
	console.log('Jedną z falsy values jest: '+ null);
}

Wszystkie te wartości przy konwertowaniu na typ Boolean (np. !!NaN) dają false. Warto zapamiętać!

Operatory porównania w JavaScript

Jeśli mowa o falsy values ciekawe rzeczy dzieją się przy ich porównywaniu. Jak wiadomo, mamy operatory == i ===. Mnóstwo ludzi wykłada się na tym, banalnym zresztą (po głębszej analizie) problemie.

Warto zapamiętać, że pierwszy operator porównuje jedynie wartości, drugi – wartości oraz typy. Poniższe przykłady dają więc prawdę:

"0" == 0
"    " == 0
[] == 0
undefined == null
false == new String("")

Fałsz zwracają natomiast podobne konstrukcje:

NaN == 0
null == 0
undefined == ""
0 == {}

Kiedy idzie o operator ścisłego porównania robi się ciekawiej – JavaScript oprócz logicznej wartości porównuje również typy zmiennych (a więc czy są obiektem, stringiem, liczbą itd.). Prawdę zwracają:

0 === 0
"" === ""
[] !== [] // dla kontrastu..

Fałsz natomiast poniższe przykłady:

"" === 0 // typ string i number
0 === null // typ number i object
[] === 0 // typ object i number
[] === "    " // typ object i string

Warto więc być ostrożnym w trakcie pisania aplikacji w JavaScript.


  1. Temat falsy values poruszył na przykład Douglas Crockford w swojej znakomitej książce “JavaScript: The Good Parts”. Polecam!

Komentarze

  1. 1

    Bardzo ciekawe. Wiele razy zastanawiałem się czy akurat “ta” konstrukcja zadziała… a nie było czasu na szukanie odpowiedzi w książkach czy necie. Tutaj mam skompilowaną odpowiedź.
    Dzięki Ferrante!

    autor komentarza:
    Piotr
    data komentarza:
    05/09/2009 @ 22:15
  2. 2

    To tylko pokazuje, jak bardzo złym tworem jest JavaScript. I nie ma dla niego alternatywy. (Czy się mylę?)

    autor komentarza:
    Nowaker
    data komentarza:
    06/09/2009 @ 01:44
  3. 3

    JavaScript jest jaki jest i trzeba sie z tym pogodzic. Ja go lubie, ale z radoscia spogladam w strone zmian w kolejnych wersjach (napisze jakiegos posta o nich), ktore troche bardziej normalizuja programowanie. Aczkolwiek z checia bym uslyszal Twoja argumentacje Nowaker.

    Pozdr.

    autor komentarza:
    ferrante
    data komentarza:
    06/09/2009 @ 12:38
  4. 4

    A dlaczego właściwie [] === [] zwraca false?

    autor komentarza:
    Wasacz
    data komentarza:
    06/09/2009 @ 20:26
  5. 5

    13.Return true if x and y refer to the same object or if they refer to objects joined to each other (see 13.1.2). Otherwise, return false.

    http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf 57 strona

    W ogole warto sie przyjrzec dokumentacji, bo powiedzenie ze === porownuje tylko typy jest przesadzone. Moze kiedys przetlumacze i wrzuce.

    autor komentarza:
    ferrante
    data komentarza:
    06/09/2009 @ 20:42
  6. 6

    Ogólnie złem są zachowania, które nie są logiczne. Dużo z tego, co podałeś właśnie takimi jest. Już godzinę po przeczytaniu manuala idzie zapomnieć, że [] == 0 i {} != 0. Programista nie będzie wydajny, jeśli będzie musiał się zastanawiać, czy właściwie null jest zerem, czy pusta tablica jest zerem, czy też nie. Bo równie dobrze twórcy JS mogli założyć, że [] != 0, czyż nie? Nie ma logicznego argumentu na to, że pusta tablica powinna być równa zeru albo i nierówna. A jeśli nie ma, to programista będzie o tym zapominał.

    No, napisz, co tam ma być w nowym JavaScripcie. W sumie front-end to nie moja działka, ale zawsze dobrze wiedzieć. Mógłbyś jeszcze mi tylko odpowiedzieć, czy istnieje w ogóle jakaś alternatywa dla JS.

    autor komentarza:
    Nowaker
    data komentarza:
    07/09/2009 @ 03:30
  7. 7

    Zgadzam się niestety z Nowakerem – te wyniki porównań nie są intuicyjne. Zmuszają (dopóki się nie ma tego w małym palcu) do skupiania się nad wydawałoby się pierdołami. Trochę PHPowo…

    Jeszcze mam pytanie o:
    # “” === new String() // dlaczego true skoro …
    # [] !== [] // … false?

    Czyżby JS też był językiem, w którym dwa Stringi o tej samej wartości są tym samym obiektem? Czy może to nie obiekt? :P

    autor komentarza:
    Reinmar
    data komentarza:
    07/09/2009 @ 18:58
  8. 8

    porownaj sobie:

    alert(typeof new String());
    alert(typeof "");

    # [] !== [] - daje true

    Zapraszam do specyfikacji ;-)

    autor komentarza:
    ferrante
    data komentarza:
    07/09/2009 @ 19:12
  9. 9

    >>> typeof new String()
    “object”
    >>> typeof “”
    “string”
    >>> “” === new String()
    false

    Chyba że to firebug coś mi krzaczy.

    autor komentarza:
    Reinmar
    data komentarza:
    07/09/2009 @ 19:18
  10. 10

    no wiec jesli typy sie nie zgadzaja, to operator === zwraca false – przeczytaj dokumentacje. Wiem, dziwne.

    autor komentarza:
    ferrante
    data komentarza:
    07/09/2009 @ 19:38
  11. 11

    Chciałem tylko Ci zwrócić uwagę, że masz w treści notki “” === new String() dające prawdę. Rozumiem, że to błąd.
    I z tego co widzę głębsza analiza specyfikacji rzeczywiście jest potrzebna (ale jakoś nie mam na to ochoty w tym momencie). Pytanie tylko czemu nie mogłoby to być intuicyjne?

    autor komentarza:
    Reinmar
    data komentarza:
    07/09/2009 @ 19:48
  12. 12

    O matko, nie wiem, skad sie to tam wzielo, moje przeoczenie, jeszcze sam analizowalem ten przyklad przed pisaniem. Eh ;-)

    Pozdrawiam

    autor komentarza:
    ferrante
    data komentarza:
    07/09/2009 @ 19:54
  13. 13

    Nie jestem pewien, ale chyba znalazlem blad:

    “”"”
    Czyli:

    1. if (!NaN) {
    2. console.log(‘Jedną z falsy values jest: ‘+ value);
    3. }

    1. if (!null) {
    2. console.log(‘Jedną z falsy values jest: ‘+ null);
    3. }

    Wszystkie te wartości dają false. Warto zapamiętać!
    “”"”

    Zamiast:
    if (!NaN)
    powinno byc chyba:
    if (NaN)

    tak samo z if (!null).

    autor komentarza:
    cx
    data komentarza:
    09/09/2009 @ 02:27
  14. 14

    Nie masz racji ;)

    autor komentarza:
    ferrante
    data komentarza:
    09/09/2009 @ 08:37
  15. 15

    Odnosząc się do szóstego komentarza autorstwa Nowakera.

    Zgadzam się, że działanie operatorów porównań nie jest łatwe do odgadnięcia “na logikę” na samym początku, ale po przeczytaniu specyfikacji wszystko staje się jasne.
    Wystarczy w zasadzie zapamiętać, że jeśli dokładnie jeden z operandów jest obiektem to przy operatorze == zostanie sprowadzony do wartości prymitywnej.
    Dlatego [] == 0, [] == “”, [0] == 0, nawet “[object Object]” == {} zwrócą true.
    Dopiero wartości prymitywne są ze sobą porównane.
    Gdy obydwa operandy są obiektami, to porównywane są referencje.

    Jeśli porównujemy String z liczbą / liczbę ze Stringiem, zawsze String zostanie sprowadzony do wartości liczbowej. W ten sposób prawdę zwrócą “1e1″ == 10, 10 == “1e1″

    W przypadku, gdy jednym z operandów jest wartość logiczna (true/false), operand ten będzie sprowadzony do liczby i dopiero porównany z drugim, dlatego prawdą będzie:
    true == 1
    true == “1″
    false == 0
    false == “0″
    false == [0]

    mam nadzieję, że nic nie pokręciłem ;-)

    autor komentarza:
    Rafał Kukawski
    data komentarza:
    10/09/2009 @ 16:21
  16. 16

    @Rafał, chodzi właśnie o to, by nie czytać żadnej specyfikacji. Aczkolwiek niżej podałeś ludzkie reguły rządzące tymi porównaniami.

    autor komentarza:
    Nowaker
    data komentarza:
    10/09/2009 @ 21:42
  17. 17

    Dlaczego nie mam racji? Przeciez
    !null == true
    a nie false, a jest napisane “Wszystkie te wartości dają false. “

    autor komentarza:
    cx
    data komentarza:
    14/09/2009 @ 18:17
  18. 18

    Poprawione w tekscie.

    autor komentarza:
    ferrante
    data komentarza:
    14/09/2009 @ 19:06
  19. 19

    a po co zawracać sobie głowę ==, != ?

    autor komentarza:
    Marek
    data komentarza:
    20/10/2009 @ 15:06
  20. 20

    Marek podał idealne rozwiązanie problemu i jedyny sposób, by nie zaprzątać sobie tym wszystkim głowy – wystarczy wyrzucić z głowy te dwa operatory ‘==’ oraz ‘!=’ i używać ich bardziej precyzyjnych odpowiedników, czyli ‘===’ oraz ‘!==’ – robię tak od ponad roku (od kiedy na porządku dziennym używam JS Lint) i w żaden sposób mi ich nie brakuje.

    autor komentarza:
    Kamil T.
    data komentarza:
    09/11/2009 @ 23:08
  21. 21

    if ( 0 == false ) document.write( ‘0 == false’ ); else document.write( ‘0 != false’ );
    document.write(”);
    if ( null == false ) document.write( ‘null == false’ ); else document.write( ‘false != null’ );
    document.write(”);
    if ( 0 == null ) document.write( ‘0 == null’ ); else document.write( ‘0 != null’ );
    document.write(”);

    if ( null )
    {
    document.write( ‘null is true’ );
    }
    else
    {
    document.write( ‘null is not true’ );
    }

    document.write(”);
    if ( null == true )
    {
    document.write( ‘null is true’ );
    }
    else
    {
    document.write( ‘null is not true’ );
    }

    document.write(”);
    if ( null == false )
    {
    document.write( ‘null is false’ );
    }
    else
    {
    document.write( ‘null is not false’ );
    }

    0 == false
    false != null
    0 != null
    null is not true
    null is not true
    null is not false

    Strasznie nielogiczne. Po to jest === zeby dostac ( null === false ) != true…

    autor komentarza:
    pakalk
    data komentarza:
    15/11/2009 @ 18:51
  22. 22

    [...] do analizy tej linii mamy prosty warunek. Jako że NaN to jedna z falsy values i przy skonwertowaniu do wartości logicznej da false, JS spróbuje wziąć sobie zmienną foobar i [...]

    autor komentarza:
    Ile tu jest błędów – rozwiązanie
    data komentarza:
    26/11/2009 @ 00:58

Dodaj komentarz

idź do góry
  • blog
  • nauka, kurs javascript, kurs jquery
  • o mnie
O mnie

Damian Wielgosik - Programista i dziennikarz. Od siedmiu lat koder front-end i back-end. Lubi dobre technologie. mail skype

Kategorie
  • CSS
  • Drawter
  • ferrante.pl
  • JavaScript
  • jQuery
  • PHP
  • Publicystyka
  • Rozmowy rolowane
  • Software
  • Usability
  • Vademecum
  • W sieci...
Czytam
  • Costa
  • Ludwik
  • Rafał Kukawski
  • RAFi
  • Szafranek
  • Warszawa78

Powered by Wordpress.
Copyright by Damian Wielgosik 2007-2010
Design by Dez.