JavaScript a-t-il une classe de constructeur de chaînes intégrée?

Réponses:

320

Si vous devez écrire du code pour Internet Explorer, assurez-vous d'avoir choisi une implémentation qui utilise des jointures de tableau. La concaténation des chaînes avec l' opérateur +ou +=est extrêmement lente sur IE. Cela est particulièrement vrai pour IE6. Sur les navigateurs modernes, +=c'est généralement aussi rapide que les jointures de tableaux.

Lorsque je dois faire beaucoup de concaténations de chaînes, je remplis généralement un tableau et n'utilise pas de classe de générateur de chaînes:

var html = [];
html.push(
  "<html>",
  "<body>",
  "bla bla bla",
  "</body>",
  "</html>"
);
return html.join("");

Notez que les pushméthodes acceptent plusieurs arguments.

Fabian Jakobs
la source
7
Et si vous générez une sortie en ligne, ou si tous les membres sont des littéraux, cela [foo(), "bar", "baz"].join("");fonctionne également.
Anonyme le
1
Bien que l'on ne puisse probablement pas s'attendre à ce que les liens Dropbox restent opérationnels pendant près de 3 ans, je serais curieux de connaître la comparaison - et si elle tient toujours.
Cornelius
1
@DaveWard, votre lien est rompu :(
Ivan Kochurkin
Je trouve que c'est beaucoup plus lisible que chaîne + chaîne + chaîne
Andrew Ehrlich
12
Je ne savais pas que je pushpouvais accepter plusieurs arguments. Les choses aléatoires que vous apprenez.
Carcigenicate
55

Je viens de revérifier les performances sur http://jsperf.com/javascript-concat-vs-join/2 . Les cas de test concaténent ou rejoignent l'alphabet 1000 fois.

Dans les navigateurs actuels (FF, Opera, IE11, Chrome), "concat" est environ 4 à 10 fois plus rapide que "join".

Dans IE8, les deux renvoient des résultats à peu près égaux.

Dans IE7, «rejoindre» est malheureusement environ 100 fois plus rapide.

Andreas
la source
3
Merci pour cela. Cela devrait être ajouté à la liste de réponses. C'est aussi beaucoup plus rapide sur IE10 (je sais que ce n'est pas un navigateur moderne, mais je le mentionne pour tous les développeurs NMCI potentiels qui le voient).
James Wilson
@Andreas Je crois que votre test atteint un chemin de code dans Chrome où il ne fait jamais la concaténation réelle car la chaîne n'est jamais lue. Même en forçant cela, cependant, la vitesse d'exécution est encore considérablement plus rapide: jsperf.com/yet-another-string-concat-test/1
Joseph Lennox
37

Non, il n'y a pas de prise en charge intégrée pour la création de chaînes. Vous devez utiliser la concaténation à la place.

Vous pouvez, bien sûr, créer un tableau de différentes parties de votre chaîne, puis appeler join()ce tableau, mais cela dépend alors de la façon dont la jointure est implémentée dans l'interpréteur JavaScript que vous utilisez.

J'ai fait une expérience pour comparer la vitesse de la str1+str2méthode par rapport à la array.push(str1, str2).join()méthode. Le code était simple:

var iIterations =800000;
var d1 = (new Date()).valueOf();
str1 = "";
for (var i = 0; i<iIterations; i++)
    str1 = str1 + Math.random().toString();
var d2 = (new Date()).valueOf();
log("Time (strings): " + (d2-d1));

var d3 = (new Date()).valueOf();
arr1 = [];
for (var i = 0; i<iIterations; i++)
    arr1.push(Math.random().toString());
var str2 = arr1.join("");
var d4 = (new Date()).valueOf();
log("Time (arrays): " + (d4-d3));

Je l'ai testé dans Internet Explorer 8 et Firefox 3.5.5, tous deux sur un Windows 7 x64.

Au début j'ai testé sur un petit nombre d'itérations (quelques centaines, quelques milliers d'éléments). Les résultats étaient imprévisibles (parfois la concaténation de chaînes prenait 0 millisecondes, parfois 16 millisecondes, la même chose pour la jonction de tableaux).

Lorsque j'ai augmenté le nombre à 50000, les résultats étaient différents selon les navigateurs - dans Internet Explorer, la concaténation des chaînes était plus rapide (94 millisecondes) et la jointure était plus lente (125 millisecondes), tandis que dans Firefox, la jointure du tableau était plus rapide (113 millisecondes) que jonction de chaînes (117 millisecondes).

Puis j'ai augmenté le nombre à 500'000. Désormais, la concaténation de chaînesarray.join() était plus lente que la concaténation de chaînes dans les deux navigateurs: la concaténation de chaînes était de 937 ms dans Internet Explorer, de 1155 ms dans Firefox, de la jointure de tableau 1265 dans Internet Explorer et de 1207 ms dans Firefox.

Le nombre maximum d'itérations que j'ai pu tester dans Internet Explorer sans avoir "le script prend trop de temps à s'exécuter" était de 850 000. Ensuite, Internet Explorer était de 1593 pour la concaténation de chaînes et 2046 pour la jointure de tableau, et Firefox avait 2101 pour la concaténation de chaîne et 2249 pour la jointure de tableau.

Résultats - si le nombre d'itérations est petit, vous pouvez essayer de l'utiliser array.join(), car cela pourrait être plus rapide dans Firefox. Lorsque le nombre augmente, la string1+string2méthode est plus rapide.

METTRE À JOUR

J'ai effectué le test sur Internet Explorer 6 (Windows XP). Le processus s'est arrêté pour répondre immédiatement et ne s'est jamais terminé, si j'essayais le test sur plus de 100 000 itérations. Sur 40000 itérations, les résultats ont été

Time (strings): 59175 ms
Time (arrays): 220 ms

Cela signifie que si vous devez prendre en charge Internet Explorer 6, choisissez celui array.join()qui est bien plus rapide que la concaténation de chaînes.

naïvistes
la source
join()fait partie d'ECMAScript et afaik chaque interpréteur JavaScript l'implémente. Pourquoi cela «dépendrait-il»?
Eli Gray
il voulait dire COMMENT il a été implémenté ... s'il est implémenté de manière à ce que, dans une boucle, la chaîne soit continuellement ajoutée par opposition à créée en même temps, alors utiliser join serait inutile
John
Oui, c'était ce que je voulais dire. Pardon mon anglais ;-) J'ai ajouté les résultats d'une comparaison à quelle vitesse quelle méthode fonctionne dans deux navigateurs. Vous pouvez voir, c'est différent.
naivistes
2
IE6, comme toujours, est l'exception :)
Gordon Tucker
10
Les gens avec IE6 ont l'habitude d'avoir tout très lent cependant. Je ne pense pas qu'ils vous blâmeront.
Lodewijk
8

Ce code ressemble à l'itinéraire que vous souhaitez emprunter avec quelques modifications.

Vous voudrez changer la méthode d'ajout pour qu'elle ressemble à ceci. Je l'ai changé pour accepter le numéro 0 et pour le faire revenir thisafin que vous puissiez enchaîner vos appendices.

StringBuilder.prototype.append = function (value) {
    if (value || value === 0) {
        this.strings.push(value);
    }
    return this;
}
Gordon Tucker
la source
Pourquoi n'accepter que les nombres non-NaN et les chaînes non vides? Votre méthode n'acceptera pas null, false, des chaînes vides, undefinedou NaN.
Eli Gray
@Elijah - Je préfère garder ma classe StringBuilder propre en n'acceptant rien d'autre que des chaînes et des nombres valides. C'est juste une préférence personnelle.
Gordon Tucker
5

La version ECMAScript 6 (alias ECMAScript 2015) de JavaScript a introduit des littéraux de chaîne .

var classType = "stringbuilder";
var q = `Does JavaScript have a built-in ${classType} class?`;

Notez que les rétro-graduations, au lieu des guillemets simples, entourent la chaîne.

Théophile
la source
17
Comment cela répond-il à la question?
Peter Mortensen
@Peter Mortensen, cette réponse donne simplement un autre moyen de construire une chaîne. L'affiche originale n'a pas précisé quel type de fonctionnalité de générateur de chaîne était recherché.
Theophilus
1
Cela ne répond pas à la question. Du tout.
Massimiliano Kraus
2

En C #, vous pouvez faire quelque chose comme

 String.Format("hello {0}, your age is {1}.",  "John",  29) 

En JavaScript, vous pouvez faire quelque chose comme

 var x = "hello {0}, your age is {1}";
 x = x.replace(/\{0\}/g, "John");
 x = x.replace(/\{1\}/g, 29);
des sports
la source
2
Je doute fortement que l'exécution d'une expression régulière à la place d'une jointure de chaîne soit plus performante
tic
De plus, c'est une mise en œuvre horrible. Il se cassera si la chaîne par laquelle {0}est remplacé contient {1}.
ikegami
@ikegami la chaîne n'est pas une variable, c'est une constante, donc vous savez ce qui est contenu a priori.
sports
@sports, copier et coller tout cela dans tout votre code est une idée encore pire.
ikegami
Une doublure avec $ 1 et $ 2 remplaçant les groupes non capturés: x..replace (/ ([\ s \ S] *?) \ {0 \} ([\ s \ S] *?) \ {1 \} / g, "$ 1Tom $ 225")
T.CK
1

Pour les personnes intéressées, voici une alternative à l'appel de Array.join:

var arrayOfStrings = ['foo', 'bar'];
var result = String.concat.apply(null, arrayOfStrings);
console.log(result);

La sortie, comme prévu, est la chaîne 'foobar'. Dans Firefox, cette approche surpasse Array.join mais est surperformée par la concaténation +. Étant donné que String.concat nécessite que chaque segment soit spécifié comme argument distinct, l'appelant est limité par toute limite de nombre d'arguments imposée par le moteur JavaScript en cours d'exécution. Jetez un œil à la documentation de Function.prototype.apply () pour plus d'informations.

Aaron
la source
Cela échoue dans Chrome, car "String.concat" n'est pas défini. À la place, vous pouvez utiliser '' .concat.apply ('', arrayOfStrings). Mais c'est encore une méthode très lente.
Andreas
1

J'ai défini cette fonction:

function format() {
        var args = arguments;
        if (args.length <= 1) { 
            return args;
        }
        var result = args[0];
        for (var i = 1; i < args.length; i++) {
            result = result.replace(new RegExp("\\{" + (i - 1) + "\\}", "g"), args[i]);
        }
        return result;
    }

Et peut être appelé comme c #:

 var text = format("hello {0}, your age is {1}.",  "John",  29);

Résultat:

bonjour John, tu as 29 ans.

TotPeRo
la source
1
J'aime ça ... ressemble à c #
Ayo Adesina
2
Cette réponse n'a rien à voir avec la question.
Massimiliano Kraus
0

Quand je me retrouve à faire beaucoup de concaténation de chaînes en JavaScript, je commence à chercher des modèles. Handlebars.js fonctionne assez bien en gardant le HTML et le JavaScript plus lisibles. http://handlebarsjs.com

début
la source