O JavaScript tem uma classe stringbuilder embutida?

Respostas:

326

Se você tiver que escrever código para o Internet Explorer, certifique-se de escolher uma implementação, que usa junções de matriz. A concatenação de strings com o operador +ou +=é extremamente lenta no IE. Isso é especialmente verdadeiro para o IE6. Em navegadores modernos+= geralmente é tão rápido quanto as junções de array.

Quando tenho que fazer muitas concatenações de string, geralmente preencho uma matriz e não uso uma classe construtora de string:

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

Observe que os pushmétodos aceitam vários argumentos.

Fabian Jakobs
fonte
7
E se você está gerando saída embutida, ou todos os membros são literais, [foo(), "bar", "baz"].join("");funciona também.
Anônimo
1
Embora provavelmente não se possa esperar que os links da caixa de depósito continuem funcionando por quase 3 anos, estou curioso para saber a comparação - e se ela ainda se mantém.
Cornelius de
1
@DaveWard, seu link está quebrado :(
Ivan Kochurkin
Acho que é muito mais legível que string + string + string
Andrew Ehrlich,
14
Eu não sabia que pushpoderia aceitar vários argumentos. As coisas aleatórias que você aprende.
Carcigenicar
56

Acabei de verificar novamente o desempenho em http://jsperf.com/javascript-concat-vs-join/2 . Os casos de teste se concatenam ou unem o alfabeto 1.000 vezes.

Nos navegadores atuais (FF, Opera, IE11, Chrome), "concat" é cerca de 4 a 10 vezes mais rápido do que "join".

No IE8, ambos retornam resultados aproximadamente iguais.

No IE7, "join" é cerca de 100 vezes mais rápido, infelizmente.

Andreas
fonte
3
Obrigado por isso. Isso deve ser aumentado na lista de respostas. Também é muito mais rápido no IE10 (sei que não é um navegador moderno, mas menciono isso para qualquer desenvolvedor de NMCI em potencial).
James Wilson
@Andreas, acredito que seu teste está atingindo um caminho de código no Chrome onde nunca faz a concatenação real porque a string nunca é lida. Mesmo quando forçando isso, porém, a velocidade de execução ainda é consideravelmente mais rápida: jsperf.com/yet-another-string-concat-test/1
Joseph Lennox
38

Não, não há suporte integrado para a construção de strings. Você deve usar a concatenação.

Você pode, é claro, fazer uma matriz de diferentes partes de sua string e, em seguida, chamar join() esse array, mas isso depende de como a junção é implementada no interpretador JavaScript que você está usando.

Fiz um experimento para comparar a velocidade do str1+str2método versus array.push(str1, str2).join()método. O código era simples:

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

Eu testei no Internet Explorer 8 e Firefox 3.5.5, ambos em um Windows 7 x64.

No início, testei em um pequeno número de iterações (algumas centenas, alguns milhares de itens). Os resultados eram imprevisíveis (às vezes a concatenação de strings levava 0 milissegundos, às vezes levava 16 milissegundos, o mesmo para a junção da matriz).

Quando aumentei a contagem para 50.000, os resultados foram diferentes em navegadores diferentes - no Internet Explorer a concatenação de strings foi mais rápida (94 milissegundos) e a junção foi mais lenta (125 milissegundos), enquanto no Firefox a junção da matriz foi mais rápida (113 milissegundos) do que junção de string (117 milissegundos).

Então, aumentei a contagem para 500.000. Agora array.join()era mais lento do que a concatenação de string em ambos os navegadores: a concatenação de string era de 937 ms no Internet Explorer, 1155 ms no Firefox, array join 1265 no Internet Explorer e 1207 ms no Firefox.

A contagem máxima de iterações que pude testar no Internet Explorer sem ter "o script está demorando muito para ser executado" foi 850.000. Então, o Internet Explorer era 1593 para concatenação de string e 2046 para junção de array, e o Firefox tinha 2101 para concatenação de string e 2249 para junção de array.

Resultados - se o número de iterações for pequeno, você pode tentar usararray.join() , pois pode ser mais rápido no Firefox. Quando o número aumenta, o string1+string2método é mais rápido.

ATUALIZAR

Realizei o teste no Internet Explorer 6 (Windows XP). O processo parava de responder imediatamente e nunca terminava, se eu tentasse o teste em mais de 100.000 iterações. Em 40.000 iterações, os resultados foram

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

Isso significa - se você precisar oferecer suporte ao Internet Explorer 6, escolha array.join()qual é mais rápido do que a concatenação de strings.

ingênuos
fonte
join()faz parte do ECMAScript e afaik todo interpretador de JavaScript o implementa. Por que isso "dependeria"?
Eli Gray de
ele quis dizer COMO foi implementado ... se for implementado de uma forma que, em um loop, a string seja continuamente anexada e criada de uma só vez, então usar o join seria inútil
João
Sim, foi o que eu realmente quis dizer. Pardon my English ;-) Eu adicionei resultados de uma comparação de quão rápido qual método funciona em dois navegadores. Você pode ver, é diferente.
ingênuos
2
O IE6, como sempre, é a exceção :)
Gordon Tucker
13
No entanto, as pessoas com IE6 estão acostumadas a ter tudo muito lento. Eu não acho que eles vão culpar você.
Lodewijk
8

Esse código se parece com a rota que você deseja seguir, com algumas alterações.

Você vai querer alterar o método append para ficar assim. Eu mudei para aceitar o número 0 e fazê-lo retornar thispara que você possa encadear seus anexos.

StringBuilder.prototype.append = function (value) {
    if (value || value === 0) {
        this.strings.push(value);
    }
    return this;
}
Gordon Tucker
fonte
Por que aceitar apenas números não NaN e strings não vazias? Seu método não irá aceitar null, false, cadeias vazias, undefinedou NaN.
Eli Gray de
@Elijah - Prefiro manter minha classe StringBuilder limpa, não aceitando nada além de strings e números válidos. É apenas uma preferência pessoal.
Gordon Tucker
5

A versão ECMAScript 6 (também conhecida como ECMAScript 2015) do JavaScript introduziu literais de string .

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

Observe que back-ticks, em vez de aspas simples, envolvem a string.

Teófilo
fonte
20
Como isso responde à pergunta?
Peter Mortensen
@Peter Mortensen, essa resposta apenas fornece outra maneira de construir uma string. O autor original não especificou que tipo de funcionalidade de construtor de string estava sendo procurada.
Theophilus de
1
Isso não responde à pergunta. Em absoluto.
Massimiliano Kraus
Eu também não acho que isso responda à pergunta, mas alguns comentários não são realmente úteis ou acolhedores para outros membros. Em absoluto.
Fabio Milheiro
2

Em C # você pode fazer algo como

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

Em JavaScript, você poderia fazer algo como

 var x = "hello {0}, your age is {1}";
 x = x.replace(/\{0\}/g, "John");
 x = x.replace(/\{1\}/g, 29);
Esportes
fonte
2
Eu duvido muito que executar uma expressão regular no lugar de uma junção de string tenha mais desempenho
tic
Além disso, esta é uma implementação terrível. Ele será interrompido se a string com a qual {0}foi substituído contiver {1}.
ikegami
@ikegami a string não é uma variável, é uma constante, então você sabe o que está contido a priori.
esportes
@sports, Copiar e colar tudo isso em seu código é uma ideia ainda pior.
ikegami
1
Isso não responde à pergunta. Uma classe StringBuilder não é para interpolação de string.
Massimiliano Kraus
1

Para os interessados, aqui está uma alternativa para invocar Array.join:

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

A saída, como esperado, é a string 'foobar'. No Firefox, essa abordagem supera Array.join, mas é superada por + concatenação. Como String.concat requer que cada segmento seja especificado como um argumento separado, o chamador é limitado por qualquer limite de contagem de argumento imposto pelo mecanismo JavaScript em execução. Dê uma olhada na documentação de Function.prototype.apply () para mais informações.

Aaron
fonte
Isso falha no Chrome, pois "String.concat" é indefinido. Em vez disso, você pode usar '' .concat.apply ('', arrayOfStrings). Mas este ainda é um método muito lento.
Andreas
1

Eu defini esta função:

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

E pode ser chamado como c #:

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

Resultado:

Olá John, você tem 29 anos.

TotPeRo
fonte
1
Eu gosto disso ... parece c #
Ayo Adesina
2
Essa resposta não tem nada a ver com a pergunta.
Massimiliano Kraus
0

Quando me vejo fazendo muita concatenação de strings em JavaScript, começo a procurar modelos. Handlebars.js funciona muito bem mantendo o HTML e o JavaScript mais legíveis. http://handlebarsjs.com

começo
fonte