[1] + [2] - [3] === 9!? Erforschen Sie JavaScript Inner Casts

Ursprünglicher Autor: Administrator wanago.io
  • Übersetzung
JavaScript ermöglicht die Typkonvertierung. Wenn dies absichtlich geschieht, liegt uns eine explizite Typumwandlung vor (Typumwandlung oder explizite Zwangsmaßnahme). Wenn dies automatisch erfolgt und versucht wird, Operationen an Werten verschiedener Typen auszuführen, spricht man von impliziter Typumwandlung (Zwang oder impliziter Zwang).
Der Autor des Materials, dessen Übersetzung wir heute veröffentlichen, bietet einen Blick darauf, wie das explizite und implizite Typcasting auf einer niedrigen Ebene aussieht. Dies wird es jedem ermöglichen, die in den Eingeweiden von JavaScript verborgenen Prozesse besser zu verstehen und eine begründete Antwort auf die Frage zu geben, warum [1] + [2] - [3] === 9.


Explizite Besetzungen


▍ Objektverpackungen primitiver Typen


Fast alle primitiven Typen in JavaScript (die Ausnahme ist nullund undefined) haben Objekt-Wrapper, die ihre Werte enthalten. Weitere Informationen dazu finden Sie lesen hier . Der Entwickler hat Zugriff auf die Designer solcher Objekte. Diese Tatsache kann verwendet werden, um Werte eines Typs in Werte eines anderen Typs umzuwandeln.

String(123); // '123'
Boolean(123); // true
Number('123'); // 123
Number(true); // 1

In dem hier gezeigten Beispiel existieren die Wrapper von Variablen primitiver Typen nicht lange: Nachdem der Job erledigt ist, werden sie vom System entfernt.

Beachten Sie dies, da die obige Aussage nicht für Fälle gilt, in denen das Schlüsselwort in einer ähnlichen Situation verwendet wird new.

const bool = new Boolean(false);
bool.propertyName = 'propertyValue';
bool.valueOf(); // false
if (bool) {
 console.log(bool.propertyName); // 'propertyValue'
}

Da es sich in diesem Fall boolum ein neues Objekt (und nicht um einen primitiven Wert) handelt, wird es im Ausdruck ifin konvertiert true.

Darüber hinaus können wir über die Äquivalenz der folgenden beiden Konstruktionen sprechen. Dieser:

if (1) {
 console.log(true);
}

Und dieser:

if ( Boolean(1) ) {
 console.log(true);
}

Sie können dies selbst überprüfen, indem Sie das folgende Experiment durchführen, bei dem die Bash-Shell verwendet wird. Wir setzen das erste Codefragment in eine Datei if1.js, das zweite in eine Datei if2.js. Jetzt machen wir Folgendes:

1. Kompilieren Sie den Code in JavaScript und konvertieren Sie ihn mit Node.js in Assembler-Code.

$ node --print-code ./if1.js >> ./if1.asm
$ node --print-code ./if2.js >> ./if2.asm

2. Bereiten Sie ein Skript zum Vergleichen der vierten Spalte (hier die Assembler-Befehle) der resultierenden Dateien vor. Speicheradressen werden nicht absichtlich verglichen, da sie variieren können.

#!/bin/bash
file1=$(awk '{ print $4 }' ./if1.asm)
file2=$(awk '{ print $4 }' ./if2.asm)
[ "$file1" == "$file2" ] && echo "The files match"

3. Führen Sie dieses Skript aus. Es wird die folgende Zeile ausgegeben, die die Identität der Dateien bestätigt.

"The files match"

▍ParseFloat-Funktion


Eine Funktion parseFloatfunktioniert ähnlich wie ein Konstruktor Number, ist jedoch in Bezug auf die an sie übergebenen Argumente freier. Wenn sie auf ein Zeichen stößt, das nicht Teil einer Zahl sein kann, gibt sie einen Wert zurück, der eine Zahl ist, die aus den Ziffern vor diesem Zeichen ermittelt wurde, und ignoriert den Rest der ihr übergebenen Zeichenfolge.

Number('123a45'); // NaN
parseFloat('123a45'); // 123

▍ParseInt-Funktion


Die Funktion parseIntrundet nach dem Parsen des übergebenen Arguments die empfangenen Zahlen ab. Es kann mit Werten arbeiten, die in verschiedenen Zahlensystemen dargestellt werden.

parseInt('1111', 2); // 15
parseInt('0xF'); // 15
parseFloat('0xF'); // 0

Die Funktion parseIntkann entweder „raten“, welches Zahlensystem zur Aufzeichnung des übergebenen Arguments verwendet wird, oder den „Hinweis“ in Form des zweiten Arguments verwenden. Die Regeln, die bei Verwendung dieser Funktion gelten, können auf MDN gelesen werden .

Diese Funktion funktioniert nicht sehr gut mit sehr großen Zahlen, daher sollte sie nicht als Alternative zur Math.floor- Funktion angesehen werden (übrigens führt sie auch Typ-Casting durch).

parseInt('1.261e7'); // 1
Number('1.261e7'); // 12610000
Math.floor('1.261e7') // 12610000
Math.floor(true) // 1

ToString-Funktion


Mit der Funktion können toStringSie Werte anderer Typen in Zeichenfolgen konvertieren. Es ist zu beachten, dass die Implementierung dieser Funktion in Prototypen von Objekten unterschiedlicher Typen unterschiedlich ist. Wenn Sie der Meinung sind, dass Sie das Konzept von Prototypen in JavaScript besser verstehen müssen, schauen Sie sich dieses Material an.

String.prototype.toString-Funktion


Diese Funktion gibt den als Zeichenfolge dargestellten Wert zurück.

const dogName = 'Fluffy';
dogName.toString() // 'Fluffy'
String.prototype.toString.call('Fluffy') // 'Fluffy'
String.prototype.toString.call({}) // Uncaught TypeError: String.prototype.toString requires that 'this' be a String

Number.prototype.toString-Funktion


Diese Funktion gibt die in einen String konvertierte Zahl zurück (als erstes Argument kann die Basis des Zahlensystems übergeben werden, in dem das von ihr zurückgegebene Ergebnis dargestellt werden soll).

(15).toString(); // "15"
(15).toString(2); // "1111"
(-15).toString(2); // "-1111"

Symbol.prototype.toString-Funktion


Diese Funktion gibt eine Zeichenfolgendarstellung eines Objekts vom Typ Symbol zurück . Es sieht wie folgt aus : `Symbol(${description})`. Um die Funktionsweise dieser Funktion zu demonstrieren, wird hier das Konzept von Schablonenzeichenfolgen verwendet .

Funktion Boolean.prototype.toString


Diese Funktion gibt trueoder zurück false.

Object.prototype.toString-Funktion


Objekte haben eine interne Bedeutung [[Class]]. Es ist ein Tag, das den Objekttyp darstellt. Die Funktion Object.prototype.toStringgibt einen String der Form: `[object ${tag}]`. Als Tag werden entweder Standardwerte verwendet (z. B. "Array", "String", "Object", "Date") oder die vom Entwickler angegebenen Werte.

const dogName = 'Fluffy';
dogName.toString(); // 'Fluffy' (здесь вызывается String.prototype.toString)
Object.prototype.toString.call(dogName); // '[object String]'

Mit ES6 werden Tags mit Objekten vom Typ Symbol definiert . Hier einige Beispiele. Hier ist der erste.

const dog = { name: 'Fluffy' }
console.log( dog.toString() ) // '[object Object]'
dog[Symbol.toStringTag] = 'Dog';
console.log( dog.toString() ) // '[object Dog]'

Hier ist der zweite.

const Dog = function(name) {
 this.name = name;
}
Dog.prototype[Symbol.toStringTag] = 'Dog';
const dog = new Dog('Fluffy');
dog.toString(); // '[object Dog]'

Hier können Sie auch ES6-Klassen mit Gettern verwenden.

class Dog {
 constructor(name) {
   this.name = name;
 }
 get [Symbol.toStringTag]() {
   return 'Dog';
 }
}
const dog = new Dog('Fluffy');
dog.toString(); // '[object Dog]'

Funktion Array.prototype.toString


Diese Funktion, wenn sie von ihrem Objekttyp aufgerufen Array, ein Anruf toStringspeichert für jedes Array - Element , die in der Zeile erhaltenen Ergebnisse, welche Elemente durch Kommata voneinander getrennt sind, und gibt die Zeichenfolge.

const arr = [
 {},
 2,
 3
]
arr.toString() // "[object Object],2,3"

Implizites Casting


Wenn Sie wissen, wie explizites Casting in JavaScript funktioniert, ist es für Sie viel einfacher, die Funktionen des impliziten Castings zu verstehen.

▍Mathenbetreiber


Pluszeichen


Ausdrücke mit zwei Operanden, zwischen denen ein Zeichen +und einer eine Zeichenfolge steht, erzeugen eine Zeichenfolge.

'2' + 2 // 22
15 + '' // '15'

Wenn Sie das Vorzeichen +in einem Ausdruck mit einem Zeichenfolgenoperanden verwenden, können Sie es in eine Zahl konvertieren:

+'12' // 12

Andere mathematische Operatoren


Bei der Anwendung anderer mathematischer Operatoren wie -oder /werden Operanden immer in Zahlen konvertiert.

new Date('04-02-2018') - '1' // 1522619999999
'12' / '6' // 2
-'1' // -1

Bei der Konvertierung von Datumsangaben in Zahlen erhalten sie die Unix-Zeit , die den Datumsangaben entspricht.

▍ Ausrufezeichen


Die Verwendung eines Ausrufezeichens in Ausdrücken führt zu der Schlussfolgerung, trueob der Anfangswert als falsch wahrgenommen wird und false- für Werte, die vom System als wahr wahrgenommen werden. Infolgedessen kann ein zweimal angewandtes Ausrufezeichen verwendet werden, um verschiedene Werte in ihre entsprechenden logischen Werte umzuwandeln.

!1 // false
!!({}) // true

ToInt32-Funktion und bitweiser OR-Operator


Hier ist die Funktion erwähnenswert ToInt32, obwohl es sich um eine abstrakte Operation handelt (ein interner Mechanismus, der im regulären Code nicht aufgerufen werden kann). ToInt32konvertiert Werte in 32-Bit-Ganzzahlen mit Vorzeichen .

0 | true          // 1
0 | '123'         // 123
0 | '2147483647'  // 2147483647
0 | '2147483648'  // -2147483648 (слишком большое)
0 | '-2147483648' // -2147483648
0 | '-2147483649' // 2147483647 (слишком маленькое)
0 | Infinity      // 0

Die Verwendung eines bitweisen Operators, ORwenn einer der Operanden Null und der zweite eine Zeichenfolge ist, führt dazu, dass sich der Wert des anderen Operanden nicht ändert, sondern in eine Zahl umgewandelt wird.

▍Weitere Fälle von implizitem Casting


Dabei können Programmierer auf andere Situationen stoßen, in denen eine implizite Typkonvertierung durchgeführt wird. Betrachten Sie das folgende Beispiel.

const foo = {};
const bar = {};
const x = {};
x[foo] = 'foo';
x[bar] = 'bar';
console.log(x[foo]); // "bar"

Dies liegt an der Tatsache, dass sie foo, barwenn sie zu einer Saite gebracht werden, in eine verwandeln "[object Object]". Hier ist, was in diesem Codeteil tatsächlich passiert.

x[bar.toString()] = 'bar';
x["[object Object]"]; // "bar"

Implizite Typkonvertierung tritt auch bei Musterzeichenfolgen auf . Im folgenden Beispiel versuchen wir, die Funktion zu überschreiben toString.

const Dog = function(name) {
 this.name = name;
}
Dog.prototype.toString = function() {
 return this.name;
}
const dog = new Dog('Fluffy');
console.log(`${dog} is a good dog!`); // "Fluffy is a good dog!"

Es ist anzumerken, dass der Grund, warum die Verwendung des nicht strengen Gleichheitsoperators ( ==) nicht empfohlen wird, in der Tatsache liegt, dass dieser Operator eine implizite Typkonvertierung durchführt, wenn die Typen der Operanden nicht übereinstimmen. Betrachten Sie das folgende Beispiel.

const foo = new String('foo');
const foo2 = new String('foo');
foo === foo2 // false
foo >= foo2 // true

Wie hier das Schlüsselwort verwendet new, foound foo2eine Hülle um die primitiven Werte darstellen (und diese - Linie 'foo'). Da die entsprechenden Variablen auf verschiedene Objekte beziehen, ist das Ergebnis die Art des Vergleichs foo === foo2erhalten wird false. Der Operator >=führt eine implizite Typkonvertierung durch, indem er eine Funktion valueOffür beide Operanden aufruft . Aus diesem Grund werden hier primitive Werte verglichen, und als Ergebnis der Berechnung des Werts des Ausdrucks foo >= foo2stellt sich heraus , dass dies der Fall ist true.

[1] + [2] - [3] === 9


Wir glauben, dass Ihnen jetzt klar ist, warum der Ausdruck wahr ist [1] + [2] – [3] === 9. Wir empfehlen jedoch, es zu zerlegen.

1. In dem Ausdruck [1] + [2]werden die Operanden unter Verwendung von in Zeichenfolgen konvertiert Array.prototype.toString, wonach die Verkettung des Geschehens durchgeführt wird. Infolgedessen haben wir hier eine Linie "12".

  • Es sollte beachtet werden, dass beispielsweise ein Ausdruck [1,2] + [3,4]eine Zeichenfolge ergibt "1,23,4";

2. Bei der Berechnung des Ausdrucks 12 - [3]wird die Subtraktion durchgeführt wird , "3"von 12diesem Willen 9.

  • Hier betrachten wir auch ein zusätzliches Beispiel. Das Ergebnis der Auswertung des Ausdrucks 12 - [3,4]ist also NaN, da das System nicht implizit "3,4"zu einer Zahl führen kann.

Zusammenfassung


Sie können auf viele Empfehlungen stoßen, deren Autoren einfach raten, implizites Typ-Casting in JavaScript zu vermeiden. Der Autor dieses Materials ist jedoch der Ansicht, dass es wichtig ist, die Merkmale dieses Mechanismus zu verstehen. Sie sollten wahrscheinlich nicht versuchen, es absichtlich zu verwenden, aber zu wissen, wie es funktioniert, wird sich zweifellos als nützlich beim Debuggen von Code erweisen und dabei helfen, Fehler zu vermeiden.

Sehr geehrte Leser! Wie stehen Sie zu implizitem Typcasting in JavaScript?


Jetzt auch beliebt: