variable - value is undefined in javascript
Rilevazione di una proprietà dell'oggetto non definita (20)
Qual è il modo migliore per verificare se una proprietà dell'oggetto in JavaScript non è definita?
' if (window.x) {} ' è sicuro da errori
Molto probabilmente lo vorrai 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 di cronologia
if (window.history) {
history.call_some_function();
}
Come funziona:
window è un oggetto che contiene tutte le variabili globali come membri ed è legale provare ad accedere a un membro non esistente. Se x non è stato dichiarato o non è stato impostato, window.x
restituisce undefined . undefined porta a false quando if () lo valuta.
Cosa significa: "proprietà dell'oggetto non definita" ?
In realtà può significare due cose completamente diverse! Primo, può significare la proprietà che non è mai stata definita nell'oggetto e, in secondo luogo, può significare la proprietà che ha un valore non definito . Diamo un'occhiata a questo codice:
var o = { a: undefined }
oa
è indefinito? Sì! Il suo valore non è definito. ob
è undefined? Sicuro! Non esiste affatto la proprietà "b"! OK, vedi ora come si comportano i diversi approcci 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 chiaramente vedere che typeof obj.prop == 'undefined'
e obj.prop === undefined
sono equivalenti e non distinguono queste diverse situazioni. E 'prop' in obj
grado di rilevare la situazione quando una proprietà non è stata definita affatto e non presta attenzione al valore della proprietà che può essere indefinito.
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 qualche proprietà e non importa del suo valore.
'prop' in obj
Gli appunti:
- Non è possibile controllare un oggetto e le sue proprietà contemporaneamente. Ad esempio, questo
xa === undefined
o questotypeof xa == 'undefined'
sollevaReferenceError: x is not defined
se x non è definito. - La variabile
undefined
è una variabile globale (quindi in realtà èwindow.undefined
nei browser). È stato supportato dalla prima edizione di ECMAScript e poiché ECMAScript 5 è di sola lettura . Quindi nei browser moderni non può essere ridefinito in modo vero come molti autori amano spaventarci, ma questo è ancora vero per i browser più vecchi.
Final fight: obj.prop === undefined
vs typeof obj.prop == 'undefined'
Plus 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
obj.prop === undefined
of obj.prop === undefined
:
-
undefined
può essere sovrascritto nei vecchi browser
Plus di typeof obj.prop == 'undefined'
:
- È davvero universale! Funziona con i browser nuovi e vecchi.
Minuses of typeof obj.prop == 'undefined'
:
-
'undefned'
( errato ) qui è solo una costante di stringa, quindi il motore JavaScript non può aiutarti se hai sbagliato ad ortografarlo come ho fatto io.
Aggiornamento (per JavaScript lato server):
Node.js supporta la variabile globale undefined
come global.undefined
(può anche essere utilizzata senza il prefisso 'global'). Non conosco altre implementazioni di JavaScript lato server.
Crossposting la mia answer dalla domanda correlata Come verificare la presenza di "undefined" in JavaScript?
Specifico per questa domanda, vedi 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 var
per i test fa la differenza quando si trova in un wrapper con scope)
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
Il problema si riduce a tre casi:
- L'oggetto ha la proprietà e il suo valore non è
undefined
. - L'oggetto ha la proprietà e il suo valore
undefined
èundefined
. - L'oggetto non ha la proprietà.
Questo ci dice qualcosa che considero importante:
C'è una differenza tra un membro indefinito e un membro definito con un valore non definito.
Ma sfortunatamente il typeof obj.foo
non ci dice quale dei tre casi abbiamo. Tuttavia possiamo combinare questo con "foo" in obj
per 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 uguali anche per le voci null
| typeof obj.x === 'undefined' | !("x" in obj)
{ x:null } | false | false
Direi che in alcuni casi ha più senso (ed è più chiaro) per verificare se la proprietà è lì, che controllare se è indefinito, e l'unico caso in cui questo controllo sarà diverso è il caso 2, il caso raro di una voce effettiva nell'oggetto con un valore non definito.
Ad esempio: ho appena effettuato 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 assegno per indefinito.
if( "x" in blob ) { fn(blob.x); }
Ma come è stato detto questi non sono esattamente gli stessi (ma sono più che sufficienti per le mie esigenze).
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, questo impedirà di restituire true
se è definito come null
o undefined
. Ciò è utile se si desidera che venga restituito true per i valori impostati come undefined
if(obj.prop === void 0) console.log("The value has never been defined");
Definito come non definito o mai definito
Se vuoi che diventi true
per i valori definiti con il valore di undefined
, o mai definito, puoi semplicemente usare === undefined
if(obj.prop === undefined) console.log("The value is defined as undefined, or never defined");
Definito come un valore falsy, 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");
}
Nell'articolo Exploring the Abyss of Null e Undefined in JavaScript ho letto che framework come Underscore.js utilizzano questa funzione:
function isUndefined(obj){
return obj === void 0;
}
Non sono sicuro da dove provenga l'origine dell'uso di ===
con typeof
, e come convenzione lo vedo usato in molte librerie, ma l'operatore typeof restituisce una stringa letterale, e lo sappiamo in anticipo, quindi perché dovresti vuoi anche controllarlo 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
Nonostante sia stato raccomandato con veemenza da molte altre risposte qui, typeof
è una cattiva scelta . Non dovrebbe mai essere usato per verificare se le variabili hanno un valore undefined
, perché agisce come un controllo combinato del valore undefined
e dell'esistenza di una variabile. Nella stragrande maggioranza dei casi, sai quando esiste una variabile, e typeof
introdurrà il potenziale per un errore silenzioso se scrivi un errore nel nome della variabile o nella stringa '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 non si stia eseguendo il rilevamento delle caratteristiche², dove c'è incertezza sulla presenza di un determinato nome nel campo di applicazione (come il controllo del typeof module !== 'undefined'
come passaggio nel codice specifico di un ambiente CommonJS), typeof
è una scelta dannosa quando viene utilizzato su una variabile e l'opzione corretta è quella di confrontare direttamente il valore:
var foo = …;
if (foo === undefined) {
⋮
}
Alcuni equivoci comuni su questo includono:
che la lettura di una variabile "non inizializzata" (
var foo
) o parametro (function bar(foo) { … }
, chiamata asbar()
) avrà esito negativo. Questo semplicemente non è vero - le variabili senza inizializzazione esplicita e i parametri a cui non sono stati dati i valori diventano sempreundefined
e sono sempre in ambito.che
undefined
può essere sovrascritto. C'è molto di più in questo.undefined
non è una parola chiave in JavaScript. Invece, è una proprietà sull'oggetto globale con il valore Non definito. Tuttavia, dal momento che ES5, questa proprietà è stata di sola lettura e non configurabile . Nessun browser moderno consentirà di modificare la proprietàundefined
e, a partire dal 2017, ciò è avvenuto da molto tempo. La mancanza di una modalità rigorosa non influisce sul comportamentoundefined
- rende solo dichiarazioni comeundefined = 5
non fare nulla invece di lanciare. Poiché non è una parola chiave, è possibile dichiarare variabili con il nomeundefined
e tali variabili potrebbero essere modificate, rendendo questo modello comune una volta:(function (undefined) { // … })()
più pericoloso dell'uso del globale
undefined
. Se devi essere compatibile ES3, sostituisciundefined
convoid 0
- non ricorrere atypeof
. (void
è sempre stato un operatore unario che valuta il valore Non definito per qualsiasi operando).
Con il modo in cui le variabili si disinteressano, è il momento di affrontare la vera domanda: le proprietà degli oggetti. Non c'è motivo di usare mai typeof
per le proprietà dell'oggetto. L'eccezione precedente relativa al rilevamento delle caratteristiche non si applica qui: typeof
ha solo un comportamento speciale sulle variabili e le espressioni che fanno riferimento alle proprietà dell'oggetto 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 motivo per cui stai usando typeof
, perché ha più senso usare ===
per verificare l'uguaglianza, perché potrebbe essere refactored per controllare il valore di una variabile più tardi, e perché sembra semplicemente migliore, dovresti sempre usare === undefined
³ anche qui .
Qualcos'altro da tenere in considerazione quando si tratta di proprietà degli oggetti è se si vuole veramente controllare per undefined
. Un dato nome di proprietà può essere assente su un oggetto (producendo il valore undefined
quando letto), presente sull'oggetto stesso con il valore undefined
, presente sul prototipo dell'oggetto con il valore undefined
o presente su uno di quelli con un valore non undefined
valore. 'key' in obj
ti dirà se una chiave è ovunque sulla catena di prototipi di un oggetto, e Object.prototype.hasOwnProperty.call(obj, 'key')
ti dirà se è direttamente sull'oggetto. Non andrò nei dettagli in questa risposta sui prototipi e sull'uso di oggetti come mappe a chiave stringa, però, perché è principalmente inteso a contrastare tutti i cattivi consigli in altre risposte, indipendentemente dalle possibili interpretazioni della domanda originale. Leggi su prototipi di oggetti su MDN per di più!
¹ scelta insolita del nome della variabile di esempio? questo è il vero codice morto dall'estensione NoScript per Firefox.
² non dare per scontato che non sapendo che cosa è in ambito è ok in generale, però. vulnerabilità bonus causata dall'abuso dello scope dinamico: Project Zero 1225
³ assumendo di nuovo un ambiente ES5 + e quello undefined
fa riferimento alla proprietà undefined
dell'oggetto globale. sostituto void 0
altrimenti.
Uso:
Per verificare se la proprietà non è definita:
if (typeof something === "undefined") {
alert("undefined");
}
Per verificare se la proprietà non è indefinita:
if (typeof something !== "undefined") {
alert("not undefined");
}
Uso:
if (typeof something === "undefined") {
alert("something is undefined");
}
Se una variabile oggetto che ha alcune proprietà puoi usare la stessa cosa in questo modo:
if (typeof my_obj.someproperties === "undefined"){
console.log('the property is not available...'); // print into console
}
Anche le stesse cose possono essere scritte più brevi:
if (!variable){
//do it if variable is Undefined
}
o
if (variable){
//do it if variable is Defined
}
C'è un modo bello ed elegante per assegnare una proprietà definita a una nuova variabile se è definita o assegnare un valore predefinito ad essa come una riserva se non è definita.
var a = obj.prop || defaultValue;
È adatto se hai 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
La soluzione non è corretta. In JavaScript,
null == undefined
ritornerà vero, perché entrambi sono "castati" su un booleano e sono falsi. Il modo corretto sarebbe di controllare
if (something === undefined)
che è l'operatore dell'identità ...
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 usando la libreria jQuery, allora 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;
Confronta con void 0
, per la precisione.
if (foo !== void 0)
Non è così verboso come if (typeof foo !== 'undefined')
Io uso if (this.variable)
per verificare se è definito. Semplice if (variable)
, consigliato sopra , non funziona per me. Si scopre che funziona solo quando la variabile è un campo di qualche oggetto, obj.someField
per verificare se è definita nel dizionario. Ma possiamo usare this
o window
come oggetto dizionario dal momento che qualsiasi variabile è un campo nella finestra corrente, come ho capito. Quindi ecco un test
if (this.abc) alert("defined"); else alert("undefined");
abc = "abc";
if (this.abc) alert("defined"); else alert("undefined");
In primo luogo rileva che la variabile abc
non è definita e viene definita dopo l'inizializzazione.
Sono sorpreso di non aver ancora visto questo suggerimento, ma ottiene ancora più specificità rispetto al test typeof
. Utilizzare Object.getOwnPropertyDescriptor()
se è necessario sapere se una proprietà dell'oggetto è stata inizializzata con undefined
o se non è mai stata inizializzata:
// to test someObject.someProperty
var descriptor = Object.getOwnPropertyDescriptor(someObject, 'someProperty');
if (typeof descriptor === 'undefined') {
// was never initialized
} else if (typeof descriptor.value === 'undefined') {
if (descriptor.get || descriptor.set) {
// is an accessor property, defined via getter and setter
} else {
// is initialized with `undefined`
}
} else {
// is initialized with some other value
}
Tutte le risposte sono incomplete. Questo è il modo giusto per 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 stata la risposta giusta seppellita in risposte sbagliate> _ <
Quindi, per tutti quelli che passano, ti darò gratuitamente gli infiniti !!
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
"propertyName" in obj //-> true | false
function isUnset(inp) {
return (typeof inp === 'undefined')
}
Restituisce false se la variabile è impostata e true se non è definita.
Quindi utilizzare:
if (isUnset(var)) {
// initialize variable here
}