JavaScript Null Check

170

Natknąłem się na następujący kod:

function test(data) {
    if (data != null && data !== undefined) {
        // some code here
    }
}

Jestem trochę nowy w JavaScript, ale z innych pytań, które tu czytałem, mam wrażenie, że ten kod nie ma większego sensu.


W szczególności ta odpowiedź stwierdza, że

Otrzymasz błąd, jeśli uzyskasz dostęp do niezdefiniowanej zmiennej w dowolnym kontekście innym niż typeof.

Aktualizacja: (cytat) powyższej odpowiedzi może wprowadzać w błąd. Powinien mówić „niezadeklarowana zmienna” zamiast „niezdefiniowana zmienna” .

Jak się dowiedziałem, w odpowiedziach Ryana ♦ , maerics i nwellnhof , nawet jeśli nie podano argumentów funkcji, jej zmienne dla argumentów są zawsze deklarowane. Fakt ten również okazuje się błędny w przypadku pierwszej pozycji na poniższej liście.


Z mojego zrozumienia mogą wystąpić następujące scenariusze:

  • Funkcja została wywołana bez argumentów, co spowodowało datautworzenie niezdefiniowanej zmiennej i spowodowanie błędu na data != null.

  • Funkcja została wywołana specjalnie z null(lub undefined) jako argumentem, w którym to przypadku data != nulljuż chroni kod wewnętrzny, renderując&& data !== undefined bezużytecznym.

  • Funkcja została wywołana z argumentem różnym od null, w którym to przypadku w trywialny sposób przekaże oba data != null i data !== undefined .

P: Czy moje rozumienie jest prawidłowe?


Próbowałem następujących rzeczy w konsoli Firefoksa:

--
[15:31:31.057] false != null
[15:31:31.061] true
--
[15:31:37.985] false !== undefined
[15:31:37.989] true
--
[15:32:59.934] null != null
[15:32:59.937] false
--
[15:33:05.221] undefined != null
[15:33:05.225] false
--
[15:35:12.231] "" != null
[15:35:12.235] true
--
[15:35:19.214] "" !== undefined
[15:35:19.218] true

Nie mogę wymyślić przypadku, w którym data !== undefined po data != null może się przydać.

afsantos
źródło
9
Po prostu użyj if (data). Jest to mnemoniczny sposób w Javascript na sprawdzenie, czy datazmienna ma wartość true. undefined, nullFalse, 0, pusty łańcuch, pusta tablica i (?) Przedmiot bez właściwości FALSE, reszta jest prawdą.
J0HN
20
@ J0HN - Użycie if(data)oznaczałoby, że nie może przekazać falseani 0jako wartości dla data.
techfoobar
@ J0HN Również ta sama odpowiedź, o której wspomniałem, stanowi również, że: if(typeof someUndefVar == whatever) -- worksi if(someUnderVar) -- error.
afsantos
2
Prawdopodobnie tak powinno być data !== null && data !== undefined, co jest równoważne temu, data != nullco jest równoważne z data != undefined. Dawna forma wydaje się być preferowane, ponieważ jest bardziej wyraźne o warunkach, podczas gdy byłoby łatwo przeoczyć, że zarówno nulli undefinedsą sprawdzane z późniejszych dwóch warunków.
zzzzBov
2
Nawiasem mówiąc, wyraźne testy undefinedto IMO zapach kodu. To nie jest chronione słowo kluczowe, jak nullzmienna, która jest niezdefiniowana. To jest całkowicie poprawne i spowoduje złamanie twojego kodu:undefined = 1
Izkata

Odpowiedzi:

106

„Niezdefiniowana zmienna” różni się od wartości undefined.

Niezdefiniowana zmienna:

var a;
alert(b); // ReferenceError: b is not defined

Zmienna o wartości undefined:

var a;
alert(a); // Alerts “undefined”

Gdy funkcja przyjmuje argument, ten argument jest zawsze deklarowany, nawet jeśli jego wartość to undefined, więc nie będzie żadnego błędu. Masz jednak rację co != nulldo !== undefinedtego, że jesteś bezużyteczny.

Ry-
źródło
32
data !== null && data !== undefinedmiałoby jednak sens.
bfavaretto
@bfavaretto: Tak, więc może to być literówka. Ale nigdy nie wiadomo…: D
Ry-
1
Tak jak myślałem, dzięki za wyjaśnienie. Nie sądzę też, żeby to była literówka. Uruchomiłem funkcję „ znajdź i zlicz” w całym skrypcie i znalazłem 10 wystąpień, więc ... Myślę, że autor również potrzebuje wyjaśnienia na ten temat.
afsantos
2
Podrap mój komentarz powyżej: w rzeczywistości data != nullsprawdzałby oba nulli undefined(ale, co ciekawe, tylko nulli undefined, a nie inne fałszywe wartości).
bfavaretto
90

W JavaScript nulljest to specjalny obiekt typu singleton, który jest pomocny przy sygnalizowaniu „brak wartości”. Możesz to sprawdzić przez porównanie i, jak zwykle w JavaScript, dobrą praktyką jest użycie ===operatora, aby uniknąć mylącego wymuszania typu:

var a = null;
alert(a === null); // true

Jak wspomina @rynah, „undefined” jest nieco mylące w JavaScript. Jednak zawsze można bezpiecznie sprawdzić, czy typeof(x)ciąg jest „niezdefiniowany”, nawet jeśli „x” nie jest zadeklarowaną zmienną:

alert(typeof(x) === 'undefined'); // true

Ponadto zmienne mogą mieć „niezdefiniowaną wartość”, jeśli nie zostały zainicjowane:

var y;
alert(typeof(y) === 'undefined'); // true

Podsumowując, Twój czek powinien wyglądać następująco:

if ((typeof(data) !== 'undefined') && (data !== null)) {
  // ...

Jednakże, ponieważ zmienna „data” jest zawsze zdefiniowana, ponieważ jest formalnym parametrem funkcji, użycie operatora „typeof” jest niepotrzebne i można bezpiecznie porównać bezpośrednio z „niezdefiniowaną wartością”.

function(data) {
  if ((data !== undefined) && (data !== null)) {
    // ...

Ten fragment sprowadza się do stwierdzenia: „jeśli funkcja została wywołana z argumentem, który jest zdefiniowany i nie jest pusty…”

maerics
źródło
5
Dlaczego miałby tak wyglądać? != nullbędzie prawdziwe dla wszystkich wartości z wyjątkiem nulli undefined, i jesteśmy pewni, że ta zmienna jest zadeklarowana. typeofw innych sytuacjach może być nawet niebezpieczne - a co jeśli błędnie wpiszesz nazwę zmiennej? To może pozostać niewykryte przez długi czas, ponieważ nie ma błędu.
Ry-
@maerics Więc jeśli następuje odpowiedź prawidłowo, w czeku zerowej jak wyżej scenariuszu nie używać !=w ogóle, tylko ścisłe porównanie, !==?
afsantos
@rynah: Nie sądzę, żebym wiedział wystarczająco dużo o ogólnym rozwiązaniu OP, aby wiedzieć, czy test zerowy jest odpowiedni, czy nie, ale redagowałem, aby wspomnieć, że używanie „typeof” jest niepotrzebne.
maerics
@afsantos: w rzeczywistości nie sądzę, aby wiele (jakichkolwiek?) wartości zostało przekonwertowanych na null; jednak najlepszą praktyką jest użycie ścisłego porównania ( ===), chyba że naprawdę wiesz, co robisz i chcesz porównać po konwersji ( ==).
maerics
1
@Izkata: Usuń każdą bibliotekę, która próbuje zmienić definicję undefined. Ponadto Safari na iPadzie nie zrobi tego w żadnych okolicznościach. Nie możesz nawetdelete window.undefined .
Ry-
10

W twoim przypadku użyj data==null(co jest prawdziwe TYLKO dla wartości null i undefined - na drugim obrazku skup się na wierszach / kolumnach null-undefined)

Tutaj masz wszystko ( src ):

Jeśli

wprowadź opis obrazu tutaj

== (jego zaprzeczenie ! = )

wprowadź opis obrazu tutaj

=== (jego zaprzeczenie ! == )

wprowadź opis obrazu tutaj

Kamil Kiełczewski
źródło
8

P: Funkcja została wywołana bez argumentów, co spowodowało, że data stała się niezdefiniowaną zmienną i spowodowała błąd w danych! = Null.

O: Tak, datazostanie ustawiony na niezdefiniowany. Zobacz rozdział 10.5 Wiązanie deklaracji Instancja specyfikacji. Jednak dostęp do niezdefiniowanej wartości nie powoduje błędu. Prawdopodobnie mylisz to z dostępem do niezadeklarowanej zmiennej w trybie ścisłym, co powoduje błąd.

P: Funkcja została wywołana specjalnie z null (lub niezdefiniowanym) jako argumentem, w którym to przypadku data! = Null już chroni kod wewnętrzny, renderując && data! == undefined bezużyteczne.

P: Funkcja została wywołana z argumentem różnym od null, w którym to przypadku w trywialny sposób przekaże zarówno dane! = Null, jak i dane! == undefined.

O: Dobrze . Zauważ, że następujące testy są równoważne:

data != null
data != undefined
data !== null && data !== undefined

Patrz sekcja 11.9.3 Algorytm abstrakcyjnego porównywania równości i sekcja 11.9.6 Algorytm ścisłego porównywania równości w specyfikacji.

nwellnhof
źródło
Nie myliłem się z niezadeklarowanymi zmiennymi, naprawdę nie wiedziałem, jak to działa, gdy nie podano argumentów. Byłem przekonany, że datato w ogóle by nie istniało, zamiast być ustawione undefined. Doceniam wyjaśnienie, a te odniesienia pomogły mi lepiej zrozumieć, jak działają obie równości.
afsantos
3

Myślę, że testowanie zmiennych pod kątem wartości, których się nie spodziewasz, nie jest ogólnie dobrym pomysłem. Ponieważ test jako swój możesz uznać za napisanie czarnej listy zabronionych wartości. Ale co, jeśli zapomnisz wymienić wszystkie zabronione wartości? Ktoś, nawet Ty, może złamać Twój kod, przekazując nieoczekiwaną wartość. Więc bardziej odpowiednim podejściem jest coś w rodzaju białej listy - testowanie zmiennych tylko dla oczekiwanych wartości, a nie nieoczekiwanych. Na przykład, jeśli oczekujesz, że wartość danych będzie ciągiem znaków, zamiast tego:

function (data) {
  if (data != null && data !== undefined) {
    // some code here
    // but what if data === false?
    // or data === '' - empty string?
  }
}

zrób coś takiego:

function (data) {
  if (typeof data === 'string' && data.length) {
    // consume string here, it is here for sure
    // cleaner, it is obvious what type you expect
    // safer, less error prone due to implicit coercion
  } 
}

źródło
2

typeof foo === "undefined"różni się od foo === undefined, nigdy ich nie myl. typeof foo === "undefined"jest tym, czego naprawdę potrzebujesz. Używaj również !==zamiast!=

Więc oświadczenie można zapisać jako

function (data) {
  if (typeof data !== "undefined" && data !== null) {
    // some code here
  }
}

Edytować:

Nie można używać foo === undefineddla niezadeklarowanych zmiennych.

var t1;

if(typeof t1 === "undefined")
{
  alert("cp1");
}

if(t1 === undefined)
{
  alert("cp2");
}

if(typeof t2 === "undefined")
{
  alert("cp3");
}

if(t2 === undefined) // fails as t2 is never declared
{
  alert("cp4");
}

źródło
1
OK, ale w tym przypadku zmienna jest zadeklarowana, więc w czym problem?
Ry-
Osobiście uważam, że foo === undefinedużywanie jest niebezpieczne. Sprawia, że ​​kod kończy się niepowodzeniem z powodu tego samego stanu, któremu próbowano zapobiec.
Mówię o argumencie do omawianej funkcji. Zobacz także mój drugi komentarz .
Ry-
1
Dlaczego tak się dzieje? Pierwsze zdanie to prawidłowe i ważne rozróżnienie!
Izkata
1
@Izkata: ponieważ nie ma wyjaśnienia dla początkowej wypowiedzi. foo === undefinedjest całkowicie akceptowalny w sytuacji PO (założenie, undefinedże nie zostało nadpisane). Odpowiedź nie wyjaśnia również, dlaczego !== powinno się ją stosować zamiast !=.
Matt
1

Prosty sposób na wykonanie testu to:

function (data) {
    if (data) { // check if null, undefined, empty ...
        // some code here
    }
}
Kadiri
źródło
5
Czy ten test nie jest zależny od kontekstu? Chodzi mi o to, że jeśli oczekiwanym typem dla datajest ciąg znaków, ten test zwraca false na pustych ciągach, co może, ale nie musi, być odpowiednie (funkcja może w jakiś sposób poradzić sobie z pustym ciągiem).
afsantos
5
Z wyjątkiem, że jeśli „dane” ma wartość ""lub 0czy NaN(lub innych) „czy” blok zostanie pominięty; co może, ale nie musi, być intencją OP.
maerics
Przepraszam @afsantos, nie widziałem twojego komentarza, jeśli chcesz otrzymać fałsz, gdy dane są niezdefiniowane, null ... z wyjątkiem sytuacji, gdy data jest pusta, musisz utworzyć inny var toTest = data; z innym testem po pierwszym, takim jak: if (toTest == "") {// tutaj jakiś kod}
Kadiri
-5
var a;
alert(a); //Value is undefined

var b = "Volvo"; 
alert(b); //Value is Volvo

var c = null;
alert(c); //Value is null
przelewowy
źródło
4
Proszę o wyjaśnienie, co to ma znaczyć.
Ry-
To naprawdę nie sprawdzić na null.
user4642212,