Rilevamento di una proprietà dell'oggetto non definita


Risposte:


2681

Il solito modo per verificare se il valore di una proprietà è il valore speciale undefinedè:

if(o.myProperty === undefined) {
  alert("myProperty value is the special value `undefined`");
}

Per verificare se un oggetto non ha effettivamente una tale proprietà e, pertanto, tornerà undefineddi default quando si tenta di accedervi:

if(!o.hasOwnProperty('myProperty')) {
  alert("myProperty does not exist");
}

Per verificare se il valore associato a un identificatore è il valore speciale undefined, o se tale identificatore non è stato dichiarato. Nota: questo metodo è l'unico modo per fare riferimento a un identificatore non dichiarato (nota: diverso dall'avere un valore di undefined) senza un errore iniziale:

if(typeof myVariable === 'undefined') {
  alert('myVariable is either the special value `undefined`, or it has not been declared');
}

Nelle versioni di JavaScript precedenti a ECMAScript 5, la proprietà denominata "non definita" sull'oggetto globale era scrivibile e quindi un semplice controllo foo === undefinedpotrebbe comportarsi in modo imprevisto se fosse stato ridefinito accidentalmente. Nel moderno JavaScript, la proprietà è di sola lettura.

Tuttavia, nel JavaScript moderno, "non definito" non è una parola chiave, quindi le variabili all'interno delle funzioni possono essere denominate "non definite" e oscurare la proprietà globale.

Se sei preoccupato per questo (improbabile) caso limite, puoi usare l'operatore vuoto per ottenere il undefinedvalore speciale stesso:

if(myVariable === void 0) {
  alert("myVariable is the special value `undefined`");
}

9
se qualcosa è null viene definito (come null), ma è possibile coniugare anche i controlli. Il dettaglio fastidioso del codice sopra è che non puoi definire una funzione per controllarla, bene puoi definire la funzione ... ma prova a usarla.
neu-rah,

5
@ neu-rah perché non riesci a scrivere una funzione? perché qualcosa del genere non dovrebbe funzionare? Sembra funzionare per me. C'è un caso che non sto prendendo in considerazione? jsfiddle.net/djH9N/6
Zack

7
@Zack I test per isNullorUndefined non hanno preso in considerazione il caso in cui si chiama isNullOrUndefined (f) ef non è dichiarato (ovvero dove non esiste una dichiarazione "var f").
pnkfelix,

109
Blah, migliaia di voti adesso. Questo è il modo peggiore per farlo. Spero che i passanti vedano questo commento e decidano di controllare ... ehm ... altre risposte.
Ry-

17
Puoi semplicemente usare obj !== undefinedora. undefinedera mutevole, come undefined = 1234quello che avrebbe causato risultati interessanti. Ma dopo Ecmascript 5, non è più scrivibile, quindi possiamo usare la versione più semplice. codereadability.com/how-to-check-for-undefined-in-javascript
Bruno Buccolo

899

Credo che ci siano diverse risposte errate a questo argomento. Contrariamente alla credenza comune, "undefined" non è una parola chiave in JavaScript e può infatti avere un valore assegnato ad essa.

Codice corretto

Il modo più efficace per eseguire questo test è:

if (typeof myVar === "undefined")

Ciò restituirà sempre il risultato corretto e gestisce anche la situazione in cui myVarnon viene dichiarato.

Codice degenerato. NON USARE.

var undefined = false;  // Shockingly, this is completely legal!
if (myVar === undefined) {
    alert("You have been misled. Run away!");
}

Inoltre, myVar === undefinedgenererà un errore nella situazione in cui myVar non è dichiarato.


133
+1 per aver notato che myVar === indefinito genererà un errore se myVar non è stato dichiarato
Enrique

73
Trovo la prima giustificazione fornita qui per non usare la === undefinedconfusione. Sì, puoi assegnarlo a undefined, ma non esiste un motivo legittimo per farlo ed è prevedibile che ciò possa violare il tuo codice. In C puoi #define true false, e in Python puoi assegnare a Truee False, ma le persone non sentono il bisogno di progettare il loro codice in quelle lingue in modo tale da proteggersi contro la possibilità di sabotare deliberatamente il proprio ambiente altrove nel codice . Perché vale la undefinedpena considerare la possibilità di assegnare anche qui?
Mark Amery,

19
oltre ai commenti di Mark, non capisco: "myVar === undefined genererà un errore nella situazione in cui myVar non è dichiarato." - perché è così male? Perché non dovrei voler avere un errore se mi riferisco a variabili non dichiarate?
eis,

5
Inoltre, tieni presente che puoi sempre fare void 0per ottenere il valore a cui undefinedpunta. Quindi puoi farlo if (myVar === void 0). il 0non è speciale, si può letteralmente mettere qualsiasi espressione lì.
Claudiu,

28
Nei browser moderni (FF4 +, IE9 +, Chrome sconosciuto), non è più possibile modificarli undefined. MDN: non definito
user247702

228

Nonostante sia raccomandato con veemenza da molte altre risposte qui, typeof è una cattiva scelta . Non dovrebbe mai essere usato per verificare se le variabili hanno il valore undefined, perché funge da controllo combinato per il valore undefinede per l'esistenza di una variabile. Nella stragrande maggioranza dei casi, sai quando esiste una variabile e typeofintrodurrai il potenziale per un errore silenzioso se fai un errore di battitura nel nome della variabile o nella stringa letterale '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!
}

Quindi, a meno che tu non stia eseguendo il rilevamento delle funzionalità², dove non vi è incertezza sul fatto che un determinato nome sia compreso nell'ambito (come il controllo typeof module !== 'undefined' compreso come passaggio nel codice specifico di un ambiente CommonJS), typeofè una scelta dannosa se utilizzato su una variabile e l'opzione corretta è per confrontare direttamente il valore:

var foo = …;

if (foo === undefined) {
    
}

Alcune idee sbagliate comuni su questo includono:

  • che la lettura di una variabile (non inizializzata var foo) ( ) o parametro (function bar(foo) { … } , chiamato come bar()) fallirà. Questo semplicemente non è vero: le variabili senza inizializzazione esplicita e i parametri a cui non sono stati dati i valori diventano sempre undefinede sono sempre nell'ambito.

  • che undefinedpuò essere sovrascritto. C'è molto di più in questo. undefinednon è una parola chiave in JavaScript. Invece, è una proprietà sull'oggetto globale con il valore Non definito. Tuttavia, da ES5, questa proprietà è stata di sola lettura e non configurabile . Nessun browser moderno consentirà di modificare la undefinedproprietà e dal 2017 questo è stato il caso per molto tempo. La mancanza di una modalità rigorosa non influisce nemmeno sul undefinedcomportamento - fa solo affermazioni come undefined = 5non fare nulla invece di lanciare. Dal momento che non è una parola chiave, tuttavia, è possibile dichiarare variabili con il nome undefinede tali variabili potrebbero essere modificate, rendendo questo modello una volta comune:

    (function (undefined) {
        // …
    })()

    più pericoloso che usare il globale undefined. Se devi essere compatibile undefinedcon ES3, sostituiscilo con void 0- non ricorrere a typeof. ( voidè sempre stato un operatore unario che valuta il valore Non definito per qualsiasi operando.)

Con il modo in cui le variabili funzionano, è il momento di rispondere alla domanda effettiva: proprietà dell'oggetto. Non c'è motivo di utilizzare mai typeofper le proprietà degli oggetti. L'eccezione precedente relativa al rilevamento di funzionalità non si applica qui: typeofha solo un comportamento speciale sulle variabili e le espressioni che fanno riferimento alle proprietà degli oggetti non sono variabili.

Questo:

if (typeof foo.bar === 'undefined') {
    
}

è sempre esattamente equivalente a questo³:

if (foo.bar === undefined) {
    
}

e tenendo conto dei consigli di cui sopra, per evitare di confondere i lettori sul perché stai usando typeof, perché ha più senso usare ===per verificare l'uguaglianza, perché potrebbe essere rifattorizzato per controllare il valore di una variabile in un secondo momento, e perché semplicemente sembra migliore, dovresti sempre usare anche === undefined³ anche qui .

Qualcos'altro da considerare quando si tratta di proprietà degli oggetti è se si vuole davvero controllare undefined. Un determinato nome di proprietà può essere assente su un oggetto (producendo il valore undefineddurante la lettura), presente sull'oggetto stesso con il valore undefined, presente sul prototipo dell'oggetto con il valore undefinedo presente su uno di quelli con prototipi non oggetto su MDN per più!undefined valore. 'key' in objti dirà se una chiave si trova ovunque nella catena di prototipi di un oggetto e Object.prototype.hasOwnProperty.call(obj, 'key')ti dirà se si trova direttamente sull'oggetto. Non entrerò nei dettagli in questa risposta sui prototipi e sull'uso di oggetti come mappe con stringhe di chiavi, perché è principalmente inteso a contrastare tutti i cattivi consigli in altre risposte, indipendentemente dalle possibili interpretazioni della domanda originale. Leggere su

¹ insolita scelta del nome della variabile di esempio? questo è un vero codice morto dall'estensione NoScript per Firefox.
² Non dare per scontato che non sapere cosa rientri nel campo di applicazione va bene in generale. vulnerabilità del bonus causata dall'abuso di ambito dinamico: Project Zero 1225
³ ancora una volta assumendo un ambiente ES5 + e che si undefinedriferisce alla undefinedproprietà dell'oggetto globale. sostituire void 0altrimenti.


@BenjaminGruenbaum Vero ma completamente fuorviante. Qualsiasi contesto non predefinito può definirne uno proprio undefined, nascondendo quello predefinito. Che per scopi pratici ha lo stesso effetto della sovrascrittura.
blgt

23
@blgt È paranoico e irrilevante per qualsiasi cosa pratica. Ogni contesto può sovrascrivere console.log, ridefinire i metodi del prototipo di array e persino ignorare l'aggancio di Function.prototype.call` e modificarlo ogni volta che si chiama una funzione in JavaScript. Proteggersi da questo è molto paranoico e piuttosto sciocco. Come ho detto io (e minitech), puoi usare il void 0confronto con indefinito, ma ancora una volta - è sciocco e eccessivo.
Benjamin Gruenbaum,

19
Vorrei avere più di un voto da dare. Questa è la risposta più corretta Voglio davvero smettere di vedere typeof something === "undefined") nel codice.
Simon Baumgardt-Wellander,

@BenjaminGruenbaum Per i programmatori pigri, void 0è (per una volta) sia più breve che più sicuro! Questa è una vittoria nel mio libro.
wizzwizz4,

4
Questa dovrebbe davvero essere la risposta accettata. È il più completo e aggiornato.
Patrick Michaelsen,

161

In JavaScript c'è null e non è definito . Hanno significati diversi.

  • indefinito significa che il valore della variabile non è stato definito; non si sa quale sia il valore.
  • null significa che il valore della variabile è definito e impostato su null (non ha valore).

Marijn Haverbeke afferma, nel suo libro online gratuito " Eloquent JavaScript " (sottolineatura mia):

Esiste anche un valore simile, null, il cui significato è "questo valore è definito, ma non ha un valore". La differenza di significato tra indefinito e nullo è per lo più accademica e di solito non molto interessante. Nei programmi pratici, è spesso necessario verificare se qualcosa "ha un valore". In questi casi, è possibile utilizzare l'espressione qualcosa == indefinito, perché, anche se non hanno esattamente lo stesso valore, null == indefinito produrrà vero.

Quindi, immagino che il modo migliore per verificare se qualcosa non era definito sarebbe:

if (something == undefined)

Spero che sia di aiuto!

Modifica: in risposta alla modifica, le proprietà degli oggetti dovrebbero funzionare allo stesso modo.

var person = {
    name: "John",
    age: 28,
    sex: "male"
};

alert(person.name); // "John"
alert(person.fakeVariable); // undefined

42
if (qualcosa == undefined) è meglio scritto come se (qualcosa === undefined)
Sebastian Rittau

59
Va sottolineato che questo non è del tutto sicuro. undefinedè solo una variabile che può essere riassegnata dall'utente: la scrittura undefined = 'a';farà sì che il tuo codice non faccia più ciò che pensi che faccia. L'uso typeofè migliore e funziona anche per variabili (non solo proprietà) che non sono state dichiarate.
Gabe Moothart,

7
se qualcosa è una variabile globale non definita, (qualcosa == non definito) viene visualizzato l'errore javascript.
Morgan Cheng,

8
Il problema è che se var a = null allora a == undefined restituisce true, anche se a è sicuramente definito.
Andrew,

6
Questa interpretazione del commento "Eloquent Javascript" è arretrata . Se vuoi davvero controllare se non è definito, il codice suggerito non funzionerà (rileverà anche la condizione definita ma nessun valore è stato ancora assegnato [ienull]). Un valore nullo. Il codice suggerito "if (qualcosa == undefined) ..." controlla sia undefined che null (nessun valore impostato), cioè è interpretato come "if ((qualcosa non è definito) OPPURE (qualcosa è null)) ..." Ciò che l'autore sta dicendo è che spesso ciò che vuoi veramente è controllare sia indefinito che nullo.
Chuck Kollars,

125

Cosa significa: "proprietà dell'oggetto non definito" ?

In realtà può significare due cose abbastanza diverse! Innanzitutto, può indicare la proprietà che non è mai stata definita nell'oggetto e, in secondo luogo, può indicare la proprietà che ha un valore indefinito . Diamo un'occhiata a questo codice:

var o = { a: undefined }

È o.aindefinito? Sì! Il suo valore non è definito. È o.bindefinito? Sicuro! Non esiste alcuna proprietà "b"! OK, vedi ora come si comportano approcci diversi in entrambe le situazioni:

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

Possiamo vederlo chiaramente typeof obj.prop == 'undefined'e obj.prop === undefinedsono equivalenti e non distinguono queste diverse situazioni. E'prop' in obj può rilevare la situazione quando una proprietà non è stata definita affatto e non presta attenzione al valore della proprietà che potrebbe non essere definito.

Quindi che si fa?

1) Vuoi sapere se una proprietà non è definita dal primo o dal secondo significato (la situazione più tipica).

obj.prop === undefined // IMHO, see "final fight" below

2) Vuoi solo sapere se l'oggetto ha delle proprietà e non ti interessa il suo valore.

'prop' in obj

Appunti:

  • Non puoi controllare un oggetto e le sue proprietà allo stesso tempo. Ad esempio, questo x.a === undefinedo questo typeof x.a == 'undefined'aumenta ReferenceError: x is not definedse x non è definito.
  • La variabile undefinedè una variabile globale (quindi in realtà è window.undefinednei browser). E 'stato sostenuto dal ECMAScript Edition 1 ° e dal momento ECMAScript 5 è in sola lettura . Quindi nei browser moderni non può essere ridefinito come vero poiché molti autori amano spaventarci, ma questo è ancora vero per i browser più vecchi.

Lotta finale: obj.prop === undefinedvstypeof obj.prop == 'undefined'

Vantaggi di obj.prop === undefined:

  • È un po 'più corto e sembra un po' più carino
  • Il motore JavaScript ti darà un errore se hai sbagliato l'ortografia undefined

Svantaggi di obj.prop === undefined:

  • undefined può essere sostituito nei vecchi browser

Vantaggi di typeof obj.prop == 'undefined':

  • È davvero universale! Funziona con browser nuovi e vecchi.

Svantaggi di typeof obj.prop == 'undefined':

  • 'undefned'( errato ) qui è solo una costante di stringa, quindi il motore JavaScript non può aiutarti se l'hai scritto male come ho appena fatto.

Aggiornamento (per JavaScript lato server):

Node.js supporta la variabile globale undefinedcome global.undefined(può anche essere usata senza il prefisso "globale"). Non conosco altre implementazioni di JavaScript lato server.


@Bergi grazie per il tuo commento. Ho corretto la mia risposta. A mia difesa, posso dire che attualmente (a partire dalla versione 1.0.18) la documentazione ufficiale di Node.js non dice nulla undefinedcome membro di global. Inoltre, né console.log(global);for (var key in global) { ... }mostra non definito come membro del globale . Ma prova come 'undefined' in globalmostra il contrario.
Konstantin Smolyanin,

4
Non aveva bisogno di ulteriore documentazione poiché è nelle specifiche EcmaScript , che dice anche che [[Enumerable]]è falso :-)
Bergi

5
Per quanto riguarda Minuses of typeof obj.prop == 'undefined', questo può essere evitato scrivendo come typeof obj.prop == typeof undefined. Questo dà anche una simmetria molto bella.
hlovdal

3
@hlovdal: Questo è contro tutto inutile obj.prop === undefined.
Ry-

1
Quando siamo fedeli al titolo della domanda " Rilevare una proprietà indefinita" , non fedele alla domanda (diversa e molto più semplice) nella prima frase ("controlla se non definita ..."), rispondi if ('foo' in o) ... la tua risposta è davvero la prima risposta corretta qui. Praticamente tutti gli altri rispondono solo a quella frase.
Frank Nocke,

70

Il problema si riduce a tre casi:

  1. L'oggetto ha la proprietà e il suo valore no undefined .
  2. L'oggetto ha la proprietà e il suo valore è undefined.
  3. L'oggetto non ha la proprietà.

Questo ci dice qualcosa che considero importante:

Esiste una differenza tra un membro non definito e un membro definito con un valore non definito.

Ma purtroppo typeof obj.foonon ci dice quale dei tre casi abbiamo. Tuttavia, possiamo combinare questo con "foo" in objper distinguere i casi.

                               |  typeof obj.x === 'undefined' | !("x" in obj)
1.                     { x:1 } |  false                        | false
2.    { x : (function(){})() } |  true                         | false
3.                          {} |  true                         | true

Vale la pena notare che questi test sono gli stessi anche per le nullvoci

                               |  typeof obj.x === 'undefined' | !("x" in obj)
                    { x:null } |  false                        | false

Direi che in alcuni casi ha più senso (ed è più chiaro) verificare se la proprietà è presente, piuttosto che verificare se non è definita, e l'unico caso in cui questo controllo sarà diverso è il caso 2, il raro caso di una voce effettiva nell'oggetto con un valore indefinito.

Ad esempio: ho appena eseguito il refactoring di un gruppo di codice che aveva un sacco di controlli se un oggetto avesse una determinata proprietà.

if( typeof blob.x != 'undefined' ) {  fn(blob.x); }

Che era più chiaro se scritto senza un segno di spunta per indefinito.

if( "x" in blob ) { fn(blob.x); }

Ma come è stato menzionato, questi non sono esattamente gli stessi (ma sono più che sufficienti per le mie esigenze).


10
Ciao Michael Ottimo consiglio, e penso che renda le cose più pulite. Un gotcha che ho trovato, tuttavia, è quando si usa il! operatore con "in". Devi dire if (!("x" in blob)) {}con parentesi attorno a in, perché il! l'operatore ha la precedenza su "in". Spero che aiuti qualcuno.
Simon East,

Mi dispiace Michael, ma questo non è corretto, o almeno fuorviante, alla luce della domanda originale. 'in' non è un modo sufficiente per verificare se una proprietà dell'oggetto ha un tipo indefinito. Per la prova, vedi questo violino: jsfiddle.net/CsLKJ/4
tex

2
Queste due parti di codice fanno una cosa diversa! Considerare e oggetto dato da a = {b: undefined}; allora typeof a.b === typeof a.c === 'undefined'ma 'b' in ae !('c' in a).
mgol,

3
+1. L'OP non chiarisce se la proprietà esiste e ha un valore indefinito o se la proprietà stessa non è definita (cioè non esiste).
RobG

Suggerirei di cambiare il punto (2.) nella tua prima tabella { x : undefined }o almeno aggiungerlo come un'altra alternativa a (2.) nella tabella - Ho dovuto pensare per un momento a rendermi conto che il punto (2.) valuta undefined(sebbene lo dici più avanti).
mucaho,

46
if ( typeof( something ) == "undefined") 

Questo ha funzionato per me mentre gli altri no.


47
le parentesi non sono necessarie poiché typeof è un operatore
aehlke,

12
Ma rendono più chiaro ciò che viene controllato. Altrimenti potrebbe essere letto come typeof (something == "undefined").
Abhi Beckert,

Se hai bisogno delle parentesi, dovresti imparare la precedenza dell'operatore in JS: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Ian

11
Le parentesi sono utili proprio perché NON è necessario apprendere la precedenza dell'operatore in JS, né è necessario ipotizzare se i futuri programmatori di manutenzione dovranno apprendere la precedenza dell'operatore in JS.
DaveWalley,

27
Le parentesi sono utili per chiarire le cose. Ma in questo caso fanno sembrare l'operatore una funzione. Senza dubbio questo chiarisce l'intento del programmatore. Ma se non sei sicuro della precedenza dell'operatore, dovresti piuttosto scriverlo come (typeof something) === "undefined".
Robert

42

Io non sono sicuro di dove l'origine di utilizzare ===con typeofprovenienza, e come una convenzione vedo io usato in molte biblioteche, ma l'operatore typeof restituisce una stringa letterale, e sappiamo che davanti, in modo perché si vuole anche per tipo controlla anche tu?

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

Ottimo punto Eric. C'è un impatto sulle prestazioni anche dal controllo del tipo?
Simon East,

5
@Simon: al contrario - ci si potrebbe aspettare un leggero calo delle prestazioni evitando la coercizione nel caso '==='. Il test rapido e sporco ha mostrato che "===" è del 5% più veloce di "==" in FF5.0.1
Antony Hatchkins il

5
Test più approfonditi hanno dimostrato che in FF, IE e Chrome "==" è più o meno veloce di "===" (5-10%) e Opera non fa alcuna differenza: jsperf.com/triple- uguale a vs due volte uguale / 6
Antony Hatchkins il

3
L'utilizzo ==richiede ancora almeno un controllo del tipo: l'interprete non può confrontare i due operandi senza prima conoscerne il tipo.
Alnitak,

7
==è un personaggio in meno di ===:)
svidgen,

25

Crossposting della mia risposta dalla domanda correlata Come verificare la presenza di "non definito" in JavaScript?

Specifico per questa domanda, vedere i casi di test con someObject.<whatever>.


Alcuni scenari che illustrano i risultati delle varie risposte: http://jsfiddle.net/drzaus/UVjM4/

(Si noti che l'uso di varper i intest fa la differenza in un wrapper con ambito)

Codice di riferimento:

(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;
    }
})();

E risultati:

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

21

Se fate

if (myvar == undefined )
{ 
    alert('var does not exists or is not initialized');
}

fallirà quando la variabile myvarnon esiste, perché myvar non è definito, quindi lo script è rotto e il test non ha alcun effetto.

Poiché l'oggetto window ha un ambito globale (oggetto predefinito) al di fuori di una funzione, una dichiarazione verrà "allegata" all'oggetto window.

Per esempio:

var myvar = 'test';

La variabile globale myvar è la stessa di window.myvar o window ['myvar']

Per evitare errori da testare quando esiste una variabile globale, è meglio usare:

if(window.myvar == undefined )
{ 
    alert('var does not exists or is not initialized');
}

La domanda se esiste davvero una variabile non ha importanza, il suo valore non è corretto. Altrimenti, è sciocco inizializzare le variabili con undefined, ed è meglio usare il valore false per inizializzare. Quando sai che tutte le variabili che dichiari sono inizializzate con false, puoi semplicemente verificarne il tipo o fare affidamento !window.myvarper verificare se ha un valore corretto / valido. Quindi, anche quando la variabile non è definita, !window.myvarè uguale per myvar = undefinedo myvar = falseo myvar = 0.

Quando ti aspetti un tipo specifico, prova il tipo di variabile. Per accelerare il test di una condizione è meglio fare:

if( !window.myvar || typeof window.myvar != 'string' )
{
    alert('var does not exists or is not type of string');
}

Quando la prima e semplice condizione è vera, l'interprete salta i test successivi.

È sempre meglio usare l'istanza / oggetto della variabile per verificare se ha ottenuto un valore valido. È più stabile ed è un modo migliore di programmare.

(Y)


19

Non ho visto (spero di non essermi perso) nessuno che controllava l'oggetto prima della proprietà. Quindi, questo è il più breve ed efficace (anche se non necessariamente il più chiaro):

if (obj && obj.prop) {
  // Do something;
}

Se obj o obj.prop è indefinito, null o "falsy", l'istruzione if non eseguirà il blocco di codice. Questo è generalmente il comportamento desiderato nella maggior parte delle istruzioni di blocco di codice (in JavaScript).


2
Se vuoi sapere perché funziona: Javascript: Operatori logici e verità / falsità
mb21

se si desidera assegnare la proprietà a una variabile se è definita, non nulla e non è falsa, altrimenti utilizzare un valore predefinito, è possibile utilizzare: var x = obj && obj.prop || 'default';
Stijn de Witt

Credo che la domanda sia per il controllo esplicito contro indefinito. La tua condizione verifica tutti i falsi valori di JS.
NikoKyriakid,

15

Nell'articolo Exploring the Abyss of Null and Undefined in JavaScript ho letto che framework come Underscore.js usano questa funzione:

function isUndefined(obj){
    return obj === void 0;
}

3
void 0è solo un modo breve di scrivere undefined(dato che è ciò che il vuoto seguito da qualsiasi espressione restituisce), salva 3 caratteri. Potrebbe anche fare var a; return obj === a;, ma questo è un altro personaggio. :-)
RobG

2
voidè una parola riservata, mentre undefinednon è cioè mentre undefinedè uguale per void 0impostazione predefinita, è possibile assegnare un valore ad undefinedes undefined = 1234.
Brian M. Hunt,

isUndefined(obj): 16 caratteri. obj === void 0: 14 caratteri. 'ha detto nough.
Stijn de Witt,

14

Semplicemente qualsiasi cosa non è definita in JavaScript, non è definita , non importa se si tratta di una proprietà all'interno di un oggetto / matrice o come una semplice variabile ...

JavaScript ha typeofche rende molto facile rilevare una variabile non definita.

Basta controllare se typeof whatever === 'undefined'e restituirà un valore booleano.

Ecco come isUndefined()è scritta la famosa funzione in AngularJs v.1x:

function isUndefined(value) {return typeof value === 'undefined';} 

Così come vedi la funzione riceve un valore, se quel valore è definito, ritornerà false, altrimenti restituisce valori non definiti true.

Quindi diamo un'occhiata a quali saranno i risultati quando passiamo i valori, comprese le proprietà degli oggetti come di seguito, questo è l'elenco delle variabili che abbiamo:

var stackoverflow = {};
stackoverflow.javascipt = 'javascript';
var today;
var self = this;
var num = 8;
var list = [1, 2, 3, 4, 5];
var y = null;

e li controlliamo come di seguito, puoi vedere i risultati davanti a loro come un commento:

isUndefined(stackoverflow); //false
isUndefined(stackoverflow.javascipt); //false
isUndefined(today); //true
isUndefined(self); //false
isUndefined(num); //false
isUndefined(list); //false
isUndefined(y); //false
isUndefined(stackoverflow.java); //true
isUndefined(stackoverflow.php); //true
isUndefined(stackoverflow && stackoverflow.css); //true

Come vedi possiamo controllare qualsiasi cosa usando qualcosa di simile nel nostro codice, come detto puoi semplicemente usare typeofnel tuo codice, ma se lo usi più e più volte, crea una funzione come il campione angolare che condivido e continui a riutilizzare come seguendo il modello di codice DRY.

Inoltre, per verificare la proprietà di un oggetto in un'applicazione reale di cui non si è certi che esista o meno l'oggetto, verificare se l'oggetto esiste per primo.

Se si controlla una proprietà su un oggetto e l'oggetto non esiste, verrà generato un errore e verrà interrotta l'intera applicazione.

isUndefined(x.css);
VM808:2 Uncaught ReferenceError: x is not defined(…)

Così semplice che puoi avvolgere in un'istruzione if come di seguito:

if(typeof x !== 'undefined') {
  //do something
}

Che equivale anche a isDefined in Angular 1.x ...

function isDefined(value) {return typeof value !== 'undefined';}

Anche altri framework javascript come underscore hanno un controllo di definizione simile, ma ti consiglio di usare typeofse non usi già alcun framework.

Aggiungo anche questa sezione da MDN che contiene informazioni utili su typeof, undefined e void (0).

Uguaglianza rigorosa e non definita
È possibile utilizzare operatori di uguaglianza e disuguaglianza non definiti e rigorosi per determinare se una variabile ha un valore. Nel codice seguente, la variabile x non è definita e l'istruzione if restituisce true.

var x;
if (x === undefined) {
   // these statements execute
}
else {
   // these statements do not execute
}

Nota: l'operatore di uguaglianza rigorosa anziché l'operatore di uguaglianza standard deve essere utilizzato qui, perché x == undefined controlla anche se x è null, mentre l'uguaglianza rigorosa no. null non equivale a undefined. Vedi gli operatori di confronto per i dettagli.


Tipo di operatore e non definito
In alternativa, è possibile utilizzare il tipo di:

var x;
if (typeof x === 'undefined') {
   // these statements execute
}

Un motivo per utilizzare typeof è che non genera un errore se la variabile non è stata dichiarata.

// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
   // these statements execute
}

if (x === undefined) { // throws a ReferenceError

}

Tuttavia, questo tipo di tecnica dovrebbe essere evitato. JavaScript è un linguaggio con ambito statico, quindi è possibile leggere se viene dichiarata una variabile verificando se è dichiarata in un contesto chiuso. L'unica eccezione è l'ambito globale, ma l'ambito globale è associato all'oggetto globale, pertanto è possibile verificare l'esistenza di una variabile nel contesto globale verificando l'esistenza di una proprietà sull'oggetto globale (utilizzando l'operatore in, per esempio).


Operatore del vuoto e non definito

L'operatore vuoto è una terza alternativa.

var x;
if (x === void 0) {
   // these statements execute
}

// y has not been declared before
if (y === void 0) {
   // throws a ReferenceError (in contrast to `typeof`)
}

altro> qui


13

' if (window.x) {} ' è sicuro

Molto probabilmente lo vuoi if (window.x). Questo controllo è sicuro anche se x non è stato dichiarato ( var x;) - il browser non genera un errore.

Esempio: voglio sapere se il mio browser supporta l'API Cronologia

if (window.history) {
    history.call_some_function();
}

Come funziona:

window è un oggetto che contiene tutte le variabili globali come membri ed è legale tentare di accedere a un membro inesistente. Se x non è stato dichiarato o non è stato impostato, window.xrestituisce un valore non definito . undefined porta a false quando if () lo valuta.


Ma cosa succede se corri in Node? typeof history != 'undefined'funziona effettivamente in entrambi i sistemi.
Stijn de Witt,

13

Leggendo questo, sono stupito di non averlo visto. Ho trovato più algoritmi che avrebbero funzionato per questo.

Mai definito

Se il valore di un oggetto non è mai stato definito, ciò impedirà la restituzione truese è definito come nullo undefined. Ciò è utile se si desidera che true venga restituito per i valori impostati comeundefined

if(obj.prop === void 0) console.log("The value has never been defined");

Definito come indefinito o mai definito

Se vuoi che risulti come trueper i valori definiti con il valore di undefined, o mai definiti, puoi semplicemente usare=== undefined

if(obj.prop === undefined) console.log("The value is defined as undefined, or never defined");

Definito come valore errato, indefinito, nullo o mai definito.

Comunemente, le persone mi hanno chiesto un algoritmo per capire se un valore è falso undefined, o null. I seguenti lavori.

if(obj.prop == false || obj.prop === null || obj.prop === undefined) {
    console.log("The value is falsy, null, or undefined");
}

4
Penso che puoi sostituire l'ultimo esempio conif (!obj.prop)
Stijn de Witt,

@StijndeWitt, puoi, ero abbastanza inesperto quando ho scritto questo, e il mio inglese sembra essere stato ugualmente cattivo, tuttavia, non c'è nulla di sbagliato nella risposta
Travis

3
var obj = {foo: undefined}; obj.foo === void 0-> true. Come è "mai definito come undefined"? Questo è sbagliato.
Patrick Roberts,

@PatrickRoberts Hai ragione. Quando ho scritto questa risposta nel febbraio 2015 (prima dell'ES6), la prima opzione che ho delineato ha funzionato, ma ora è obsoleta.
Travis

12
"propertyName" in obj //-> true | false

10

Confronta con void 0, per terseness.

if (foo !== void 0)

Non è così prolisso come if (typeof foo !== 'undefined')


3
Ma genererà un ReferenceError se foonon è dichiarato.
daniel1426

1
@ daniel1426: Quindi se c'è un errore nel tuo codice, vuoi nasconderlo invece di ripararlo? Non è un ottimo approccio, IMO.

Questo non è usato per nascondere errori. È il modo comune di rilevare le proprietà dell'ambiente per definire i polifilloli. Ad esempio: if (typeof Promise === 'undefined') {/ * define Promise * /}
gaperton

10

La soluzione non è corretta In JavaScript,

null == undefined

tornerà vero, perché entrambi sono "espressi" in un valore booleano e sono falsi. Il modo corretto sarebbe quello di verificare

if (something === undefined)

che è l'operatore di identità ...


3
Per essere chiari, ===è tipo uguaglianza + (uguaglianza primitiva | identità dell'oggetto), dove le primitive includono stringhe. Penso che molte persone considerino 'abab'.slice(0,2) === 'abab'.slice(2)non intuitivo se si considera ===l'operatore di identità.
Clacke,

1
Sbagliato. Ciò genera un errore se la variabile non è stata creata. Non dovrebbe essere votato. Usa invece typeof.
Simon East,

10

È possibile ottenere un array tutto non definito con percorso utilizzando il seguente codice.

 function getAllUndefined(object) {

        function convertPath(arr, key) {
            var path = "";
            for (var i = 1; i < arr.length; i++) {

                path += arr[i] + "->";
            }
            path += key;
            return path;
        }


        var stack = [];
        var saveUndefined= [];
        function getUndefiend(obj, key) {

            var t = typeof obj;
            switch (t) {
                case "object":
                    if (t === null) {
                        return false;
                    }
                    break;
                case "string":
                case "number":
                case "boolean":
                case "null":
                    return false;
                default:
                    return true;
            }
            stack.push(key);
            for (k in obj) {
                if (obj.hasOwnProperty(k)) {
                    v = getUndefiend(obj[k], k);
                    if (v) {
                        saveUndefined.push(convertPath(stack, k));
                    }
                }
            }
            stack.pop();

        }

        getUndefiend({
            "": object
        }, "");
        return saveUndefined;
    }

Collegamento jsFiddle


Sebbene ciò non influisca sulla validità del tuo codice, hai un refuso: getUndefienddovrebbe essere getUndefined.
icktoofay

8

Ecco la mia situazione:

Sto usando il risultato di una chiamata REST. Il risultato deve essere analizzato da JSON a un oggetto JavaScript.

C'è un errore che devo difendere. Se l'args alla chiamata di riposo era errato per quanto l'utente specificava l'args errata, la chiamata di riposo ritorna sostanzialmente vuota.

Durante l'utilizzo di questo post per aiutarmi a difendermi da questo, ho provato questo.

if( typeof restResult.data[0] === "undefined" ) { throw  "Some error"; }

Per la mia situazione, se restResult.data [0] === "oggetto", posso tranquillamente iniziare a ispezionare il resto dei membri. Se non definito, gettare l'errore come sopra.

Quello che sto dicendo è che per la mia situazione, tutti i suggerimenti sopra riportati in questo post non hanno funzionato. Non sto dicendo che ho ragione e tutti hanno torto. Non sono affatto un maestro JavaScript, ma spero che questo possa aiutare qualcuno.


La tua typeofguardia in realtà non protegge da nulla che un confronto diretto non possa gestire. Se restResultnon definito o non dichiarato, verrà comunque lanciato.

Nel tuo caso, puoi semplicemente verificare se l'array è vuoto:if(!restResult.data.length) { throw "Some error"; }
Headbank,

8

Esiste un modo semplice ed elegante per assegnare una proprietà definita a una nuova variabile se è definita o assegnare un valore predefinito ad essa come fallback se non definito.

var a = obj.prop || defaultValue;

È adatto se si dispone di una funzione, che riceve una proprietà di configurazione aggiuntiva:

var yourFunction = function(config){

   this.config = config || {};
   this.yourConfigValue = config.yourConfigValue || 1;
   console.log(this.yourConfigValue);

}

Ora in esecuzione

yourFunction({yourConfigValue:2});
//=> 2

yourFunction();
//=> 1

yourFunction({otherProperty:5});
//=> 1

7

Tutte le risposte sono incomplete. Questo è il modo giusto di sapere che esiste una proprietà "definita come non definita":

var hasUndefinedProperty = function hasUndefinedProperty(obj, prop){
  return ((prop in obj) && (typeof obj[prop] == 'undefined')) ;
} ;

Esempio:

var a = { b : 1, e : null } ;
a.c = a.d ;

hasUndefinedProperty(a, 'b') ; // false : b is defined as 1
hasUndefinedProperty(a, 'c') ; // true : c is defined as undefined
hasUndefinedProperty(a, 'd') ; // false : d is undefined
hasUndefinedProperty(a, 'e') ; // false : e is defined as null

// And now...
delete a.c ;
hasUndefinedProperty(a, 'c') ; // false : c is undefined

Peccato che questa sia la risposta giusta sia sepolta in risposte sbagliate> _ <

Quindi, per chiunque passi, ti darò gratuitamente undefined !!

var undefined ; undefined ; // undefined
({}).a ;                    // undefined
[].a ;                      // undefined
''.a ;                      // undefined
(function(){}()) ;          // undefined
void(0) ;                   // undefined
eval() ;                    // undefined
1..a ;                      // undefined
/a/.a ;                     // undefined
(true).a ;                  // undefined

7

Passando attraverso i commenti, per coloro che vogliono controllare entrambi è indefinito o il suo valore è nullo:

//Just in JavaScript
var s; // Undefined
if (typeof s == "undefined" || s === null){
    alert('either it is undefined or value is null')
}

Se stai utilizzando la libreria jQuery, jQuery.isEmptyObject()sarà sufficiente per entrambi i casi,

var s; // Undefined
jQuery.isEmptyObject(s); // Will return true;

s = null; // Defined as null
jQuery.isEmptyObject(s); // Will return true;

//Usage
if (jQuery.isEmptyObject(s)) {
    alert('Either variable:s is undefined or its value is null');
} else {
     alert('variable:s has value ' + s);
}

s = 'something'; // Defined with some value
jQuery.isEmptyObject(s); // Will return false;

jQuery si occuperà anche di eventuali problemi di compatibilità tra browser con le diverse API JavaScript.
Henry Heleine,

7

Se si utilizza Angular:

angular.isUndefined(obj)
angular.isUndefined(obj.prop)

Underscore.js:

_.isUndefined(obj) 
_.isUndefined(obj.prop) 

2
Come aggiungo 1alla variabile x? Ho bisogno di Underscore o jQuery? (sorprendente che le persone useranno le librerie anche per le operazioni più elementari come un typeofcontrollo)
Stijn de Witt

6

Uso if (this.variable)per verificare se è definito. Semplice if (variable), consigliato sopra , fallisce per me. Si scopre che funziona solo quando la variabile è un campo di un oggetto, obj.someFieldper verificare se è definito nel dizionario. Ma possiamo usare thiso windowcome oggetto dizionario poiché qualsiasi variabile è un campo nella finestra corrente, a quanto ho capito. Pertanto, ecco un test

if (this.abc) alert("defined"); else alert("undefined");

abc = "abc";
if (this.abc) alert("defined"); else alert("undefined");

Rileva innanzitutto che la variabile abcnon è definita e viene definita dopo l'inizializzazione.


5

Fornisco tre modi qui per coloro che si aspettano risposte strane:

function isUndefined1(val) {
    try {
        val.a;
    } catch (e) {
        return /undefined/.test(e.message);
    }
    return false;
}
function isUndefined2(val) {
    return !val && val+'' === 'undefined';
}
function isUndefined3(val) {
    const defaultVal={};
    return ((input=defaultVal)=>input===defaultVal)(val);
}
function test(func){
    console.group(`test start :`+func.name);
    console.log(func(undefined));
    console.log(func(null));
    console.log(func(1));
    console.log(func("1"));
    console.log(func(0));
    console.log(func({}));
    console.log(func(function () { }));
    console.groupEnd();
}
test(isUndefined1);
test(isUndefined2);
test(isUndefined3);

isUndefined1:

Prova a ottenere una proprietà del valore di input, controlla il messaggio di errore se esiste. Se il valore di input non è definito, il messaggio di errore sarebbe Uncaught TypeError: Impossibile leggere la proprietà 'b' di undefined

isUndefined2:

Converti il ​​valore di input in stringa per confrontarlo "undefined"e assicurati che sia un valore negativo.

isUndefined3:

In js, il parametro opzionale funziona quando il valore di input è esattamente undefined.


5

ES2019 ha introdotto una nuova funzione - concatenamento opzionale che è possibile utilizzare per utilizzare una proprietà di un oggetto solo quando un oggetto è definito in questo modo:

const userPhone = user?.contactDetails?.phone;

Si farà riferimento alla proprietà del telefono solo quando sono definiti user e contactDetails.

Ref. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining


Usavo molto la funzione che si ottiene da lodash, molto comoda per accedere a questo tipo di oggetti, ma il nuovo concatenamento opzionale copre la maggior parte degli usi di _.get
Al Hill

4
function isUnset(inp) {
  return (typeof inp === 'undefined')
}

Restituisce false se la variabile è impostata e true se non è definito.

Quindi utilizzare:

if (isUnset(var)) {
  // initialize variable here
}

5
No. Non farlo. È sufficiente un test molto semplice per dimostrare che non è possibile racchiudere in modo significativo un typeoftest in una funzione. Incredibile che 4 persone abbiano votato per questo. -1.
Stijn de Witt,

4

Vorrei mostrarti qualcosa che sto usando per proteggere la undefinedvariabile:

Object.defineProperty(window, 'undefined', {});

Ciò vieta a chiunque di modificare il window.undefinedvalore, distruggendo quindi il codice basato su quella variabile. Se si utilizza "use strict", qualsiasi cosa che provi a modificarne il valore finirà per errore, altrimenti verrebbe ignorato silenziosamente.


4

puoi anche usare Proxy, funzionerà con le chiamate nidificate, ma richiederà un controllo extra:

function resolveUnknownProps(obj, resolveKey) {
  const handler = {
    get(target, key) {
      if (
        target[key] !== null &&
        typeof target[key] === 'object'
      ) {
        return resolveUnknownProps(target[key], resolveKey);
      } else if (!target[key]) {
        return resolveUnknownProps({ [resolveKey]: true }, resolveKey);
      }

      return target[key];
    },
  };

  return new Proxy(obj, handler);
}

const user = {}

console.log(resolveUnknownProps(user, 'isUndefined').personalInfo.name.something.else); // { isUndefined: true }

quindi lo userai come:

const { isUndefined } = resolveUnknownProps(user, 'isUndefined').personalInfo.name.something.else;
if (!isUndefined) {
  // do someting
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.