Maison >interface Web >js tutoriel >Ne craignez pas les jumeaux maléfiques - sitepoint

Ne craignez pas les jumeaux maléfiques - sitepoint

Jennifer Aniston
Jennifer Anistonoriginal
2025-02-22 08:58:11896parcourir

Don't Fear the Evil Twins - SitePoint

Le développeur JavaScript Douglas Crockford a une fois qualifié les opérateurs javascript == et != de "jumeaux maléfiques" qui devraient être évités. Cependant, une fois que vous les comprenez, ces opérateurs ne sont pas si mauvais et peuvent réellement être utiles. Cet article explorera == et !=, expliquera comment ils fonctionnent et vous aideront à mieux les comprendre.

Points clés

  • Comprendre les bases: et == Les opérateurs en JavaScript ne sont pas intrinsèquement mauvais; ils effectuent des moulages de type lors de la comparaison de différents types de valeurs, ce qui est à la fois utile et délicat. !=
  • Apprenez quand utiliser lequel: utilisez et === pour les comparaisons de type direct et de valeur sans moulage, ce qui est plus clair et il est généralement recommandé d'éviter des résultats inattendus. Utilisez !== et == lorsque vous devez lancer ou comparer des valeurs dont les types peuvent changer dynamiquement. !=
  • Apprenez les règles de la distribution: familiarisé avec la façon dont JavaScript jette les types pendant les comparaisons et ==, afin de prédire les résultats plus précisément et d'éviter les pièges courants. !=
  • Explorez des exemples pratiques: Creusez dans les exemples pour voir comment et == exécuter dans divers scénarios, tels que la comparaison des chaînes aux nombres ou des objets aux valeurs d'origine, pour consolider la compréhension. !=
  • N'ayez pas peur, mais soyez prudent: bien que et == ne soient pas effrayants, ils nécessitent une bonne compréhension des règles de distribution de type JavaScrip localement. !=

problématique et == opérateurs !=

Le langage JavaScript contient deux ensembles d'opérateurs d'égalité:

et ===, et !== et ==. Comprendre pourquoi il existe deux ensembles d'opérateurs d'égalité et dans quelles situations à utiliser quel opérateur a été la source de confusion pour de nombreuses personnes. Les opérateurs != et === ne sont pas difficiles à comprendre. Lorsque les deux types d'opérande sont les mêmes et que les valeurs sont les mêmes, !== renvoie === et true renvoie !==. Cependant, lorsque la valeur ou le type est différent, false renvoie ===, false renvoie !==. Les opérateurs true et == se comportent de la même manière lorsque les deux types d'opérands sont les mêmes. Cependant, lorsque les types sont différents, JavaScript lance un opérande != à un autre type pour rendre l'opérande compatible avant comparaison. Les résultats sont souvent déroutants, comme suit:

Parce qu'il n'y a que deux valeurs booléennes possibles, vous pourriez penser que l'une des expressions devrait être calculée comme
<code class="language-javascript">"this_is_true" == false // false
"this_is_true" == true  // false</code>
. Cependant, ils sont tous calculés comme

. Une confusion supplémentaire se produit lorsque vous supposez que la relation de passe (si A est égale à B et B est égal à c) devrait s'appliquer: true

<code class="language-javascript">"this_is_true" == false // false
"this_is_true" == true  // false</code>

Cet exemple montre que == manque de transittivité. Si la chaîne vide est égale au nombre 0, et si le nombre 0 est égal à la chaîne composée de caractères 0, la chaîne vide doit être égale à la chaîne composée de 0. Mais ce n'est pas le cas. Lorsqu'un type incompatible est rencontré lors de la comparaison des opérandes via == ou !=, JavaScript lance un type à un autre pour le rendre comparable. Inversement, lors de l'utilisation de === et !==, il n'effectue jamais de moulages de type (ce qui entraîne une légère amélioration des performances). En raison de différents types, === renvoie toujours false dans le deuxième exemple. Comprendre les règles qui contrôlent comment JavaScript jette les opérandes à différents types afin que les deux types d'opérands soient compatibles avant d'appliquer == et != peut vous aider à déterminer quand il est préférable d'utiliser == et !=, et d'avoir confiance en en utilisant ces opérateurs. Dans la section suivante, nous explorerons les règles de distribution utilisées avec les opérateurs == et !=.

Comment fonctionne

== et !=?

La meilleure façon d'apprendre comment le travail

et == est d'étudier les spécifications du langage ECMAScript. Cette section se concentre sur ECMAScript 262. La section 11.9 de la spécification présente l'opérateur d'égalité. Les opérateurs != et == apparaissent dans la production de syntaxe != et EqualityExpression. (Contrairement à la première génération, la deuxième génération évite l'opérateur EqualityExpressionNoIn.) Vérifions la génération in illustrée ci-dessous. EqualityExpression

<code class="language-javascript">'' == 0   // true
0 == '0' // true
'' == '0' // false</code>
Selon cette génération, l'expression égale est soit une expression relationnelle, soit une expression égale qui est égale à une expression relationnelle, soit une expression égale qui n'est pas égale à une expression relationnelle, etc. (J'ai négligé

et ==, qui ne sont pas liés à cet article.) La section 11.9.1 fournit les informations suivantes sur le fonctionnement de !=: === !== == La formule de production

est calculée comme suit:

EqualityExpression : EqualityExpression == RelationalExpression Soit

le résultat du calcul
    .
  1. lref Soit EqualityExpression être
  2. .
  3. lval Soit GetValue(lref) le résultat du calcul
  4. .
  5. rref Soit RelationalExpression être
  6. .
  7. rval Renvoie le résultat de la réalisation d'une comparaison d'égalité abstraite GetValue(rref). (Voir 11.9.3.)
  8. rval == lval
  9. La section 11.9.2 fournit des informations similaires sur le fonctionnement
Fonctionne:

!= La formule de production

est calculée comme suit:
  1. Soit lref le résultat du calcul EqualityExpression.
  2. Soit lval être GetValue(lref).
  3. Soit rref le résultat du calcul RelationalExpression.
  4. Soit rval être GetValue(rref).
  5. Soit r le résultat de la réalisation de la comparaison de l'égalité abstraite rval != lval. (Voir 11.9.3.)
  6. Si r est true, retournez false. Sinon, retournez true.

lref et rref sont des références sur les côtés gauche et droit des opérateurs == et !=. Chaque référence est transmise à la fonction interne GetValue() pour renvoyer la valeur correspondante. Le noyau de la façon dont == et != le travail est spécifié par l'algorithme de comparaison d'égalité abstrait, donné dans la section 11.9.3:

Comparez x == y, où x et y sont des valeurs, résultant en true ou false. Cette comparaison est effectuée comme suit:

  1. si Type(x) est le même que Type(y), alors
    1. Si Type(x) est Undefined, retournez true.
    2. Si Type(x) est Null, retournez true.
    3. si Type(x) est Number, alors
      1. Si x est NaN, retournez false.
      2. Si y est NaN, retournez false.
      3. Si x et y sont la même valeur numérique, renvoyez true.
      4. si x est 0 et y est -0, retournez true.
      5. Si x est -0 et y est 0, alors true sera retourné.
      6. return false.
    4. si Type(x) est String, si x et y sont exactement la même séquence de caractères (la même longueur et les mêmes caractères dans la position correspondante), alors true est renvoyé. Sinon, retournez false.
    5. si Type(x) est Boolean, alors si x et y sont les deux true ou sont les deux false, retournez true. Sinon, retournez false.
    6. Si x et y se référer au même objet, retournez true. Sinon, retournez false.
  2. si x est null et y est undefined, puis retournez true.
  3. si x est undefined et y est null, puis retournez true.
  4. Si Type(x) est Number et Type(y) est String, le résultat de la comparaison x == ToNumber(y) est renvoyé.
  5. Si Type(x) est String et Type(y) est Number, le résultat de la comparaison ToNumber(x) == y est renvoyé.
  6. Si Type(x) est Boolean, le résultat de la comparaison ToNumber(x) == y est renvoyé.
  7. Si Type(y) est Boolean, le résultat de la comparaison x == ToNumber(y) est renvoyé.
  8. Si Type(x) est String ou Number et Type(y) est Object, le résultat de la comparaison x == ToPrimitive(y) est renvoyé.
  9. Si Type(x) est Object et Type(y) est String ou Number, le résultat de la comparaison ToPrimitive(x) == y est renvoyé.
  10. return false.

Étape 1 Le type d'opérande est le même lorsqu'il est exécuté dans cet algorithme. Il montre que undefined est égal à undefined, et null est égal à null.Il montre également que rien égal à NaN (non-nombre), deux valeurs identiques sont égales, 0 est égal à -0, deux chaînes avec la même longueur et la même séquence de caractères sont égales, true égaux true, false est égal à false, et deux références au même objet sont égales. Les étapes 2 et 3 montrent pourquoi null != undefined renvoie false. JavaScript considère que ces valeurs sont les mêmes. À partir de l'étape 4, l'algorithme devient intéressant. Cette étape se concentre sur l'égalité entre les valeurs Number et String. Lorsque le premier opérande est Number et que le deuxième opérande est String, le deuxième opérande est converti en ToNumber() via la fonction interne de Number. L'expression x == ToNumber(y) signifie la récursivité; l'algorithme à partir de la section 11.9.1 est réappliqué. L'étape 5 est équivalente à l'étape 4, mais le premier opérande a un type String et doit être converti en type Number. Les étapes 6 et 7 convertissent l'opérande booléen en un type Number et récursivement. Si l'autre opérande est un booléen, il sera converti en Number la prochaine fois que cet algorithme sera exécuté, ce qui reviendra à nouveau. D'un point de vue de performance, vous pouvez vous assurer que les deux opérandes sont des types booléens pour éviter deux étapes récursives. L'étape 9 montre que si le type d'opérande est Object, l'opérande est converti en valeur d'origine via la fonction interne ToPrimitive() et l'algorithme récursivement. Enfin, l'algorithme considère que les deux opérandes ne sont pas égaux et renvoient false à l'étape 10. Bien que détaillée, l'algorithme de comparaison d'égalité abstrait est assez facile à comprendre. Cependant, il fait référence à une paire de fonctions internes ToNumber() et ToPrimitive(), dont le travail interne doit être exposé pour bien comprendre l'algorithme. La fonction ToNumber() convertit ses paramètres en Number et est décrite dans la section 9.3. La liste suivante résume les paramètres non nucères possibles et les valeurs de retour équivalentes:

  • Si le paramètre est Undefined, retournez NaN.
  • Si le paramètre est Null, retournez 0.
  • Si le paramètre est une valeur booléenne true, retournez 1. Si le paramètre est une valeur booléenne false, retournez 0.
  • Si le type de paramètre est Number, le paramètre d'entrée est renvoyé - pas de conversion.
  • Si le type du paramètre est String, alors la section 9.3.1 «Tonumber du type de chaîne» est appliquée. Renvoie la valeur correspondant au paramètre de chaîne indiqué par la syntaxe. Si le paramètre ne correspond pas à la syntaxe indiquée, retournez NaN. Par exemple, le paramètre "xyz" provoque le retour NaN. De plus, le paramètre "29" entraîne un retour de 29.
  • Si le type de paramètre est Object, appliquez les étapes suivantes:
    1. Soit primValue être ToPrimitive(输入参数, 提示Number).
    2. return ToNumber(primValue).
La fonction

ToPrimitive() accepte un paramètre d'entrée et un paramètre facultatif PreferredType. Les paramètres d'entrée sont convertis en type non objet. Si l'objet peut être converti en plusieurs types primitifs, ToPrimitive() utilisez l'invite PreferredType facultative pour biaiser le type préféré. La conversion est effectuée comme suit:

  1. Si le paramètre d'entrée est Undefined, le paramètre d'entrée (Undefined) est renvoyé - pas de conversion.
  2. Si le paramètre d'entrée est Null, le paramètre d'entrée (Null) est renvoyé - pas de conversion.
  3. Si le type de paramètre d'entrée est Boolean, renvoyez le paramètre d'entrée - pas de conversion.
  4. Si le type de paramètre d'entrée est Number, renvoyez le paramètre d'entrée - pas de conversion.
  5. Si le type de paramètre d'entrée est String, renvoyez le paramètre d'entrée - pas de conversion.
  6. Si le type du paramètre d'entrée est Object, la valeur par défaut correspondant au paramètre d'entrée est renvoyée. Récupérez la valeur par défaut de l'objet en appelant la méthode interne de l'objet [[DefaultValue]] et en passant une invite PreferredType facultative. Le comportement de [[DefaultValue]] est défini dans la section 8.12.8 pour tous les objets ECMascript natifs.

Cette section présente pas mal de théories. Dans la section suivante, nous nous tournerons en pratiquant en fournissant diverses expressions impliquant == et != et en effectuant progressivement des étapes algorithmiques.

comprendre les jumeaux maléfiques

Maintenant que nous avons compris comment == et != fonctionnent selon les spécifications ECMAScript, profitons de ces connaissances en explorant les différentes expressions impliquant ces opérateurs. Nous allons expliquer comment évaluer ces expressions et découvrir pourquoi ils sont true ou false. Pour mon premier exemple, considérons les paires d'expression suivantes introduites vers le début de l'article:

<code class="language-javascript">"this_is_true" == false // false
"this_is_true" == true  // false</code>

Suivez l'algorithme de comparaison d'égalité abstrait pour évaluer ces expressions selon les étapes suivantes:

  1. Sautez l'étape 1 car les types sont différents: typeof "this_is_true" Renvoie "String", tandis que typeof false ou typeof true Renvoie "booléen".
  2. Sautez les étapes 2 à 6 qui ne sont pas applicables car elles ne correspondent pas au type d'opérande. Cependant, l'étape 7 s'applique car le bon paramètre a un type Boolean. L'expression est convertie en "this_is_true" == ToNumber(false) et "this_is_true" == ToNumber(true).
  3. ToNumber(false) Renvoie 0, ToNumber(true) Renvoie 1, qui simplifie les expressions à "this_is_true" == 0 et "this_is_true" == 1 respectivement. À cette époque, l'algorithme récursivement.
  4. Sautez les étapes 1 à 4 qui ne sont pas applicables car elles ne correspondent pas au type d'opérande. Cependant, l'étape 5 s'applique car le type de l'opérande gauche est String et le type de l'opérande droit est Number. L'expression est convertie en ToNumber("this_is_true") == 0 et ToNumber("this_is_true") == 1.
  5. ToNumber("this_is_true") Renvoie NaN, ce qui simplifie les expressions à NaN == 0 et NaN == 1 respectivement. À cette époque, l'algorithme récursivement.
  6. Passez à l'étape 1, car les types de NaN, 0 et 1 sont tous Number. Évitez les étapes 1.A et 1.B qui ne sont pas applicables. Cependant, l'étape 1.C.I s'applique car l'opérande gauche est NaN. L'algorithme renvoie désormais false (NaN n'est égal à rien, y compris lui-même) car la valeur de chaque expression d'origine et recouvrent la pile pour quitter la récursivité complètement.

Mon deuxième exemple (basé sur l'explication de la signification de la vie dans le "Galaxy Wandering Guide") compare un objet avec un nombre de == et renvoie true:

<code class="language-javascript">"this_is_true" == false // false
"this_is_true" == true  // false</code>

Les étapes suivantes montrent comment JavaScript utilise l'algorithme de comparaison d'égalité abstrait pour obtenir true comme valeur de l'expression:

  1. Sautez les étapes 1 à 8 qui ne sont pas applicables car elles ne correspondent pas au type d'opérande. Cependant, l'étape 9 s'applique car le type de l'opérande gauche est Object et le type de l'opérande droit est Number. L'expression est convertie en ToPrimitive(lifeAnswer) == 42.
  2. ToPrimitive() Appelez la méthode interne lifeAnswer de [[DefaultValue]], sans invite. Selon la section 8.12.8 de la spécification ECMAScript 262, le [[DefaultValue]] appelle la méthode toString(), qui renvoie "42". L'expression est convertie en "42" == 42, et l'algorithme est récursif.
  3. Sautez les étapes 1 à 4 qui ne sont pas applicables car elles ne correspondent pas au type d'opérande. Cependant, l'étape 5 s'applique car le type de l'opérande gauche est String et le type de l'opérande droit est Number. L'expression est convertie en ToNumber("42") == 42.
  4. ToNumber("42") Renvoie 42, et l'expression est convertie en 42 == 42. L'algorithme recurse et exécute l'étape 1.C.III. Parce que les nombres sont les mêmes, true est retourné et élargi récursivement.

Pour mon dernier exemple, découvrons pourquoi la séquence suivante ne montre pas la transitivité, où la troisième comparaison reviendra true au lieu de false:

<code class="language-javascript">"this_is_true" == false // false
"this_is_true" == true  // false</code>

Les étapes suivantes montrent comment JavaScript utilise l'algorithme de comparaison d'égalité abstrait pour obtenir true comme valeur de '' == 0.

  1. Exécuter l'étape 5, résultant en ToNumber('') == 0, qui est converti en 0 == 0, et l'algorithme récursivement. (La section 9.3.1 de la spécification indique que StringNumericLiteral ::: [vide] MV [Valeur mathématique] est 0. En d'autres termes, la valeur d'une chaîne vide est 0.)
  2. Exécuter l'étape 1.C.III, qui se compare 0 à 0 et renvoie true (et élargit la récursivité).

Les étapes suivantes montrent comment JavaScript utilise l'algorithme de comparaison d'égalité abstrait pour obtenir true comme valeur de 0 == '0':

  1. Exécuter l'étape 4, résultant en 0 == ToNumber('0'), qui est converti en 0 == 0, et l'algorithme récursivement.
  2. Exécuter l'étape 1.C.III, qui se compare 0 à 0 et renvoie true (et élargit la récursivité).

Enfin, JavaScript effectue l'étape 1.D dans l'algorithme de comparaison d'égalité abstrait pour obtenir true comme valeur de '' == '0'. Parce que les deux chaînes ont des longueurs différentes (0 et 1), retournez false.

Conclusion

Vous vous demandez peut-être pourquoi vous devriez prendre la peine d'utiliser == et !=. Après tout, des exemples précédents ont montré que ces opérateurs peuvent être plus lents que les opérateurs === et !== en raison de la coulée et de la récursivité de type. Vous voudrez peut-être utiliser == et != car dans certains cas, il n'y a aucun avantage. Considérez l'exemple suivant: ===

<code class="language-javascript">"this_is_true" == false // false
"this_is_true" == true  // false</code>
L'opérateur

typeof renvoie une valeur String. Étant donné que la valeur String est comparée à une autre valeur String ("objet"), aucune coulée de type ne se produit, et == est aussi efficace que ===. Peut-être qu'un débutant JavaScript qui n'a jamais rencontré === trouvera un tel code plus clair. De même, l'extrait de code suivant ne nécessite pas de coulée de type (les types des deux opérandes sont Number), donc != est aussi efficace que !==:

<code class="language-javascript">'' == 0   // true
0 == '0' // true
'' == '0' // false</code>

Ces exemples montrent que == et != conviennent aux comparaisons qui ne nécessitent pas de coulée. Lorsque les types d'opérands sont différents, === et !== sont les meilleurs choix car ils retournent false plutôt que des valeurs inattendues (par exemple false == "" renvoie true). Si le type d'opérande est le même, il n'y a aucune raison de ne pas utiliser == et !=. Il est peut-être temps d'arrêter d'avoir peur des jumeaux diaboliques, et une fois que vous les comprenez, ils sont moins mauvais.

FAQS pour les opérateurs de l'égalité et de comparaison JavaScript (FAQ)

Quelle est la différence entre

== et === dans JavaScript?

en javascript, == et === sont des opérateurs de comparaison. Cependant, ils diffèrent dans la façon dont ils comparent les valeurs. L'opérateur == (également connu sous le nom de l'opérateur d'égalité lâche) effectue une coulée de type avant la comparaison. Cela signifie que si vous comparez deux types de valeurs différents, JavaScript essaiera de convertir un type en un autre avant d'effectuer la comparaison. D'un autre côté, l'opérateur === (appelé l'opérateur d'égalité strict) n'effectue pas de coulée de type. Il compare les valeurs et les types en même temps, ce qui signifie que si les deux types de valeurs sont différents, JavaScript les considérera comme inégaux.

Pourquoi devrais-je utiliser === au lieu de == en javascript?

est généralement recommandé d'utiliser === au lieu de == dans JavaScript, car il fournit des comparaisons plus strictes, ce qui signifie qu'il n'effectue pas de fonds de type et vérifie les valeurs et les types. Cela peut aider à éviter des résultats inattendus lors de la comparaison de différents types de valeurs. Par exemple, lors de l'utilisation de ==, JavaScript considère le nombre 0 et la chaîne vide "" égale, car il convertit le type avant la comparaison. Cependant, en utilisant ===, ils seront considérés comme inégaux car ils sont de types différents.

Qu'est-ce que le type est jeté en javascript?

Le type coulé dans JavaScript fait référence à la conversion automatique ou implicitement des valeurs d'un type de données en un autre. Cela se produit lorsque les opérateurs sont utilisés pour différents types d'opérands ou lorsqu'il est nécessaire d'un certain type. Par exemple, lors de l'utilisation de l'opérateur d'égalité lâche (==), JavaScript essaiera de convertir les opérandes en types généraux avant de faire des comparaisons.

Comment JavaScript gère-t-il la comparaison des objets?

Dans JavaScript, les objets sont comparés par référence, et non par valeur. Cela signifie que même si deux objets ont exactement les mêmes propriétés et valeurs, elles ne sont pas considérées comme égales car elles se réfèrent à différents objets en mémoire. Le seul cas où les objets sont considérés comme égaux est qu'ils se réfèrent exactement au même objet.

Quelle est la différence entre

== et != dans JavaScript?

== et != sont des opérateurs de comparaison en JavaScript. L'opérateur == vérifie si les valeurs des deux opérandes sont égales et effectue des lancers si nécessaire. D'un autre côté, l'opérateur != vérifie si les valeurs des deux opérandes ne sont pas égales et effectue des lancers de type si nécessaire.

Quelle est la différence entre

=== et !== dans JavaScript?

=== et !== sont des opérateurs de comparaison en JavaScript. L'opérateur === vérifie si les valeurs des deux opérandes sont égales, en tenant compte des valeurs et des types. En revanche, l'opérateur !== vérifie si les valeurs des deux opérandes ne sont pas égales, en tenant compte des valeurs et des types.

Comment comparer deux tableaux en JavaScript?

Dans JavaScript, les tableaux sont des objets, par rapport à la référence, et non par valeur. Cela signifie que même si deux tableaux contiennent les mêmes éléments dans le même ordre, ils ne sont pas considérés comme égaux car ils se réfèrent à différents objets en mémoire. Pour comparer deux tableaux par leur contenu, vous devez comparer chaque élément séparément.

Comment JavaScript gère-t-il la comparaison entre null et undefined?

dans JavaScript, null et undefined sont considérés comme vaguement égaux (==) car ils représentent tous les deux des valeurs manquantes. Cependant, ils ne sont pas strictement égaux (===) car ils sont de types différents.

Quel est l'ordre prioritaire des opérateurs de comparaison en JavaScript?

En JavaScript, les opérateurs de comparaison ont le même niveau de priorité. Ils sont calculés de gauche à droite. Cependant, il est important de noter qu'ils ont une priorité inférieure à celle des opérateurs arithmétiques et bit, mais plus élevés que les opérateurs logiques.

Puis-je utiliser des opérateurs de comparaison avec des chaînes en JavaScript?

Oui, vous pouvez utiliser des opérateurs de comparaison avec des chaînes en JavaScript. JavaScript utilise l'ordre lexical (dictionnaire) lors de la comparaison des chaînes. Cependant, il est important de noter que les lettres majuscules sont considérées comme "petites" que les lettres minuscules car elles ont des valeurs ASCII plus petites.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:Fondation 5Article suivant:Fondation 5