Dieses Kapitel gibt einen Überblick über Operatoren.
Alle Operatoren wandeln (wie in Typkonvertierung besprochen) ihre Operanden in entsprechende Typen um. Die meisten Operatoren arbeiten nur mit primitiven Werten (z. B. arithmetische und Vergleichsoperatoren). Das bedeutet, dass Objekte in primitive Typen umgewandelt werden, bevor etwas mit ihnen geschieht. Ein Beispiel, wo das unglücklich ist, ist der Plus-Operator, den viele Sprachen zur Verkettung von Arrays verwenden. Das ist jedoch nicht bei JavaScript der Fall, wo dieser Operator Arrays in Zeichenketten umwandelt und sie anhängt:
> [1, 2] + [3] '1,23' > String([1, 2]) '1,2' > String([3]) '3'
Es gibt keine Möglichkeit, Operatoren in JavaScript zu überladen oder anzupassen, nicht einmal die Gleichheit.
Es gibt verschiedene Möglichkeiten, den einfachen Zuweisungsoperator zu verwenden:
x = wert
x einen Wert zuvar x = wert
obj.propKey = wert
obj['propKey'] = wert
arr[index] = wert
Eine Zuweisung ist ein Ausdruck, der zum zugewiesenen Wert ausgewertet wird. Dies ermöglicht Ihnen, Zuweisungen zu verketten. Beispielsweise weist die folgende Anweisung 0 sowohl y als auch x zu
x=y=0;
Ein zusammengesetzter Zuweisungsoperator wird als op= geschrieben, wobei op einer von mehreren binären Operatoren ist und = der Zuweisungsoperator ist. Die folgenden beiden Ausdrücke sind äquivalent:
myvarop=valuemyvar=myvaropvalue
Mit anderen Worten, ein zusammengesetzter Zuweisungsoperator op= wendet op auf beide Operanden an und weist das Ergebnis dem ersten Operanden zu. Sehen wir uns ein Beispiel für die Verwendung des Plus-Operators (+) über eine zusammengesetzte Zuweisung an
> var x = 2; > x += 3 5 > x 5
Die folgenden sind alle zusammengesetzte Zuweisungsoperatoren:
*=, /=, %=, +=, -=<<=, >>=, >>>=, &=, ^=, |=+=JavaScript hat zwei Möglichkeiten, festzustellen, ob zwei Werte gleich sind:
===) und strikte Ungleichheit (!==) betrachtennur Werte gleichen Typs als gleich. ==) und Ungleichheit (!=) versuchen, Werte unterschiedlicher Typen zu konvertieren, bevor sie sie wie bei strikter (Un-)Gleichheit vergleichen. Leniente Gleichheit ist in zweierlei Hinsicht problematisch. Erstens ist die Art und Weise, wie die Konvertierung durchgeführt wird, verwirrend. Zweitens können aufgrund der sehr nachsichtigen Operatoren Typfehler länger versteckt bleiben.
Verwenden Sie immer strikte Gleichheit und vermeiden Sie leniente Gleichheit. Sie müssen sich nur mit Letzterer beschäftigen, wenn Sie wissen wollen, warum sie vermieden werden sollte.
Gleichheit ist nicht anpassbar. Operatoren können in JavaScript nicht überladen werden, und Sie können nicht anpassen, wie Gleichheit funktioniert. Es gibt einige Operationen, bei denen Sie den Vergleich oft beeinflussen müssen – zum Beispiel Array.prototype.sort() (siehe Sortieren und Umkehren von Elementen (destruktiv)). Diese Methode akzeptiert optional eine Callback-Funktion, die alle Vergleiche zwischen Array-Elementen durchführt.
Werte mit unterschiedlichen Typen sind niemals strikt gleich. Wenn beide Werte denselben Typ haben, dann gelten die folgenden Aussagen:
undefined === undefined
null === null
Zwei Zahlen
x===x// unless x is NaN+0===-0NaN!==NaN// read explanation that follows
> var b = {}, c = {};
> b === c
false
> b === b
trueDer spezielle Zahlenwert NaN (siehe NaN) ist nicht gleich sich selbst:
> NaN === NaN false
Daher müssen Sie andere Mittel verwenden, um ihn zu überprüfen, die in Fallstrick: Überprüfen, ob ein Wert NaN ist beschrieben sind.
Ein strikter Ungleichheits-Vergleich:
x!==y
ist äquivalent zur Negation eines strikten Gleichheitsvergleichs
!(x===y)
Der Algorithmus für den Vergleich über normale Gleichheit funktioniert wie folgt. Wenn beide Operanden denselben Typ haben (einer der sechs Spezifikationstypen – Undefined, Null, Boolean, Number, String und Object), dann vergleichen Sie sie über strikte Gleichheit.
Andernfalls, wenn die Operanden
undefined und null sind, dann werden sie als lenient gleich betrachtet
> undefined == null true
Andernfalls – wenn keiner der oben genannten Fälle zutrifft – ist das Ergebnis des lenienten Vergleichs false.
Ein Ungleichheits-Vergleich:
x!=y
ist äquivalent zur Negation eines Gleichheitsvergleichs
!(x==y)
Schritt 3 bedeutet, dass Gleichheit und Konvertierung in einen Boolean (siehe Konvertierung in Boolean) unterschiedlich funktionieren. Wenn Zahlen größer als 1 in einen Boolean konvertiert werden, werden sie true (z. B. in if-Anweisungen). Aber diese Zahlen sind nicht lenient gleich true. Die Kommentare erklären, wie die Ergebnisse berechnet wurden
> 2 == true // 2 === 1 false > 2 == false // 2 === 0 false > 1 == true // 1 === 1 true > 0 == false // 0 === 0 true
Ähnlich verhält es sich so, dass die leere Zeichenkette gleich false ist, aber nicht alle nicht-leeren Zeichenketten gleich true sind:
> '' == false // 0 === 0 true > '1' == true // 1 === 1 true > '2' == true // 2 === 1 false > 'abc' == true // NaN === 1 false
Ein Teil der Lenienz kann nützlich sein, abhängig davon, was Sie möchten:
> 'abc' == new String('abc') // 'abc' == 'abc'
true
> '123' == 123 // 123 === 123
trueAndere Fälle sind problematisch, aufgrund der Art und Weise, wie JavaScript Zeichenketten in Zahlen umwandelt (siehe Konvertierung in Zahl)
> '\n\t123\r ' == 123 // usually not OK true > '' == 0 // 0 === 0 true
> {} == '[object Object]'
true
> ['123'] == 123
true
> [] == 0
trueZwei Objekte sind jedoch nur dann gleich, wenn sie dasselbe Objekt sind. Das bedeutet, dass Sie keine Wrapper-Objekte wirklich vergleichen können
> new Boolean(true) === new Boolean(true)
false
> new Number(123) === new Number(123)
false
> new String('abc') == new String('abc')
falseMan liest manchmal über gültige Anwendungsfälle für leniente Gleichheit (==). Dieser Abschnitt listet sie auf und weist auf bessere Alternativen hin.
Der folgende Vergleich stellt sicher, dass x weder undefined noch null ist:
if(x!=null)...
Obwohl dies eine kompakte Schreibweise für diese Prüfung ist, verwirrt sie Anfänger, und Experten können nicht sicher sein, ob es sich um einen Tippfehler handelt oder nicht. Wenn Sie also überprüfen möchten, ob x einen Wert hat, verwenden Sie die Standardprüfung auf Wahrhaftigkeit (behandelt in Wahrheitswerte und Falschwerte)
if(x)...
Wenn Sie präziser sein möchten, sollten Sie eine explizite Prüfung für beide Werte durchführen
if(x!==undefined&&x!==null)...
if(x==123)...
Das Vorherige prüft, ob x entweder 123 oder '123' ist. Wiederum ist dies sehr kompakt, und wieder ist es besser, explizit zu sein
if(Number(x)===123)...
Leniente Gleichheit ermöglicht Ihnen den Vergleich von primitiven Werten mit gewrappten primitiven Werten:
> 'abc' == new String('abc')
trueEs gibt drei Gründe gegen diesen Ansatz. Erstens funktioniert leniente Gleichheit nicht zwischen gewrappten primitiven Werten:
> new String('abc') == new String('abc')
falseZweitens sollten Sie Wrapper ohnehin vermeiden. Drittens, wenn Sie sie doch verwenden, ist es besser, explizit zu sein
if(wrapped.valueOf()==='abc')...
JavaScript kennt die folgendenReihenfolgeoperatoren:
<)<=)>)>=)Diese Operatoren funktionieren für Zahlen und für Zeichenketten:
> 7 >= 5 true > 'apple' < 'orange' true
Für Zeichenketten sind sie nicht sehr nützlich, da sie Groß- und Kleinschreibung beachten und keine Funktionen wie Akzente gut handhaben (Details siehe Vergleich von Zeichenketten).
Sie werten einen Vergleich aus
x<y
indem Sie die folgenden Schritte durchführen:
obj werden über die interne Operation ToPrimitive(obj, Number) in primitive Werte umgewandelt (siehe Algorithmus: ToPrimitive()—Konvertierung eines Wertes in einen primitiven Wert), die obj.valueOf() und möglicherweise obj.toString() aufruft, um dies zu tun.Die anderen Reihenfolgeoperatoren werden ähnlich behandelt.
Im Großen und Ganzen untersucht der Plus-Operator seine Operanden. Wenn einer davon eine Zeichenkette ist, wird der andere ebenfalls in eine Zeichenkette konvertiert und beide werden verkettet:
> 'foo' + 3 'foo3' > 3 + 'foo' '3foo' > 'Colors: ' + [ 'red', 'green', 'blue' ] 'Colors: red,green,blue'
Andernfalls werden beide Operanden in Zahlen konvertiert (siehe Konvertierung in Zahl) und addiert
> 3 + 1 4 > 3 + true 4
Das bedeutet, dass die Reihenfolge, in der Sie auswerten, wichtig ist
> 'foo' + (1 + 2)
'foo3'
> ('foo' + 1) + 2
'foo12'Sie werten eine Addition aus
value1+value2
indem Sie die folgenden Schritte durchführen
obj werden über die interne Operation ToPrimitive(obj) in primitive Werte umgewandelt (siehe Algorithmus: ToPrimitive()—Konvertierung eines Wertes in einen primitiven Wert), die obj.valueOf() und möglicherweise obj.toString() aufruft, um dies zu tun. Für Daten, obj.toString() wird zuerst aufgerufen.Boolean-Operatoren
Binäre logische Operatoren (siehe Binäre logische Operatoren: Und (&&) und Oder (||))
x&&y,x||y
Logisches Nicht (siehe Logisches Nicht (!))
!x
Zahlenoperatoren
Arithmetische Operatoren (siehe Arithmetische Operatoren)
x+y,x-y,x*y,x/y,x%y++x,--x,x++,x---x,+x
Bitweise Operatoren (siehe Bitwise-Operatoren)
~xx&y,x|y,x^yx<<y,x>>y,x>>>y
Hier überprüfen wir spezielle Operatoren, nämlich den bedingten Operator, den Kommaoperator und den void-Operator.
Der bedingte Operator ist ein Ausdruck:
«condition»?«if_true»:«if_false»
Wenn die Bedingung true ist, ist das Ergebnis if_true; andernfalls ist das Ergebnis if_false. Zum Beispiel
varx=(obj?obj.prop:null);
Die Klammern um den Operator sind nicht erforderlich, aber sie erleichtern das Lesen.
«left»,«right»
Der Kommaoperator wertet beide Operanden aus und gibt das Ergebnis von right zurück. Im Großen und Ganzen tut er für Ausdrücke, was das Semikolon für Anweisungen tut.
Dieses Beispiel zeigt, dass der zweite Operand zum Ergebnis des Operators wird
> 123, 'abc' 'abc'
Dieses Beispiel zeigt, dass beide Operanden ausgewertet werden
> var x = 0; > var y = (x++, 10); > x 1 > y 10
Der Kommaoperator ist verwirrend. Es ist besser, nicht clever zu sein und stattdessen zwei separate Anweisungen zu schreiben, wann immer Sie können.
Die Syntax für den void-Operator ist:
void«expr»
was expr auswertet und undefined zurückgibt. Hier sind einige Beispiele
> void 0 undefined > void (0) undefined > void 4+7 // same as (void 4)+7 NaN > void (4+7) undefined > var x; > x = 3 3 > void (x = 5) undefined > x 5
Wenn Sie also void als Funktion implementieren, sieht es so aus
functionmyVoid(expr){returnundefined;}
Der void-Operator ist eng mit seinem Operanden verbunden, verwenden Sie daher Klammern, wo nötig. Zum Beispiel bindet void 4+7 als (void 4)+7.
Unter ECMAScript 5 ist void selten nützlich. Seine Haupt-Anwendungsfälle sind:
void 0 als Synonym für undefinedundefined unter ECMAScript 5 einigermaßen sicher vor Änderungen, was diesen Anwendungsfall weniger wichtig macht (Details siehe Ändern von undefined).In einigen Situationen ist es wichtig, undefined zurückzugeben, im Gegensatz zum Ergebnis eines Ausdrucks. Dann kann void verwendet werden, um dieses Ergebnis zu verwerfen. Eine solche Situation betrifft javascript: URLs, die für Links vermieden werden sollten, aber für Bookmarklets nützlich sind. Wenn Sie eine dieser URLs besuchen, ersetzen viele Browser das aktuelle Dokument durch das Ergebnis der Auswertung des „Inhalts“ der URL, aber nur, wenn das Ergebnis nicht undefined ist. Wenn Sie also ein neues Fenster öffnen möchten, ohne den aktuell angezeigten Inhalt zu ändern, können Sie Folgendes tun:
javascript:voidwindow.open("http://example.com/")
void (siehe IIFE-Variation: Präfixoperatoren).[11]Ich habe den
void-Operator vor der Veröffentlichung von Netscape 2 zu JS hinzugefügt, um es einfach zu machen, jeden nicht-undefinierten Wert in einer javascript: URL zu verwerfen.[12]
Wenn Sie einen Wert kategorisieren möchten, müssen Sie leider zwischen primitiven Werten und Objekten unterscheiden (siehe Kapitel 8) in JavaScript
typeof unterscheidet primitive Werte von Objekten und bestimmt die Typen von primitiven Werten.instanceof bestimmt, ob ein Objekt eine Instanz eines gegebenen Konstruktors ist. Weitere Informationen zur objektorientierten Programmierung in JavaScript finden Sie in Kapitel 17.typeof«value»
gibt eine Zeichenkette zurück, die beschreibt, welche Art von Wert value ist. Hier sind einige Beispiele
> typeof undefined
'undefined'
> typeof 'abc'
'string'
> typeof {}
'object'
> typeof []
'object'typeof wird verwendet, um primitive Werte und Objekte zu unterscheiden und primitive Werte zu kategorisieren (die nicht von instanceof behandelt werden können). Leider sind die Ergebnisse dieses Operators nicht vollständig logisch und entsprechen nur lose den Typen der ECMAScript-Spezifikation (die in JavaScript-Typen erklärt werden)
| Operand | Ergebnis |
|
|
|
|
Boolean-Wert |
|
Zahlenwert |
|
String-Wert |
|
Funktion |
|
Alle anderen normalen Werte |
|
(Von der Engine erzeugter Wert) | JavaScript-Engines dürfen Werte erstellen, für die |
Leider ist typeof null 'object'. Dies wird als Fehler betrachtet (null ist kein Mitglied des internen Typs Object), aber es kann nicht behoben werden, da dies bestehenden Code brechen würde. Sie müssen daher null vorsichtig behandeln. Beispielsweise prüft die folgende Funktion, ob value ein Objekt ist:
functionisObject(value){return(value!==null&&(typeofvalue==='object'||typeofvalue==='function'));}
Ausprobieren
> isObject(123)
false
> isObject(null)
false
> isObject({})
trueDie erste JavaScript-Engine stellte JavaScript-Werte als 32-Bit-Wörter dar. Die niedrigsten 3 Bits eines solchen Wortes wurden als Typ-Tag verwendet, um anzugeben, ob der Wert ein Objekt, eine Ganzzahl, eine Gleitkommazahl, eine Zeichenkette oder ein Boolean war (wie Sie sehen können, speicherte selbst diese frühe Engine Zahlen bereits als Ganzzahlen, wenn möglich).
Das Typ-Tag für Objekte war 000. Um den Wert null darzustellen, verwendete die Engine den Maschinen-NULL-Zeiger, ein Wort, bei dem alle Bits Null sind. typeof prüfte das Typ-Tag, um den Werttyp zu bestimmen, weshalb es null als Objekt meldete.[13]
Die Prüfung:
typeofx==='undefined'
hat zwei Anwendungsfälle
x undefined ist.x existiert.Hier sind Beispiele für beide Anwendungsfälle
> var foo; > typeof foo === 'undefined' true > typeof undeclaredVariable === 'undefined' true
Für den ersten Anwendungsfall ist der direkte Vergleich mit undefined in der Regel besser. Für den zweiten Anwendungsfall funktioniert dies jedoch nicht
> var foo; > foo === undefined true > undeclaredVariable === undefined ReferenceError: undeclaredVariable is not defined
Der instanceof-Operator:
«value»instanceof«Constr»
bestimmt, ob value vom Konstruktor Constr oder einem Unterkonstruktor erstellt wurde. Hier sind einige Beispiele
> {} instanceof Object
true
> [] instanceof Array // constructor of []
true
> [] instanceof Object // super-constructor of []
trueWie erwartet, ist instanceof für die Nicht-Werte undefined und null false
> undefined instanceof Object false > null instanceof Object false
Aber es ist auch false für alle anderen primitiven Werte
> 'abc' instanceof Object false > 123 instanceof Object false
Details zu instanceof finden Sie in Der instanceof-Operator.
Die folgenden drei Operatoren arbeiten auf Objekten. Sie werden an anderer Stelle erklärt:
new (siehe Schicht 3: Konstruktoren – Fabriken für Instanzen)new Point(3, 5) delete (siehe Eigenschaften löschen)delete obj.prop in (siehe Iteration und Erkennung von Eigenschaften)'prop' in obj [10] Streng genommen ist das Setzen eines Array-Elements ein Spezialfall des Setzens einer Eigenschaft.
[11] Danke an Brandon Benvie (@benvie), der mich auf die Verwendung von void für IIFEs aufmerksam gemacht hat.
[12] Quelle: http://en.wikipedia.org/wiki/Bookmarklet
[13] Danke an Tom Schuster (@evilpies) für den Hinweis auf den Quellcode der ersten JavaScript-Engine.