Чи вбудований JavaScript у клас струнбудівників?


Відповіді:


319

Якщо вам потрібно написати код для Internet Explorer, переконайтеся, що ви вибрали реалізацію, яка використовує масив приєднання. Об'єднання рядків з оператором +або +=оператором надзвичайно повільно на IE. Особливо це стосується IE6. На сучасних браузерах+= зазвичай так само швидко, як і приєднується масив.

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

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

Зауважте, що pushметоди приймають кілька аргументів.


7
І якщо ви генеруєте вихідний вбудований текст, або всі учасники є буквальними [foo(), "bar", "baz"].join("");, теж працює.
Анонімний

1
Хоча, напевно, не можна очікувати, що посилання на папку "папка" працюватимуть майже 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, які це бачать).
Джеймс Вілсон

@Andreas Я вважаю, що ваш тест потрапляє до кодового шляху в Chrome, де він ніколи не робить фактичного з'єднання, оскільки рядок ніколи не читається. Навіть при змушенні
Джозеф Леннокс

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 мілісекунд).

Тоді я збільшив кількість до 500000. Тепер конкатенація рядків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 повторень. На 40 000 повторень результати були

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

Це означає - якщо вам потрібно підтримати Internet Explorer 6, виберіть, array.join()який шлях швидше, ніж з'єднання рядків.


join()є частиною ECMAScript і afaik, кожен інтерпретатор 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

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

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

@ikegami рядок не є змінною, це константа, тому ви знаєте, що міститься апріорі.
спорт

@спорт, Копіювання та вставлення всього цього у ваш код - ще гірша ідея.
ikegami

Один вкладиш з $ 1 і $ 2 замінює групи, які не захоплюють: x..replace (/ ([\ s \ S] *?) \ {0 \} ([\ s \ S] *?) \ {1 \} / g, "$ 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 #
Айо Адесіна

2
Ця відповідь не має нічого спільного з питанням.
Массіміліано Краус

0

Коли я виявляю, що в JavaScript відбувається багато об'єднання рядків, я починаю шукати шаблони. Handlebars.js працює добре, зберігаючи HTML і JavaScript більш читабельними. http://handlebarsjs.com


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.