Чи вбудований 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.