Использует ли javascript неизменяемые или изменяемые строки? Нужен ли мне «строитель строк»?
Использует ли javascript неизменяемые или изменяемые строки? Нужен ли мне «строитель строк»?
Ответы:
Они неизменны. Вы не можете изменить символ в строке с чем-то вроде var myString = "abbdef"; myString[2] = 'c'
. Методы работы со строками, такие как trim
, slice
возвращают новые строки.
Таким же образом, если у вас есть две ссылки на одну и ту же строку, изменение одной не влияет на другую
let a = b = "hello";
a = a + " world";
// b is not affected
Тем не менее, я всегда слышал, что Эш упомянул в своем ответе (что использование Array.join быстрее для конкатенации), поэтому я хотел опробовать различные методы конкатенации строк и быстрого абстрагирования в StringBuilder. Я написал несколько тестов, чтобы увидеть, правда ли это (это не так!).
Я думал, что это будет самый быстрый способ, хотя я продолжал думать, что добавление вызова метода может сделать его медленнее ...
function StringBuilder() {
this._array = [];
this._index = 0;
}
StringBuilder.prototype.append = function (str) {
this._array[this._index] = str;
this._index++;
}
StringBuilder.prototype.toString = function () {
return this._array.join('');
}
Вот тесты скорости производительности. Все три из них создают гигантскую строку, состоящую "Hello diggity dog"
из сто тысяч конкатенаций в пустую строку.
Я создал три типа тестов
Array.push
иArray.join
Array.push
, затем с помощьюArray.join
Затем я создал те же три теста, абстрагировав их StringBuilderConcat
, StringBuilderArrayPush
и StringBuilderArrayIndex
http://jsperf.com/string-concat-without-sringbuilder/5 Перейдите туда и запустите тесты, чтобы мы могли получить хороший образец. Обратите внимание, что я исправил небольшую ошибку, поэтому данные для тестов были стерты, я обновлю таблицу, как только будет достаточно данных о производительности. Перейдите по ссылке http://jsperf.com/string-concat-without-sringbuilder/5 для старой таблицы данных.
Вот некоторые цифры (последнее обновление в Ma5rch 2018), если вы не хотите переходить по ссылке. Число в каждом тесте в 1000 операций в секунду (чем выше, тем лучше )
| Browser | Index | Push | Concat | SBIndex | SBPush | SBConcat |
---------------------------------------------------------------------------
| Chrome 71.0.3578 | 988 | 1006 | 2902 | 963 | 1008 | 2902 |
| Firefox 65 | 1979 | 1902 | 2197 | 1917 | 1873 | 1953 |
| Edge | 593 | 373 | 952 | 361 | 415 | 444 |
| Exploder 11 | 655 | 532 | 761 | 537 | 567 | 387 |
| Opera 58.0.3135 | 1135 | 1200 | 4357 | 1137 | 1188 | 4294 |
Выводы
В настоящее время все вечнозеленые браузеры хорошо справляются с конкатенацией строк. Array.join
помогает только IE 11
В целом, Opera работает быстрее, в 4 раза быстрее, чем Array.join
Firefox занимает второе место и Array.join
лишь немного медленнее в FF, но значительно медленнее (в 3 раза) в Chrome.
Chrome - третий, но конкат строки в 3 раза быстрее, чем Array.join
Создание StringBuilder, похоже, не сильно влияет на производительность.
Надеюсь, кто-то еще найдет это полезным
Другой тестовый кейс
Поскольку @RoyTinker считал, что мой тест некорректен, я создал новый случай, в котором не создается большая строка путем объединения одной и той же строки, для каждой итерации он использует разные символы. Конкатенация строк все еще казалась более быстрой или такой же быстрой. Давайте запустим эти тесты.
Я предлагаю всем подумать о других способах проверки этого, и не стесняйтесь добавлять новые ссылки в различные тестовые примеры ниже.
join
против конкатенации, следовательно , построение массива до испытания. Я не думаю, что это обман, если эта цель понятна (и join
перечисляет массив внутренне, так что тоже не обмануть пропустить for
цикл из join
теста).
Array.join
из книги носорогов :
В JavaScript строки являются неизменяемыми объектами, что означает, что символы внутри них не могут быть изменены и что любые операции над строками фактически создают новые строки. Строки присваиваются по ссылке, а не по значению. Как правило, когда объект назначается по ссылке, изменение, внесенное в объект посредством одной ссылки, будет видно через все другие ссылки на объект. Однако, поскольку строки нельзя изменить, вы можете иметь несколько ссылок на строковый объект и не беспокоиться о том, что значение строки изменится без вашего ведома.
null
undefined
number
и boolean
. Строки присваиваются по значению, а не по ссылке и передаются как таковые. Таким образом, строки не просто неизменны, они являются ценностью . Изменение строки "hello"
на "world"
это похоже на решение, что теперь число 3 - это число 4 ... это не имеет смысла.
var a = "hello";var b=a;a.x=5;console.log(a.x,b.x);
String
объекты, созданные с помощью строкового конструктора, являются оболочками вокруг строковых значений JavaScript. Вы можете получить доступ к строковому значению типа в штучной упаковке, используя .valueOf()
функцию - это также верно для Number
объектов и числовых значений. Важно отметить, что String
объекты, созданные с использованием new String
не реальных строк, а оберток или блоков вокруг строк. См. Es5.github.io/#x15.5.2.1 . О том, как вещи преобразуются в объекты, см. Es5.github.io/#x9.9
Совет по производительности:
Если вам нужно объединить большие строки, поместите части строк в массив и используйте Array.Join()
метод, чтобы получить общую строку. Это может быть во много раз быстрее для объединения большого количества строк.
Там нет StringBuilder
в JavaScript.
Просто чтобы уточнить для простых умов, как мой (из MDN ):
Неизменяемыми являются объекты, состояние которых нельзя изменить после создания объекта.
Строка и числа неизменны.
Неизменный означает, что:
Вы можете сделать так, чтобы имя переменной указывало на новое значение, но предыдущее значение все еще сохраняется в памяти. Отсюда и необходимость сбора мусора.
var immutableString = "Hello";
// В приведенном выше коде создается новый объект со строковым значением.
immutableString = immutableString + "World";
// Теперь мы добавляем «Мир» к существующему значению.
Похоже, мы изменяем строку «immutableString», но это не так. Вместо:
При добавлении «immutableString» со строковым значением происходят следующие события:
- Существующее значение «immutableString» извлекается
- «Мир» добавляется к существующему значению «immutableString»
- Результирующее значение затем выделяется для нового блока памяти
- Объект «immutableString» теперь указывает на вновь созданное пространство памяти
- Ранее созданное пространство памяти теперь доступно для сборки мусора.
Значение типа string является неизменным, но объект String, который создается с помощью конструктора String (), является изменяемым, потому что это объект, и вы можете добавлять к нему новые свойства.
> var str = new String("test")
undefined
> str
[String: 'test']
> str.newProp = "some value"
'some value'
> str
{ [String: 'test'] newProp: 'some value' }
Между тем, хотя вы можете добавлять новые свойства, вы не можете изменить уже существующие свойства
Скриншот теста в консоли Chrome
В заключение, 1. все значения типа строки (тип примитива) являются неизменяемыми. 2. Объект String является изменяемым, но значение строкового типа (тип примитива), которое он содержит, является неизменным.
new String
генерирует изменчивую обертку вокруг неизменной строки
String
объекту (оболочке), то есть он не является неизменным (по умолчанию; как и любой другой объект, вы можете вызвать Object.freeze
его, чтобы сделать его неизменным). Но примитивный тип строкового значения, независимо от того, содержится он в String
объектной обертке или нет, всегда неизменен.
Что касается вашего вопроса (в вашем комментарии к ответу Эша) о StringBuilder в ASP.NET Ajax, то эксперты, похоже, с этим не согласны.
Кристиан Венц говорит в своей книге « Программирование ASP.NET AJAX (O'Reilly)», что «этот подход не оказывает какого-либо ощутимого влияния на память (на самом деле, реализация кажется медленнее, чем стандартный подход)».
С другой стороны, Галло и др. В своей книге ASP.NET AJAX в действии (Мэннинг) говорят, что «Когда число объединяемых строк больше, построитель строк становится важным объектом, позволяющим избежать огромных падений производительности».
Я полагаю, вам нужно будет сделать свой собственный сравнительный анализ, и результаты могут отличаться в разных браузерах. Однако, даже если это не улучшает производительность, его все равно можно считать «полезным» для программистов, которые привыкли кодировать с помощью StringBuilders на таких языках, как C # или Java.
Это поздний пост, но я не нашел хорошую цитату из ответов.
Вот определенный, кроме как из надежной книги:
Строки являются неизменяемыми в ECMAScript, что означает, что после их создания их значения не могут измениться. Чтобы изменить строку, содержащуюся в переменной, исходная строка должна быть уничтожена, а переменная должна быть заполнена другой строкой, содержащей новое значение ... - Профессиональный JavaScript для веб-разработчиков, 3-е изд., С.43
Теперь, ответ, который цитирует отрывок из книги Носорога, верен в отношении неизменности строк, но неверен: «Строки назначаются по ссылке, а не по значению». (вероятно, они изначально хотели поставить слова противоположным образом).
Неправильное представление «ссылка / значение» разъясняется в разделе «Профессиональный JavaScript», глава «Примитивные и ссылочные значения»:
Пять примитивных типов ... [являются]: Undefined, Null, Boolean, Number и String. Говорят, что эти переменные доступны по значению, потому что вы манипулируете фактическим значением, хранящимся в переменной. —Профессиональный JavaScript для веб-разработчиков, 3-е изд., С.85
это в отличие от объектов :
Когда вы манипулируете объектом, вы действительно работаете со ссылкой на этот объект, а не с самим объектом. По этой причине такие значения считаются доступными по ссылке. —Профессиональный JavaScript для веб-разработчиков, 3-е изд., С.85
Строки JavaScript действительно неизменны.
Строки в Javascript неизменны