Есть ли в JavaScript встроенный класс stringbuilder?


Ответы:


320

Если вам нужно написать код для Internet Explorer, убедитесь, что вы выбрали реализацию, которая использует соединения с массивами. Конкатенация строк с оператором +или +=является чрезвычайно медленной в IE. Это особенно верно для IE6. В современных браузерах+= это обычно так же быстро, как присоединение массивов.

Когда мне приходится делать много конкатенаций строк, я обычно заполняю массив и не использую класс построителя строк:

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

Обратите внимание, что pushметоды принимают несколько аргументов.


7
И если вы генерируете вывод inline, или все члены являются литералами [foo(), "bar", "baz"].join("");, тоже работает.
Аноним

1
Хотя вряд ли можно ожидать, что ссылки в Dropbox будут работать в течение почти 3 лет, мне было бы любопытно сравнить их - и будет ли оно все еще актуальным.
Корнелиус

1
@DaveWard, ваша ссылка не работает :(
Иван Кочуркин

Я считаю, что это намного более читабельно, чем строка + строка + строка
Эндрю Эрлих,

12
Я не знал, pushмог принять несколько аргументов. Случайные вещи, которые вы изучаете.
Carcigenicate

55

Я только что проверил производительность на http://jsperf.com/javascript-concat-vs-join/2 . Контрольные примеры объединяют или присоединяют алфавит 1000 раз.

В современных браузерах (FF, Opera, IE11, Chrome) «concat» примерно в 4-10 раз быстрее, чем «join».

В IE8 оба возвращают примерно одинаковые результаты.

В IE7 «соединение», к сожалению, примерно в 100 раз быстрее.


3
Спасибо за это. Это должно быть увеличено в списке ответов. Это также намного быстрее на IE10 (я знаю, что это не современный браузер, но я упоминаю это для любых потенциальных разработчиков NMCI, видящих это).
Джеймс Уилсон

@ Андреас Я полагаю, что ваш тест находится в пути кода в Chrome, где он никогда не выполняет фактическую конкатенацию, потому что строка никогда не читается. Однако даже при этом скорость выполнения все еще значительно выше: jsperf.com/yet-another-string-concat-test/1
Джозеф Леннокс,

37

Нет, встроенной поддержки для построения строк нет. Вместо этого вы должны использовать конкатенацию.

Конечно, вы можете создать массив различных частей вашей строки и затем вызвать join()этот массив, но это зависит от того, как соединение реализовано в используемом вами интерпретаторе JavaScript.

Я провел эксперимент, чтобы сравнить скорость str1+str2метода и array.push(str1, str2).join()метода. Код был прост:

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

Я протестировал его в Internet Explorer 8 и Firefox 3.5.5, оба на Windows 7 x64.

В начале я тестировал на небольшом количестве итераций (несколько сотен, несколько тысяч наименований). Результаты оказались непредсказуемыми (иногда конкатенация строк занимала 0 миллисекунд, иногда - 16 миллисекунд, то же самое для объединения массивов).

Когда я увеличил счет до 50 000, результаты были разными в разных браузерах - в Internet Explorer конкатенация строк была быстрее (94 миллисекунды), а соединение было медленнее (125 миллисекунд), в то время как в Firefox соединение массивов было быстрее (113 миллисекунд), чем соединение строк (117 миллисекунд).

Затем я увеличил счет до 500'000. Теперь array.join()была медленнее , чем конкатенация строк в обоих браузерах: конкатенация был 937 мс в Internet Explorer, 1155 мс в Firefox, массив присоединиться 1265 в Internet Explorer и 1207 мс в Firefox.

Максимальное число итераций, которое я мог протестировать в Internet Explorer, не имея «сценария занимает слишком много времени для выполнения», составило 850 000. Тогда Internet Explorer был 1593 для конкатенации строк и 2046 для соединения массивов, а Firefox имел 2101 для конкатенации строк и 2249 для соединения массивов.

Результаты - если количество итераций невелико, вы можете попробовать использовать его array.join(), поскольку в Firefox это может быть быстрее. Когда число увеличивается, string1+string2метод быстрее.

ОБНОВИТЬ

Я выполнил тест в Internet Explorer 6 (Windows XP). Процесс перестал отвечать немедленно и никогда не заканчивался, если я пробовал тестировать более 100 000 итераций. На 40000 итераций результаты были

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

Это означает, что если вам нужна поддержка Internet Explorer 6, выберите array.join()способ, который быстрее, чем конкатенация строк.


join()является частью ECMAScript, и каждый его интерпретатор JavaScript реализует его. Почему это "зависит"?
Эли Грей

он имел в виду, КАК это было реализовано ... если оно реализовано таким образом, что в цикле строка постоянно добавляется, а не создается сразу, тогда использование объединения было бы бессмысленным
Джон

Да, это было то, что я имел в виду. Извините за мой английский ;-) Я добавил результаты сравнения того, как быстро какой метод работает в двух браузерах. Вы можете видеть, это отличается.
наивисты

2
IE6, как всегда, является исключением :)
Гордон Такер

10
Люди с IE6 привыкли все делать очень медленно. Я не думаю, что они будут винить тебя.
Lodewijk

8

Этот код выглядит как маршрут, по которому вы хотите пойти, с несколькими изменениями.

Вы захотите изменить метод добавления так, чтобы он выглядел следующим образом. Я изменил его, чтобы принять число 0 и вернуть его, thisчтобы вы могли связать свои добавления.

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

Почему принимаются только не NaN числа и непустые строки? Ваш метод не будет принимать null, falseпустые строки, undefinedили NaN.
Эли Грей

@Elijah - я предпочитаю содержать мой класс StringBuilder в чистоте, не принимая ничего, кроме допустимых строк и чисел. Это просто личное предпочтение.
Гордон Такер

5

Версия JavaScript ECMAScript 6 (также известная как ECMAScript 2015) представила строковые литералы .

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

Обратите внимание, что обратные тики вместо одинарных кавычек заключают строку.


17
Как это отвечает на вопрос?
Питер Мортенсен

@ Питер Мортенсен, этот ответ просто дает другой способ построить строку. На оригинальном плакате не было указано, какой тип функциональности строителя строк ищется.
Феофил

1
Это не отвечает на вопрос. Вообще.
Массимилиано Краус

2

В C # вы можете сделать что-то вроде

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

В JavaScript вы можете сделать что-то вроде

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

2
Я очень сомневаюсь, что выполнение регулярного выражения вместо объединения строк будет более производительным
тик

Кроме того, это ужасная реализация. Это сломается, если строка, которой {0}заменяется, содержит {1}.
Икегами

@ikegami строка не переменная, это константа, так что вы знаете, что в ней содержится априори.
спортивные состязания

@sports, Копирование и вставка всего этого в ваш код - еще худшая идея.
икегами

Один вкладыш с $ 1 и $ 2, заменяющими группы без захвата: x..replace (/ ([\ s \ S] *?) \ {0 \} ([\ s \ S] *?) \ {1 \} / г, "$ 1Tom $ 225")
T.CK

1

Для тех, кто заинтересован, вот альтернатива вызову Array.join:

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

Результатом, как и ожидалось, является строка 'foobar'. В Firefox этот подход превосходит Array.join, но опережает + конкатенация. Поскольку String.concat требует, чтобы каждый сегмент указывался в качестве отдельного аргумента, вызывающая сторона ограничена пределом количества аргументов, установленным исполняющим движком JavaScript. Посмотрите на документацию Function.prototype.apply () для получения дополнительной информации.


Это терпит неудачу в Chrome, так как "String.concat" не определен. Вместо этого вы можете использовать '' .concat.apply ('', arrayOfStrings). Но это все еще очень медленный метод.
Андреас

1

Я определил эту функцию:

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

И может быть назван как C #:

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

Результат:

привет Джон, тебе 29 лет.


1
Мне это нравится ... выглядит как C #
Ayo Adesina

2
Этот ответ не имеет ничего общего с вопросом.
Массимилиано Краус

0

Когда я обнаружил, что в JavaScript много конкатенации строк, я начинаю искать шаблоны. Handlebars.js работает довольно хорошо, сохраняя HTML и JavaScript более читабельным. http://handlebarsjs.com


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.