Pourquoi ("foo" === new String ("foo")) est-il évalué à faux en JavaScript?

98

J'allais commencer à utiliser === (triple égal, comparaison stricte) tout le temps lors de la comparaison des valeurs de chaîne, mais maintenant je trouve que

"foo" === new String("foo")

est faux, et pareil avec ceci:

var f = "foo", g = new String("foo");
f === g; // false

Bien sûr:

f == g; // true

Il est donc recommandé de toujours utiliser == pour la comparaison de chaînes, ou de toujours convertir les variables en chaînes avant de comparer?

Michael Butler
la source
6
Peut-être parce que fooc'est la chaîne pure et new String("foo")est la chaîne d'objet
Danilo Valente
6
Il est recommandé de ne pas créer de chaînes avec new String(Complètement inutile) plutôt que d'utiliser==
Esailija
2
Pourquoi quelqu'un voudrait-il utiliser une construction comme new String("foo")en Javascript en premier lieu? Je n'ai jamais vu un tel code dans le code, c'est-à-dire jQuery ...
Robert Koritnik
2
Vous pouvez utiliser String(obj)pour convertir une chaîne encadrée en primitive une fois que vous avez reçu votre paramètre "chaîne". ("foo" === String(new String("foo"))) === true
OrangeDog

Réponses:

126

"foo"est une chaîne primitive . (ce concept n'existe pas en C # ou Java)

new String("foo") est un objet de chaîne encadré.

L' ===opérateur se comporte différemment sur les primitives et les objets .
Lors de la comparaison de primitives (du même type), ===retournera true si les deux ont la même valeur.

Lors de la comparaison d'objets, ===retournera vrai uniquement s'ils font référence au même objet (comparaison par référence). Ainsi, new String("a") !== new String("a").

Dans votre cas, ===renvoie false car les opérandes sont de types différents (l'un est une primitive et l'autre est un objet).


Les primitives ne sont pas du tout des objets.
L' typeofopérateur ne reviendra pas "object"pour les primitives.

Lorsque vous essayez d'accéder à une propriété d'une primitive (en l'utilisant comme objet), le langage Javascript l'encadrera dans un objet, créant à chaque fois un nouvel objet. Ceci est décrit dans la spécification .

C'est pourquoi vous ne pouvez pas mettre de propriétés sur les primitives:

var x = "a";
x.property = 2;
alert(x.property) //undefined

Chaque fois que vous écrivez x.property, un objet encadré différentString est créé.

SLaks
la source
33
+1 typeof "foo"; // "string",typeof new String("foo"); // "object"
Sampson
1
Intéressant, je pensais que les chaînes étaient des objets dans JS.
Cameron Martin
1
@Sarfraz: Presque tout. N'oubliez pas nullet undefined.
2
if( Object(a) !== a ) { //it's a primitive }
Esailija
1
Java a des primitives / .Net n'a pas
Marcelo De Zen
34

En utilisant ===,

  • un objet n'est jamais égal à rien sauf à une autre référence à lui-même.

  • une primitive est égale par rapport à une autre primitive si leur type et leur valeur sont identiques.


la source
3
new String("foo") === new String("foo")est false:-P
Rocket Hazmat
10

Le newmot est un criminel ici ( comme d'habitude , puis-je dire) ...

Lorsque vous utilisez new, vous exprimez explicitement votre désir de travailler avec un objet . Cela peut être surprenant pour vous, mais ceci:

var x = new String('foo');
var y = new String('foo');
x === y; 

... vous donnera un puissant false. C'est simple: comparés ne sont pas les intérieurs des objets, mais les références des objets. Et ils, bien sûr, ne sont pas égaux, car deux objets différents ont été créés.

Ce que vous souhaitez probablement utiliser est la conversion :

var x = String('foo');
var y = String('foo');
x === y;

... et cela vous donnera, comme prévu, truecomme résultat, afin que vous puissiez vous réjouir et prospérer avec votre égal foospour toujours. )

raina77ow
la source
2
question rapide sur son utilisation. Vous appelez String (un constructeur?) Sans le mot clé 'new'. Cela ne signifie-t-il pas que vous polluerez la portée avec toutes les propriétés affectées dans le constructeur String? Ou cela ne se produit-il pas parce que le constructeur est du code natif? En d'autres termes, supposons que la fonction String contienne "this.a = 1;" - cela signifie que votre fonction / objet aurait maintenant une propriété a = 1.
Michael Butler
Je suppose (mais je ne peux pas le dire avec certitude) que chacune des fonctions du «constructeur de boxe» vérifie d'abord son contexte - et si ce n'est pas un «nouveau» (c'est-à-dire un objet prototype), passe immédiatement à la méthode de conversion. Dans le cas de String, ce serait la toString()méthode, par exemple.
raina77ow
4

fooest la chaîne pure et new String("foo")est la chaîne d'objet

Danilo Valente
la source
2

Depuis le REPL node.js ("node" sur la ligne de commande s'il est installé):

> "foo" === (new String("foo")).valueOf()
true
> "foo" === new String("foo")
false
> typeof("foo")
'string'
> typeof(new String("foo"))
'object'
> typeof((new String("foo")).valueOf())
'string'
mda
la source