variabile === non definito vs. tipo di variabile === "non definito"


300

Le Linee guida sullo stile di base di jQuery suggeriscono due modi diversi per verificare se una variabile è definita.

  • Variabili globali: typeof variable === "undefined"
  • Variabili locali: variable === undefined
  • Proprietà: object.prop === undefined

Perché jQuery utilizza un approccio per le variabili globali e un altro per i locali e le proprietà?


Non posso rispondere alla domanda sul perché JQuery utilizzi entrambi gli approcci, ma Javascript ha alcune stranezze interessanti che significano che queste due cose sono leggermente diverse. La maggior parte delle volte non dovrebbe importare (cioè se il tuo codice è sano), ma ci sono comunque delle differenze: vedi qui per una recensione - wtfjs.com/2010/02/15/undefined-is-mutable
Spudley

2
Come sottolineato da @Struppi, la funzione più esterna di jQuery ha un argomento chiamato indefinito. All'interno di jQuery, foo === undefinedsta verificando la copia locale di indefinita anziché globale (window.undefined), che potrebbe essere stata modificata da un codice folle. Vale la pena notare che undefined è mutevole e sono contento che tu l'abbia fatto. (+1)
Patrick McElhaney,

1
Il link corrente per quell'articolo è wtfjs.com/wtfs/2010-02-15-undefined-is-mutable
enigment

Risposte:


366

Per le variabili non dichiarate, typeof foorestituirà il valore letterale della stringa "undefined", mentre il controllo dell'identità foo === undefinedinnescherebbe l'errore "foo non definito" .

Per le variabili locali (che sai essere dichiarate da qualche parte), non si verificherebbe un tale errore, quindi il controllo dell'identità.


3
@goreSplatter Non puoi eliminarlo ora. :-) È stato difficile scegliere, ma il modo in cui viene formulata la domanda, questa risposta è più adatta. Chiunque sia interessato a come funziona indefinito in generale (come lo ero io) dovrebbe anche guardare le altre risposte, in particolare @ Tim.
Patrick McElhaney il

4
Vorrei aggiungere le virgolette ( typeof foo; // -> "undefined") per sottolineare che è una stringa e non il valore primitivo undefined.
24

117

Continuerei a usare typeof foo === "undefined"ovunque. Questo non può mai andare storto.

Immagino che il motivo per cui jQuery raccomanda i due diversi metodi sia che definiscono la propria undefinedvariabile all'interno della funzione in cui vive il codice jQuery, quindi all'interno di quella funzione undefinedè al sicuro da manomissioni dall'esterno. Immagino anche che qualcuno da qualche parte abbia confrontato i due diversi approcci e scoperto che foo === undefinedè più veloce e quindi ha deciso che è la strada da percorrere. [AGGIORNAMENTO: come notato nei commenti, anche il confronto con undefinedè leggermente più breve, il che potrebbe essere una considerazione.] Tuttavia, il guadagno in situazioni pratiche sarà assolutamente insignificante: questo controllo non sarà mai, mai, nessun tipo di collo di bottiglia, e cosa la perdita è significativa: la valutazione di una proprietà di un oggetto host per il confronto può generare un errore mentre atypeof il controllo non lo farà mai.

Ad esempio, in IE viene utilizzato quanto segue per l'analisi di XML:

var x = new ActiveXObject("Microsoft.XMLDOM");

Per verificare se ha un loadXMLmetodo sicuro:

typeof x.loadXML === "undefined"; // Returns false

D'altro canto:

x.loadXML === undefined; // Throws an error

AGGIORNARE

Un altro vantaggio del typeofcontrollo che ho dimenticato di menzionare è che funziona anche con variabili non dichiarate, che il foo === undefinedcontrollo non ha, e infatti genera un ReferenceError. Grazie a @LinusKleen per avermelo ricordato. Per esempio:

typeof someUndeclaredVariable; // "undefined"
someUndeclaredVariable === undefined; // throws a ReferenceError

Bottom line: usa sempre il typeofsegno di spunta.


10
Grazie Tim. Il tuo punto sulle prestazioni ha un senso. Il team di jQuery è probabilmente più preoccupato per l'impatto sulla dimensione del file. foo === undefined, se ridotto a icona, è probabilmente qualcosa di simile f===u, mentre typeof foo === "undefined"può essere ridotto a typeof f==="undefined".
Patrick McElhaney,

1
Potresti definirlo var u = "undefined"e ridurlo a typeof f==u, il che migliora le cose ma è ancora più grande.
Tim Down,

5
Aspetti positivi, ma non sono sicuro che la sicurezza typeofrispetto alle variabili non dichiarate sia un vantaggio. Semmai lascia che gli errori di battitura scivolino più facilmente, e non riesco a vedere quando vorresti davvero controllare il tipo di variabili non dichiarate.
David Tang,

2
@ Box9: posso immaginare di usarlo in una libreria per verificare la presenza di un'altra libreria.
Tim Down,

2
@jontro: questa è una ragione per non usare JSLint allora.
Tim Down,

29

Ancora un altro motivo per usare la variante typeof: undefinedpuò essere ridefinito.

undefined = "foo";
var variable = "foo";
if (variable === undefined)
  console.log("eh, what?!");

Il risultato di typeof variable impossibile.

Aggiornamento : notare che questo non è il caso di ES5 in cui il globale undefinedè una proprietà non configurabile e non scrivibile:

15.1.1 Proprietà del valore dell'oggetto globale
[...]
15.1.1.3 undefined
Il valore di undefinednon è definito (vedere 8.1). Questa proprietà ha gli attributi
{[[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false}.

Ma può ancora essere ombreggiato da una variabile locale:

(function() {
  var undefined = "foo";
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})()

o parametro:

(function(undefined) {
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})("foo")

17
Non può essere ridefinito in ES5.
Ry-

6
La undefinedproprietà globale non può essere ridefinita in ES5, ma può comunque essere ombreggiata con una variabile locale. void 0è più breve e più sicuro.
Oriol,

7

Perché undefinednon è sempre dichiarato, ma jQuery dichiara undefinednella sua funzione principale. Quindi usano undefinedinternamente il valore sicuro , ma all'esterno usano lo typeofstile per essere sicuri.



1

Per le variabili locali, il controllo con localVar === undefinedfunzionerà perché devono essere stati definiti da qualche parte nell'ambito locale o non saranno considerati locali.

Per le variabili che non sono locali e non definite da nessuna parte, il controllo someVar === undefinedgenererà un'eccezione: Uncaught ReferenceError: j non è definito

Ecco un po 'di codice che chiarirà ciò che sto dicendo sopra. Si prega di prestare attenzione ai commenti incorporati per ulteriore chiarezza .

function f (x) {
    if (x === undefined) console.log('x is undefined [x === undefined].');
    else console.log('x is not undefined [x === undefined.]');

    if (typeof(x) === 'undefined') console.log('x is undefined [typeof(x) === \'undefined\'].');
    else console.log('x is not undefined [typeof(x) === \'undefined\'].');

    // This will throw exception because what the hell is j? It is nowhere to be found.
    try
    {
        if (j === undefined) console.log('j is undefined [j === undefined].');
        else console.log('j is not undefined [j === undefined].');
    }
    catch(e){console.log('Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.');}

    // However this will not throw exception
    if (typeof j === 'undefined') console.log('j is undefined (typeof(x) === \'undefined\'). We can use this check even though j is nowhere to be found in our source code and it will not throw.');
    else console.log('j is not undefined [typeof(x) === \'undefined\'].');
};

Se chiamiamo il codice sopra in questo modo:

f();

L'output sarebbe questo:

x is undefined [x === undefined].
x is undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.

Se chiamiamo il codice sopra come questo (con qualsiasi valore effettivamente):

f(null); 
f(1);

L'output sarà:

x is not undefined [x === undefined].
x is not undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.

Quando esegui il controllo in questo modo typeof x === 'undefined':, essenzialmente lo chiedi: controlla se la variabile xesiste (è stata definita) da qualche parte nel codice sorgente. (più o meno). Se conosci C # o Java, questo tipo di controllo non viene mai eseguito perché se non esiste, non verrà compilato.

<== Fiddle Me ==>


1

Sommario:

Quando nell'ambito globale vogliamo effettivamente restituire true se la variabile non è dichiarata o ha il valore undefined:

var globalVar1;

// This variable is declared, but not defined and thus has the value undefined
console.log(globalVar1 === undefined);

// This variable is not declared and thus will throw a referenceError
console.log(globalVar2 === undefined);

Perché nell'ambito globale non siamo sicuri al 100% se viene dichiarata una variabile, ciò potrebbe darci un errore di riferimento. Quando utilizziamo l' typeofoperatore sulla variabile sconosciuta non stiamo riscontrando questo problema quando la variabile non viene dichiarata:

var globalVar1;

console.log(typeof globalVar1 === 'undefined');
console.log(typeof globalVar2 === 'undefined');

Ciò è dovuto al fatto che l' typeofoperatore restituisce la stringa undefinedquando una variabile non viene dichiarata o attualmente detiene il valore undefinedche è esattamente quello che vogliamo.


  • Con le variabili locali non abbiamo questo problema perché sappiamo in anticipo che questa variabile esisterà. Possiamo semplicemente guardare nella rispettiva funzione se la variabile è presente.
  • Con le proprietà degli oggetti non abbiamo questo problema perché quando proviamo a cercare una proprietà dell'oggetto che non esiste otteniamo anche il valore undefined

var obj = {};

console.log(obj.myProp === undefined);


-5

typeof a === 'undefined'è più veloce a === 'undefined'di circa 2 volte sul nodo v6.9.1.


3
Quelle non sono le stesse cose che hai digitato. Penso che volevi dire undefinednella seconda parte, non'undefined'
spaventoso
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.