Vorhandensein von Funktion überprüfen
nam
- javascript
Hallo
Neulich bin ich über folgende Notation gestolpert:
if("sessionStorage" in window) {
//do something
}
Ich kannte diese Notation bislang nicht und hätte es stattdessen so geschrieben:
if(window.sessionStorage) {
//do something
}
Gibt es irgendwo ein Dokumentation der Notation mit in
? Und gibt es Unterschiede bei der Ausführung?
Danke und Gruss,
Mathias
Hallo Mathias,
Gibt es irgendwo ein Dokumentation der Notation mit
in
?
SELFHTML kennt den Operator nur in Schleifen, Google Doctype hat kein Kapitel über Javascript als Sprache, Mozillas Wiki dagegen kennt und dokumentiert ihn.
Und gibt es Unterschiede bei der Ausführung?
Laut der ECMAScript-Spezifikation liefert "attr" in obj
mit der Ausführung der dem Javascript-Interpreter eigenen Methode [[HasProperty]] immer direkt einen bool'schen Wert zurückgibt, obj.attr
(und obj["attr"]
) liefern eine Referenz auf ein Objekt zurück, das dann erst dereferenziert und mit der internen Funktion ToBoolean zu einem Bool'schen Wert abgebildet wird. Das ist nur minimalst mehr; ausser diesem Unterschied machen beide Notationen praktisch das gleiche; es wäre also größtenteils Geschmackssache.
Es gibt jedoch Grenzfälle: Mal angenommen window.property wäre kein Wasauchimmer-Objekt sondern eine Referenz auf undefined, null, eine Zahl, die Null oder NaN wäre oder auf einen leeren String. Im Falle von "property" in window
würde das das erwünschte True liefern; schließlich exisiert die Eigenschaft von window. Boolean(window.property)
dagegen würde False liefern – das referenzierte Objekt würde mit ToBoolean zu einem Wahrheitswert abgebildet und dieser evaluiert dann zu falsch. Das ist dann nicht das, was man eigentlich meinte. Das sind jedoch ziemliche Grenzfälle, in der normalen Nutzung ist das dann meistens ein Objekt oder eine Funktion, die zu True evaluieren.
(Ich privat habe eine kleine Bevorzugung des in-Operators, das kommt aber eher durch zuviel Python.)
Tim
Gibt es irgendwo ein Dokumentation der Notation mit
in
?SELFHTML kennt den Operator nur in Schleifen,
Nicht ganz, zumindest in einem neuerem Artikel hat Mathias diese Verwendung erwähnt.
Struppi.
Hi
Vielen Dank für eure Antworten, Tim und Struppi.
Habe auf eure Antworten hin noch tiefer geforscht und meine Verwirrung hat sich damit vergrössert. Ich weiss, das Folgende ist schon ein Grenzfall, aber ich hatte in meinem Script genau dieses Problem und brauchte lange (sehr lange), bis ich den Bug gefunden hatte. Vereinfacht sieht es so aus:
function Foo () {
var n;
this.noini;
this.ini=n;
}
var foo = new Foo();
Beide Properties foo.noini
und foo.ini
sind mit undefined
initialisiert, wobei letzteres seinen Wert von der Variable n bezieht.
Gemäss molily (siehe Link von Struppi) ergeben (typeof foo.ini != 'undefined')
und (typeof foo.noini != 'undefined')
beide false
; soweit kann ich das nachvollziehen.
Aber:
('ini' in foo)
ergibt true
und ('noini' in foo)
ergibt false
.(!)
Testscript liegt hier:http://mnn.ch/diversa/inTest.html
Was jetzt?
Oder steh ich auf dem Schlauch?
var n;
this.ini=n;
Das ist tatsächlich eine Initialisierung mit undefined.
this.noini;
Das ist überhaupt keine Initialisierung. Das ist ein Expression Statement mit einem Identifier, der undefined ergibt. Es findet aber keine Wertzuweisung statt. Wenn du einfach
window.bla;
notierst, dann hat bla danach auch keinen Wert (also nichtmal undefined)! Wie kommst du darauf, dass es anders sein sollte?
Im Übrigen, welchen Sinn sollte eine solche Initialisierung mit undefined haben?
Wenn du eine Variable deklarieren willst, sie aber "keinen Wert" haben soll, dann nutzt man für gewöhnlich den speziellen Wert null.
Gemäss molily (siehe Link von Struppi) ergeben
(typeof foo.ini != 'undefined')
und(typeof foo.noini != 'undefined')
beidefalse
; soweit kann ich das nachvollziehen.
Du brauchst die Eigenschaften nicht mit undefined füllen, damit das zutrifft.
Wie gesagt ist auch nur die eine "gefüllt".
Aber:
Nichts aber. Sondern folgerichtig.
('ini' in foo)
ergibttrue
und('noini' in foo)
ergibtfalse
.(!)
Das ist ganz logisch.
Mathias
Hi molily
var n;
this.ini=n;Das ist tatsächlich eine Initialisierung mit undefined.
this.noini;
Das ist überhaupt keine Initialisierung. Das ist ein Expression Statement mit einem Identifier, der undefined ergibt. Es findet aber keine Wertzuweisung statt. Wenn du einfach
window.bla;
notierst, dann hat bla danach auch keinen Wert (also nichtmal undefined)! Wie kommst du darauf, dass es anders sein sollte?
Darauf bin ich durch meine Angewohnheit gekommen, beim Debuggen Werte ausgeben zu lassen. Sowohl alert(foo.ini), als auch alert(foo.noini) zeigen 'undefined' an. Heisst das, foo.ini *hat* den Wert 'undefined' und foo.noini *ist* undefined? Oder wie?
Im Übrigen, welchen Sinn sollte eine solche Initialisierung mit undefined haben?
Na, wohl keinen, war ja der Bug in meinem Script. Es handelte sich um eine Factory, die eine Art Objekt-Template (Fall foo.noini) hätte bereitstellen sollen, das dann - je nach Client - mit verschiedenen Werten befüllt (Fall foo.ini) werden sollte. Beim Test, ob alle Objekt-Properties gesetzt wurden, bin ich dann gestolpert, weil 'undefined' einmal zu 'true' führte und einmal zu 'false'. Wie gesagt, ich habe den Bug ja gefunden, will aber verstehen, warum das so ist.
Gruss,
Mathias
Heisst das, foo.ini *hat* den Wert 'undefined' und foo.noini *ist* undefined? Oder wie?
Ja.
undefined ist ein Wert, den man einer Eigenschaft zuweisen kann (da unterscheidet er sich nicht von null, true, 1, "bla" usw.). Es ist aber auch der Wert, der herauskommt, wenn man auf eine nicht existente Eigenschaft zugreift.
Mathias
var n;
this.noini;
Vielleicht erkläre ich nochmal diesen Unterschied.
Das erste ist ein Variable Statement: Da kann man einfach var n; ohne Wertzuweisung schreiben und die Variable n wird dann deklariert, aber nicht mit einem Wert gefüllt. Sowas geht aber nur mit dem Variable Statement!
Das zweite ist wie gesagt ein Expression Statement. Also eine Anweisung, die bloß aus einem (zusammengesetzten) Ausdruck besteht. Und dieser Ausdruck besteht bloß aus einem Keyword (this), einem "Property Accessor"-Operator (.) und einem Identifier (noini). Dieser Ausdruck wird aufgelöst: Es wird also die Eigenschaft noini von this geholt. Es gibt keine solche, daher ist das Ergebnis des gesamten Ausdrucks undefined. Mit diesem Ergebnis wird nichts gemacht. Wie gesagt gibt es nur eine "Dereferenzierung", keine Wertzuweisung. Dazu müsstest du schon this.noini = undefined schreiben - ich wüsste aber nicht, welchen Sinn das hätte.
Mathias
Hi,
Und gibt es Unterschiede bei der Ausführung?
Der in-Operator benötigt einen aktuellen Browser (mit JavaScript Version 1.5 oder höher - also z.B. Mozilla), während die "klassische" Abfrage immer funktioniert (also seit JavaScrippt 1.0 im Netscape Navigator 2).
Gruß, Cybaer
Gibt es irgendwo ein Dokumentation der Notation mit
in
? Und gibt es Unterschiede bei der Ausführung?
Am besten liest du dir mal den besagten Artikel durch:
Objektabfragen und Fallunterscheidungen in JavaScript
Dort wird if (objekt.unterobjekt) erklärt und was es tut: Nämlich das Objekt nach Boolean umwandeln.
sessionStorage wird nun als Object angenommen, deshalb ist diese Abfrage spezifischer als "eigenschaft" in objekt. Dabei findet wie gesagt kein Vergleich mit true statt.
Auf die in-Schreibweise kann man m.E. eigentlich immer verzichten, in den meisten Fällen auch auf typeof, wenn if (objekt.unterobjekt) ausreicht. Und das tut es, wenn man Objects oder Functions abfragen will.
Mathias
Hi molily
Habe inzwischen deinen Artikel studiert. Ist vor dem Hintergrund meiner Fragestellung und überhaupt sehr aufschlussreich.
Tatsächlich bin ich gescheitert, weil ich bis anhin nicht zwischen Expression Statement ("ist undefined") und Variable Statement ("hat den Wert undefined") unterschieden habe.
Hirn wieder eingerenkt.
Danke und Gruss,
Mathias