Jaki jest powód, aby używać wartości null zamiast undefined w JavaScript?

103

Pisałem JavaScript już od dłuższego czasu i nigdy nie miałem powodu, aby go używać null. Wydaje się, że undefinedjest to zawsze lepsze i programowo służy temu samemu celowi. Jakie są praktyczne powody, aby używać nullzamiast undefined?

Jimmy Cuadra
źródło
To jest możliwy duplikat stackoverflow.com/questions/461966/ ...
lawnsea
Cóż, są metody, document.getElementById()które mogą zwracać, nullale nie undefined, więc w takich przypadkach dlaczego miałbyś testować zwrot undefined? (Jasne, zadziałałoby, gdybyś użył ==zamiast ===, ale nadal, dlaczego celowo miałbyś testować pod kątem niewłaściwej rzeczy?)
nnnnnn
Przydatne może być posiadanie przewidywalnych typów, co może pomóc w myśleniu o używaniu jednego lub drugiego. Tam, gdzie obiekt jest zawsze zwracany, potrzebny lub pożądany przez projekt, użyj wartości null dla fałszywych wyników (np document.getElementById('does-not-exist').). Zmienne var a;i funkcje zwracają wartości domyślnie niezdefiniowane. W przeszłości wartość null znajdowała się w zasięgu globalnym, więc użycie go spowolniło wykonywanie i skłoniło mnie do preferowania innych fałszywych typów (fałsz, „, 0)” zamiast swobodnych odwołań. Osobiście unikam null, chyba że istnieje ważny powód, który jest inny, ponieważ uważam, że jest to prostsze, co generalnie jest lepsze.
Jimmont

Odpowiedzi:

60

Null i undefined to zasadniczo dwie różne wartości, które oznaczają to samo. Jedyną różnicą są konwencje, w jakich używasz ich w swoim systemie. Jak niektórzy wspomnieli, niektórzy ludzie używają null w znaczeniu „brak obiektu”, gdzie czasami możesz otrzymać obiekt, podczas gdy undefined oznacza, że ​​nie oczekiwano żadnego obiektu (lub że wystąpił błąd). Mój problem z tym polega na tym, że jest to całkowicie arbitralne i zupełnie niepotrzebne.

To powiedziawszy, jest jedna zasadnicza różnica - zmienne, które nie zostały zainicjowane (w tym między innymi parametry funkcji, dla których nie przekazano żadnego argumentu) są zawsze niezdefiniowane.

Dlatego w moim kodzie nigdy nie używam wartości null, chyba że coś, czego nie kontroluję, zwróci wartość null (na przykład dopasowanie wyrażeń regularnych). Piękno tego polega na tym, że bardzo upraszcza to. Nigdy nie muszę sprawdzać, czy x === undefined || x === null. A jeśli masz zwyczaj używania == lub po prostu rzeczy takich jak if (x) .... Przestań. !xzwróci wartość true dla pustego łańcucha, 0, null, NaN - czyli rzeczy, których prawdopodobnie nie chcesz. Jeśli chcesz napisać javascript, który nie jest okropny, zawsze używaj potrójnego równa się === i nigdy nie używaj null (zamiast tego użyj undefined). To znacznie ułatwi ci życie.

BT
źródło
138
Nie zgadzam się z tym. Null służy do definiowania czegoś programowo pustego. Niezdefiniowane oznacza, że ​​odniesienie nie istnieje. Wartość null ma zdefiniowane odniesienie do „nic”. Jeśli wywołujesz nieistniejącą właściwość obiektu, otrzymasz undefined. Jeśli miałbym uczynić tę właściwość celowo pustą, to musi być zerowa, abyś wiedział, że jest celowo. Wiele bibliotek javascript działa w ten sposób.
com2ghz
6
@ com2ghz To, co opisujesz, jest jedną z wielu filozofii. Wiele bibliotek js rzeczywiście działa w ten sposób. Wiele też nie działa w ten sposób. W javascript możesz równie łatwo przechowywać jawną niezdefiniowaną wartość w obiekcie lub tablicy, jak w przypadku null. Znaczenie obu jest całkowicie i całkowicie zależne od kontekstu. IE mają na myśli to, co chcesz, aby oznaczały.
BT,
3
Dlatego JS jest okropnym językiem. Jak mówisz, wiele bibliotek ma własne filozofie, ale dołączasz wiele bibliotek do 1 projektu. Więc spotykasz się z wieloma konwencjami tych bibliotek. Ile razy musisz dokonywać różnych fałszywych kontroli. Nie byłby to ostatni raz, kiedy łączysz obiekt zerowy z łańcuchem i otrzymujesz „null” jako łańcuch. Albo przekazanie 0 jako wartości liczbowej i zastanawianie się, dlaczego instrukcja IF traktuje t jako fałsz.
com2ghz
2
@ com2ghz Więc JS jest okropnym językiem, ponieważ ma zarówno wartość null, jak i undefined? Potrafię policzyć dziesiątki złych decyzji językowych we wszystkich głównych językach, js nie jest tu wyjątkiem. Dosłownie nigdy nie potrzebuję lub nie chcę używać fałszywych kontroli w moim kodzie i zawsze używam ===lub !==. JS to fantastycznie wyrazisty język, jeśli wiesz, jak go używać.
BT,
6
Dobrze. Właśnie dowiedziałem się, że dychotomia null/ undefinedbyła konieczna, ponieważ pierwotna wersja JS nie miała hasOwnPropertyani inoperatora. Teraz, kiedy tak jest, nie bardzo rozumiem, dlaczego jedna z nich nie została zniesiona w ES6 ani w żadnej z propozycji ES7, które widziałem.
Andy
86

Naprawdę nie mam odpowiedzi, ale według Nicholasa C. Zakasa na stronie 30 jego książki Professional JavaScript for Web Developers :

Podczas definiowania zmiennej, która ma później przechowywać obiekt, zaleca się zainicjowanie zmiennej nullw przeciwieństwie do czegokolwiek innego. W ten sposób można jawnie sprawdzić wartość, nullaby określić, czy zmienna została później wypełniona odwołaniem do obiektu

bbg
źródło
8
+1 tak, zgadzam się i zawsze staram się pamiętać o inicjalizacji vars na zero. Wtedy jestem (całkiem) pewien, że undefinedoznacza to katastrofę. Po prostu imho.
Pete Wilson,
9
@Pete - ale nic nie mówi o „katastrofie”, więc po co? I możesz to założyć tylko wtedy, gdy wiesz, że funkcja jest zgodna z konwencją.
RobG,
7
Z drugiej strony można również zainicjować zmienną za pomocą var myVar;i jawnie sprawdzić wartość, undefinedaby określić, czy została później wypełniona odwołaniem do obiektu. Chodzi mi o to, że jest to całkowicie akademickie - możesz to zrobić w dowolny sposób, a każdy, kto doradza jedną, a nie drugą, po prostu forsuje własną konwencję.
thdoan
1
Jedyny problem, jaki mam (odkąd zacząłem korzystać z JavaScript 15 lat temu), to to, że zbyt często musisz testować undefinedi null. To wciąż jest naprawdę irytujące. Unikam przypisywania zmiennej nulltylko po to, aby zmniejszyć liczbę dodatkowych nulltestów.
G Man
4
@GMan - jest to jedyne miejsce, w którym ==porównanie (w przeciwieństwie do ===) ma sens: v == null(lub v == undefined) sprawdzi, czy nie ma wartości null lub undefined.
Rick Love
15

Na koniec dnia, ponieważ oba nulli undefinedzmuszają do tej samej wartości ( Boolean(undefined) === false && Boolean(null) === false), możesz technicznie użyć dowolnego, aby wykonać zadanie. Jest jednak właściwy sposób, IMO.

  1. Pozostaw użycie undefinedkompilatora JavaScript.

    undefinedsłuży do opisywania zmiennych, które nie wskazują na odniesienie. Jest to coś, czym zajmie się za Ciebie kompilator JS. W czasie kompilacji silnik JS ustawi wartość wszystkich podniesionych zmiennych naundefined . Gdy silnik przechodzi przez kod i wartości stają się dostępne, silnik przypisze odpowiednie wartości do odpowiednich zmiennych. W przypadku tych zmiennych, dla których nie znalazł wartości, zmienne nadal zachowywały odniesienie do prymitywu undefined.

  2. Używaj wartości null tylko wtedy, gdy jawnie chcesz oznaczyć wartość zmiennej jako „bez wartości”.

    Jak stwierdza @ com2gz: nullsłuży do definiowania czegoś programowo pustego. undefinedoznacza, że ​​odniesienie nie istnieje. nullWartość ma zdefiniowaną odniesienie do „niczego”. Jeśli wywołujesz nieistniejącą właściwość obiektu, otrzymasz undefined. Jeśli miałbym uczynić tę nieruchomość celowo pustą, to musi być nulltak, abyś wiedział, że jest celowo.

TLDR; Nie używaj undefinedprymitywów. Jest to wartość, którą kompilator JS automatycznie ustawi za Ciebie, gdy deklarujesz zmienne bez przypisania lub próbujesz uzyskać dostęp do właściwości obiektów, do których nie ma odniesienia. Z drugiej strony, użyj nullwtedy i tylko wtedy, gdy celowo chcesz, aby zmienna nie miała „wartości”.

Nigdy wyraźnie nie ustawiłem niczego na niezdefiniowane (i nie spotkałem się z tym w wielu bazach kodu, z którymi miałem kontakt). Rzadko używam null. Używam tylko nullsytuacji, gdy chcę oznaczyć wartość argumentu funkcji jako pozbawioną wartości, tj .:

function printArguments(a,b) {
  console.log(a,b);
}

printArguments(null, " hello") // logs: null hello
Govind Rai
źródło
To powinna być wybrana odpowiedź
alaboudi
13

nieokreślone jest wtedy, gdy nie istnieje żadne pojęcie rzeczy; nie ma typu i nigdy wcześniej nie było do niego odwołań w tym zakresie; null jest tam, gdzie wiadomo, że istnieje, ale nie ma wartości.

Yaplex
źródło
4
Skąd wiadomo, że podjęto próbę przypisania wartości, ale nie powiodła się i zamiast tego przypisano wartość undefined ?
RobG,
11

Każdy ma swój własny sposób kodowania i własną wewnętrzną semantykę, ale przez lata odkryłem, że jest to najbardziej intuicyjna rada, której udzielam osobom zadającym to pytanie: w razie wątpliwości rób to, co robi JavaScript .

Powiedzmy, że pracujesz z właściwościami obiektu, takimi jak opcje wtyczki jQuery ... zadaj sobie pytanie, jaką wartość JavaScript daje właściwość, która nie została jeszcze zdefiniowana - odpowiedź brzmi undefined. Dlatego w tym kontekście zainicjowałbym te typy rzeczy wartością „undefined”, aby była zgodna z JavaScriptem (w przypadku zmiennych możesz zrobić var myVar;zamiastvar myVar = undefined; ).

Powiedzmy teraz, że robisz manipulację DOM ... jaką wartość przypisuje JavaScript nieistniejącym elementom? Odpowiedź tonull . Jest to wartość, którą zainicjowałbym, jeśli tworzysz zmienną zastępczą, która później będzie zawierała odniesienie do elementu, fragmentu dokumentu lub czegoś podobnego, który odnosi się do DOM.

Jeśli pracujesz z JSON, musisz zrobić specjalny przypadek: dla niezdefiniowanych wartości właściwości powinieneś ustawić je na ""lub nullponieważ wartośćundefined nie jest uważana za właściwy format JSON.

Mając to na uwadze, jak wyraził poprzedni plakat, jeśli okaże się, że inicjujesz rzeczy z nulllub undefinedwięcej niż raz na niebieskim księżycu, może powinieneś ponownie rozważyć, jak zabrać się za kodowanie aplikacji.

thdoan
źródło
Chociaż jest to dobre stanowisko, chciałbym dodać tę odpowiedź: stackoverflow.com/a/37980662/883303
Frederik Krautwald
@FrederikKrautwald dzięki za link - to jest bardzo jasne określenie.
thdoan
10

Możesz przyjąć sugerowaną tutaj konwencję, ale tak naprawdę nie ma ku temu dobrego powodu. Nie jest używany wystarczająco konsekwentnie, aby mieć znaczenie.

Aby konwencja była użyteczna, najpierw musisz wiedzieć, że wywoływana funkcja jest zgodna z konwencją. Następnie musisz jawnie przetestować zwracaną wartość i zdecydować, co zrobić. Jeśli otrzymujesz undefined , możesz założyć, że wystąpił jakiś błąd , o którym wiedziała wywoływana funkcja . Ale jeśli wystąpił błąd, a funkcja wiedziała o tym, i warto wysłać to w szersze środowisko, dlaczego nie użyć obiektu błędu? czyli wyrzucić błąd?

Ostatecznie więc konwencja jest praktycznie bezużyteczna w niczym innym niż w bardzo małych programach w prostych środowiskach.

RobG
źródło
3

Przydatna właściwość o wartości null, która nie została zdefiniowana :

> null + 3
3
> undefined + 3
NaN

Używam, nullgdy chcę „wyłączyć” wartość numeryczną lub zainicjować jakąś. Moim ostatnim użyciem było manipulowanie transformacją CSS:

const transforms = { perspective : null, rotateX : null };
// if already set, increase, if not, set to x
runTimeFunction((x) => { trasforms.perspective += x; });
// still useful, as setting perspective to 0 is different than turning it off
runTimeFunction2((x) => { transforms.perspective = null; });

// toCss will check for 'null' values and not set then at all
runTimeFunction3(() => { el.style.transform = toCss(transforms); });

Nie jestem pewien, czy powinienem skorzystać z tej właściwości ...

Faccion
źródło
2

Węzły i elementy DOM nie są niezdefiniowane, ale mogą mieć wartość NULL.

  • NextSibling ostatniego elementu podrzędnego elementu ma wartość null.

  • Poprzedni element potomny pierwszego dziecka jest zerowy.

  • Odniesienie document.getElementById ma wartość null, jeśli element nie istnieje w dokumencie.

Ale w żadnym z tych przypadków wartość nie jest niezdefiniowana ; po prostu nie ma tam węzła.

kennebec
źródło
Dziękuję za wyjaśnienie. Dla mnie to nie mogło być bardziej sprzeczne z intuicją.
tomekwi
To naprawdę zależy od tego, co próbujesz sprawdzić. Na przykład, jeśli chcesz sprawdzić, czy istnieje zmienna globalna o nazwie „myVar”, window.myVarzwróci „undefined”, jeśli nie istnieje. W JavaScript jest mnóstwo rzeczy, które zwracają „undefined”, ale jest mnóstwo rzeczy, które zwracają „null” - wszystko zależy od kontekstu.
thdoan
2

Kilku powiedziało, że inicjalizacja obiektów w programie jest w porządku null. Chciałem tylko zaznaczyć, że destrukturyzacja domyślnych argumentów nie działa null. Na przykład:

const test = ({ name } = {}) => {
  console.log(name)
}

test() // logs undefined
test(null) // throws error

Wymaga to nullsprawdzenia przed wywołaniem funkcji, co może się często zdarzać.

Matt Way
źródło
1

Właśnie teraz pracuję nad tym pytaniem i przyglądam się następującej filozofii:

  1. Każda funkcja, która ma zwrócić wynik, powinna zwrócić wartość null, jeśli nie uda jej się znaleźć wyniku
  2. Każda funkcja, która NIE jest przeznaczona do zwracania wyniku niejawnie, zwraca wartość undefined.

Dla mnie to pytanie jest znaczące, ponieważ każdy, kto wywołuje funkcję zwracającą wynik, nie powinien mieć pytania, czy testować pod kątem wartości undefined czy null.

Ta odpowiedź nie dotyczy:

  1. Wartości właściwości równe null vs undefined
  2. Zmienne w funkcjach są puste a niezdefiniowane

Moim zdaniem zmienne są Twoją własną firmą i nie są częścią Twojego API, a właściwości w każdym systemie OO są zdefiniowane i dlatego powinny być zdefiniowane z wartością inną niż byłyby, gdyby nie zostały zdefiniowane (null dla zdefiniowanego, niezdefiniowane to uzyskać podczas uzyskiwania dostępu do czegoś, czego nie ma w obiekcie).

Michael
źródło
1

Oto powód: var undefined = 1 jest to legalny skrypt javascript, ale var null = 1jest to błąd składniowy. Różnica polega na tym, że nulljest to słowo kluczowe języka, a undefinedz jakiegoś powodu nie.

Jeśli twój kod opiera się na porównaniach, undefinedtak jakby to było słowo kluczowe ( if (foo == undefined)- bardzo łatwy błąd), działa to tylko dlatego, że nikt nie zdefiniował zmiennej o takiej nazwie. Cały ten kod jest narażony na przypadkowe lub złośliwe zdefiniowanie zmiennej globalnej o tej nazwie. Oczywiście wszyscy wiemy, że przypadkowe zdefiniowanie zmiennej globalnej jest całkowicie niemożliwe w javascript ...

Joel Mueller
źródło
1
Użyj void 0zamiast undefined.
Frederik Krautwald
1

Chcę tylko dodać, że przy użyciu niektórych bibliotek javascript, null i undefined mogą mieć niezamierzone konsekwencje.

Na przykład getfunkcja lodash , która przyjmuje wartość domyślną jako trzeci argument:

const user = {
  address: {
    block: null,
    unit: undefined,
  }
}
console.log(_.get(user, 'address.block', 'Default Value')) // prints null
console.log(_.get(user, 'address.unit', 'Default Value')) // prints 'Default Value'
console.log(_.get(user, 'address.postalCode', 'Default Value')) // prints 'Default Value'

Inny przykład: jeśli używasz defaultProps w Reakcie, jeśli właściwość jest przekazywana null, domyślne właściwości nie są używane, ponieważ null jest interpretowane jako zdefiniowana wartość . na przykład

class MyComponent extends React.Component {
   static defaultProps = {
      callback: () => {console.log('COMPONENT MOUNTED')},
   }
   componentDidMount() {
      this.props.callback();
   }
}
//in some other component
<MyComponent />   // Console WILL print "COMPONENT MOUNTED"
<MyComponent callback={null}/>   // Console will NOT print "COMPONENT MOUNTED"
<MyComponent callback={undefined}/>   // Console WILL print "COMPONENT MOUNTED"
lilbitofchee
źródło
0

Zupełnie nie zgadzam się, że użycie wartości null lub undefined jest niepotrzebne. undefined to rzecz, która podtrzymuje cały proces łączenia prototypów. Zatem kompilator tylko z wartością null nie może sprawdzić, czy ta właściwość jest równa null, czy też nie jest zdefiniowana w prototypie punktu końcowego. W innych językach z typami dynamicznymi (np. Python) rzuca wyjątek, jeśli chcesz uzyskać dostęp do niezdefiniowanej właściwości, ale w przypadku języków opartych na prototypach kompilator powinien również sprawdzić prototypy nadrzędne i tutaj jest miejsce, w którym niezdefiniowane najbardziej potrzebują.

Całe znaczenie używania wartości null polega po prostu na powiązaniu zmiennej lub właściwości z obiektem, który jest singletonem i ma znaczenie pustki, a także użycie wartości null ma na celu wydajność. Ten kod 2 ma różny czas wykonania.

var p1 = function(){this.value = 1};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p1();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p;
});
big_array.reduce((sum, p)=> sum + p.value, 0)

var p2 = function(){this.value = 1, p.x = null};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p2();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p; 
});
big_array.reduce((sum, p)=> sum + p.value, 0)
VahagnNikoghosian
źródło
undefinednie ma specjalnego znaczenia dla dziedziczenia prototypów. Właściwość ustawiona na undefinednadal przesłoni właściwość (o tej samej nazwie) odziedziczoną z prototypu.
Matthijs
0

Nieznana zmienna: undefined .

Jeszcze nie wiadomo zmienna wartość: null.

  1. Otrzymujesz obiekt z serwera, server_object .
  2. Ty się odwołujesz server_object.errj. Mówi ci, że toundefined . To znaczy, że nie wie, co to jest.
  3. Teraz odwołujesz się server_object.err. Mówi ci, że to null. Oznacza to, że odwołujesz się do poprawnej zmiennej, ale jest ona pusta; dlatego nie ma błędu.

Problem polega na tym, że deklarujesz nazwę zmiennej bez wartości ( var hello) js deklaruje, że jako undefined: ta zmienna nie istnieje; podczas gdy programiści mają na myśli głównie: „Nie nadałem mu jeszcze wartości”, definicjanull .

Zatem domyślne zachowanie programisty - deklarowanie zmiennej bez wartości jako nic - jest sprzeczne z js - deklarowanie jej jako nieistniejącej. A poza tym, !undefinedi !nulloba są, truewięc większość programistów traktuje je jako równoważne.

Możesz oczywiście upewnić się, że zawsze to robisz, var hello = nullale większość z nich nie zaśmieci swojego kodu jako takiego, aby zapewnić poprawność typu w umyślnie luźnym języku, gdy oni i !operator traktują oba undefinedi nulljako równoważne.

newfivefour
źródło