¿JavaScript tiene una clase integrada de stringbuilder?

Respuestas:

320

Si tiene que escribir código para Internet Explorer, asegúrese de elegir una implementación que utilice combinaciones de matriz. Las cadenas de concatenación con el operador +o +=son extremadamente lentas en IE. Esto es especialmente cierto para IE6. En navegadores modernos+= generalmente es tan rápido como la matriz se une.

Cuando tengo que hacer muchas concatenaciones de cadenas, generalmente lleno una matriz y no uso una clase de generador de cadenas:

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

Tenga en cuenta que los pushmétodos aceptan múltiples argumentos.

Fabian Jakobs
fuente
77
Y si está generando salida en línea, o todos los miembros son literales, también [foo(), "bar", "baz"].join("");funciona.
Anónimo el
1
Si bien uno probablemente no puede esperar que los enlaces de Dropbox sigan funcionando durante casi 3 años, me interesaría la comparación, y si aún se mantiene.
Cornelius
1
@DaveWard, su enlace está roto :(
Ivan Kochurkin
Creo que esto es mucho más legible que cadena + cadena + cadena
Andrew Ehrlich
12
No sabía que pushpodía aceptar múltiples argumentos. Las cosas al azar que aprendes.
Carcigenicate
55

Acabo de volver a comprobar el rendimiento en http://jsperf.com/javascript-concat-vs-join/2 . Los casos de prueba concatenan o unen el alfabeto 1,000 veces.

En los navegadores actuales (FF, Opera, IE11, Chrome), "concat" es aproximadamente 4-10 veces más rápido que "join".

En IE8, ambos devuelven resultados iguales.

Desafortunadamente, en IE7, "unirse" es aproximadamente 100 veces más rápido.

Andreas
fuente
3
Gracias por esto. Esto debería aparecer en la lista de respuestas. También es mucho más rápido en IE10 también (sé que no es un navegador moderno, pero lo menciono para cualquier desarrollador potencial de NMCI que vea esto).
James Wilson
@Andreas Creo que su prueba está llegando a una ruta de código en Chrome donde nunca está haciendo la concatenación real porque la cadena nunca se lee. Sin embargo, incluso al forzar eso, la velocidad de ejecución sigue siendo considerablemente más rápida: jsperf.com/yet-another-string-concat-test/1
Joseph Lennox
37

No, no hay soporte integrado para construir cadenas. Tienes que usar concatenación en su lugar.

Por supuesto, puede hacer una variedad de diferentes partes de su cadena y luego llamar join() esa matriz, pero luego depende de cómo se implemente la unión en el intérprete de JavaScript que está utilizando.

Hice un experimento para comparar la velocidad del str1+str2método versus el array.push(str1, str2).join()método. El código era 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));

Lo probé en Internet Explorer 8 y Firefox 3.5.5, ambos en Windows 7 x64.

Al principio probé en un pequeño número de iteraciones (unos cientos, algunos miles de artículos). Los resultados fueron impredecibles (a veces la concatenación de cadenas tardó 0 milisegundos, a veces tomó 16 milisegundos, lo mismo para la unión de matriz).

Cuando aumenté el recuento a 50,000, los resultados fueron diferentes en diferentes navegadores: en Internet Explorer la concatenación de cadenas fue más rápida (94 milisegundos) y la unión fue más lenta (125 milisegundos), mientras que en Firefox la unión de la matriz fue más rápida (113 milisegundos) que unión de cadenas (117 milisegundos).

Luego aumenté el conteo a 500'000. Ahora elarray.join() era más lento que la concatenación de cadenas en ambos navegadores: la concatenación de cadenas era de 937 ms en Internet Explorer, 1155 ms en Firefox, la combinación de matrices 1265 en Internet Explorer y 1207 ms en Firefox.

El recuento máximo de iteraciones que pude probar en Internet Explorer sin tener "el script tarda demasiado en ejecutarse" fue 850,000. Luego, Internet Explorer era 1593 para la concatenación de cadenas y 2046 para la unión de matrices, y Firefox tenía 2101 para la concatenación de cadenas y 2249 para la unión de matrices.

Resultados : si el número de iteraciones es pequeño, puede intentar usararray.join() , ya que podría ser más rápido en Firefox. Cuando el número aumenta, el string1+string2método es más rápido.

ACTUALIZAR

Realicé la prueba en Internet Explorer 6 (Windows XP). El proceso se detuvo para responder de inmediato y nunca terminó, si probé la prueba en más de 100,000 iteraciones. En 40,000 iteraciones los resultados fueron

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

Esto significa que si necesita admitir Internet Explorer 6, elija array.join()cuál es mucho más rápido que la concatenación de cadenas.

naivistas
fuente
join()es parte de ECMAScript y afaik cada intérprete de JavaScript lo implementa. ¿Por qué "dependería"?
Eli Gray
se refería a CÓMO se implementó ... si se implementa de una manera que, en un bucle, la cadena se agrega continuamente opuesta a la creada de una vez, entonces usar join sería inútil
John
Sí, era lo que realmente quise decir. Perdón por mi inglés ;-) Agregué resultados de una comparación de la rapidez con que método funciona en dos navegadores. Puedes ver, es diferente.
naivistas
2
IE6, como siempre, es la excepción :)
Gordon Tucker
10
Sin embargo, las personas con IE6 están acostumbradas a tener todo realmente lento. No creo que te culpen.
Lodewijk
8

Ese código se parece a la ruta que desea tomar con algunos cambios.

Querrás cambiar el método de agregar para que se vea así. Lo he cambiado para aceptar el número 0 y hacer que regrese thispara que pueda encadenar sus anexos.

StringBuilder.prototype.append = function (value) {
    if (value || value === 0) {
        this.strings.push(value);
    }
    return this;
}
Gordon Tucker
fuente
¿Por qué solo acepta números que no son NaN y cadenas no vacías? Su método no aceptará null, falsecadenas vacías undefined, o NaN.
Eli Gray
@Elijah: prefiero mantener limpia mi clase StringBuilder al no aceptar nada más que cadenas y números válidos. Es solo una preferencia personal.
Gordon Tucker
5

La versión ECMAScript 6 (también conocida como ECMAScript 2015) de JavaScript introdujo literales de cadena .

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

Observe que las marcas de retroceso, en lugar de comillas simples, encierran la cadena.

Teófilo
fuente
17
¿Cómo responde esto a la pregunta?
Peter Mortensen
@ Peter Mortensen, esta respuesta simplemente da otra forma de construir una cadena. El póster original no especificaba qué tipo de funcionalidad de generador de cadenas se buscaba.
Theophilus
1
Esto no responde la pregunta. En absoluto.
Massimiliano Kraus
2

En C # puedes hacer algo como

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

En JavaScript podrías hacer algo como

 var x = "hello {0}, your age is {1}";
 x = x.replace(/\{0\}/g, "John");
 x = x.replace(/\{1\}/g, 29);
Deportes
fuente
2
Dudo mucho que ejecutar una expresión regular en lugar de una unión de cadena sea más
eficaz
Además, esta es una implementación horrible. Se romperá si la cadena con la que {0}se reemplaza contiene {1}.
ikegami
@ikegami la cadena no es una variable, es una constante, así que ya sabes lo que contiene a priori.
deportes
@sports, copiar y pegar todo eso en tu código es una idea aún peor.
ikegami
Una línea con $ 1 y $ 2 reemplazando los grupos sin captura: x..replace (/ ([\ s \ S] *?) \ {0 \} ([\ s \ S] *?) \ {1 \} / g, "$ 1Tom $ 225")
T.CK
1

Para aquellos interesados, aquí hay una alternativa para invocar Array.join:

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

La salida, como se esperaba, es la cadena 'foobar'. En Firefox, este enfoque supera a Array.join pero es superado por + concatenación. Como String.concat requiere que cada segmento se especifique como un argumento separado, la persona que llama está limitada por cualquier límite de recuento de argumentos impuesto por el motor de ejecución de JavaScript. Consulte la documentación de Function.prototype.apply () para obtener más información.

Aaron
fuente
Esto falla en Chrome, ya que "String.concat" no está definido. En su lugar, podría usar '' .concat.apply ('', arrayOfStrings). Pero este sigue siendo un método muy lento.
Andreas
1

He definido esta función:

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;
    }

Y se puede llamar como c #:

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

Resultado:

hola John, tu edad es 29.

TotPeRo
fuente
1
Me gusta ... parece C #
Ayo Adesina
2
Esta respuesta no tiene nada que ver con la pregunta.
Massimiliano Kraus
0

Cuando me encuentro haciendo mucha concatenación de cadenas en JavaScript, empiezo a buscar plantillas. Handlebars.js funciona bastante bien manteniendo HTML y JavaScript más legibles. http://handlebarsjs.com

comenzando
fuente