Je n'ai pas vraiment compris à partir de Rayonne de répondre à la manière dont valueOf
et toString
entrent en jeu lors de la conversion d'un objet à une valeur primitive; alors j'ai creusé dans le ECMAScript 2015 cahier des charges.
Avertissement: Longue réponse.
Nous voulons vérifier l'expression 1 == [1]
.
À partir de la 12.10 Opérateurs d'Égalité , nous voyons que, après l'extraction des expressions de valeurs, la dernière étape est
- De retour à la suite de l'exécution de l'Abstrait Comparaison d'Égalité rval == lval
Résumé Comparaison d'Égalité est définie au chapitre 7.2.12 Abstrait Comparaison d'Égalité.
7.2.12 Abstrait Comparaison D'Égalité
La comparaison x == y, où x et y sont des valeurs, produit des vrai ou faux. Une telle comparaison est effectuée comme suit:
- ReturnIfAbrupt(x).
- ReturnIfAbrupt(y).
- Si le Type(x) est le même que le Type(y), alors
un. Retourner le résultat de l'exécution Stricte Comparaison d'Égalité x === y.
- Si x est nul et y est pas défini, retourner la valeur true.
- Si x n'est pas définie et y est nul, retourne true.
- Si le Type(x) est le Nombre et le Type(y) est une Chaîne, retourner le résultat de la comparaison x == ToNumber(y).
- Si le Type(x) est une Chaîne et le Type(y) est le Nombre, de retourner le résultat de la comparaison ToNumber(x) == y.
- Si le Type(x) est de type Boolean, retourner le résultat de la comparaison ToNumber(x) == y.
- Si le Type(y) est un Booléen, retourner le résultat de la comparaison x == ToNumber(y).
-
Si le Type(x) est une Chaîne, un Nombre ou un Symbole et le Type(y) est l'Objet, puis
retourner le résultat de la comparaison x == ToPrimitive(y).
- Si le Type(x) est l'Objet et le Type(y) est une Chaîne, un Nombre ou un Symbole, puis retourner le résultat de la comparaison ToPrimitive(x) == y.
- Retourne la valeur false.
L'expression 1 == [1]
relève de cas 10.
Donc, fondamentalement, comme prévu, le tableau [1]
est convertie en une valeur de type primitif.
ToPrimitive est de définir au 7.1.1 ToPrimitive ( input [, PreferredType] )
Le résumé de l'opération ToPrimitive prend un argument d'entrée et un argument optionnel PreferredType. L'
résumé de l'opération ToPrimitive convertit son argument d'entrée à un non-type d'Objet.
Je n'ai pas compris la citation complète depuis le seul intéressant, pour cet exemple, les pièces sont:
- Le PreferredType argument (en fait un indicateur de var) est converti à partir de "par défaut" (puisqu'il n'est pas passé) à "nombre".
-
OrdinaryToPrimitive
est appelée avec les mêmes arguments.
E maintenant la partie intéressante, OrdinaryToPrimitive effectuer les opérations suivantes:
- Affirmer: Type(O) est l'Objet
- Affirmer: Type(indice) est une Chaîne de caractère et sa valeur est "chaîne" ou "nombre".
- Si le soupçon est la "chaîne", puis
un. Laissez methodNames être «"toString", "valueOf"».
- Autre chose,
un. Laissez methodNames être «"valueOf", "toString"».
- Pour chaque nom dans methodNames dans l'ordre de la Liste, n'
un. Laissez la méthode Get(O, nom).
b. ReturnIfAbrupt(méthode).
c. Si IsCallable(méthode) est vrai, alors
... j'. Laissez résultat(Appel de méthode, O).
... ii. ReturnIfAbrupt(le résultat).
... iii. **Si le Type(résultat) n'est pas Objet, résultat de retour. **
- Jeter une exception TypeError
Afin de convertir [1]
valeur primitive, le moteur d'exécution tout d'abord essayer de l'appeler valueOf
. Cette méthode retourne un tableau lui-même, qui est un objet par 5.c.iii la méthode toString
est ensuite appelée.
Cette méthode retourne les éléments de la matrice comme une liste séparée par des virgules, donc elle retourne la chaîne de caractères "1"
.
Nous sommes donc réduits en comparant 1 == "1"
qui, de par les règles de l' Abstrait Comparaison d'Égalité, point 6, les moyens de convertir "1"
en nombre 1
et que d'effectuer la comparaison triviale 1 = 1
.
Le triste lecteur est invité à vérifier comment l'Égalité Stricte Comparaison est en fait défini dans la norme.
Vous pouvez jouer avec cette conversions pour mieux comprendre, voici un exemple d'aire de jeux fichier HTML
<html>
<head><title>title</title></head>
<body>
<script>
var old_valueOf = Array.prototype.valueOf;
var old_toString = Array.prototype.toString;
Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return old_valueOf.apply(this); };
Array.prototype.toString = function(){ console.log("Array::toString"); return old_toString.apply(this); };
console.log(1 == [1]); //Array::valueOf, Array::toString, true
Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return 2; };
console.log(1 == [1]); //Array::valueOf, false
Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return {}; };
Array.prototype.toString = function(){ console.log("Array::toString"); return {} };
console.log(1 == [1]); //Array::valueOf, Array::toString, Uncaught TypeError: Cannot convert object to primitive value
</script>
</body>
</html>