Czy lepiej jest zwrócić „undefined” lub „null” z funkcji javascript?

102

Mam funkcję, którą napisałem, która w zasadzie wygląda tak:

function getNextCard(searchTerms) {
  // Setup Some Variables

  // Do a bunch of logic to pick the next card based on termed passed through what I'll call here as 'searchTerms' all of this logic is omitted because it's not important for my question.
  // ...

  // If we find a next card to give, than give it
  if (nextCardFound)
    return nextCardFound;

  // Otherwise - I'm returning undefined
  return undefined;
}

Pytanie: Czy lepiej byłoby zwrócić tutaj „null”?

Mogę oddać cokolwiek zechcę - oczywiście ... Po prostu nie byłam pewna, co najlepiej użyć.

Kod, który wywołuje tę funkcję, wie, jak radzić sobie z undefined (tak naprawdę nigdy się nie wydarzy, chyba że coś pójdzie nie tak)

Powodem, dla którego zadaję to pytanie, jest to, że gdzieś usłyszałem coś, co brzmiało jak „Nie przypisuj wartości niezdefiniowanej do zmiennych” lub coś takiego - że utrudni to debugowanie. Tak więc fakt, że widzę, że nulljest przekazywany z powrotem, mówi mi, że zwrot działa - ale zasadniczo działa podobnie do undefined.


Dokumentacja:

Dokumenty Mozilla nie odpowiedziały na moje pytanie ... Google też nie: \

To TAK pytanie - było zbyt szerokie, jak na to, co próbuję tutaj zrozumieć.

Jeremy Iglehart
źródło
1
Nie robi to SO pytanie odpowiedź?
warkentien2
8
Moim zdaniem wróć null. Zostaw undefinedsam JavaScript. Nie ma jednak „lepszego”, więc to kwestia opinii.
Felix Kling
@ warkentien2 Dzięki, to było pomocne - ale nadal nie jestem pewien, jaka jest tu konwencja powrotu z funkcji pobierającej.
Jeremy Iglehart
1
Czytam nulljako „nie ma odpowiedniej wartości dla tego, o co prosisz” i undefinedjako „Nie mogę zrozumieć, o co prosisz”.
Marty
@ warkentien2 to pytanie i to, które podałem w mojej odpowiedzi, są powiązane, ale oba wydają się pytać, jaka jest między nimi różnica, a nie kiedy użyć jednego lub drugiego jako wartości zwracanej.
chiliNUT

Odpowiedzi:

39

Będę argumentował, że nie ma najlepszego sposobu, a nawet standardowe funkcje czasami wybierają jedną lub drugą.

Na przykład:

  • [[Prototyp]]

    Zwykłe obiekty mają wewnętrzną szczelinę [[Prototype]], która określa, z jakiego innego obiektu dziedziczą. Oczywiście musi istnieć sposób, aby powiedzieć, że obiekt nie dziedziczy po żadnym innym. W tym przypadku „nie ma takiego obiektu” jest reprezentowane za pomocą null.

  • Object.getOwnPropertyDescriptor

    Oczekuje się, że zwróci deskryptor właściwości, czyli obiekt, który opisuje właściwość (np. Wartość, możliwość zapisu, wyliczalność i konfigurowalność). Jednak nieruchomość może nie istnieć. W tym przypadku „nie ma takiej właściwości” jest reprezentowane za pomocą undefined.

  • document.getElementById

    Oczekuje się, że zwróci element o podanym identyfikatorze. Jednak może nie być elementu z tym identyfikatorem. W tym przypadku „nie ma takiego elementu” jest reprezentowane za pomocą null.

Więc po prostu wybierz to, co wolisz lub uważasz, że ma większy sens w Twoim konkretnym przypadku.

Oriol
źródło
3
po przeczytaniu tego postanowiłem zasugerować void 0przyszłym widzom technikę tej odpowiedzi. Dodałem też trochę kodu, aby wyjaśnić twój punkt widzenia. Dziękuję za Twoją odpowiedź!
Jeremy Iglehart
117

Undefined zazwyczaj odnosi się do czegoś, co nie zostało jeszcze przypisane (jeszcze). Null odnosi się do czegoś, co ostatecznie nie ma wartości. W takim przypadku zalecam zwrócenie wartości null. Zwróć uwagę, że funkcja bez określonej wartości zwracanej niejawnie zwraca wartość undefined.

Ze specyfikacji ECMAScript2015

4.3.10 wartość niezdefiniowana

wartość pierwotna używana, gdy zmiennej nie przypisano wartości

4.3.12 wartość zerowa

wartość pierwotna, która reprezentuje celowy brak wartości obiektu

http://www.ecma-international.org/ecma-262/6.0/#sec-terms-and-definitions-undefined-type

Czytaj dalej:

Kiedy wartość null lub undefined jest używana w JavaScript?

chiliNUT
źródło
1
Tak, niezdefiniowana to wartość używana, gdy zmiennej nie przypisano wartości. Dlaczego dokładnie oznacza to, że nie należy zwracać undefined w funkcji?
Oriol
1
@Oriol, moim zdaniem, ponieważ funkcja void zwraca undefined, czyli wartość zarezerwowaną dla funkcji tego typu, więc podczas obsługi wartości zwracanej funkcji null mówi mi, że zdecydowała się zwrócić wartość null, podczas gdy undefined mówi mi to albo zdecydował się zwrócić undefined, albo postanowił nie zwracać niczego, ale ostatecznie nie wiem, które. Ponadto, jeśli to robię var x=someFunc();, celowo przypisuję wartość xa i wolałbym, aby nie przechodził żadnych testów, które wskazują, że nie została (lub mogła nie mieć) przypisana wartość. Just
imho
To powinna być akceptowana odpowiedź. W ten sposób miał być używany w specyfikacji
Cynk
1
Nie czytam tego w ten sposób. Czytam to jako: Jeśli zdefiniujesz zmienną, ale jej nie zainicjujesz, zamiast tego będzie miała wartość początkową undefined. Programista powinien użyć wartości Null, aby celowo wskazać, że zmienna jest pusta. IMHO undefined nigdy nie powinien być przypisywany do zmiennej przez programistę, pozostaw to silnikowi js, aby go użył. Termin „wartość obiektu” jest mylący, ponieważ w JS nawet prymitywy zachowują się jak obiekty w większości z powodu autoboxingu
chiliNUT
1
Tak, to ma sens. Szczerze mówiąc, nie mam nic przeciwko używaniu jednego nad drugim (chociaż jestem do tego bardziej przyzwyczajony null), o ile trzymasz się jednego, ale posiadanie 2 wartości wskazujących na brak wartości (bez względu na „typ”) zawsze jest mylące
Sergio Rosas
40

Podam ci mój osobisty uparty sposób wyboru między tymi dwoma.

Moje proste pytanie brzmi: czy można zdefiniować wartość, biorąc pod uwagę inne dane wejściowe / stan / kontekst?

Jeśli odpowiedź brzmi tak, użyj nullelse użyj undefined. Mówiąc bardziej ogólnie, każda funkcja zwracająca obiekt powinna zwrócić, nullgdy zamierzony obiekt nie istnieje. Ponieważ może istnieć przy innym wejściu / stanie / kontekście.

nullreprezentuje brak wartości dla danego wejścia / stanu / kontekstu. To pośrednio oznacza, że pojęcie samej wartości istnieje w kontekście twojej aplikacji, ale może być nieobecne. W twoim przykładzie istnieje koncepcja następnej karty, ale sama karta może nie istnieć. nullpowinien być używany.

undefinedniejawnie reprezentuje brak znaczenia tej wartości w kontekście aplikacji. Na przykład, jeśli manipuluję userobiektem z podanym zestawem właściwości i próbuję uzyskać dostęp do właściwości pikatchu. Wartość tej właściwości powinna być ustawiona na, undefinedponieważ w moim kontekście nie ma sensu mieć takiej właściwości.

ngryman
źródło
1
To brzmi tak prawdziwie dla mnie. Czyste funkcje IMO powinny powrócić null, podczas gdy funkcje ze skutkami ubocznymi powinny powrócić undefined, gdy myśli się jak programista funkcjonalny.
Jake
4

undefinednie jest czymś, do czego powinieneś przypisywać. Możesz rozważyć zwrot czegoś innego niż undefined. W twoim przypadku, nawet jeśli w ogóle nic nie zwrócisz, wynik będzie undefinedjuż. Więc proponuję nullzamiast tego.

Rozważ tę próbkę,

function getSomething() {
     // .. do something
     return undefined;
}

function doSomething() {
     // .. I'm not gonna return anything.
}

var a = getSomething();
var b = doSomething();

Wynik powyższej próbki to a === b, czyli undefined. Różnica polega na tym, że zapisujesz wykonanie 1 instrukcji.

choz
źródło
@Oriol mam na myśli, undefinednie musi być przypisany. Wszystkie zadeklarowane zmienne bez wartości są już undefined.
choz
@choz & @Oriol - jak wspomniano wcześniej w @chiliNUT "Zwróć uwagę, że funkcja bez określonej wartości zwracanej niejawnie zwraca wartość undefined." - to prawda, ponieważ (function(){ /* code */ })()zwraca wartość null w konsoli.
Jeremy Iglehart
1
@JeremyIglehart Ten kod właściwie nic nie zwraca. A poza tym daje undefinedna mojej konsoli Chrome i Firefox.
choz
OK, nie rozumiem twojego punktu. Tak, jeśli nie zwrócisz niczego jawnie, wartość undefined zostanie zwrócona niejawnie. Ale dlaczego to ma znaczenie?
Oriol
1
@Oriol, myślę, że to, co @choz próbował powiedzieć (jak kilka innych również wspomniało w tym pytaniu), że jeśli chcę wrócić, undefinedjeśli coś innego nie wróci wcześniej - nie muszę, ponieważ domyślne zachowanie funkcji, jeśli nie zwracasz niczego, to zwracasz undefined - po prostu mówią, że nie jest to potrzebne. Co więcej ... Podoba mi się to, co miałeś do powiedzenia o wbudowanych funkcjach getter zwracających wartość null. Prosimy o przesłanie odpowiedzi w tej sprawie, a ja ją przyjmuję.
Jeremy Iglehart
3

Zależy od tego, co musisz zrobić ze zwróconą wartością.

typeof null zwraca obiekt. ten obiekt ma wartość undefined

typeof undefined zwraca undefined

Dan
źródło
Osobiście zwykle używam null.
Dan
4
„ten obiekt ma wartość undefined” Nie, to nie jest obiekt, to jest Null. typeofniekoniecznie zwraca prawdziwy typ danych wartości, ma mapę, która mapuje typy danych na etykiety i zwraca odpowiednią etykietę.
Felix Kling
Nie ufaj typeof, pomimo swojej nazwy, nie podaje typu wartości.
Oriol
3

Oto przykład, w którym undefinedma więcej sensu niżnull :

Używam funkcji opakowującej, JSON.parsektóra konwertuje wyjątek na undefined:

// parses s as JSON if possible and returns undefined otherwise
// return undefined iff s is not a string or not parseable as JSON; undefined is not a valid JSON value https://stackoverflow.com/a/14946821/524504
function JSON_parse_or_undefined(s) {
    if ("string" !== typeof s) return undefined

    try {
        const p = JSON.parse(s)
        return p
    } catch (x){}

    return undefined
}

Zauważ, że nulljest to poprawne w JSON, a undefinednie.

masterxilo
źródło
Widzę, co tam robisz - i nie mogę powiedzieć, że się mylisz - ponieważ w pewnym sensie myślę, że mógłbyś to zrobić tutaj i byłoby dobrze. Mam inny wzorzec, którego używam do wykonania tej operacji, który mi się bardziej podoba, ponieważ wykonuję później krok „walidacji”. Wydaje mi się, że jest to mieszanie walidacji z zwracaniem wartości. Oto co mam zrobić: let getStringOrJSON = value => { try { value = JSON.parse(value); } catch(e) { return value; } return value; };. Teraz jestem pewien, że te dwa zwroty można potraktować inaczej i mogą nie wygrać zawodów golfowych JS. To działa.
Jeremy Iglehart
2

Twierdziłbym, że w tym przypadku nullpowinien zostać zwrócony.

Jeśli wziąć pod uwagę kwestię z teoretycznego punktu widzenia informatyki następnie niezdefiniowana służy do wskazania zakaz wypowiedzenia / non-obliczalności (czyli zastępczy nieokreślonym punkcie xz częściową funkcją f , która jest często napisanef(x) = ⊥ ).

getNextCardwydaje się jednak, że jest w stanie obliczyć następną kartę (jeśli istnieje), a także być w stanie obliczyć, jeśli nie ma następnej karty. Innymi słowy, funkcja jest całkowita ponieważ kończy się dla każdego wejścia.

Mając to na uwadze, wymagana jest specjalna wartość zakończenia sygnalizacji bez znaczącego wyniku (tj. „Nie ma karty, którą mogę zwrócić dla tego wejścia”), a dla mnie nullnie jest undefined.


UWAGI:

Możesz zobaczyć pewne wsparcie dla tego argumentu w niektórych innych językach z typami typów, gdzie zakończenie bez znaczącego wyniku jest wyrażane za pomocą typu opcji (czasami nazywanego również typem dopuszczającym wartość null ). Przykładem tego jest Może w Haskell .

Z drugiej strony, oczywiście nie wiemy, co undefinedtak naprawdę ma oznaczać JavaScript. Tak więc analogia do undefined jest nieco wątpliwa. Co więcej, ponieważ zawsze chcemy pracować z funkcjami całkowitymi, oznacza to „nigdy nie wracaj undefinedz funkcji”. Co wydaje się być nieco surowe, ponieważ ograniczyłoby użycie undefineddo właściwości / zmiennych, które nie zostały ustawione.

Ostatecznie wolę nigdy nie wracać undefinedtam, gdzie mogę wrócić, nulli argumentowałbym również, że jest to lepsza konwencja kodowania (ponieważ między innymi x !== nulljest krótsza niż typeof x !== 'undefined').

FK82
źródło
1

Pierwsza odpowiedź jest prawidłowa. Mają teoretycznie inne znaczenie. Jednak nie zawsze jest jasne, który wybrać.

Zwykle używam null w moim rozwoju, chociaż myślę, że jest to całkowicie subiektywne.

Używam tego głównie dlatego, że:

  1. niezdefiniowana zmienna może zostać nadpisana w starszych przeglądarkach, więc jej zwrócenie jest nieco bardziej skomplikowane. Ten sam problem zmusza do korzystania typeof var === 'undefined'z wyników funkcji. połączyć

  2. Inne języki często używają wartości null w szerokim zakresie, wiele z nich nie ma nawet wartości undefined (na przykład php). To daje mi pewną konsekwencję podczas szybkiego przełączania się między językami.

Maciej Paprocki
źródło
1

Myślę, że jest bardzo dyskusyjne, czego użyć. Wolę kod, który jest semantycznie tak dokładny, jak to tylko możliwe, więc myślęundefined jest odpowiedni w tym przypadku.

Myślę o nullprzypisaniach jako o „zmiennej ustawionej na nic”. To w przeciwieństwie doundefined znaczenia „tego w ogóle nie ma”

Jak wskazano w poprzedniej odpowiedzi, powrót undefinedwiąże się z problemami i od Ciebie zależy, czy to Ci przeszkadza. Nie przeszkadzałoby mi to.

Ryan Laboucane
źródło
2
Ale document.getElementById('iDoNotExist')powraca null, mimo że znaczenie jest bliższe „tego czegoś w ogóle nie ma”. Jeśli standardowe metody to robią, dlaczego nie OP?
Oriol
@Oriol Właściwie najbardziej lubię twoje rozumowanie. Prosimy o przesłanie odpowiedzi w tej sprawie, a ja ją zaakceptuję. (W razie potrzeby mógłbym nawet dodać kilka zmian)
Jeremy Iglehart
Tak, @Oriol, właśnie dlatego lubię debaty, nawet na stronach z pytaniami i odpowiedziami. Naprawdę dobrze jest uzyskać kontrprzykłady. I zapewniłeś dobry.
Ryan Laboucane
-2

Moja osobista opinia, zgodnie z moim doświadczeniem, brzmi: nie używaj undefined i null, jeśli nie chcesz zepsuć kodu. Przynajmniej uniknąłbym tego osobiście. W JavaScript jest wiele funkcji, które zwracają wartość undefined i ok, musimy do tego użyć. Ale kiedy projektujesz swój kod, nie używaj go. Ważne jest, aby zawsze "false"przynajmniej coś zwrócić . Na przykład, jeśli masz tablicę i mapujesz ją. Nie jest dobrze wracać [undefined, undefined.....]ani po prostu undefined. Lepiej, jeśli zachowasz typ oryginalnej tablicy. Przykład:

 const mapper:Map <string[],boolean[]>  
['i', 'dont', 'use', 'null or undefined'] -> [false, true, false, true, false]
or ['', dont, '', '', use] 
or al the stuff above and then filter(v => v)
that will keep all undefined and null out

To jest pomysł. Cały czas staram się tego uniknąć. Ponieważ nulllub undefinedmoże łatwo spowodować awarię kodu

rubendmatos1985
źródło