Was genau ist Typenzwang in Javascript?

121

Was genau ist Typenzwang in Javascript?

Zum Beispiel bei der Verwendung von ==anstelle von ===?

gespinha gespinha
quelle
20
(true == 1) => true/ (true === 1) => false.
VisioN
5
@VisioN Ihr Kommentar hilft überhaupt nicht, ich frage: "Warum" passiert das?
gespinha
3
Dies geschieht, weil JavaScript auf diese Weise entwickelt wurde. Mein Kommentar sollte Ihre Hauptfrage beantworten: Was genau ist Typenzwang in Javascript?
VisioN
5
Via YDJS: "Das Konvertieren eines Werts von einem Typ in einen anderen wird oft als" Typumwandlung "bezeichnet, wenn dies explizit erfolgt, und als" Zwang ", wenn dies implizit erfolgt (erzwungen durch die Regeln für die Verwendung eines Werts)." - github.com/getify/You-Dont-Know-JS/blob/master/…
mattLummus

Antworten:

175

Typzwang bedeutet, dass, wenn die Operanden eines Operators unterschiedliche Typen sind, einer von ihnen in einen "äquivalenten" Wert des Typs des anderen Operanden konvertiert wird. Wenn Sie zum Beispiel Folgendes tun:

boolean == integer

Der boolesche Operand wird in eine Ganzzahl konvertiert: falsewird 0, truewird 1. Dann werden die beiden Werte verglichen.

Wenn Sie jedoch den nicht konvertierenden Vergleichsoperator verwenden ===, erfolgt keine solche Konvertierung. Wenn die Operanden unterschiedlichen Typs sind, gibt dieser Operator zurück falseund vergleicht die Werte nur, wenn sie vom gleichen Typ sind.

Barmar
quelle
1
Wie kann ich dies auf eine praktische Situation bringen? Sollte ich nicht immer verwenden, ===wenn ich vergleichen möchte, ob ein Wert einem anderen entspricht?
gespinha
1
Es hängt davon ab, was Sie tun. Siehe die verknüpfte Frage.
Barmar
8
@GEspinha Nun, das ist die "Kunst", eine lose getippte Sprache zu verwenden. Einige Leute denken so und denken im Allgemeinen, dass lose getippte Sprachen die Geißel der Programmierwelt sind. Wenn Sie jedoch wissen, was Sie tun, kann dies zu kürzerem und flexiblerem Code führen.
Crayon Violent
2
@Barmar Gilt das auch für > , <?
Royi Namir
2
Eine ausgezeichnete Referenz und Erklärung zum Zwang: github.com/getify/You-Dont-Know-JS/blob/master/…
Greg Bell
55

Beginnen wir mit einer kurzen Einführung in Typsysteme, die Ihnen meiner Meinung nach helfen wird, die allgemeine Idee des Typzwangs zu verstehen.

Das Typsystem einer Sprache definiert Regeln, die uns mitteilen, welche Datentypen in dieser Sprache vorhanden sind und wie sie mit verschiedenen Operatoren kombiniert werden können. Eine solche Regel könnte beispielsweise festlegen, dass der Plus-Operator (+) nur auf Zahlen wirkt. Diese Regeln dienen in erster Linie dazu, Sie daran zu hindern, sich in den Fuß zu schießen. Aber was passiert, wenn der Programmierer diese Regel im Programm verletzt? Es gibt nichts , den Programmierer von der Eingabe zu verhindern {} + {}oder “hello” + 5in einem Programm , auch wenn die Sprache nicht denken , diese Ausdrücke keinen Sinn.

Was letztendlich in diesen Situationen passiert, hängt davon ab, wie streng die Sprache hinsichtlich ihrer Typregeln ist.

Ein Sprachtyp-System hat häufig eine von zwei Positionen, in denen Sie gegen seine Regeln verstoßen:

  1. Sag "Hey, das ist nicht cool!" und stürzen Sie sofort Ihr Programm ab.
  2. Sagen Sie "Ich kann nichts mit {} machen ... aber ich kann etwas mit Zahlen machen" und versuchen Sie, {} in eine Zahl umzuwandeln.

Sprachen mit Typsystemen, die in Bezug auf ihre Regeln die erste Position einnehmen, werden umgangssprachlich als "stark typisierte" Sprachen bezeichnet. Sie sind streng darauf bedacht, dass Sie nicht gegen die Regeln verstoßen. Diejenigen, die den zweiten Ansatz verfolgen (z. B. JavaScript), werden als "schwach typisierte" oder "lose typisierte" Sprachen bezeichnet. Natürlich können Sie gegen die Regeln verstoßen, aber wundern Sie sich nicht, wenn die in Ihrem Programm beschriebenen Datentypen gewaltsam konvertiert werden, um die Regeln einzuhalten. Dieses Verhalten ist bekannt als ... (Trommelwirbel) ... Zwang .

Schauen wir uns nun einige Beispiele in JavaScript an. Beginnen wir zunächst mit einem Ausdruck, der nicht zu Typenzwang führt.

5 + 5

Verwendung des Operators + mit zwei Zahlen, was vollkommen gültig ist. Das Programm behandelt + als "Hinzufügen" und fügt die beiden Zahlen glücklich hinzu. Keine Konvertierung notwendig.

Aber was ist mit …

[] + 5

Oh oh. +Kann in JavaScript bedeuten, zwei Zahlen hinzuzufügen oder zwei Zeichenfolgen zu verketten. In diesem Fall haben wir weder zwei Zahlen noch zwei Zeichenfolgen. Wir haben nur eine Nummer und ein Objekt. Nach den Typregeln von JavaScript ist dies logisch nicht sinnvoll. Da es verzeiht, dass Sie gegen die Regeln verstoßen, versucht es, anstatt es zum Absturz zu bringen, trotzdem einen Sinn daraus zu machen. Was macht JavaScript? Nun, es weiß, wie man Strings verkettet, also konvertiert es sowohl [] als auch 5 in Strings und das Ergebnis ist der String-Wert "5".

Was ist mit den Vergleichsoperatoren ==und ===? Warum gibt es zwei Vergleichsoperatoren?

==ist nicht immun gegen das Typkonvertierungsverhalten von JavaScript. Ausdrücke wie werden als 5 == “5”wahr ausgewertet, da JavaScript versucht, einen von ihnen so zu konvertieren, dass derselbe Datentyp verglichen wird.

In vielen Fällen ist dies nicht wünschenswert, da Sie wahrscheinlich wissen möchten, ob einige Daten, mit denen Sie vergleichen, von einem anderen Typ sind, damit Sie entscheiden können, was Sie dagegen tun möchten. Hier kommt der ===Operator ins Spiel. Bei Verwendung ===findet keine Typkonvertierung statt. Daher wird der Ausdruck 5 === “5”als falsch ausgewertet.

Linstantnudeln
quelle
4
Vielen
1
Dies sollte die akzeptierte Antwort sein, da sie den automatischen Typenzwang in mehreren Facetten zeigt, nicht nur im Vergleichsbeispiel ==. Diese Antwort beantwortet die Frage insgesamt viel besser und beseitigt alle Unklarheiten. Vielen Dank, dass Sie sich die Zeit genommen haben, es aufzuschreiben.
Der Chad
6

Wenn Sie in Python versuchen, beispielsweise Zeichenfolgen und Ganzzahlen hinzuzufügen, wird folgende Fehlermeldung angezeigt:

>>> "hi" + 10
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects

In JavaScript ist dies jedoch nicht der Fall. Das 10wird in einen String konvertiert:

> "hi" + 10
"hi10"

"Typenzwang" ist nur eine ausgefallene Fehlbezeichnung für das oben Gesagte. Tatsächlich hat keine Sprache "Typen" im Sinne von Java oder C oder andere Sprachen mit statischen Typsystemen. Wie die Sprachen Interaktionen zwischen den verschiedenen nicht statisch typisierten Werten behandeln, ist eine Frage der Wahl und der Konvention.

Claudiu
quelle
1
Ich denke, es gibt ein kleines Problem mit dem Beispiel, das Sie genommen haben. Was Sie als Beispiel für JS vorgeschlagen haben, funktioniert einwandfrei mit Java und C #. Also, nach dieser Antwort, wenn man zu dem Schluss kommt, dass Java und C # Typ Zwang unterstützen , wird das nicht ganz wahr sein ...
Romeo Sierra
3

Lassen Sie mich den Typenzwang anhand des folgenden Beispiels erklären

Typenzwang bedeutet, dass Javascript automatisch (im laufenden Betrieb) eine Variable von einem Datentyp in einen anderen konvertiert

Beispiel: 123 + "4"Löst im Allgemeinen einen Fehler aus, führt jedoch in Javascript aufgrund von Typenzwang zu 1234einer Zeichenfolge

if(23 == "23"){
    console.log(" this line is inside the loop and is executed ");
}

Im obigen Code glaubt JavaScript aufgrund von Typenzwang, dass 23(Zahl) und "23"(Zeichenfolge) dasselbe sind. Dadurch wird die Bedingung erfüllt und das console.log gedruckt

Im anderen Fall

if(23 === "23"){
   console.log(" this line is inside the loop and is NOT executed");
}

Für den ===Fall, dass Javascript keine Typenzwang ausführt und da 23eine Zahl und "23"ein String ist und aufgrund ===dieser beiden Datentypen unterschiedlich sind und dies zu einer falschen Bedingung führt. Das console.log wird nicht gedruckt

In einfachen Worten

In diesem Fall handelt =es sich um einen Zuweisungsoperator, der Werte wie var a = 3;usw. Zuweist

(Die folgenden Operatoren dienen zum Vergleich)

In diesem Fall ==konvertiert / erzwingt Javascript den Datentyp in einen anderen und vergleicht ihn dann.

In diesem Fall === konvertiert / erzwingt Javascript den Datentyp nicht

Um Fehler zu vermeiden und zu Debugging-Zwecken ===wird meistens verwendet

Bitte teilen Sie mir die Richtigkeit der oben genannten Informationen mit.

PRagh
quelle
2

Was ist Zwang:

Typenzwang in Javascript tritt auf, wenn die Javascript-Engine eine bestimmte Operation ausführen muss, für die Daten eines bestimmten Typs erforderlich sind. Wenn die Engine auf Daten eines bestimmten Typs stößt, die für den Vorgang nicht zutreffen, werden die Daten zu einem bestimmten Typ gezwungen. Dies ist erforderlich, da Variablen in Javascript dynamisch typisiert werden. Dies bedeutet, dass einer bestimmten Variablen ein Wert eines beliebigen Typs zugewiesen werden kann.

Beispiel:


if(1){
  // 1 gets coerced to true
}


if(4 > '3') {
  // 3 gets coerced into a number
}


44 == "44"  // true, the string 44 gets converted to a nr

Boolescher Zwang:

Beim Javascript-Zwang werden alle Werte konvertiert, mit trueAusnahme der folgenden Werte, zu denen erzwungen wird false:

console.log(!!"");         // false
console.log(!!0);          // false
console.log(!!null);       // false
console.log(!!undefined);  // false
console.log(!!NaN);        // false
console.log(!!false);      // false

Beachten Sie auch, dass im obigen Beispiel das Doppel! Operator wird verwendet. Das ! Der Markierungsoperator erzwingt einen Wert in einen Booleschen Wert mit dem entgegengesetzten Wert. Wir können diesen Operator zweimal verwenden, um einen beliebigen Wert in einen Booleschen Wert umzuwandeln.

Willem van der Veen
quelle
1

a == bMittel Javascript bewerten wird agegen bbasierend auf , wenn die Werte gleich bewertet werden. false == 0Wird beispielsweise true auswerten, da 0 auch der Wert von Boolean false ist. Allerdings false === 0wird falsch beurteilen , weil streng zu vergleichen, 0 nicht die gleiche physikalische Größe wie falsch ist. Ein anderes Beispiel ist false == ''also im Grunde genommen ein lockerer Vergleich mit einem strengen Vergleich, da Javascript eine lose typisierte Sprache ist. Das heißt, Javascript versucht, die Variable basierend auf dem Kontext des Codes zu konvertieren, und dies hat zur Folge, dass die Dinge gleich werden, wenn sie nicht streng verglichen werden. PHP hat auch dieses Verhalten.

Wachsmalstift gewalttätig
quelle
0 is not the same physical value as false. IMO ist physisch falsegenau 0im Speicher. Ich würde eher sagen, dass sie sich nach Typ unterscheiden, da sie falseboolesch sind, während sie 0ganzzahlig sind.
VisioN
1

Beim Typzwang wird der Wert von einem Typ in einen anderen konvertiert (z. B. Zeichenfolge in Zahl, Objekt in Boolescher Wert usw.). Jeder Typ, sei es primitiv oder ein Objekt, ist ein gültiges Subjekt für Typenzwang. Um sich zu erinnern, sind Grundelemente: Zahl, Zeichenfolge, Boolescher Wert, Null, undefiniert + Symbol (in ES6 hinzugefügt).

Impliziter oder expliziter Zwang Typ-Zwang kann explizit und implizit sein.

Wenn ein Entwickler die Absicht zum Ausdruck bringt, zwischen Typen zu konvertieren, indem er den entsprechenden Code schreibt, spricht Number(value)man von explizitem Typenzwang (oder Typumwandlung).

Da JavaScript eine schwach typisierte Sprache ist, können Werte auch automatisch zwischen verschiedenen Typen konvertiert werden. Dies wird als impliziter Typenzwang bezeichnet. Es geschieht in der Regel , wenn Sie Operatoren auf Werte verschiedenen Typen gelten, wie 1 == null, 2/’5', null + new Date()oder es kann durch den umgebenden Kontext ausgelöst werden, wie mit if (value) {…}, wo Wert auf boolean wird dazu gezwungen.

Ein Operator, der keinen impliziten Typzwang auslöst ===, ist der Operator für strikte Gleichheit. Der lose Gleichheitsoperator ==hingegen führt bei Bedarf sowohl Vergleiche als auch Typzwang durch.

Impliziter Typenzwang ist ein zweischneidiges Schwert: Es ist eine große Quelle für Frustration und Fehler, aber auch ein nützlicher Mechanismus, mit dem wir weniger Code schreiben können, ohne die Lesbarkeit zu verlieren.

Drei Arten der Konvertierung Die erste Regel, die Sie kennen sollten, ist, dass es in JavaScript nur drei Arten der Konvertierung gibt:

  • zu bespannen
  • zu boolesch
  • zu nummerieren

Zweitens funktioniert die Konvertierungslogik für Grundelemente und Objekte unterschiedlich, aber sowohl Grundelemente als auch Objekte können nur auf diese drei Arten konvertiert werden.

Beginnen wir zuerst mit Primitiven.

String-Konvertierung

Um Werte explizit in einen String zu konvertieren, wenden Sie die Funktion String () an. Impliziter Zwang wird vom binären + Operator ausgelöst, wenn ein Operand eine Zeichenfolge ist:

String(123) // explicit
123 + ''    // implicit

Alle primitiven Werte werden natürlich wie erwartet in Zeichenfolgen konvertiert:

String(123)                   // '123'
String(-12.3)                 // '-12.3'
String(null)                  // 'null'
String(undefined)             // 'undefined'
String(true)                  // 'true'
String(false)                 // 'false'

Die Symbolkonvertierung ist etwas schwierig, da sie nur explizit, aber nicht implizit konvertiert werden kann.

String(Symbol('my symbol'))   // 'Symbol(my symbol)'
'' + Symbol('my symbol')      // TypeError is thrown

Boolesche Konvertierung

Um einen Wert explizit in einen Booleschen Wert zu konvertieren, wenden Sie die Boolean()Funktion an. Die implizite Konvertierung erfolgt im logischen Kontext oder wird von logischen Operatoren ( || && !) ausgelöst .

Boolean(2)          // explicit
if (2) { ... }      // implicit due to logical context
!!2                 // implicit due to logical operator
2 || 'hello'        // implicit due to logical operator

Hinweis: Logische Operatoren führen beispielsweise || and &&intern boolesche Konvertierungen durch, geben jedoch den Wert der ursprünglichen Operanden zurück, auch wenn sie nicht boolesch sind.

// returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123;   // x === 123

Sobald es nur zwei mögliche Ergebnisse der Booleschen Konvertierung gibt: wahr oder falsch, ist es einfacher, sich die Liste der falschen Werte zu merken.

Boolean('')           // false
Boolean(0)            // false     
Boolean(-0)           // false
Boolean(NaN)          // false
Boolean(null)         // false
Boolean(undefined)    // false
Boolean(false)        // false

Jeder Wert, der nicht in der Liste enthalten ist umgewandelt wird true, einschließlich object, function, Array, Date, benutzerdefinierter Typ, und so weiter. Symbole sind wahrheitsgemäße Werte. Leere Objekte und Arrays sind ebenfalls wahrheitsgemäße Werte:

Boolean({})             // true
Boolean([])             // true
Boolean(Symbol())       // true
!!Symbol()              // true
Boolean(function() {})  // true

Numerische Konvertierung

Wenden Sie für eine explizite Konvertierung einfach die Number()Funktion an, genau wie Sie es mit Boolean()und getan haben String().

Die implizite Konvertierung ist schwierig, da sie in mehreren Fällen ausgelöst wird:

  • Vergleichsoperatoren (>, <, <=,> =)

  • bitweise Operatoren (| & ^ ~)

  • arithmetische Operatoren (- + * /%). Beachten Sie, dass binäres + keine numerische Konvertierung auslöst, wenn ein Operand eine Zeichenfolge ist.

  • unär + Operator

  • loser Gleichheitsoperator == (inkl.! =).

    Beachten Sie, dass == keine numerische Konvertierung auslöst, wenn beide Operanden Zeichenfolgen sind.

    Zahl ('123') // explizit + '123' // implizit 123! = '456' // implizit 4> '5' // implizit 5 / null // implizit wahr | 0 // implizit

So werden primitive Werte in Zahlen umgewandelt:

Number(null)                   // 0
Number(undefined)              // NaN
Number(true)                   // 1
Number(false)                  // 0
Number(" 12 ")                 // 12
Number("-12.34")               // -12.34
Number("\n")                   // 0
Number(" 12s ")                // NaN
Number(123)                    // 123
Tejas Savaliya
quelle
0

Beim Typzwang wird der Wert von einem Typ in einen anderen konvertiert (z. B. Zeichenfolge in Zahl, Objekt in Boolescher Wert usw.). Jeder Typ, sei es primitiv oder ein Objekt, ist ein gültiges Subjekt für Typenzwang. Um sich zu erinnern, sind Grundelemente: Zahl, Zeichenfolge, Boolescher Wert, Null, undefiniert + Symbol (in ES6 hinzugefügt).

Typenzwang kann explizit und implizit sein.

Wenn ein Entwickler die Absicht zum Ausdruck bringt, zwischen Typen zu konvertieren, indem er den entsprechenden Code wie Number (Wert) schreibt, spricht man von explizitem Typenzwang (oder Typumwandlung).

Da JavaScript eine schwach typisierte Sprache ist, können Werte auch automatisch zwischen verschiedenen Typen konvertiert werden. Dies wird als impliziter Typenzwang bezeichnet. Dies geschieht normalerweise, wenn Sie Operatoren auf Werte unterschiedlichen Typs anwenden, z. B. 1 == null, 2 / '5', null + new Date (), oder es kann durch den umgebenden Kontext ausgelöst werden, z. B. mit if (value) {… }, wobei der Wert zum Booleschen Wert gezwungen wird.

Hier ist ein Beispiel für impliziten Zwang:

true + false
12 / "6"
"number" + 15 + 3
15 + 3 + "number"
[1] > null
"foo" + + "bar"
'true' == true
false == 'false'
null == ''
!!"false" == !!"true"
[‘x’] == x
[] + null + 1
[1,2,3] == [1,2,3]
{}+[]+{}+[1]
!+[]+[]+![]
new Date(0) - 0
new Date(0) + 0

Lesen Sie mehr: https://www.freecodecamp.org/news/js-type-coercion-explained-27ba3d9a2839/

Mahdi Salehian
quelle
-1
var str = 'dude';
console.log(typeof str); // "string"
console.log(!str); // false
console.log(typeof !str); // "boolean"

Beispiel einer Variablen, die anfänglich als Zeichenfolge deklariert wird und mit dem! Operator

Herr P.
quelle
3
Bitte erläutern Sie Ihre Antwort. Nur-Code-Antworten sind nicht wirklich hilfreich.
Cezar
2
Ich persönlich finde Code-Beispiele nur prägnant, selbsterklärend und sehr nützlich. Ich denke, es ist eine Frage der persönlichen Meinung
Mister P
-2

Wenn der Datentyp nicht gleich ist, geschieht Zwang. wie 3 == "3" oder boolen == Ganzzahl

ASAbir
quelle