Jaki jest najlepszy sposób sprawdzenia, czy właściwość obiektu w kodzie JavaScript jest niezdefiniowana?
Jaki jest najlepszy sposób sprawdzenia, czy właściwość obiektu w kodzie JavaScript jest niezdefiniowana?
Posługiwać się:
if (typeof something === "undefined") {
alert("something is undefined");
}
Jeśli zmienna obiektowa posiadająca pewne właściwości, możesz użyć tego samego:
if (typeof my_obj.someproperties === "undefined"){
console.log('the property is not available...'); // print into console
}
Od ECMAScript 5, undefined
nie można nadpisać, więc my_obj === undefined
też by działało, ale tylko jeśli my_obj
istnieje. To może lub nie może być pożądane, ponieważ możesz równie dobrze wykorzystać null
jeśli potrzebujesz tego semantycznego (zob Jaka jest różnica między wartością null i niezdefiniowaną w JavaScript?). Jednak dla właściwości obiektu działa niezależnie od tego, czy właściwość istnieje.
Uważam, że istnieje wiele niepoprawnych odpowiedzi na ten temat. W przeciwieństwie do powszechnego przekonania, "niezdefiniowane" jest nie słowo kluczowe w JavaScript i może w rzeczywistości mieć przypisaną wartość.
Najsolidniejszym sposobem wykonania tego testu jest:
if (typeof myVar === "undefined")
To zawsze zwróci poprawny wynik, a nawet zajmie się sytuacją, w której myVar
nie jest zadeklarowane.
var undefined = false; // Shockingly, this is completely legal!
if (myVar === undefined) {
alert("You have been misled. Run away!");
}
Do tego, myVar === undefined
spowoduje błąd w sytuacji, gdy myVar jest niezadeklarowany.
W JavaScript jest zero i jest niezdefiniowany. Mają różne znaczenia.
Marijn Haverbeke podaje w swojej bezpłatnej książce internetowej "Eloquent JavaScript"(podkreślenie moje):
Istnieje również podobna wartość, null, której znaczenie to "ta wartość jest zdefiniowana, ale nie ma wartości". Różnica w znaczeniu między niezdefiniowanym i zerowym jest w większości akademicka i zazwyczaj niezbyt interesująca. W programach praktycznych często konieczne jest sprawdzenie, czy coś "ma wartość". W takich przypadkach można użyć wyrażenia something == undefined, ponieważ, mimo że nie są one dokładnie tej samej wartości, null == undefined da wartość true.
Sądzę więc, że najlepszym sposobem sprawdzenia, czy coś jest nieokreślone, jest:
if (something == undefined)
Mam nadzieję że to pomoże!
Edytować: W odpowiedzi na edycję właściwości obiektu powinny działać w ten sam sposób.
var person = {
name: "John",
age: 28,
sex: "male"
};
alert(person.name); // "John"
alert(person.fakeVariable); // undefined
Pomimo, że jest tu gorąco rekomendowany przez wiele innych odpowiedzi, typeof
jest złym wyborem. Nigdy nie należy go używać do sprawdzania, czy zmienne mają wartość undefined
, ponieważ działa jako połączona kontrola wartości undefined
i czy istnieje zmienna. W ogromnej większości przypadków wiesz, kiedy istnieje zmienna, i typeof
po prostu wprowadzi możliwość cichej awarii, jeśli popełnisz literówkę w nazwie zmiennej lub w ciągu literowym 'undefined'
.
var snapshot = …;
if (typeof snaposhot === 'undefined') {
// ^
// misspelled¹ – this will never run, but it won’t throw an error!
}
var foo = …;
if (typeof foo === 'undefned') {
// ^
// misspelled – this will never run, but it won’t throw an error!
}
Więc chyba, że robisz detekcję², gdzie nie ma pewności, czy dane nazwisko znajdzie się w zasięgu (jak sprawdzanie typeof module !== 'undefined'
jako krok w kodzie specyficznym dla środowiska CommonJS), typeof
jest szkodliwym wyborem w przypadku użycia zmiennej, a właściwą opcją jest bezpośrednie porównanie wartości:
var foo = …;
if (foo === undefined) {
⋮
}
Oto kilka typowych nieporozumień na ten temat:
czytanie "niezainicjowanej" zmiennej (var foo
) lub parametr (function bar(foo) { … }
, zwany jako bar()
) zawiedzie. To po prostu nie jest prawdą - zmienne bez jawnej inicjalizacji i parametry, które nie zostały podane, zawsze stają się wartościami undefined
i zawsze są w zasięgu.
że undefined
można nadpisać. Jest o wiele więcej. undefined
nie jest słowem kluczowym w JavaScript. Zamiast tego jest to właściwość obiektu globalnego o wartości niezdefiniowanej. Jednak od wersji ES5 ta właściwość została tylko czytać i nie można konfigurować. Żadna nowoczesna przeglądarka nie zezwoli na undefined
właściwość do zmiany, a od 2017 r. ma to miejsce od dłuższego czasu. Brak trybu ścisłego nie ma wpływu undefined
Zachowanie też - po prostu sprawia, że oświadczenia undefined = 5
nie rób nic zamiast rzucania. Ponieważ nie jest to słowo kluczowe, możesz ogłosić zmienne o nazwie undefined
, a te zmienne można zmienić, tworząc ten jeden wspólny wzorzec:
(function (undefined) {
// …
})()
jeszcze niebezpieczne niż używanie globalnego undefined
. Jeśli musisz być kompatybilny z ES3, wymień undefined
z void 0
- nie uciekaj się do typeof
. (void
zawsze był operatorem jednoargumentowym, który ocenia wartość niezdefiniowaną dla dowolnego operandu).
Ze względu na to, że zmienne nie działają poprawnie, nadszedł czas, aby zająć się rzeczywistym pytaniem: właściwości obiektu. Nie ma powodu, aby kiedykolwiek skorzystać typeof
dla właściwości obiektu. Wcześniejszy wyjątek dotyczący wykrywania cech nie ma tutaj zastosowania - typeof
ma tylko specjalne zachowanie na zmiennych, a wyrażenia odwołujące się do właściwości obiektu nie są zmiennymi.
To:
if (typeof foo.bar === 'undefined') {
⋮
}
jest zawsze dokładnie równoważny do tego3:
if (foo.bar === undefined) {
⋮
}
i biorąc pod uwagę powyższe porady, aby nie pomylić czytelników, dlaczego używasz typeof
, ponieważ ma sens w użyciu ===
aby sprawdzić równość, ponieważ może być refaktoryzowana do sprawdzenia wartości zmiennej później, a ponieważ po prostu wygląda lepiej, powinieneś zawsze używać === undefined
³ również tutaj.
Coś innego do rozważenia, jeśli chodzi o właściwości obiektów, jest to, czy naprawdę chcesz sprawdzić undefined
w ogóle. Dana nazwa właściwości może być nieobecna na obiekcie (tworząc wartość undefined
przy odczycie), obecny na samym obiekcie z wartością undefined
, obecne na prototypie obiektu z wartością undefined
lub obecne na którymkolwiek z osóbundefined
wartość. 'key' in obj
powie ci, czy klucz jest gdziekolwiek w łańcuchu prototypów obiektu, i Object.prototype.hasOwnProperty.call(obj, 'key')
powie ci, czy jest to bezpośrednio na obiekcie. Nie będę jednak szczegółowo omawiał tej odpowiedzi na temat prototypów i używania obiektów w postaci map z ciągami znaków, ponieważ ma ona głównie na celu przeciwdziałanie złym radom w innych odpowiedziach, niezależnie od możliwych interpretacji pierwotnego pytania. Czytaj dalej prototypy obiektów na MDN więcej!
¹ nietypowy wybór przykładowej nazwy zmiennej? to jest prawdziwy martwy kod z rozszerzenia NoScript dla Firefoksa.
² nie zakładaj, że nie wie jednak, co jest w zasięgu. podatna luka spowodowana nadużyciem zakresu dynamicznego: Project Zero 1225
³ po raz kolejny zakładając środowisko ES5 + i inne undefined
odnosi się do undefined
własność obiektu globalnego. zastąpić void 0
Inaczej.
Co to znaczy: "niezdefiniowana właściwość obiektu"?
Właściwie może to oznaczać dwie zupełnie różne rzeczy! Po pierwsze, może to oznaczać właściwość, która nigdy nie została zdefiniowana w obiekcie, a po drugie, może oznaczać właściwość, która ma niezdefiniowaną wartość. Spójrzmy na ten kod:
var o = { a: undefined }
Jest o.a
niezdefiniowany? Tak! Jego wartość jest niezdefiniowana. Jest o.b
niezdefiniowany? Pewnie! W ogóle nie ma własności "b"! OK, zobacz teraz, jak różne podejścia zachowują się w obu sytuacjach:
typeof o.a == 'undefined' // true
typeof o.b == 'undefined' // true
o.a === undefined // true
o.b === undefined // true
'a' in o // true
'b' in o // false
Możemy to wyraźnie zobaczyć typeof obj.prop == 'undefined'
i obj.prop === undefined
są równoważne i nie rozróżniają tych różnych sytuacji. I 'prop' in obj
potrafi wykryć sytuację, gdy właściwość nie została w ogóle zdefiniowana i nie zwraca uwagi na wartość właściwości, która może być nieokreślona.
1) Chcesz wiedzieć, czy właściwość jest niezdefiniowana przez pierwsze lub drugie znaczenie (najbardziej typowa sytuacja).
obj.prop === undefined // IMHO, see "final fight" below
2) Chcesz wiedzieć, czy obiekt ma jakąś własność i nie przejmuje się jego wartością.
'prop' in obj
x.a === undefined
albo to typeof x.a == 'undefined'
podnosi ReferenceError: x is not defined
jeśli x nie jest zdefiniowane.undefined
jest zmienną globalną (tak naprawdę jest window.undefined
w przeglądarkach). Jest wspierany od wydania ECMAScript 1st Edition i od wersji ECMAScript 5 tylko czytać. Więc w nowoczesnych przeglądarkach tak być nie może ponownie zdefiniowane jako prawdziwe jak wielu autorów uwielbia nas straszyć, ale jest to nadal prawdziwe w przypadku starszych przeglądarek.obj.prop === undefined
vs typeof obj.prop == 'undefined'
Plusy obj.prop === undefined
:
undefined
Minusy obj.prop === undefined
:
undefined
mogą być przesłonięte w starszych przeglądarkachPlusy typeof obj.prop == 'undefined'
:
Minusy typeof obj.prop == 'undefined'
:
'undefned'
(błędnie napisany) tutaj jest tylko stała łańcuchowa, więc silnik JavaScript nie może ci pomóc, jeśli masz błąd w pisowni, tak jak właśnie.Node.js obsługuje zmienną globalną undefined
tak jak global.undefined
(może być również używany bez prefiksu "globalnego"). Nie wiem o innych implementacjach JavaScript po stronie serwera.
Problem sprowadza się do trzech przypadków:
undefined
.undefined
.To mówi nam coś, co uważam za ważne:
Istnieje różnica między niezdefiniowanym elementem a zdefiniowanym elementem o nieokreślonej wartości.
Ale nieszczęśliwie typeof obj.foo
nie mówi nam, które z trzech spraw mamy. Jednak możemy to połączyć z "foo" in obj
rozróżniać przypadki.
| typeof obj.x === 'undefined' | !("x" in obj)
1. { x:1 } | false | false
2. { x : (function(){})() } | true | false
3. {} | true | true
Warto zauważyć, że te testy są takie same null
również wpisy
| typeof obj.x === 'undefined' | !("x" in obj)
{ x:null } | false | false
Twierdzę, że w niektórych przypadkach bardziej sensowne (i bardziej przejrzyste) jest sprawdzenie, czy nieruchomość tam jest, niż sprawdzenie, czy jest ona nieokreślona, a jedynym przypadkiem, w którym ta kontrola będzie inna, jest przypadek 2, rzadki przypadek faktyczny wpis w obiekcie o nieokreślonej wartości.
Na przykład: Właśnie refactorowałem wiązkę kodu, która zawierała kilka sprawdzeń, czy obiekt ma daną właściwość.
if( typeof blob.x != 'undefined' ) { fn(blob.x); }
Które było wyraźniejsze, gdy napisane bez sprawdzenia dla nieokreślonego.
if( "x" in blob ) { fn(blob.x); }
Ale jak już wspomniano, nie są one dokładnie takie same (ale są więcej niż wystarczająco dobre dla moich potrzeb).
if ( typeof( something ) == "undefined")
To działało dla mnie, podczas gdy inni nie.
Nie jestem pewien, skąd pochodzi używanie ===
z typeof
pochodzę i jako konwencja widzę, że jest on używany w wielu bibliotekach, ale operator typeof zwraca literał łańcuchowy i wiemy o tym z góry, więc dlaczego chcesz go również wpisać?
typeof x; // some string literal "string", "object", "undefined"
if (typeof x === "string") { // === is redundant because we already know typeof returns a string literal
if (typeof x == "string") { // sufficient
Crossposting my odpowiedź z pokrewnego pytania Jak sprawdzić "niezdefiniowany" w JavaScript?
Specyficzne dla tego pytania, zobacz przypadki testowe z someObject.<whatever>
.
Niektóre scenariusze ilustrujące wyniki różnych odpowiedzi: http://jsfiddle.net/drzaus/UVjM4/
(Należy pamiętać, że użycie var
dla in
testy robią różnicę w opakowaniu z zakresem)
Kod referencyjny:
(function(undefined) {
var definedButNotInitialized;
definedAndInitialized = 3;
someObject = {
firstProp: "1"
, secondProp: false
// , undefinedProp not defined
}
// var notDefined;
var tests = [
'definedButNotInitialized in window',
'definedAndInitialized in window',
'someObject.firstProp in window',
'someObject.secondProp in window',
'someObject.undefinedProp in window',
'notDefined in window',
'"definedButNotInitialized" in window',
'"definedAndInitialized" in window',
'"someObject.firstProp" in window',
'"someObject.secondProp" in window',
'"someObject.undefinedProp" in window',
'"notDefined" in window',
'typeof definedButNotInitialized == "undefined"',
'typeof definedButNotInitialized === typeof undefined',
'definedButNotInitialized === undefined',
'! definedButNotInitialized',
'!! definedButNotInitialized',
'typeof definedAndInitialized == "undefined"',
'typeof definedAndInitialized === typeof undefined',
'definedAndInitialized === undefined',
'! definedAndInitialized',
'!! definedAndInitialized',
'typeof someObject.firstProp == "undefined"',
'typeof someObject.firstProp === typeof undefined',
'someObject.firstProp === undefined',
'! someObject.firstProp',
'!! someObject.firstProp',
'typeof someObject.secondProp == "undefined"',
'typeof someObject.secondProp === typeof undefined',
'someObject.secondProp === undefined',
'! someObject.secondProp',
'!! someObject.secondProp',
'typeof someObject.undefinedProp == "undefined"',
'typeof someObject.undefinedProp === typeof undefined',
'someObject.undefinedProp === undefined',
'! someObject.undefinedProp',
'!! someObject.undefinedProp',
'typeof notDefined == "undefined"',
'typeof notDefined === typeof undefined',
'notDefined === undefined',
'! notDefined',
'!! notDefined'
];
var output = document.getElementById('results');
var result = '';
for(var t in tests) {
if( !tests.hasOwnProperty(t) ) continue; // bleh
try {
result = eval(tests[t]);
} catch(ex) {
result = 'Exception--' + ex;
}
console.log(tests[t], result);
output.innerHTML += "\n" + tests[t] + ": " + result;
}
})();
I wyniki:
definedButNotInitialized in window: true
definedAndInitialized in window: false
someObject.firstProp in window: false
someObject.secondProp in window: false
someObject.undefinedProp in window: true
notDefined in window: Exception--ReferenceError: notDefined is not defined
"definedButNotInitialized" in window: false
"definedAndInitialized" in window: true
"someObject.firstProp" in window: false
"someObject.secondProp" in window: false
"someObject.undefinedProp" in window: false
"notDefined" in window: false
typeof definedButNotInitialized == "undefined": true
typeof definedButNotInitialized === typeof undefined: true
definedButNotInitialized === undefined: true
! definedButNotInitialized: true
!! definedButNotInitialized: false
typeof definedAndInitialized == "undefined": false
typeof definedAndInitialized === typeof undefined: false
definedAndInitialized === undefined: false
! definedAndInitialized: false
!! definedAndInitialized: true
typeof someObject.firstProp == "undefined": false
typeof someObject.firstProp === typeof undefined: false
someObject.firstProp === undefined: false
! someObject.firstProp: false
!! someObject.firstProp: true
typeof someObject.secondProp == "undefined": false
typeof someObject.secondProp === typeof undefined: false
someObject.secondProp === undefined: false
! someObject.secondProp: true
!! someObject.secondProp: false
typeof someObject.undefinedProp == "undefined": true
typeof someObject.undefinedProp === typeof undefined: true
someObject.undefinedProp === undefined: true
! someObject.undefinedProp: true
!! someObject.undefinedProp: false
typeof notDefined == "undefined": true
typeof notDefined === typeof undefined: true
notDefined === undefined: Exception--ReferenceError: notDefined is not defined
! notDefined: Exception--ReferenceError: notDefined is not defined
!! notDefined: Exception--ReferenceError: notDefined is not defined
Jeśli zrobisz
if (myvar == undefined )
{
alert('var does not exists or is not initialized');
}
zawiedzie, gdy zmienna myvar
nie istnieje, ponieważ myvar nie jest zdefiniowany, więc skrypt jest zepsuty, a test nie działa.
Ponieważ obiekt okna ma zakres globalny (obiekt domyślny) poza funkcją, deklaracja zostanie "dołączona" do obiektu okna.
Na przykład:
var myvar = 'test';
Zmienna globalna myvar jest taki sam jak window.myvar lub okno ['myvar']
Aby uniknąć błędów podczas testowania, gdy istnieje zmienna globalna, lepiej użyj:
if(window.myvar == undefined )
{
alert('var does not exists or is not initialized');
}
Pytanie, czy zmienna rzeczywiście istnieje, nie ma znaczenia, jej wartość jest niepoprawna. W przeciwnym razie niemądrze jest zainicjować zmienne o niezdefiniowanej wartości i lepiej użyć wartości false do zainicjowania. Kiedy wiesz, że wszystkie deklarowane zmienne są inicjowane z wartością false, możesz po prostu sprawdzić jego typ lub polegać na nim !window.myvar
aby sprawdzić, czy ma prawidłową / prawidłową wartość. Więc nawet wtedy, gdy zmienna nie jest zdefiniowana, wtedy !window.myvar
jest taki sam dla myvar = undefined
lub myvar = false
lub myvar = 0
.
Kiedy oczekujesz określonego typu, przetestuj typ zmiennej. Aby przyspieszyć testowanie stanu, lepiej wykonaj:
if( !window.myvar || typeof window.myvar != 'string' )
{
alert('var does not exists or is not type of string');
}
Kiedy pierwszy i prosty warunek jest prawdziwy, interpreter pomija następne testy.
Zawsze lepiej jest użyć instancji / obiektu zmiennej, aby sprawdzić, czy otrzymała poprawną wartość. Jest bardziej stabilny i jest lepszym sposobem programowania.
(y)
Nie widziałem (mam nadzieję, że mi tego nie brakowało), kto sprawdzał obiekt przed nieruchomością. Jest to najkrótsza i najskuteczniejsza (choć niekoniecznie najbardziej przejrzysta):
if (obj && obj.prop) {
// Do something;
}
Jeśli obj lub obj.prop jest niezdefiniowany, null lub "falsy", instrukcja if nie wykona bloku kodu. To jest zazwyczaj pożądane zachowanie w większości instrukcji blokowych kodu (w JavaScript).