Pourquoi ne ++[[]][+[]]+[+[]] de retour de la chaîne “10”?
C'est valide et renvoie la chaîne "10"
en JavaScript (d'autres exemples ici):
JS:
console.log(++[[]][+[]]+[+[]])
Pourquoi? Ce qui se passe ici?
- Commencer par comprendre que
+[]
jette un tableau vide à0
... puis les déchets d'un après-midi... 😉 - Connexes stackoverflow.com/questions/4170978/explain-why-this-works .
- Jetez un oeil à wtfjs.com - elle a pas mal de choses comme ça avec explanatinos.
- où voulez-vous apprendre ce genre de choses? Quels livres? J'apprends le JS de la SOCIÉTÉ et ils n'enseignent pas ces choses
- De la même manière que vous venez de faire: quelqu'un a posté à ce sujet quelque part et il m'est arrivé de le lire.
- Ces arent vraiment des choses que vous devriez utiliser dans la programmation normale. C'est juste un caprice de canard-typage et la conversion implicite. Vous avez probablement vu que vous pouvez utiliser
!
pour transformer un nombre en une valeur de type boolean. Vous pouvez utiliser+
à son tour un booléen ou une chaîne en un nombre. À partir de là, tout ce que vous devez comprendre est que les valeurs de retour truthy (contraindre à true ou 1) et les valeurs de retour falsey (contraindre à false ou 0)
Vous devez vous connecter pour publier un commentaire.
Si nous diviser, le carré est égal à:
En JavaScript, il est vrai que
+[] === 0
.+
convertit quelque chose dans un certain nombre, et dans ce cas, il sera de+""
ou0
(voir la spécification des détails ci-dessous).Par conséquent, nous pouvons le simplifier (
++
a precendence sur+
):Parce que
[[]][0]
signifie: obtenir le premier élément de[[]]
, il est vrai que:[[]][0]
renvoie l'intérieur array ([]
). En raison de références, il est faux de dire[[]][0] === []
, mais nous allons appeler l'intérieur de la matrice deA
pour éviter la mauvaise notation.++[[]][0] == A + 1
, depuis++
signifie "incrément par un".++[[]][0] === +(A + 1)
; en d'autres termes, il sera toujours un nombre (+1
ne renvoie pas nécessairement à un nombre, alors que++
le fait toujours - grâce à Tim vers le Bas pour le signaler).Encore une fois, nous pouvons simplifier le désordre dans quelque chose de plus lisible. Nous allons remplacer
[]
de retour pourA
:En JavaScript, c'est vrai:
[] + 1 === "1"
, parce que[] == ""
(joindre un tableau vide), donc:+([] + 1) === +("" + 1)
, et+("" + 1) === +("1")
, et+("1") === 1
Nous allons simplifier encore plus:
Aussi, c'est vrai qu'en JavaScript:
[0] == "0"
, parce que c'est rejoindre un tableau avec un seul élément. Joindre à concaténer les éléments séparés par des,
. Avec un seul élément, vous pouvez en déduire que cette logique du premier élément lui-même.Donc, à la fin, nous obtenons (nombre + string = string):
Des spécifications détaillées pour
+[]
:C'est un labyrinthe, mais de faire
+[]
, d'abord, il est converti en chaîne, car c'est ce que+
dit:ToNumber()
dit:ToPrimitive()
dit:[[DefaultValue]]
dit:La
.toString
d'un tableau dit:Donc
+[]
revient à+""
, parce que[].join() === ""
.Encore une fois, la
+
est défini comme:ToNumber
est défini pour""
comme:Donc
+"" === 0
, et donc+[] === 0
.++[[]][0]
à[] + 1
?[[]][0]
est que imbriquée[]
.++
incréments de avec un, il retourne[] + 1
.++[[]][0]
à[] + 1
" transformation explicite dans le post. Cela rend la chose beaucoup plus compréhensible pour ceux d'entre nous qui ne connais pas le JavaScript!=
pour l'affectation et l'==
pour comparaison. Qu'est-ce que===
?true
si à la fois la valeur et de la nature sont les mêmes.0 == ""
retournetrue
(même après la conversion de type), mais0 === ""
estfalse
(pas les mêmes types).1 + [0]
, pas"1" + [0]
, parce que le préfixe (++
) opérateur renvoie toujours un nombre. Voir bclary.com/2004/11/07/#a-11.4.4++[[]][0]
renvoie en effet1
, mais++[]
renvoie une erreur. Ce qui est remarquable, parce qu'il ressemble à++[[]][0]
ne se résument++[]
. Avez-vous peut-être une idée de pourquoi++[]
déclenche une erreur alors que++[[]][0]
ne l'est pas?PutValue
appel (ES3 terminologie, 8.7.2) dans le préfixe de l'opération.PutValue
requiert une Référence alors que[]
comme une expression de sa propre ne produit pas une Référence. Une expression contenant une référence à une variable (disons nous avions défini précédemmentvar a = []
puis++a
travaux) ou l'accès à la propriété d'un objet (comme[[]][0]
) produit de Référence. En termes plus simples, le préfixe de l'opérateur non seulement produit une valeur, elle a également besoin d'un endroit pour mettre cette valeur.var a = []; ++a
,a
est 1. Après l'exécution de++[[]][0]
, le tableau créé par le[[]]
expression est maintenant contient juste le numéro 1 à l'indice 0.++
requiert une Référence pour ce faire.instanceof Array
(comme[]
) sera jamais===
unArray
autres que lui-même, comme l'Opérateur de Comparaison Stricte compare simplement lref à rref (c'est à dire les emplacements de mémoire de chaque instance). Je ne recommanderais pas ce qui implique même ce. Vous pouvez également noter dans votre réponse que JS' Unaire+
Opérateur a la préséance sur le résultat d'une expression arithmétique résultat ou la concaténation de chaîne (selon le contexte) avec++
ou+
c'est pourquoi+[]
obtient d'abord évaluée.Ensuite, nous avons une concaténation de chaîne
===
plutôt que=>
?Ce qui suit est adapté à partir d'un post de blog de répondre à cette question que j'ai posté alors que cette question était encore fermé. Les liens sont à (HTML copie de) la ECMAScript 3 spec, toujours la référence pour JavaScript aujourd'hui couramment utilisé des navigateurs web.
Tout d'abord, un commentaire: ce genre d'expression ne va jamais à faire (sane) environnement de production et n'a d'utilité que comme un exercice de la façon dont le lecteur connaît la sale bords de JavaScript. Le principe général que les opérateurs JavaScript implicitement la conversion entre les types de est utile, comme le sont certains de la commune de conversions, mais beaucoup de détails dans ce cas, ne l'est pas.
L'expression
++[[]][+[]]+[+[]]
peut au premier abord sembler plutôt imposant et obscure, mais est en fait relativement facile de briser dans des expressions séparées. Ci-dessous, j'ai simplement ajouté entre parenthèses pour plus de clarté, je peux vous assurer qu'ils ne changent rien, mais si vous voulez vérifier que alors n'hésitez pas à lire les groupement de l'opérateur. Ainsi, l'expression peut être écrite plus clairement queFaire, nous pouvons simplifier en observant que
+[]
évalue à0
. Pour satisfaire vous-même pourquoi c'est vrai, consultez le unaire + opérateur et suivez les légèrement tortueux sentier qui se termine avec ToPrimitive convertir le vide d'un tableau dans une chaîne vide, ce qui est finalement converti à0
par ToNumber. Nous pouvons maintenant remplacer0
pour chaque instance de+[]
:Plus simple déjà. Comme pour
++[[]][0]
, qui est une combinaison de la préfixe opérateur d'incrémentation (++
), un littéral de tableau la définition d'un tableau à un seul élément qui est lui-même un tableau vide ([[]]
) et un propriété de l'accesseur ([0]
) a appelé la matrice définie par le littéral de tableau.Donc, nous pouvons simplifier
[[]][0]
juste[]
et nous avons++[]
, droit? En fait, ce n'est pas le cas, car l'évaluation de++[]
renvoie une erreur, ce qui peut paraître déroutant. Cependant, un peu de réflexion sur la nature de++
est clair à ce sujet: il est utilisé pour incrémenter une variable (par exemple,++i
) ou une propriété de l'objet (par exemple,++obj.count
). Non seulement il s'évaluer à une valeur, il stocke également que la valeur de quelque part. Dans le cas de++[]
, il n'a nulle part où mettre la nouvelle valeur (quelle qu'elle soit) parce qu'il n'y est fait aucune référence à une propriété de l'objet ou variable de mise à jour. Dans spec termes, cela est couvert par l'interne PutValue opération, qui est appelée par le préfixe de l'opérateur d'incrémentation.Alors, ce n'
++[[]][0]
faire? Eh bien, par la même logique que+[]
, à l'intérieur de la matrice est converti à0
et cette valeur est incrémentée par1
pour nous donner une valeur finale de1
. La valeur de la propriété0
à l'extérieur tableau est mis à jour pour1
et l'ensemble de l'expression est évaluée à1
.Ce qui nous laisse avec
... qui est une simple utilisation de la opérateur d'addition. Les deux opérandes sont d'abord converti primitives et si une primitive de la valeur est une chaîne, la concaténation de chaîne est exécutée, sinon addition est effectuée.
[0]
convertit à"0"
, de sorte que la concaténation de chaîne est utilisé, la production de"10"
.Comme une finale de côté, quelque chose qui peut ne pas être immédiatement apparent est primordial, soit l'un des
toString()
ouvalueOf()
méthodes deArray.prototype
va changer le résultat de l'expression, parce que les deux sont contrôlés et utilisés s'il est présent lors de la conversion d'un objet en une valeur primitive. Par exemple, la suite... produit
"NaNfoo"
. Pourquoi cela se produit est laissé comme exercice pour le lecteur...Nous allons faire simple:
Ce que l'on évalue de la même mais un peu plus petit
est donc évalue à
Alors maintenant, vous l'avez compris, essayez celui-ci:
+[] prend la valeur 0
[...] ensuite somme (+ fonctionnement) avec quoi que ce soit convertit tableau contenu de sa représentation sous forme de chaîne composée des éléments rejoint par des virgules.
Autre chose comme prendre de l'indice du tableau (ont râpe prioritaire que l'opération+) est ordinale et ne trouve rien d'intéressant.
Peut-être la plus courte possible, des moyens pour évaluer une expression en "10" sans chiffres sont les suivants:
+!+[] + [+[]]
//"10"-~[] + [+[]]
//"10"//========== Explication ==========\\
+!+[]
:+[]
Convertit à 0.!0
convertit àtrue
.+true
convertit à 1.-~[]
=-(-1)
qui est de 1[+[]]
:+[]
Convertit à 0.[0]
est un tableau à un seul élément 0.Puis JS évalue la
1 + [0]
, ainsiNumber + Array
expression. Puis la spécification ECMA travaux:+
opérateur convertit les deux opérandes d'une chaîne en appelant letoString()/valueOf()
fonctions à partir de la baseObject
prototype. Il fonctionne comme un additif de la fonction si les deux opérandes d'une expression sont que des chiffres. Le truc, c'est que les piles de convertir facilement leurs éléments dans une chaîne concaténée représentation.Quelques exemples:
Il y a une belle exception de deux
Objects
plus de résultats dansNaN
:+" ou " + [] évalue 0.
[]
est pas équivalent à""
. D'abord l'élément est extrait, puis converti par++
.Étape par étapes de l',
+
son tour de la valeur à un nombre et si vous ajoutez à un tableau vide+[]
...comme c'est vide et est égale à0
, ilDonc à partir de là, maintenant, regardez dans votre code, il est
++[[]][+[]]+[+[]]
...Et il n'y a plus entre eux
++[[]][+[]]
+[+[]]
De sorte que ces
[+[]]
sera de retour[0]
comme ils ont un tableau vide qui est converti à0
à l'intérieur de l'autre tableau...De sorte que l'imaginer, la première valeur est un 2 dimensions tableau avec un tableau à l'intérieur... donc
[[]][+[]]
sera égal à[[]][0]
qui sera de retour[]
...Et à la fin
++
le convertir et l'augmenter pour1
...De sorte que vous pouvez l'imaginer,
1
+"0"
sera"10"
...