Was ist ein Typ? Einfach ausgedrückt besteht ein Typ darin, einer Binärsequenz im Speicher eine bestimmte Bedeutung zuzuweisen. Beispielsweise ist die Binärsequenz 0100 0000 0111 0000 0001 0101 0100 1011 1100 0110 1010 0111 1110 1111 1001 1110 4643234631018606494, wenn sie als 64-Bit-Ganzzahltyp ohne Vorzeichen betrachtet wird. 54 Regeln zur binären Darstellung von Gleitkommazahlen (siehe Anhang 1) double Präzision Der Gleitkommatyp ist 257.331.
Die meisten Computersprachen verwenden Variablen zum Speichern und Darstellen von Daten. Einige Sprachen geben einen Typ für Variablen an. Dieser Typ kann nicht im gesamten Programm geändert werden (weder zur Kompilierzeit noch zur Laufzeit). Im Gegensatz dazu können Variablen in JavaScript und einigen anderen Sprachen jeden Typ speichern und verwenden untypisierte Variablen. Ob der Variablentyp existiert, hat nichts mit der Syntax zu tun. C# stellt beispielsweise auch Variablen vom Typ var bereit. Die folgende Anweisung führt jedoch zu einem Fehler in C#.
var a=1;
a="string";
Der Grund dafür ist, dass das var-Schlüsselwort von C# nur die Variablentypdeklaration weglässt und den Variablentyp automatisch basierend auf dem Initialisierungsausdruck ableitet, sodass die var-Variable von C# immer noch einen Typ hat. In JavaScript können Sie einer bestimmten Variablen jederzeit einen beliebigen Wert zuweisen, sodass JavaScript-Variablen untypisiert sind.
Gemäß der Entwurfsmethode des Computersprachentypsystems kann es in zwei Typen unterteilt werden: starker Typ und schwacher Typ. Der Unterschied zwischen beiden besteht darin, ob die implizite Konvertierung zwischen verschiedenen Typen für den Benutzer während der Berechnung transparent sein kann. Wenn eine Sprache aus Benutzersicht alle ihre Typen implizit konvertieren kann, können ihre Variablen, Ausdrücke usw., selbst wenn der Typ falsch ist, durch implizite Konvertierung immer noch den richtigen Typ erhalten Für den Benutzer Es ist, als ob alle Typen alle Operationen ausführen können, daher wird eine solche Sprache als schwach typisiert bezeichnet. Im Gegensatz dazu gibt es in einer stark typisierten Sprache möglicherweise nicht unbedingt implizite Konvertierungen zwischen Typen (C++ ist beispielsweise eine stark typisierte Sprache, aber double und int können in C++ ineinander konvertiert werden, es ist jedoch eine Umwandlung zwischen double und any erforderlich). Art des Zeigers.
Typen können Programmierern dabei helfen, korrekte Programme zu schreiben, und sie fungieren als Einschränkungen im eigentlichen Prozess des Programmschreibens. Als allgemeine Regel gilt: Je stärker die Einschränkung ist, desto weniger fehleranfällig ist sie, desto schwieriger ist es jedoch, das Programm zu schreiben. Stark typisierte Sprachen mit Variablen, die über Typen verfügen, weisen die stärksten Einschränkungen auf, und der typische Vertreter ist C++. Schwach typisierte Sprachen mit nicht typisierten Variablen weisen die schwächsten Einschränkungen auf, wobei JavaScript der typische Vertreter ist. Da die Einschränkungen in JavaScript relativ schwach sind, tritt dieser Fehler häufig auf:
var a =200;
var b="1";
var c= a + b;
Sie könnten erwarten, dass c 201 ist, aber tatsächlich ist es „2001“, ein Fehler, der in stark typisierten Sprachen nie auftritt. Gerade weil JavaScript jedoch nicht über diese Einschränkungen verfügt, kann es problemlos numerische und String-Typen verketten. Daher sind Einschränkungen und Flexibilität immer eine Reihe von Funktionen, die für Sprachdesigner in Einklang gebracht werden müssen.
Ein Typ ist eine Einschränkung, die durch Typprüfung funktioniert. In verschiedenen Sprachen erfolgt die Typprüfung in unterschiedlichen Phasen, die in eine Prüfung zur Kompilierungszeit und eine Prüfung zur Laufzeit unterteilt werden können. Für interpretierte Sprachen wie JavaScript gibt es Phasen, die dem Kompilierungsprozess ähneln, nämlich die lexikalische Analyse und die Syntaxanalyse. Wenn die Typprüfung interpretierter Sprachen während der Syntaxanalyse oder der vorherigen Phase abgeschlossen wird, kann dies ebenfalls berücksichtigt werden ähnelt der Überprüfung zur Kompilierungszeit. Eine vernünftigere Aussage ist also die statische Typprüfung und die dynamische Typprüfung.
Interessanterweise können viele Sprachen Typen zur Laufzeit überprüfen, ihre Typinformationen können jedoch weiterhin zur Laufzeit abgerufen werden. C# verwendet beispielsweise Metadaten, um Typinformationen während der Laufzeit abzurufen und zu verwenden.
JavaScript legt in jedem Aspekt seines Designs großen Wert auf Flexibilität. Daher verwendet es eine dynamische Typprüfung und prüft Typen nur dann aktiv, wenn nur sehr wenige spezifische Vorgänge ausgeführt werden. Sie können die Typinformationen jeder Variablen oder jedes Ausdrucks zur Laufzeit abrufen und deren Richtigkeit mithilfe der Programmlogik überprüfen.
Im JavaScript-Standard sind 9 Typen spezifiziert: Undefinierter Null-Boolean-String-Nummer-Objekt-Referenzlisten-Vervollständigung
Unter diesen werden die drei Arten der Referenzlistenvervollständigung nur während der Sprachanalyse-Laufzeit verwendet und können nicht direkt vom Programm aus aufgerufen werden. Sie werden hier nicht vorgestellt. Im Folgenden können wir mehr über diese sechs Typen erfahren:
Der undefinierte Typ hat nur einen Wert, undefiniert. Dies ist der Wert, wenn der Variablen kein Wert zugewiesen ist. In JS verfügt das globale Objekt über eine undefinierte Eigenschaft, die undefiniert darstellt Weisen Sie der globalen undefinierten Eigenschaft einen Wert zu, um ihren Wert zu ändern.
Der Null-Typ hat ebenfalls nur einen Wert, null, aber JavaScript stellt ihm ein Schlüsselwort null zur Verfügung, um diesen eindeutigen Wert darzustellen. Die Semantik des Null-Typs ist „eine leere Objektreferenz“.
Boolean hat zwei Werte: wahr und falsch
Die formale Interpretation des String-Typs ist eine Folge von 16-Bit-Ganzzahltypen ohne Vorzeichen, die tatsächlich zur Darstellung von in UTF-16 codierten Textinformationen verwendet wird.
Die Zahl von JavaScript hat insgesamt 18437736874454810627 (d. h. 264-253 +3) Werte. Die Zahl von JavaScript wird im Gleitkommatyp mit doppelter Genauigkeit gespeichert, mit der Ausnahme, dass 9007199254740990 NaN darstellt, das IEEE 754 entspricht (siehe Anhang 1) und 64 Bit und 8 Byte belegt.
Der komplexeste Typ in JavaScript ist Object, eine ungeordnete Sammlung einer Reihe von Eigenschaften. Function ist ein Objekt, das die private Eigenschaft [[call]] implementiert.
Ich habe bereits über die im JS-Standard angegebenen Typen gesprochen. Ein Problem, das nicht ignoriert werden kann, ist, dass der JS-Standard beispielsweise für JS-Benutzer geschrieben wurde , weil JS ist Wenn der Vorgang ausgeführt wird, werden Nicht-Objekttypen automatisch in entsprechende Objekte konvertiert, sodass „str“.length tatsächlich äquivalent zu (new String(„str“)).length ist Es ist keine schlechte Idee, wenn beide vom gleichen Typ sind. Wir verwenden einige Sprachfunktionen in JS, um die Laufzeittypunterscheidung durchzuführen, aber die Ergebnisse dieser Methoden sind unterschiedlich. Sie müssen entscheiden, welche besser oder schlechter ist.
Typeof ist ein Operator in der JS-Sprache und wird offensichtlich verwendet, um den Typ zu erhalten. Gemäß dem JavaScript-Standard gibt es 6 mögliche Ergebnisse. bool, Zahl, undefiniert, Objekt, Funktion und der JavaScript-Standard ermöglicht es seinen Implementierern, den Werttyp einiger Objekte anzupassen.
Im JS-Standard gibt es eine solche Beschreibungsliste:
Typ | Ergebnis |
Undefiniert | "undefiniert" |
Null | "Objekt" |
Boolescher Wert | „boolean“ |
Nummer | "Nummer" |
Zeichenfolge | „Zeichenfolge“ |
Objekt (nativ und implementiert [[Aufruf]] nicht) | "Objekt" |
Objekt (nativ und implementiert [[Aufruf]]) | "Funktion" |
Objekt (Host) | Implementierungsabhängig |
Das folgende Beispiel stammt von Rimifon von 51js und zeigt die Situation, in der das Ergebnis von typeof im IE „Datum“ und „unbekannt“ erzeugt:
var xml=document.createElement("xml");
var rs=xml.recordset;
rs.Fields.Append("date", 7, 1);
rs.Fields.Append("bin", 205, 1);
rs.Open();
rs.AddNew();
rs.Fields.Item("date").Value = 0;
rs.Fields.Item("bin").Value = 21704;
rs.Update();
var date = rs.Fields.Item("date").Value;
var bin = rs.Fields.Item("bin").Value;
rs.Close();
Warnung(Datum);
alarm(bin);
Alert([Typ des Datums, Typ des Behälters]);
try{alert(date.getDate())}catch(err){alert(err.message)}
Es gibt tatsächlich viele Kritikpunkte an dieser Beurteilungsmethode, die der „Typ“-Semantik am nächsten kommt. Einer davon ist, dass sie nicht zwischen verschiedenen Objekten („abc“) und neuer Zahl (123) unterscheiden kann Bei der JS-Programmierung wird häufig eine große Anzahl verschiedener Objekte verwendet, und typeof kann für alle Objekte nur ein vages Ergebnis „Objekt“ liefern, was seine Praktikabilität erheblich einschränkt.
Die Bedeutung von „instanceof“ wird ins Chinesische übersetzt als „ist eine Instanz von …“. Wörtlich genommen handelt es sich um einen Begriff, der auf klassenbasierter objektorientierter Programmierung basiert, und JS bietet eigentlich keine Unterstützung für klassenbasierte Programmierung Sprachniveau. Obwohl der JavaScript-Standard kein Wort erwähnt, deutet das Design einiger integrierter Objekte und Operatoreinstellungen alle auf eine „offizielle“ Methode zur Implementierung von Klassen hin, d. h. auf die Verwendung von Funktionen als Klassen, wenn der neue Operator agiert Auf der Funktion wird das Prototypattribut der Funktion auf den Prototyp des neu erstellten Objekts gesetzt und die Funktion selbst wird als Konstruktor verwendet.
Daher werden Objekte, die aus der neuen Operation derselben Funktion erstellt wurden, als Instanzen einer Klasse betrachtet. Diese Objekte haben Folgendes gemeinsam: 1. Sie haben denselben Prototyp und 2. Sie werden von demselben Konstruktor verarbeitet. Und „instanceof“ ist ein Operator, der in Verbindung mit dieser Art der Klassenimplementierung prüft, „ob eine Instanz zu einer Klasse gehört“. Sie können sich auch vorstellen, dass es sehr schwierig ist, zu überprüfen, ob ein Objekt von einem Konstruktor verarbeitet wurde, aber es ist viel einfacher, zu überprüfen, was sein Prototyp ist. Daher wird die Implementierung von „instanceof“ aus der Perspektive des Prototyps verstanden Überprüfen Sie, ob das Attribut [[prototype]] mit dem Prototyp einer bestimmten Funktion übereinstimmt. Beachten Sie, dass es sich bei [[prototype]] hier um eine private Eigenschaft handelt, auf die mit __proto__ in SpiderMonkey (der JS-Engine von Firefox) zugegriffen werden kann.
Der Prototyp ist nur für den im Standard beschriebenen Objekttyp von Bedeutung, daher wird „Instanceof“ für alle Nicht-Objektobjekte „false“ erhalten, und „Instanceof“ kann nur feststellen, ob es zu einem bestimmten Typ gehört, kann den Typ jedoch nicht erhalten Es ist auch offensichtlich, dass es sich um ein aus einer definierten „Klasse“ konstruiertes Objekt handelt.
Tatsächlich kann die Instanz von getäuscht werden. Obwohl das private Attribut [[Prototyp]] des verwendeten Objekts nicht geändert werden kann, ist der Prototyp der Funktion ein öffentliches Attribut.
Funktion ClassA(){};
function ClassB(){};
var o = new ClassA();//Konstruiere ein Objekt der Klasse A
ClassB.prototype = ClassA.prototype; //ClassB.prototype ersetzen
Alert(o Instanz von ClassB)//wahre Täuschung erfolgreich - -!
Object.prototype.toString ist ursprünglich schwer aufzurufen. Alle in JavaScript integrierten Klassen decken die toString-Methode ab. Für Objekte, die von nicht integrierten Klassen erstellt wurden, kann Object.prototype.toString nur das bedeutungslose [object Object] abrufen Ergebnis. Daher wurde die magische Wirkung dieser Funktion lange Zeit nicht entdeckt.
Im Standard besteht die Beschreibung von Object.prototype.toString nur aus 3 Sätzen
1. Rufen Sie das [[class]]-Attribut dieses Objekts ab
2. Berechnen Sie eine Zeichenfolge, indem Sie die drei Zeichenfolgen „[object“, result(1) und „]“ verketten.
3. Geben Sie das Ergebnis zurück (2).
Offensichtlich ruft Object.prototype.toString tatsächlich nur das [[class]]-Attribut des Objekts ab, aber ich weiß nicht, ob es beabsichtigt ist. Alle in JS integrierten Funktionsobjekte String Number Array RegExp... werden alle verwendet Wenn Sie new zum Erstellen von Objekten verwenden, legen Sie das Attribut [[class]] fest, damit das Attribut [[class]] als gute Grundlage für die Beurteilung des Typs verwendet werden kann.
Da Object.prototype.toString die Eigenschaft dieses Objekts übernimmt, können Sie dieses Objekt angeben und dann den Typ mithilfe von Object.prototype.toString.call oder Object.prototype.toString.apply abrufen.
Obwohl Object.prototype.toString clever ist, kann es den von der benutzerdefinierten Funktion erstellten Objekttyp nicht abrufen, da die benutzerdefinierte Funktion [[Klasse]] nicht festlegt und auf diese private Eigenschaft im Programm nicht zugegriffen werden kann. Der größte Vorteil von Object.prototype.toString besteht darin, dass es 1 und new Number(1) zum gleichen Objekttyp machen kann. Meistens werden beide auf die gleiche Weise verwendet.
Es ist jedoch zu beachten, dass das Ergebnis genau das Gegenteil von false ist, wenn new Boolean(false) zu diesem Zeitpunkt als derselbe Typ betrachtet wird, was leicht zu Fehlern führt, die schwer zu beheben sind überprüfen.
Um die oben genannten drei Arten von Beurteilungsmethoden zu vergleichen, habe ich eine Tabelle erstellt, damit jeder einen Gesamtvergleich mehrerer Methoden haben kann. Um den Vergleich zu erleichtern, habe ich die mit mehreren Beurteilungsmethoden erzielten Ergebnisse vereinheitlicht:
Objekt | Art von | Instanz von | Object.prototype.toString | Standard |
"ABC" | Zeichenfolge | —— | Zeichenfolge | Zeichenfolge |
neuer String("abc") | Objekt | Zeichenfolge | Zeichenfolge | Objekt |
Funktion hallo(){} | Funktion | Funktion | Funktion | Objekt |
123 | Nummer | —— | Nummer | Nummer |
newNumber(123) | Objekt | Nummer | Nummer | Objekt |
neues Array(1,2,3) | Objekt | Array | Array | Objekt |
newMyType() | Objekt | MeinTyp | Objekt | Objekt |
null | Objekt | —— | Objekt | Null |
undefiniert | Undefiniert | —— | Objekt | Undefiniert |
Tatsächlich ist es schwierig zu sagen, welche der oben genannten Methoden sinnvoller ist. Selbst die Bestimmungen im Standard spiegeln nur den Laufzeitmechanismus von JS wider und nicht die besten Verwendungspraktiken. Meine persönliche Meinung ist, das Konzept des „Typs“ herunterzuspielen und mich mehr auf die Einschränkungen zu konzentrieren, „wie möchte ich dieses Objekt verwenden“, um bei Bedarf den gleichen Effekt wie eine stark typisierte Sprache zu erzielen.
Vorzeichenbit: Wird zur Darstellung positiver und negativer Vorzeichen verwendet
Exponent: Wird zur Darstellung von Potenzzahlen verwendet
Mantisse (Mantisse): Wird zur Angabe der Genauigkeit verwendet