JavaScript: Undefined vs. null

Znajomy zapytał mnie dzisiaj czy to dobry kod:

W pierwszym odruchu utwierdziłem go (pytał by się upewnić), że nie, że lepiej byłoby użyć słowa kluczowego null. Argumentowałem nawet, że undefined można sobie swobodnie nadpisać. Wyczytałem to zdaje się na Stackoverflow.

Jednak kiedy, spróbowałem sprawdzić moje własne słowa, znalazłem tą oto małą notkę:

JavaScript 1.8.5 note

Starting in JavaScript 1.8.5 (Firefox 4), undefined is non-writable, as per the ECMAScript 5 specification.

W skrócie: nie można (przynajmniej w nowszych przeglądarkach) nadpisać undefined. Operator === też działa prawidłowo z użyciem undefined. Nie ma więc nie bezpieczeństwa? Czyżbym wpuścił kolegę niechcący w maliny?

Ale dalej mi się to wszystko nie podobało. Należy pamiętać, że:

  • undefined nie jest stałą
  • nie jest też słowem kluczowym języka JavaScript (sprawdźcie sami)
  • nie jest nawet słowem zastrzeżonym pod przyszłe użycie
  • otrzymamy wyjątek jeśli napiszemy coś takiego: if (zmienna_niezadeklarowana_wcześniej === undefined) (trzeba więc użyć operatora typeof)

Czym więc jest undefined? Jest zmienną globalną (choć tylko do odczytu od jakiegoś czasu). Lokalnie (wewnątrz funkcji) możemy ją sobie swobodnie nadpisać. Więc, jeśli nawet nie widać niczego złego przy wywołaniu kodu:

{geshi lang=javascript}var a; var undefined = 42; console.log(a); // undefined console.log(undefined); // undefined console.log(a == undefined); // true

To wystarczy wstawić go do wewnątrz funkcji:

)();

Podsumowanie

Morał jest więc prosty: jeśli cenicie sobie jakość swojego dzieła, nie chcecie, aby się z was koledzy śmiali: używajcie null do inicjacji zmiennych, nie polegajcie na tych małym potworku jakim jest undefined. Jego używamy tylko do analizy np. zmiennych globalnych. Ja widzę też jeszcze powód dla którego lepiej jest użyć null: jeśli chcemy przywrócić pierwotną wartość zmiennej, bardziej naturalne jest przypisanie do niej właśnie null.

Taka jest moja opinia. Bardzo chętnie zapoznam się z jakąś dobrą argumentacją (jeśli jest takowa) przeciw.

Linki

24 thoughts on “JavaScript: Undefined vs. null

  1. Nie zgodzę się. Bo niby czemu tak uważasz? Jaka jest Twoja argumentacja? Czy “bo JS, nie przypomina języka X, jaki lubię”? Ten argument jest słaby.
    Zaprezentowany przeze mnie post nie wytyka błędu języka, ale jego użytkowników.

    Like

  2. Nie zgodzę się. Bo niby czemu tak uważasz?
    Bo takie mam zdanie na temat tego języka. Pozwala na rzeczy, które IMO są dziwne, tak jak właśnie nadpisywanie różnych elementów. Niby taki undefined nie jest częścią języka ale jest traktowany w specjalny sposób. Takich obejść jak to jest więcej i powinieneś wiedzieć o tym lepiej ode mnie – JS-a używam od święta.

    Like

  3. W ten sposób możnaby powiedzieć, że nie powinno się używać asm, bo można się podpiąć pod niewłaściwe przerwanie albo sobie płytę główną spalić 😛

    A może po prostu trzeba uświadomić sobie, że z wielką mocą wiąże się wielka odpowiedzialność?

    i nie jest to cytat ze spidermana tylko z Woltera 😀

    Like

  4. Pozwala na rzeczy, które IMO są dziwne, tak jak właśnie nadpisywanie różnych elementów.

    To jest po prostu plastyczność języka. A co do “undefined”, to nie ma być coś, co masz używać normalnie, tylko w bardzo specyficznych sytuacjach, o czym ten artykuł przypomina.

    @mt3o++

    Like

  5. Powinno się raczej powiedzieć: wykorzystuj właściwe narzędzia do właściwych celów. Bo właśnie to miałem na myśli. Czy w asemblerze będziesz pisał wysokopoziomową logikę czy raczej krytyczne/specyficzne wstawki i czy nie ograniczysz się tylko do wstawek z tego właśnie względu, że możesz bardzo łatwo zrobić coś niechcący źle? Wielka moc czasami jest zbędna i tylko przeszkadza. JS nie jest wyjątkiem, chociaż mocy porównywalnej do asemblera zdecydowanie nie ma. Zresztą gdyby było to narzędzie idealne, nikt by się nie bawił się np. w CoffeScript, GWT, czy jeszcze inne wynalazki, które pozwalają robić pewne rzeczy trochę inaczej/łatwiej/szybciej, a być może nawet wszyscy zaczęliby hura optymistycznie używać JS poza przeglądarkami.

    I to “trochę inaczej” jest chyba kluczem jeśli chodzi o moją ocenę JS. Dla każdego kto na co dzień używa innych języków bardzo łatwo jest się przejechać na kilku popularnych konstrukcjach z tego względu, że z jednej strony jest podobny do C czy ActionScripta, a z drugiej wiele rzeczy zachowuje się diametralnie inaczej i części rzeczy po prostu nie ma.

    A tak w sumie to czuję się lekko zaskoczony, że nie próbujecie mnie inaczej uświadomić. Z JS jestem na bakier, ale takie slogany co najmniej podejrzanie śmierdzą, każdy język ma swoje upierdliwości a po waszych uwagach mam wrażenie, że czysty JS nadaje się do pisania pełnowymiarowych aplikacji i to bez żadnych zastrzeżeń.

    Like

  6. Nie nadaje się z choćby z powodu wydajności silników js. Z tym nikt nie dyskutuje. Ale do szybkiego prototypowania czy wstawek sklejających GUI oparte na HTML – jest wystarczające. Do większych rzeczy w przeglądarce – sam podałeś choćby GWT.
    Każdy język ma swoje upierdliwości ale są języki w których trudno zrobić sobie krzywdę, choćby java. W innych językach są inne niuanse, to oczywiste że pisząc w danym języku trzeba je znać.
    Kurczę, język to tylko narzędzie i w sporej liczbie przypadków ważniejsze jest to jak dobrze znasz język a nie to który jest prawomyślny.
    na marginesie, im więcej piszę w js tym bardziej chcę go używać gdzie tylko mogę. Do cs/ts pewnie jeszcze dorosnę.

    Btw, jest kompilator js do kodu dotnetowego, do javy pewnie też coś się znajdzie. Pewnie są duże projekty które z tego korzystają 😉

    Like

  7. Te silniki JS są wydajniejsze kilkadziesiąt razy od większości języków dynamicznych jak Python, Ruby i PHP. Nie na darmo powstało NodeJS.
    To co jest obecnie wolne to obsługa DOM. W zastępstwie mamy Canvas i WebAudio, które pomijają DOM i są wystarczająco wydajne do ciekawych zastosowań.
    A AsmJS pracowników Mozilli jest podobno 1.6x wolniejszy od rozwiązań natywnych.

    Like

  8. Czy w asemblerze będziesz pisał wysokopoziomową logikę

    Da się, kiedyś to był język, w którym pisano systemy operacyjne. Ale jak słusznie zauważyłeś: dobieramy narzędzie do celu. W tej chwili nie ma chyba alternatywy do JS na stronach WWW.

    Tak BTW: ActionScript jest oparty na tym samym co i JavaScript.

    Like

  9. To się wszystko zgadza. Dlatego też w pierwszej wypowiedzi pojawiła się mordka ‘;)’. Jakkolwiek bym nie lubił JS, jest to narzędzie, które ma swoje zastosowania i jest w nich niezastąpione. Zresztą nie ma chyba języka, który bym po prostu kochał, każdy ma swoje „kwiatuszki”.

    Like

  10. undefined nie jest stałą

    if (foo === void 0) i problem z głowy.

    otrzymamy wyjątek jeśli napiszemy coś takiego: if (zmienna_niezadeklarowana_wcześniej === undefined)

    Jeżeli napiszemy if (zmienna_niezadeklarowana_wcześniej === null) też dostaniemy wyjątek, więc nie za bardzo widzę co ten argument ma pokazywać.

    Like

  11. if (foo === void 0) i problem z głowy.

    Bo “undefined nie jest stałą”? “Nie za bardzo widzę, co ten argument ma przekazywać”.
    Udziwnianie kodu nie jest czymś pożądanym w normalnych rozwiązaniach.
    Ale przyznam, że instrukcji(?) “void 0” nie znałem.

    Jeżeli napiszemy if (zmienna_niezadeklarowana_wcześniej === null) też dostaniemy wyjątek, więc nie za bardzo widzę co ten argument ma pokazywać.

    Tutaj nieco ci się pomieszało. To nie jest argument za używaniem nulla, ale przeciwko stosowaniu undefined. O nullach piszę dalej.

    Like

  12. Udziwnianie kodu nie jest czymś pożądanym w normalnych rozwiązaniach.

    /*
     * Returns true if value passed as argument is not undefined.
     */
    function defined(value) {
        /* Use "void 0" since it always has undefined value while
         * "undefined" variable may be overwritten and some weird
         * funky stuff can happen with it. */
        return value !== void 0;
    }
    

    To nie jest argument za używaniem nulla, ale przeciwko stosowaniu undefined.

    Nadal nie wiem co ten argument ma pokazywać. Użycie niezadeklarowanej zmiennej generuje wyjątek – co to ma do undefined?

    Like

  13. Napisałeś funkcję, fajnie. Ktoś inny pewnie nie napisze i mamy zonk. Lepiej już pomyśleć nieco i nie używać jawnie undefined.

    Użycie niezadeklarowanej zmiennej generuje wyjątek – co to ma do undefined

    Może przeczytaj mój tekst w kontekście? Tam to jest napisane.

    Like

  14. Napisałeś funkcję, fajnie. Ktoś inny pewnie nie napisze i mamy zonk. Lepiej już pomyśleć nieco i nie używać jawnie undefined.

    To, że jakiś „mityczny” ktoś czegoś nie zrobi, nie jest samo w sobie wystarczającym argumentem, żeby zrezygnować z korzystania z jakiejś funkcji języka. Ktoś zapewne nie poda drugiego argumentu do funkcji parseInt, czy jest to powód, żeby przestać z tej funkcji korzystać?

    Może przeczytaj mój tekst w kontekście? Tam to jest napisane.

    Twój tekst traktuje o sprawdzaniu, czy zmienna jest zainicjowana — ma to się tylko trochę do sprawdzania, czy zmienna została zadeklarowana. To że niezadeklarowana_zmienna === undefined rzuca wyjątek (swoją drogą to tylko w „strict mode”), nie jest argumentem ani za ani przeciw stosowaniu undefined.

    Owszem, zgodzę, się, że jeżeli chcemy sprawdzić, czy zmienna jest zainicjowana, lepiej przy deklaracji przypisać jej wartość null, ale jest to z zupełnie innych powodów, niż opisane w tekście.

    Ogólnie argument, że undefined można nadpisać jest kiepski. W JavaScript wiele rzeczy można nadpisać (np. wspomniane już wcześniej parseInt) i zepsuć cały skrypt. Programowanie do pewnego stopnia opiera się na założeniu, że programista nie będzie robił nic głupiega — nadpisywanie undefined jest czymś głupim.

    Like

  15. To, że jakiś „mityczny” ktoś czegoś nie zrobi, nie jest samo w sobie wystarczającym argumentem, żeby zrezygnować z korzystania z jakiejś funkcji języka.

    Kojarzysz może “goto”?

    ale jest to z zupełnie innych powodów, niż opisane w tekście.

    Śmiało.

    Ogólnie argument, że undefined można nadpisać jest kiepski.

    Rozumiem, że nie przeczytałeś pozostałych.

    Like

  16. Kojarzę i korzystam:

    Chyba nie ty. Po drugie co ty mi tu dałeś? Jednym z przykazań każdego szanującego się programisty jest: nie używanie goto. Istnieje parę uzasadnionych przypadków, kiedy można to robić, ale w językach wyższego poziomu nic cię nie usprawiedliwia (w niektórych nawet nie da się tego tak używać). Od tego są while, for itp.
    Dlaczego w kodzie Linuksa jest tyle goto? Może występuje w komentarzach, może część jest w asemblerze:D, a może nie dało się inaczej. Tak czy siak, źródła systemu tak długo żyjącego operacyjnego, nijak się nie mają do języków skryptowych (jak JS).

    Ważniejsze: Przykładów, jakimi się chwaliłeś nie podałeś.

    Like

  17. Chyba nie ty.

    Owszem, również ja:

    $ git blame -- drivers/usb/gadget/f_mass_storage.c |grep -c 'Michal Nazarewicz.*\bgoto\b' 
    19
    # Zsumowanie z innych plików, które dotykałem pozostawiam
    # jako ćwiczenie dla czytelnika.
    

    Tak czy siak, źródła systemu tak długo żyjącego operacyjnego, nijak się nie mają do języków skryptowych (jak JS).

    Pragnę zwrócić uwagę, że nie ja przywołałem przykład goto.

    Przykładów, jakimi się chwaliłeś nie podałeś.

    Jakich przykładów?

    Like

  18. Owszem, również ja:

    Gratuluję. Ale przynajmniej uściśliłeś i już nie przypisujesz sobie całości kodu.

    Pragnę zwrócić uwagę, że nie ja przywołałem przykład goto.

    Znowu brak kontekstu. W skrócie, chodziło o przykład istniejącej konstrukcji języka, której jednak nie należy używać (by w ogóle nie zachęcać do jej używania, pomimo, iż jest prawidłową. Takie jest goto (w językach bardziej abstrakcyjnych niż asembler), takie jest undefined (w JS) – ma zastosowanie jedynie przy zmiennych spoza twojej wiedzy.

    Jakich przykładów?

    To musisz popatrzeć wyżej.

    Like

  19. Aż programować się odechciewa. Nie powinno się używać bo różni ludzie robią to źle i zdecydowanie za często (i podejrzewam, że we większość przypadków jedynym negatywnym efektem jest gorsza czytelność kodu), a później powstaje z tego religia. I ładnie ktoś podsumował zakaz używania goto – to bzdura, języki wysokiego poziomu są nafaszerowane goto pod różnymi postaciami, głupi break czy continue to praktycznie to samo i tak samo potrafi kopnąć w tyłek.

    Undefined w JS częściowo, wg moich kryteriów, też się łapie na taką bzdurę, a nawet paranoję (nie używaj, bo ktoś może nadpisać). Może zamiast nawoływać do nieużywania undefined warto było by zacząć nawoływać do nienadpisywania tej zmiennej i wykluczania z użycia kodu, który to robi. 😉

    Like

  20. Może zamiast nawoływać do nieużywania undefined warto było by zacząć nawoływać do nienadpisywania tej zmiennej i wykluczania z użycia kodu, który to robi. 😉

    Przecież to tylko cześć problemu.

    I ładnie ktoś podsumował zakaz używania goto – to bzdura, języki wysokiego poziomu są nafaszerowane goto pod różnymi postaciami,

    I dlatego ty z niego masz nie korzystać.

    Like

  21. I dlatego ty z niego masz nie korzystać.

    I w 99,99999% nie korzystam – przez 3 lata użyłem tej instrukcji dwa razy. Raz się opłacało, raz zrobiłem to źle ale nie było czasu żeby przerabiać kod na coś lepszego – każdy głupi potrafi coś pozmieniać, a testować nie ma komu. 😉

    Like

Comments are closed.