JavaScript ha una classe stringbuilder integrata?


Risposte:


320

Se devi scrivere codice per Internet Explorer, assicurati di aver scelto un'implementazione, che utilizza i join di array. La concatenazione di stringhe con l' operatore +o +=è estremamente lenta su IE. Ciò è particolarmente vero per IE6. Nei browser moderni di +=solito è veloce quanto i join di array.

Quando devo fare molte concatenazioni di stringhe di solito riempio un array e non uso una classe builder:

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

Si noti che i pushmetodi accettano più argomenti.


7
E se stai generando output in linea, o tutti i membri sono letterali, [foo(), "bar", "baz"].join("");funziona anche.
Anonimo il

1
Anche se probabilmente non ci si può aspettare che i link a dropbox continuino a funzionare per quasi 3 anni, sarei curioso di sapere il confronto - e se regge ancora.
Cornelio,

1
@DaveWard, il tuo collegamento è interrotto :(
Ivan Kochurkin,

Trovo che questo sia molto più leggibile che stringa + stringa + stringa
Andrew Ehrlich

12
Non sapevo che pushpotesse accettare più argomenti. Le cose casuali che impari.
Carcigenicate

55

Ho appena ricontrollato le prestazioni su http://jsperf.com/javascript-concat-vs-join/2 . I casi di test concatenano o uniscono l'alfabeto 1.000 volte.

Negli attuali browser (FF, Opera, IE11, Chrome), "concat" è circa 4-10 volte più veloce di "join".

In IE8, entrambi restituiscono risultati uguali.

In IE7, "join" è purtroppo circa 100 volte più veloce.


3
Grazie per questo. Questo dovrebbe essere aumentato nella lista delle risposte. È anche molto più veloce su IE10 (so che non è un browser moderno ma lo menziono per tutti i potenziali sviluppatori NMCI che lo vedono).
James Wilson,

@Andreas Credo che il tuo test stia colpendo un percorso di codice in Chrome in cui non sta mai eseguendo il concatenato effettivo perché la stringa non viene mai letta. Anche se costringendolo, tuttavia, la velocità di esecuzione è ancora considerevolmente più alta: jsperf.com/yet-another-string-concat-test/1
Joseph Lennox

37

No, non esiste un supporto integrato per la creazione di stringhe. Devi invece usare la concatenazione.

Naturalmente, puoi creare un array di diverse parti della tua stringa e quindi chiamare join()quell'array, ma dipende quindi da come viene implementato il join nell'interprete JavaScript che stai utilizzando.

Ho fatto un esperimento per confrontare la velocità del str1+str2metodo rispetto al array.push(str1, str2).join()metodo. Il codice era semplice:

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

L'ho provato in Internet Explorer 8 e Firefox 3.5.5, entrambi su Windows 7 x64.

All'inizio ho testato un numero limitato di iterazioni (alcune centinaia, alcune migliaia di elementi). I risultati erano imprevedibili (a volte la concatenazione di stringhe impiegava 0 millisecondi, a volte impiegava 16 millisecondi, lo stesso per l'unione di array).

Quando ho aumentato il conteggio a 50.000, i risultati erano diversi nei diversi browser: in Internet Explorer la concatenazione di stringhe era più veloce (94 millisecondi) e l'unione era più lenta (125 millisecondi), mentre in Firefox l'unione dell'array era più veloce (113 millisecondi) rispetto a unione di stringhe (117 millisecondi).

Quindi ho aumentato il conteggio a 500'000. Ora array.join()era più lento della concatenazione di stringhe in entrambi i browser: la concatenazione di stringhe era 937 ms in Internet Explorer, 1155 ms in Firefox, array array 1265 in Internet Explorer e 1207 ms in Firefox.

Il numero massimo di iterazioni che ho potuto testare in Internet Explorer senza che "l'esecuzione dello script richieda troppo tempo" era 850.000. Quindi Internet Explorer era il 1593 per la concatenazione di stringhe e il 2046 per l'unione di array e Firefox aveva 2101 per la concatenazione di stringhe e 2249 per l'unione di array.

Risultati : se il numero di iterazioni è ridotto, puoi provare a utilizzare array.join(), poiché potrebbe essere più veloce in Firefox. Quando il numero aumenta, il string1+string2metodo è più veloce.

AGGIORNARE

Ho eseguito il test su Internet Explorer 6 (Windows XP). Il processo ha smesso di rispondere immediatamente e non è mai terminato, se ho provato il test su oltre 100.000 iterazioni. Su 40.000 iterazioni i risultati furono

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

Ciò significa che, se è necessario supportare Internet Explorer 6, scegliere array.join()quale è molto più veloce della concatenazione di stringhe.


join()fa parte di ECMAScript e afaik lo implementa ogni interprete JavaScript. Perché dovrebbe "dipendere"?
Eli Grey,

intendeva COME era implementato ... se fosse implementato in modo che, in un ciclo, la stringa venisse continuamente aggiunta e non fosse stata creata tutta in una volta, allora usare join sarebbe stato inutile
John

Sì, era quello che intendevo davvero. Perdonate il mio inglese ;-) Ho aggiunto i risultati di un confronto con quale metodo veloce funziona in due browser. Puoi vedere, è diverso.
naivisti il

2
IE6, come sempre, fa eccezione :)
Gordon Tucker,

10
Le persone con IE6 sono abituate ad avere tutto molto lentamente però. Non credo che ti biasimeranno.
Lodewijk,

8

Quel codice sembra il percorso che vuoi prendere con alcune modifiche.

Ti consigliamo di cambiare il metodo append in modo che assomigli a questo. L'ho modificato per accettare il numero 0 e per farlo tornare in thismodo da poter concatenare i tuoi allegati.

StringBuilder.prototype.append = function (value) {
    if (value || value === 0) {
        this.strings.push(value);
    }
    return this;
}

Perché accettare solo numeri non NaN e stringhe non vuote? Il tuo metodo non accetta null, falsestringhe vuote undefinedo NaN.
Eli Gray,

@Elia - Preferisco mantenere pulita la mia classe StringBuilder non accettando altro che stringhe e numeri validi. È solo una preferenza personale.
Gordon Tucker,

5

La versione ECMAScript 6 (aka ECMAScript 2015) di JavaScript ha introdotto valori letterali stringa .

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

Si noti che i segni di spunta, anziché le virgolette singole, racchiudono la stringa.


17
Come risponde alla domanda?
Peter Mortensen,

@Peter Mortensen, questa risposta offre semplicemente un altro modo per costruire una stringa. Il poster originale non specificava quale tipo di funzionalità di generatore di stringhe veniva ricercata.
Teofilo,

1
Questo non risponde alla domanda. Affatto.
Massimiliano Kraus,

2

In C # puoi fare qualcosa del genere

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

In JavaScript potresti fare qualcosa del genere

 var x = "hello {0}, your age is {1}";
 x = x.replace(/\{0\}/g, "John");
 x = x.replace(/\{1\}/g, 29);

2
Dubito fortemente esecuzione un'espressione regolare al posto di una stringa join sarà più performante
tic

Inoltre, questa è un'implementazione terribile. Si interromperà se la stringa con cui {0}viene sostituita contiene {1}.
ikegami,

@ikegami la stringa non è una variabile, è una costante, quindi sai cosa conteneva a priori.
sport

@sports, Copiare e incollare tutto ciò nel codice è un'idea ancora peggiore.
ikegami,

Un liner con $ 1 e $ 2 in sostituzione dei gruppi non di acquisizione: x..replace (/ ([\ s \ S] *?) \ {0 \} ([\ s \ S] *?) \ {1 \} / g, "$ 1Tom $ 225")
T.CK

1

Per coloro che sono interessati, ecco un'alternativa all'invocazione di Array.join:

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

L'output, come previsto, è la stringa "foobar". In Firefox, questo approccio supera Array.join ma è sovraperformato da + concatenazione. Poiché String.concat richiede che ogni segmento sia specificato come argomento separato, il chiamante è limitato da qualsiasi limite di conteggio degli argomenti imposto dal motore JavaScript in esecuzione. Dai un'occhiata alla documentazione di Function.prototype.apply () per maggiori informazioni.


Ciò non riesce in Chrome, poiché "String.concat" non è definito. Invece, potresti usare '' .concat.apply ('', arrayOfStrings). Ma questo è ancora un metodo molto lento.
Andreas,

1

Ho definito questa funzione:

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 può essere chiamato come c #:

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

Risultato:

ciao John, hai 29 anni.


1
Mi piace ... sembra c #
Ayo Adesina,

2
Questa risposta non ha nulla a che fare con la domanda.
Massimiliano Kraus,

0

Quando mi ritrovo a fare molta concatenazione di stringhe in JavaScript, inizio a cercare il modello. Handlebars.js funziona abbastanza bene mantenendo HTML e JavaScript più leggibili. http://handlebarsjs.com


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.