web-dev-qa-db-fra.com

Pourquoi + est-il si mauvais pour la concaténation?

Tout le monde continue de dire que l'un des problèmes de JavaScript utilise + [ exemple ] pour la concaténation de chaînes. Certains disent que le problème n'utilise pas +, c'est du type coercition [voir les commentaires de l'exemple précédent]. Mais les langues fortement typées utilisent + pour les types de concaténation et de contrainte sans aucun problème. Par exemple, en C #:

int number = 1;
MyObject obj = new MyObject();

var result = "Hello" + number + obj;
// is equivalent to
string result = "hello" + number.ToString() + obj.ToString();

Alors pourquoi la concaténation de chaînes en JavaScript est-elle un si gros problème?

44
configurator

Considérez ce morceau de code JavaScript:

var a = 10;
var b = 20;
console.log('result is ' + a + b);

Cela enregistrera

le résultat est 1020

Ce qui n'est probablement pas ce qui était prévu et peut être un bug difficile à suivre.

69
Mchl

Quand vous dites "mauvais", voulez-vous dire "incorrect" ou voulez-vous dire "lent"? L'argument sur l'utilisation d'opérateurs mathématiques pour effectuer la concaténation de chaînes est sans doute un argument "incorrect", mais il y a également un argument à faire selon lequel + faire beaucoup de concaténation de chaînes peut être très lent.

Nous ne parlons pas de "Hello" + number lorsque nous parlons de performances, nous parlons de construire une chaîne relativement grande en y ajoutant plusieurs fois en boucle.

var combined = "";
for (var i = 0; i < 1000000; i++) {
    combined = combined + "hello ";
}

En JavaScript (et C # d'ailleurs) les chaînes sont immuables. Ils ne peuvent jamais être modifiés, seulement remplacés par d'autres chaînes. Vous savez probablement que combined + "hello " ne modifie pas directement la variable combined - l'opération crée une nouvelle chaîne qui résulte de la concaténation des deux chaînes, mais vous devez ensuite affecter cette nouvelle chaîne à la variable combined si vous voulez qu'il soit changé.

Donc, ce que fait cette boucle, c'est de créer un million d'objets chaîne différents et d'en jeter 999 999. Créer autant de chaînes dont la taille ne cesse de croître n'est pas rapide, et maintenant le garbage collector a beaucoup de travail à faire pour nettoyer après cela.

C # a exactement le même problème, qui est résolu dans cet environnement par la classe StringBuilder . En JavaScript, vous obtiendrez de bien meilleures performances en créant un tableau de toutes les chaînes que vous souhaitez concaténer, puis en les réunissant une fois à la fin, au lieu d'un million de fois dans la boucle:

var parts = [];
for (var i = 0; i < 1000000; i++) {
    parts.Push("hello");
}
var combined = parts.join(" ");
44
Joel Mueller

Ce n'est pas mal d'utiliser + pour l'addition et la concaténation, tant que vous ne pouvez ajouter que des nombres, et seulement concaténer des chaînes. Cependant, Javascript convertira automatiquement entre les nombres et les chaînes selon les besoins, vous avez donc:

3 * 5 => 15
"3" * "5" => 15
2 + " fish" => "2 fish"
"3" + "5" => "35"  // hmmm...

Peut-être plus simplement, la surcharge de "+" en présence d'une conversion de type automatique rompt l'associativité attendue de l'opérateur +:

("x" + 1) + 3 != "x" + (1 + 3)
14
kevin cline

Le problème typique soulevé pour la concaténation de chaînes tourne autour de quelques problèmes:

  1. le symbole + est surchargé
  2. erreurs simples
  3. les programmeurs étant paresseux

#1

Le premier problème avant tout avec l'utilisation de + Pour la concaténation de chaînes et est que vous utilisez + Pour la concaténation de chaînes ( et addition.

si vous avez des variables a et b, et que vous définissez c = a + b, il y a une ambiguïté qui dépend des types de a et b . Cette ambiguïté vous oblige à prendre des mesures supplémentaires pour atténuer le problème:

Concat String:

c = '' + a + b;

Une addition:

c = parseFloat(a) + parseFloat(b);

Cela m'amène à mon deuxième point

# 2

Il est très facile de convertir accidentellement une variable en chaîne sans le réaliser. Il est également facile d'oublier que votre entrée arrive sous forme de chaîne:

a = Prompt('Pick a number');
b = Prompt('Pick a second number');
alert( a + b );

Produira des résultats non intuitifs car Prompt renvoie la valeur de chaîne de l'entrée.

# 3

Avoir besoin de taper parseFloat ou Number() chaque fois que je veux faire un ajout est fastidieux et ennuyeux. Je me considère comme assez intelligent pour me souvenir de ne pas gâcher mes types dynamiques, mais cela ne signifie pas que je n'ai jamais foiré mes types dynamiques . La vérité est que je suis trop paresseux pour taper parseFloat ou Number() chaque fois que je fais un ajout, parce que je fais beaucoup d'addition.

Solution?

Toutes les langues n'utilisent pas + Pour la concaténation de chaînes. PHP utilise . Pour concaténer des chaînes, ce qui permet de faire la distinction entre quand vous voulez ajouter des nombres et quand vous voulez joindre des chaînes.

N'importe quel symbole peut être utilisé pour concaténer des chaînes, mais la plupart sont déjà utilisés, et il est préférable d'éviter la duplication. Si je le pouvais, j'utiliserais probablement _ Pour joindre des chaînes et interdire _ Dans les noms de variables.

10
zzzzBov