Являются ли строки JavaScript неизменяемыми?Нужен ли мне «построитель строк» в JavaScript?
-
09-06-2019 - |
Вопрос
Использует ли 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 решил, что мой тест ошибочен, я создал новый случай, который не создает большую строку путем объединения одной и той же строки, а использует разные символы для каждой итерации.Конкатенация строк по-прежнему казалась более быстрой или такой же быстрой.Давайте запустим эти тесты.
Я предлагаю всем продолжать думать о других способах проверки этого и не стесняться добавлять новые ссылки на различные тестовые примеры ниже.
Другие советы
из книга о носороге:
В JavaScript строки являются неизменными объектами, что означает, что персонажи внутри них не могут быть изменены и что любые операции на строках фактически создают новые строки.Строки присваиваются ссылкой, а не по значению.В целом, когда объект назначается ссылкой, изменение, внесенное в объект через одну ссылку, будет видно во всех других ссылках на объект.Однако, поскольку строки нельзя изменить, вы можете иметь несколько ссылок на строковый объект и не беспокоиться о том, что строковое значение изменится без вашего знания.
Совет по производительности:
Если вам нужно объединить большие строки, поместите части строки в массив и используйте Array.Join()
метод для получения общей строки.Это может быть во много раз быстрее при объединении большого количества строк.
Здесь нет StringBuilder
в JavaScript.
Строки неизменяемы – они не могут измениться, мы можем только создавать новые струны.
Пример:
var str= "Immutable value"; // it is immutable
var other= statement.slice(2, 10); // new 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 является изменчивым, но содержащееся в нем значение строкового типа (примитивный тип) является неизменяемым.
Просто чтобы прояснить для простых умов, таких как мой (из МДН):
Неизменяемые — это объекты, состояние которых не может быть изменено после создания объекта.
Строка и числа неизменяемы.
Неизменяемость означает, что:
Вы можете сделать так, чтобы имя переменной указывало на новое значение, но предыдущее значение все равно будет храниться в памяти.Отсюда и необходимость вывоза мусора.
var immutableString = "Hello";
// В приведенном выше коде создается новый объект со строковым значением.
immutableString = immutableString + "World";
// Теперь мы добавляем «World» к существующему значению.
Похоже, мы изменяем строку immutableString, но это не так.Вместо:
При добавлении «immutableString» к строковому значению происходят следующие события:
- Существующее значение «immutableString» извлекается.
- «Мир» добавляется к существующему значению «immutableString».
- Результирующее значение затем выделяется в новый блок памяти.
- Объект immutableString теперь указывает на вновь созданное пространство памяти.
- Ранее созданное пространство памяти теперь доступно для сбора мусора.
Что касается вашего вопроса (в комментарии к ответу Эша) о StringBuilder в ASP.NET Ajax, эксперты, похоже, не согласны с этим.
Кристиан Венц говорит в своей книге Программирование ASP.NET AJAX (О'Рейли), что «этот подход не оказывает какого-либо измеримого влияния на память (фактически, реализация кажется немного медленнее, чем стандартный подход)».
С другой стороны, Галло и др. говорят в своей книге: ASP.NET AJAX в действии (Мэннинг) что «Когда количество объединяемых строк больше, построитель строк становится важным объектом, позволяющим избежать значительного падения производительности».
Я думаю, вам придется провести собственное тестирование, и результаты могут также отличаться в разных браузерах.Однако даже если это не улучшит производительность, его все равно можно считать «полезным» для программистов, привыкших писать код с помощью StringBuilders на таких языках, как C# или Java.
Это поздний пост, но среди ответов я не нашел хорошей цитаты из книги.
Вот определенная выдержка из надежной книги:
Строки являются неизменяемыми в ECMAScript, а это означает, что после их создания их значения не могут измениться.Чтобы изменить строку, хранящуюся в переменной, исходную строку необходимо уничтожить, а переменную заполнить другой строкой, содержащей новое значение... —Профессиональный JavaScript для веб-разработчиков, 3-е изд., стр. 43.
Теперь ответ, который цитирует отрывок из Rhino Book, прав в отношении неизменности строки, но неправильно говоря: «Строки присваиваются ссылкой, а не по значению». (Вероятно, они изначально предназначались для того, чтобы поставить слова противоположным образом).
Заблуждение «ссылка/значение» разъясняется в главе «Профессиональный JavaScript», глава «Примитивные и ссылочные значения»:
Пять примитивных типов...[являются]:Неопределенное, пустое, логическое, число и строка.Говорят, что доступ к этим переменным осуществляется по значению, поскольку вы манипулируете фактическим значением, хранящимся в переменной. —Профессиональный JavaScript для веб-разработчиков, 3-е изд., стр.85.
это против объекты:
Когда вы манипулируете объектом, вы на самом деле работаете над ссылкой на этот объект, а не над самим объектом.По этой причине говорят, что такие значения доступны по ссылке.—Профессиональный JavaScript для веб-разработчиков, 3-е изд., стр.85.
Строки JavaScript действительно неизменяемы.
Строки в Javascript неизменяемы.