171 votes

Pourquoi 2 == [2] en JavaScript?

J'ai récemment découvert que 2 == [2] en JavaScript. Comme il s'avère, de ce caprice a un couple d'intéressantes conséquences:

var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true

De même, les ouvrages suivants:

var a = { "abc" : 1 };
a[["abc"]] === a["abc"]; // this is also true

Encore plus étrange encore, cela fonctionne ainsi:

[[[[[[[2]]]]]]] == 2; // this is true too! WTF?

Ces comportements semblent compatibles sur tous les navigateurs.

Aucune idée de pourquoi c'est une fonctionnalité du langage?

EDIT: Voici encore plus fou les conséquences de cette "fonctionnalité":

[0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!

var a = [0];
a == a // true
a == !a // also true, WTF?

Ces exemples ont été trouvés par jimbojw de trépan et http://jimbojw.com la renommée ainsi que walkingeyerobot.

138voto

Christoph Points 64389

Vous pouvez rechercher l'algorithme de comparaison dans l'ECMA-spec (sections pertinentes de l'ECMA-262, 3e édition pour votre problème: 11.9.3, 9.1, 8.6.2.6).

Si vous traduire les algorithmes abstraits retour à la JS, ce qui se passe lors de l'évaluation d' 2 == [2] est essentiellement ceci:

2 === Number([2].valueOf().toString())

valueOf() pour les tableaux retourne le tableau lui-même et de la chaîne-représentation d'un élément de tableau est la représentation sous forme de chaîne de l'élément unique.

Ce qui explique aussi le troisième exemple que [[[[[[[2]]]]]]].toString() est toujours juste de la corde 2.

Comme vous pouvez le voir, il ya beaucoup de derrière-le-scène quelque chose de magique, c'est pourquoi je l'utilise généralement l'opérateur d'égalité stricte ===.

Le premier et le deuxième exemple est plus facile de suivre que les noms de propriétés sont toujours des chaînes, donc

a[[2]]

est équivalent à

a[[2].toString()]

ce qui est juste

a["2"]

Gardez à l'esprit que même les touches numériques sont traités comme des noms de propriété (c'est à dire des chaînes de caractères) avant tout de la matrice magie qui se passe.

10voto

Chetan Sastry Points 14742

C'est à cause de la conversion de type implicite de l'opérateur == .

[2] est converti en Nombre est 2 par rapport à un Nombre. Essayez l'opérateur unaire + sur [2].

 > +[2]
2
 

10voto

Shawn Points 8120
var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true

Sur le côté droit de l'équation, nous avons l'un[2], qui renvoie un nombre de type avec la valeur 2. Sur la gauche, nous sommes d'abord la création d'un nouveau tableau avec un seul objet de 2. Ensuite, nous faisons appel à un[(tableau est ici)]. Je ne suis pas sûr si elle correspond à une chaîne ou un nombre. 2, ou "2". Permet de prendre la chaîne de cas première. Je crois qu'un["2"] créer une nouvelle variable et renvoie null. null !== 2. Donc permet de supposer qu'il est en fait implicitement la conversion d'un nombre. [2] serait de retour 2. 2 et 2 correspondent au type (donc === travaux) et de la valeur. Je pense que c'est implicitement la conversion du tableau pour un certain nombre, car un[valeur] s'attend à une chaîne ou un nombre. Il ressemble à nombre prend la priorité.

Sur une note de côté, je me demande qui détermine que la préséance. C'est parce que [2] a un certain nombre, comme c'est le premier élément, de sorte qu'il convertit en un nombre? Ou est-ce que lors du passage d'un tableau en une[array] il tente de transformer le tableau en un nombre premier, alors la chaîne. Qui sait?

var a = { "abc" : 1 };
a[["abc"]] === a["abc"];

Dans cet exemple, vous créez un objet appelé un avec un membre appelé abc. Le côté droit de l'équation est assez simple; il est équivalent à un.abc. Cela renvoie 1. Le côté gauche d'abord crée un littéral de tableau ["abc"]. Ensuite, vous recherchez une variable sur un objet en passant dans le tableau nouvellement créé. Depuis cette attend une chaîne, il convertit le tableau en une chaîne de caractères. Cette évalue maintenant à un["abc"], qui est égal à 1. 1 et 1 sont du même type (c'est pourquoi === travaux) et de valeur équivalente.

[[[[[[[2]]]]]]] == 2;

C'est juste une conversion implicite. === ne fonctionne pas dans cette situation parce qu'il y est une incompatibilité de type.

8voto

Dan Hook Points 1765

Pour le cas == , c'est pourquoi Doug Crockford recommande toujours d'utiliser === . Il ne fait aucune conversion de type implicite.

Pour les exemples avec === , la conversion de type implicite est effectuée avant l'appel de l'opérateur d'égalité.

8voto

Alexander Abramov Points 603
 [0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!
 

C'est intéressant, ce n'est pas que [0] soit à la fois vrai et faux,

 [0] == true // false
 

C'est la façon amusante de traiter l'opérateur if () de javascript.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X