Dlaczego w JavaScript występuje wartość „null”?

116

W JavaScript istnieją dwie wartości, które zasadniczo mówią „nie istnieje” - undefinedi null.

Właściwość, do której programista niczego nie przypisał, będzie undefined, ale aby właściwość stała się null, nullmusi być do niej jawnie przypisana.

Kiedyś myślałem, że jest potrzeba, nullponieważ undefinedjest to prymitywna wartość i nullprzedmiot. Tak nie jest, nawet jeśli typeof nullda 'object': W rzeczywistości obie są wartościami pierwotnymi - co oznacza, że undefinedani ani nie nullmogą zostać zwrócone z funkcji konstruktora, ponieważ obie zostaną przekonwertowane na pusty obiekt (trzeba zgłosić błąd, aby ogłosić błąd w konstruktorach).

Oba oceniają również falsew kontekstach logicznych. Jedyną prawdziwą różnicą, o której przychodzi mi do głowy NaN, jest to, że jedna ocenia się , a druga 0w kontekstach numerycznych.

Dlaczego więc jest jedno undefinedi drugie i nulljeśli to tylko dezorientuje programistów, którzy nieprawidłowo sprawdzają null, czy właściwość została ustawiona, czy nie?

Chciałbym wiedzieć, czy ktoś ma rozsądny przykład, w którym konieczne jest użycie, nullktórego nie można wyrazić za pomocą undefinedzamiast tego.

Tak więc ogólny konsensus wydaje się być taki, że undefinedoznacza to „nie ma takiej własności”, podczas gdy nulloznacza „właściwość istnieje, ale nie ma wartości”.

Mógłbym z tym żyć, gdyby implementacje JavaScript faktycznie wymuszały takie zachowanie - ale undefinedjest to całkowicie poprawna wartość pierwotna, więc można ją łatwo przypisać do istniejących właściwości, aby złamać ten kontrakt. Dlatego jeśli chcesz się upewnić, czy właściwość istnieje, musisz użyć inoperatora lub hasOwnProperty()mimo wszystko. A więc jeszcze raz: jakie jest praktyczne zastosowanie oddzielnych wartości dla undefinedi null?

Właściwie używam, undefinedgdy chcę anulować wartości właściwości, które nie są już używane, ale których nie chcę delete. Powinienem użyć nullzamiast tego?

Christoph
źródło
3
Odpowiadając na ostatnie pytanie: Nie, nie powinieneś ustawiać właściwości na undefined.
Shog9
4
„undefined” to po prostu zmienna o zasięgu globalnym z wartością pierwotną „undefined”. Możliwe jest zdefiniowanie innej wartości zmiennej: {undefined = "Hello"; alert (undefined);} Bardziej niezawodny sposób testowania wartości undefined: {if (typeof myvar === "undefined") alert ("undefined")}
około
1
Zobacz sekcję 4.3.9 - 12 w ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf dla undefined / null i 15.1.1.3 dla zmiennej „undefined” w zakresie globalnym.
jakiś
1
Powinieneś albo usunąć obiekt, albo ustawić go na wartość null, jeśli ma to większy sens, ale nie na niezdefiniowaną.
jakiś
4
In JavaScript, there are two values which basically say 'I don't exist' - undefined and null.Nie, tylko to undefinedmówi.
Wyścigi lekkości na orbicie

Odpowiedzi:

78

Pytanie tak naprawdę nie brzmi „dlaczego w JS istnieje wartość zerowa” - w większości języków istnieje jakaś wartość zerowa i jest ona ogólnie uważana za bardzo użyteczną.

Pytanie brzmi: „dlaczego JS ma niezdefiniowaną wartość”. Główne miejsca, w których jest używany:

  1. kiedy deklarujesz, var x;ale nie przypisujesz do niego, xhold undefined;
  2. kiedy twoja funkcja otrzymuje mniej argumentów niż deklaruje;
  3. kiedy uzyskujesz dostęp do nieistniejącej właściwości obiektu.

nullz pewnością działałby równie dobrze dla (1) i (2) *. (3) powinien naprawdę od razu zgłosić wyjątek, a fakt, że tak się nie dzieje, zamiast undefinedzwrócić ten dziwny błąd , który później się nie powiedzie, jest dużym źródłem problemów z debugowaniem.

*: możesz również argumentować, że (2) powinno zgłosić wyjątek, ale wtedy musiałbyś zapewnić lepszy, bardziej wyraźny mechanizm dla argumentów domyślnych / zmiennych.

Jednak JavaScript początkowo nie miał wyjątków ani żadnego sposobu, aby zapytać obiekt, czy ma członka o określonej nazwie - jedynym sposobem było (i czasami nadal jest) uzyskanie dostępu do członka i zobaczenie, co otrzymujesz. Biorąc pod uwagę, że nullmiał już cel i możesz chcieć ustawić go jako członka, wymagana była inna wartość poza pasmem. Mamy więc undefinedproblem, jak zauważyłeś, i jest to kolejna świetna „funkcja” JavaScript, której nigdy nie będziemy w stanie się pozbyć.

W rzeczywistości używam undefined, gdy chcę usunąć wartości właściwości, które nie są już używane, ale których nie chcę usuwać. Czy powinienem zamiast tego użyć wartości null?

Tak. Zachowaj undefinedjako specjalną wartość do sygnalizowania, kiedy inne języki mogą zamiast tego zgłosić wyjątek.

nulljest ogólnie lepsze, z wyjątkiem niektórych interfejsów IE DOM, w których ustawienie czegoś nullmoże spowodować błąd. Często w tym przypadku ustawienie na pusty łańcuch zwykle działa.

bobince
źródło
10
Argumenty można rozszerzać. Możesz wrzucić tyle, ile chcesz, a funkcja może potencjalnie przejść przez iterację i wykorzystać je wszystkie. W dowolnym momencie obiektom można przypisać nową właściwość. Są to obie potężne funkcje, ale podejrzewam, że rzucanie wyjątków, tak jak wolisz, byłoby dużym obciążeniem. IMO, to jest warte kompromisu. Spędzam dużo mniej czasu na sprawdzaniu istnienia JS, niż zazwyczaj na castingach w bardziej rygorystycznych paradygmatach językowych.
Erik Reppen
Zabawne, że zaakceptowana odpowiedź na pytanie zaczyna się od „to naprawdę nie jest pytanie ...”
Phillip
@bobince czy wczesne wersje JS nie miały inoperatora lub hasOwnProperty? Ponieważ są o wiele bezpieczniejsze niż obj.hello !== undefinedsprawdzanie, czy właściwość istnieje na obiekcie.
Andy
Nieważne, odpowiedziałem na własne pytanie. Według MDN oba zostały wprowadzone w ES3.
Andy
37

Najlepiej opisane tutaj , ale podsumowując:

undefined to brak typu i wartości, a null to brak wartości.

Co więcej, jeśli robisz proste porównania „==”, masz rację, wychodzą one tak samo. Ale spróbuj ===, która porównuje zarówno typ, jak i wartość, a zauważysz różnicę.

Eddie Parker
źródło
1
Wiem to null !== undefined- moje pytanie brzmiało: dlaczego potrzebne są dwie rzeczy, które wyrażają tę samą koncepcję semantyczną; Twój link wspomina również, że „null to obiekt” - to źle, to prymityw ...
Christoph
2
To nie jest ta sama koncepcja semantyczna. Przynajmniej dla mnie istnieje znacząca różnica między właściwością, której przypisano wartość zerową, a właściwością nieistniejącą.
Daniel Schaffer,
Ale to po prostu to, to nie jest ta sama koncepcja semantyczna. Wartość null jest wymuszana, gdy używa się == do sugerowania tego samego, co jest wygodą dla programisty.
Eddie Parker
1
@EricElliott: typeofkłamstwa - przeczytaj specyfikację lub spróbuj wrócić nullod konstruktora
Christoph
5
@EricElliott: wartość zwracana przez konstruktorów nie ma nic wspólnego z fałszywością, ale z przedmiotowością: jeśli wartość zwracana jest obiektem, zwróć to; jeśli jest to prymityw, taki jak nulllub 42, odrzuć zwracaną wartość i zamiast tego zwróć nowo utworzony obiekt
Christoph
17

Myślę, że nie ma powodu, aby mieć jedno nulli drugie, a undefinedponieważ jedyny powód, dla którego wiele osób sugeruje („ undefinedoznacza, że ​​nie ma takiej zmiennej / właściwości”), jest nieprawidłowy, przynajmniej w JavaScript. undefinednie mogę powiedzieć, czy zmienna / właściwość istnieje, czy nie.

console.log(foo);               // "ReferenceError: foo is not defined"
                                // foo does not exist
var foo;
console.log(foo);               // "undefined", a different response
console.log(foo === undefined); // "true", but it does exist

var obj = {};
console.log(obj.hasOwnProperty("foo")); // "false", no such property
obj.foo = undefined;
console.log(obj.hasOwnProperty("foo")); // "true", it exists and has the value "undefined"
console.log(obj.foo === undefined);     // "true", but it does exist

obj.bar = "delete me";
obj.bar = undefined;
console.log(obj.hasOwnProperty("bar")); // "true", not actually deleted
delete obj.bar;
console.log(obj.hasOwnProperty("bar")); // "false", deleted

Jak widać, sprawdzenie foo === undefinednie mówi, czy fooistnieje, a ustawienie w obj.bar = undefinedrzeczywistości nie usuwa bar.

Być może pierwotna intencja autora JavaScript undefinedpowinna przedstawiać „nieistnienie”. Jednak wdrożenie nie potoczyło się w ten sposób.

Lei Zhao
źródło
1
Wymień undefinedsię nullw twoich powyższych przykładów kodu, a odpowiedzi są takie same. Nie jestem pewien, jak to odpowiada na pytanie. Czy miał to być komentarz do cudzej odpowiedzi?
Eric Elliott
1
@EricElliott Moja odpowiedź na to pytanie jest taka, że ​​nie ma powodu, aby mieć jedno nulli drugie, a undefinedponieważ jedyny powód, który sugeruje wiele osób, jest nieważny.
Lei Zhao
Powinieneś zmienić swoją odpowiedź i faktycznie to powiedzieć. Mogłabym zagłosować za, gdybyś udzielił takiej odpowiedzi. =)
Eric Elliott
@EricElliott Myślę, że masz rację. Zmieniłem odpowiedź. Dzięki!
Lei Zhao
3
Ten przykład faktycznie pokazuje, że jeśli nie przypisałeś zmiennej, ona zwraca undefined. Ale jeśli przypisałeś undefineddo niego, to tak naprawdę nie jest undefined- został zdefiniowany undefinedi ma do niego odniesienie. Jedyną różnicą między undefinedi nulljest ich użycie i historyczny cel. Obie są atomowe.
Aleksej Komarov
6

Jest całkowicie możliwe, że potrzebujesz obu. Na przykład, jeśli odpytujesz WMI, jest całkowicie możliwe, aby klasa zwracała właściwości, które mają wartość null. Są zdefiniowane, po prostu akurat w tym czasie trzymają wartość zerową.

EBGreen
źródło
6

Myślę, że twój wniosek, że JavaScript definiuje undefinedjako „nie ma takiej właściwości” i nulljako „właściwość nie ma wartości”, jest całkowicie poprawny. W języku tak dynamicznym jak JavaScript jest to bardzo ważne rozróżnienie. Stosowanie kaczych znaków oznacza, że ​​musimy być w stanie odróżnić nieruchomość nieistniejącą od niemającej wartości. Jest to nasz podstawowy sposób uzyskiwania informacji o typie. w języku z typami statycznymi istnieje wyraźne rozróżnienie między polem, które jest puste, a polem nieistniejącym. W JavaScript nie jest inaczej. Jednak jest on sprawdzany w czasie wykonywania i może być modyfikowany do tego czasu.

Muszę się zgodzić, że implementacja jest dziwna, ponieważ bardzo często rozróżnienie jest rozmyte. Myślę jednak, że w JavaScript to rozróżnienie jest ważne. A umiejętność przypisywania undefinedjest niezbędna.

Pamiętam, jak jakiś czas temu przeczytałem wpis na blogu o grze RPG online napisanej w JavaScript. Wykorzystał przykłady, w których obiekty były tworzone jako kopie istniejących instancji, a nie jako prototypy (klasy, funkcje, cokolwiek), a następnie były modyfikowane. To naprawdę sprawiło, że zrozumiałem, jak potężne undefinedmoże to być podczas modyfikowania istniejących obiektów, ale nie pamiętam, kto to napisał.

Jack Ryan
źródło
Czy mógłbyś podzielić się tą grą RPG?
Michael
3

Semantycznie oznaczają różne rzeczy. Typ null ma dokładnie jedną wartość w swojej domenie, null, a właściwość może mieć przypisaną tę konkretną wartość. Niezdefiniowany oznacza wyraźny brak przypisania jakiejkolwiek wartości.

AnthonyWJones
źródło
1
ale możesz użyć undefineddobrze, aby przypisać do właściwości, więc ten kontrakt (zwrot tylko undfinedjeśli nie ma takiej właściwości) może łatwo zostać złamany przez programistę ...
Christoph,
2
Państwo może , ale z całą pewnością nie należy. Niezdefiniowany jest używany jako bardzo podstawowa / uproszczona forma wyjątku w JavaScript - nie używaj go jako wartości i przypisz go do jakiejś właściwości! To szalony człowiek.
rfunduk
3

Jako programista Java widzę ogromną różnicę między undefined a null. Kodowanie JavaScript, nie tak bardzo, ponieważ JavaScript nie jest silnie typowany, a różnice między undefined i null są zatarte przez automatyczne konwersje, które są często wykonywane przez środowisko wykonawcze. Przy okazji, często korzystam z tych konwersji; sprawiają, że mój kod JS jest bardziej zwarty i czytelny.

Odpowiadając na twoje pytanie, wartość undefined oznacza, że ​​wartość nigdy nie została ustawiona. Praktycznie rzecz biorąc, zazwyczaj wskazuje to na błąd. Jeśli obiekt yourObject.property jest niezdefiniowany, oznacza to, że z jakiegoś powodu nie ustawiłeś właściwości lub szukam czegoś, co w ogóle nie istnieje. Jest to prawdziwy problem podczas pracy nad projektem z więcej niż jednym koderem.

null oznacza, że ​​jawnie nie ustawiono żadnej wartości. Mówiąc praktycznie, mówisz mi coś o nieruchomości, być może, że nie jest ona używana w tym kontekście lub że wartość nie została jeszcze określona.

W Javie próby uzyskania dostępu do niezdefiniowanego pola zawsze kończą się wyjątkiem. W rzeczywistości kompilator może ostrzegać o tym w kodzie.

Steve11235
źródło
0

Wypróbuj ten przykład:

<html>
<head>
    <script type="text/javascript">
        function ShowObjProperties(obj) {
            var property, propCollection = "";

            for(property in obj) {
                propCollection += (property + ": " + obj[property] + "\n");
            }

            alert(propCollection);
        }

        var obj = {
            userid: 3,
            name: 'me!',
            speak: function() { alert('Hi! My name is ' + this.name + ' and my ID is ' + this.userid + '.'); }
        }

        //Shows all properties
        ShowObjProperties(obj);

        //The Speak function is no longer in the list!
        delete obj.speak;
        alert(typeof obj.speak);
        ShowObjProperties(obj);

        //The UserID is still listed, it just has no value!
        obj.userid = null;
        ShowObjProperties(obj);
    </script>
</head>
<body>

</body>
</html>

Myślę, że istnieje tutaj bardzo realne zastosowanie dla 2 różnych typów.

EndangeredMassa
źródło
Myślę, że w prototypach element członkowski jest pusty lub po prostu niezdefiniowany.
Kev
ale to działa tylko tak długo, jak długo nikt nie będzie próbował go złamać - jeśli ustawię obj.userid = undefined, to się nie powiedzie - zobacz ostatnią edycję mojego pytania
Christoph
0

Sprowadza się to do dynamicznej natury skryptów JavaScript.

Rzeczy mogą być niezdefiniowane, aby można je było dodać później. Prawdopodobnie dlatego javascript jest tak potężny i rozszerzalny.

Rob Stevenson-Leggett
źródło
i to jest istotne dla mojego pytania w jaki sposób?
Christoph,
2
Jest to istotne, ponieważ odpowiada na Twoje pytanie. „null” jest „singletonem”, co oznacza „nie ma wartości”. „nieokreślony” mówi ci, że coś jest… szokujące, wiem… nieokreślone. To zupełnie inne rzeczy.
rfunduk
0

jest to ważna funkcja języka, jeśli opuścisz swój program wokół zdarzeniowego paradygmatu javascript.

// a key exists as a placeholder for something
if(obj[name] === null) 
// no key exists int eh hashtable that is in this object
if(obj[name] === undefined)

jest to bardzo przydatne, jeśli masz do czynienia z zestawem danych, które wymagają wartości reprezentującej „nic”, aby wskazać jakąś akcję inną niż użycie „nic” do wskazania akcji domyślnej.

filter_func_pt = {
  date:function(d){ return Math.round(d.getTime()/1000);},
  user: null,
}

function transform(obj){
    var ret = {};
    for( var prop in obj){
       var f = filter_func_pt[prop];
       if(f)
          ret[prop] = f(obj);
       else if(filter_func_pt[prop] === null)
         continue;
       else
         ret[prop] == obj;
    }
  return ret;
}

var a = {
   date: new Date(),
   user: 'sam'
   votes: [23, 41, 55] 
};

var b = transform(a);

/* b = {
 *    date: 1298582417
 *    votes: [23, 41, 55]
 * }
 */

w powyższym kodzie słowo kluczowe null i niezdefiniowany serwer są bardzo jasne i mają różne cele. wyszukiwanie, które nie zostało znalezione w obiekcie filter_func_pt, które zwraca nieokreśloną wartość, oznacza dodanie właściwości do zwracanego obiektu w takiej postaci, w jakiej jest, podczas gdy wartość null wskazuje, że wartość powinna zostać wstrzymana, a nie dodana, oraz obecność jakiejkolwiek prawdziwej wartości w tym case reprezentuje funkcję używaną do przekształcenia wartości przed dodaniem jej do obiektu ret .

Fire Crow
źródło
Ten przykład jest wymyślony i trochę bezsensowny. Null w ogóle nie wyjaśnia twojego zamiaru - raczej go maskuje. Mogłeś użyć bardziej wyraźnego ciągu, aby wyjaśnić znaczenie. Na przykład „wstrzymaj” lub „usuń”, a wtedy możesz również uzyskać bardziej szczegółowe informacje o typie funkcji i faktycznie sprawdzić, czy funkcja istnieje.
Eric Elliott
0

null jest piękne

podobnie jak wszystkie inne typy skryptów na żywo.

cite: W JavaScript istnieją dwie wartości, które zasadniczo mówią „nie istnieje” - undefined i null.

Dlaczego chcesz mówić niepoprawne rzeczy ?!

„null” to „pusty obiekt”, tak jak „0” jest „pustą liczbą . 0, nie jest niczym - jednak istnieje jako rzecz Type of a Number. null jest oczywiście również puste, ale „jest” i jest to dobrze zdefiniowana rzecz typu obiektu .

Często mówi się o tych rzeczach jako o „typach”, gdy tak nie jest. W rzeczywistości są to „kategorie”. Ale to już koniec.

Więc trzymam się tego, aby powiedzieć, że „null” jest Typem Obiektu bez Rodzaju. A „null” mówi: „Bardzo istnieję [!], Ale nie mam treści tego rodzaju”.

Podczas gdy undefined nie ma zarówno typu, jak i rodzaju, podczas gdy undefined jest również jego definicją typu. Nieokreślony typ typu staje się jego charakterystyczną typologią. Coś w rodzaju pytania [czy „nic” nie istnieje i jak definiujesz „nic”?].

cite: undefined ani null mogą zostać zwrócone z funkcji konstruktora, ponieważ obie będą konwertowane na pusty obiekt

Po raz kolejny udało ci się powiedzieć niewłaściwą rzecz. Oczywiście, że nie, „nieokreślony” nie jest przedmiotem, to zwykły Token, który my, ludzie, rozumiemy; ale w przeciwieństwie do tego null jest - i to ci mówi: jego typ jest poprawny, ale rodzaj, którego szukasz, nie jest w nim zawarty, a przynajmniej nie jest w tej chwili. Odwiedź nas później, gdy umieścimy w nim \ przypisany obiekt \.

cite: Jedyną prawdziwą różnicą, o której przychodzi mi do głowy, jest to, że jedna zwraca się na NaN, a druga na 0 w kontekstach numerycznych.

To właśnie stanowi sedno ich podstawowego rozróżnienia, jak wspomniano: undefined to zwykły symbol, a ponieważ składa się z tego samego „materiału genetycznego”, co jego odlegli krewniacy: łańcuchy, operacja [+ undefined] spowoduje jego zamianę na NaN, podobnie null oczywiście przekształci się w prawidłowy rodzaj 0 \ Number, aw przeciwieństwie do undefined , który przekształci się w łańcuch (! Który nie jest pusty!) I właśnie dlatego zwraca zamiast tego NaN . Gdzie: + undefined >> + "undefined" >> NaN. Ponieważ kontekst numeryczny oczekuje jawnej wartości.

Podczas gdy kontekst boolowski oczekuje odniesienia - nie znajduje niczego do konwersji i zwraca „fałsz”.

Przejdźmy teraz ...

cite: Więc jeszcze raz: jakie jest praktyczne zastosowanie oddzielnych wartości dla undefined i null?

Spróbuję podać tylko dwa przykłady empiryczne i mam nadzieję, że wystarczą

oElement.onclick >> null

// oznacza - własność istnieje; jego oczekiwana wartość to Type: Object , a ten oElement obsługuje zdarzenie „onclick”!

oElement.innerText >> ""

// oznacza - własność istnieje; jego oczekiwana wartość to Type: String , co oznacza, że ​​oElement obsługuje właściwość „innerText”.

w obu przypadkach - jeśli otrzymasz „undefined”, oznacza to, że właściwość nie istnieje; nie jest obsługiwany lub ma nieprawidłową implementację (dostawca UA).

Trzymaj się mrozu i baw się dobrze.

Bill the Lizard
źródło
Nie niszcz swoich postów, aeneas. Usuń je (za pomocą przycisku Usuń tuż nad tym komentarzem), jeśli chcesz usunąć swój wkład.
Michael Petrotta
nie ma przycisku usuwania - ale jeśli go widzisz - kliknij go!
0

po przeczytaniu niesamowitej dyskusji dotyczącej undefined vs null, małe wyszukiwanie w Google zaprowadziło mnie do Dokumentacji Mozilli https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null, o czym wspomina się - null jest często pobierane w miejscu, w którym można się spodziewać obiektu, ale żaden obiekt nie jest istotny.

Nie jest podobny do wzorca obiektu o wartości Null https://en.wikipedia.org/wiki/Null_object_pattern

Więc myślę, że ma to sens, aby mieć typ danych Null.

Dokumentacja wymieniona również jako typeof null // "object" (nie "null" z powodów starszych)

Nie wiem, jakie są starsze powody

Vishal Bhandare
źródło