Variable === undefiniert vs. Variablentyp === “undefiniert”

300

Die jQuery Core Style Guidelines schlagen zwei verschiedene Möglichkeiten vor, um zu überprüfen, ob eine Variable definiert ist.

  • Globale Variablen: typeof variable === "undefined"
  • Lokale Variablen: variable === undefined
  • Eigenschaften: object.prop === undefined

Warum verwendet jQuery einen Ansatz für globale Variablen und einen anderen für Lokale und Eigenschaften?

Patrick McElhaney
quelle
Ich kann die Frage nicht beantworten, warum JQuery beide Ansätze verwenden würde, aber Javascript hat einige interessante Macken, die bedeuten, dass diese beiden Dinge subtil unterschiedlich sind. Es sollte die meiste Zeit keine Rolle spielen (dh wenn Ihr Code vernünftig ist), aber es gibt dennoch Unterschiede: Eine Beschreibung finden Sie hier - wtfjs.com/2010/02/15/undefined-is-mutable
Spudley
2
Wie @Struppi hervorhob, hat die äußerste Funktion von jQuery ein Argument mit dem Namen undefined. foo === undefinedPrüft in jQuery anhand der lokalen Kopie von undefined anstelle der globalen (window.undefined), die möglicherweise durch verrückten Code geändert wurde. Die Tatsache, dass undefiniert veränderlich ist, ist definitiv erwähnenswert und ich bin froh, dass Sie es getan haben. (+1)
Patrick McElhaney
1
Aktueller Link für diesen Artikel ist wtfjs.com/wtfs/2010-02-15-undefined-is-mutable
enigment

Antworten:

366

Gibt für nicht deklarierte Variablen typeof foodas Zeichenfolgenliteral zurück "undefined", während die Identitätsprüfung foo === undefinedden Fehler "foo ist nicht definiert" auslösen würde .

Bei lokalen Variablen (von denen Sie wissen , dass sie irgendwo deklariert sind) würde kein solcher Fehler auftreten, daher die Identitätsprüfung.

Linus Kleen
quelle
3
@goreSplatter Sie können es jetzt nicht löschen. :-) Es war schwer zu wählen, aber wie die Frage formuliert ist, passt diese Antwort besser. Jeder, der daran interessiert ist, wie undefiniert im Allgemeinen funktioniert (wie ich), sollte sich auch die anderen Antworten ansehen, insbesondere @ Tims.
Patrick McElhaney
4
Ich würde Anführungszeichen ( typeof foo; // -> "undefined") hinzufügen, um hervorzuheben, dass es sich um eine Zeichenfolge und nicht um den primitiven Wert handelt undefined.
c24w
117

Ich würde mich typeof foo === "undefined"überall daran halten. Das kann nie schief gehen.

Ich stelle mir vor, dass jQuery die beiden verschiedenen Methoden empfiehlt, weil sie ihre eigene undefinedVariable innerhalb der Funktion definieren , in der sich der jQuery-Code befindet, sodass diese Funktion undefinedvor Manipulationen von außen sicher ist. Ich würde mir auch vorstellen, dass irgendwo jemand die beiden unterschiedlichen Ansätze verglichen und festgestellt hat, dass dies foo === undefinedschneller ist, und daher entschieden hat, dass dies der richtige Weg ist. [UPDATE: Wie in den Kommentaren erwähnt, ist der Vergleich mit undefinedauch etwas kürzer, was eine Überlegung sein könnte.] Der Gewinn in praktischen Situationen wird jedoch völlig unbedeutend sein: Diese Überprüfung wird niemals irgendeine Art von Engpass sein, und was auch immer Ihr Verlust ist von Bedeutung: Das Auswerten einer Eigenschaft eines Hostobjekts zum Vergleich kann einen Fehler auslösen, während atypeof überprüfen wird nie wird.

Im IE wird beispielsweise Folgendes zum Parsen von XML verwendet:

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

So überprüfen Sie, ob eine loadXMLMethode sicher vorhanden ist:

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

Andererseits:

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

AKTUALISIEREN

Ein weiterer Vorteil der typeofPrüfung, den ich vergessen habe zu erwähnen, war, dass sie auch mit nicht deklarierten Variablen funktioniert, was bei der foo === undefinedPrüfung nicht der Fall ist und tatsächlich a auslöst ReferenceError. Vielen Dank an @LinusKleen für die Erinnerung. Zum Beispiel:

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

Fazit: Verwenden Sie immer den typeofScheck.

Tim Down
quelle
10
Danke Tim. Ihr Punkt über Leistung macht Sinn. Das jQuery-Team ist wahrscheinlich mehr besorgt über die Auswirkungen auf die Dateigröße. foo === undefined, wenn minimiert, ist wahrscheinlich so etwas wie f===u, während typeof foo === "undefined"kann nur auf reduziert werden typeof f==="undefined".
Patrick McElhaney
1
Sie können es definieren var u = "undefined"und reduzieren typeof f==u, was die Dinge verbessert, aber immer noch größer ist.
Tim Down
5
Gute Punkte, aber ich bin mir nicht sicher, ob die Sicherheit typeofgegen nicht deklarierte Variablen von Vorteil ist. Wenn überhaupt, können Tippfehler leichter vorbeigehen, und ich kann nicht sehen, wann Sie den Typ der nicht deklarierten Variablen tatsächlich überprüfen möchten.
David Tang
2
@ Box9: Ich kann mir vorstellen, es in einer Bibliothek zu verwenden, um das Vorhandensein einer anderen Bibliothek zu überprüfen.
Tim Down
2
@jontro: Das ist ein Grund, JSLint dann nicht zu verwenden.
Tim Down
29

Ein weiterer Grund für die Verwendung der Variablentyp: undefinedkann neu definiert werden.

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

Das Ergebnis von typeof variable kann nicht.

Update : Beachten Sie, dass dies in ES5 nicht der Fall ist, da die globale undefinedEigenschaft nicht konfigurierbar und nicht beschreibbar ist:

15.1.1 Werteigenschaften des globalen Objekts
[...]
15.1.1.3 undefiniert
Der Wert von undefinedist undefiniert (siehe 8.1). Diese Eigenschaft hat die Attribute
{[[Beschreibbar]]: falsch, [[Aufzählbar]]: falsch, [[Konfigurierbar]]: falsch}.

Es kann jedoch weiterhin von einer lokalen Variablen überschattet werden:

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

oder Parameter:

(function(undefined) {
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})("foo")
Jakob
quelle
17
Kann in ES5 nicht neu definiert werden.
Ry-
6
Die globale undefinedEigenschaft kann in ES5 nicht neu definiert werden, kann jedoch mit einer lokalen Variablen überschattet werden. void 0ist kürzer und sicherer.
Oriol
7

Weil undefinednicht immer deklariert wird, sondern jQuery undefinedin seiner Hauptfunktion deklariert . Sie verwenden den sicheren undefinedWert also intern, aber außerhalb verwenden sie den typeofStil, um sicher zu sein.

Struppi
quelle
1

Bei lokalen Variablen localVar === undefinedfunktioniert die Überprüfung mit , da sie irgendwo im lokalen Bereich definiert wurden oder nicht als lokal betrachtet werden.

Für Variablen, die nicht lokal sind und nirgendwo definiert sind, löst die Prüfung someVar === undefinedeine Ausnahme aus: Nicht erfasster Referenzfehler: j ist nicht definiert

Hier ist ein Code, der klarstellt, was ich oben sage. Bitte beachten Sie die Inline-Kommentare für weitere Klarheit .

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\'].');
};

Wenn wir den obigen Code so nennen:

f();

Die Ausgabe wäre folgende:

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.

Wenn wir den obigen Code wie folgt aufrufen (mit einem beliebigen Wert):

f(null); 
f(1);

Die Ausgabe wird sein:

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.

Wenn Sie die Prüfung wie typeof x === 'undefined'folgt durchführen:, fragen Sie im Wesentlichen Folgendes: Bitte prüfen Sie, ob die Variable xirgendwo im Quellcode vorhanden ist (definiert wurde). (mehr oder weniger). Wenn Sie C # oder Java kennen, wird diese Art der Überprüfung nie durchgeführt, da sie nicht kompiliert wird, wenn sie nicht vorhanden ist.

<== Fiddle Me ==>

Codierung von Yoshi
quelle
1

Zusammenfassung:

Im globalen Bereich möchten wir tatsächlich true zurückgeben, wenn die Variable nicht deklariert ist oder den Wert hat 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);

Da wir im globalen Bereich nicht 100% sicher sind, ob eine Variable deklariert ist, kann dies zu einem Referenzfehler führen. Wenn wir den typeofOperator für die unbekannte Variable verwenden, tritt dieses Problem nicht auf, wenn die Variable nicht deklariert ist:

var globalVar1;

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

Dies liegt an der Tatsache, dass der typeofOperator die Zeichenfolge zurückgibt, undefinedwenn eine Variable nicht deklariert ist oder derzeit den Wert enthält, undefinedder genau das ist, was wir wollen.


  • Bei lokalen Variablen haben wir dieses Problem nicht, da wir vorher wissen, dass diese Variable existieren wird. Wir können einfach in die jeweilige Funktion schauen, ob die Variable vorhanden ist.
  • Bei Objekteigenschaften haben wir dieses Problem nicht, da wir beim Versuch, eine nicht vorhandene Objekteigenschaft zu suchen, auch den Wert erhalten undefined

var obj = {};

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

Willem van der Veen
quelle
-5

typeof a === 'undefined'ist schneller als a === 'undefined'etwa 2 mal auf Knoten v6.9.1.

Eduard Popov
quelle
3
Das sind nicht die gleichen Dinge, die Sie eingegeben haben. Ich denke, Sie meinten undefinedim zweiten Teil nicht'undefined'
Scaryguy