
Как хранить строки по ссылке в JavaScript
Строки JavaScript хранятся по значению и ведут себя так же, как любой другой примитив. Это означает, что каждый раз, когда мы разрезаем строку, мы фактически занимаем дополнительные слоты памяти. Хотя этот компромисс делает кодирование более удобным и намного проще, он очень неэффективен в памяти:
edit: После исследования я обнаружил, что некоторые браузеры используют интернирование строк, что означает, что браузер будет хранить пул строковых литералов со ссылками на его подстроки, поэтому управление памятью может привести к чему-то разные, однако; официально это не является частью спецификации TC39 и может отличаться в зависимости от браузера / разных операций / разных вызовов функций.
Более того, как только вы создаете строку, вы создаете ее навсегда. Если вы хотите изменить один из его символов, вам придется заново определять его:
Хочу познакомить вас с классом ArrayBuffer. ArrayBuffer позволяет напрямую выделять память и управлять ею. Он существует уже давно, примерно с 2012 года, но его очень не замечают. Первоначально он был рожден из-за необходимости иметь эффективный способ обработки двоичных данных в WebGL, но его можно использовать для любых целей независимо.
Предполагая, что мы хотели бы создать строку, состоящую из кодовых единиц UTF-16, которая включает наиболее распространенные символы, которые могут быть представлены одним 16-битным значением, нам придется выделить 2 байта на символ:
Другой набор классов, которые идут рука об руку с ArrayBuffer, - это TypedArrays. Объект TypedArray описывает представление нижележащего буфера двоичных данных в виде массива. В нашем случае, поскольку мы хотим представить строку UTF-16, мы будем использовать TypedArray Uint16Array, который состоит из 16-битных целых чисел без знака:
Поскольку мы используем один и тот же объект ArrayBuffer, любое изменение, которое мы внесем в один TypedArray, отразится на другом:
Чтобы завершить работу, мы можем преобразовать байтовый код в строку с помощью функции String.fromCharCode():
Все вышеперечисленное можно объединить в пару классов, которые обернут эту логику и даже добавят несколько удобных служебных функций:
Итак, возвращаясь к самому первому фрагменту кода в этой статье, вот как будет выглядеть память при разделении строки "hello world":
Обратите внимание, что ArrayBuffers также можно использовать для ссылки на другие типы примитивных значений, такие как числа или логические значения, это не обязательно относится к строке. Пока вы знаете, сколько памяти занимает данное примитивное значение, все готово:
ArrayBuffers эффективны, но будьте осторожны:
- Ни один из методов-прототипов, которые обычно доступны для примитивных значений, будет недоступен.
- Их длина заранее определена и не может быть изменена или превышена.
Если вы знаете об этих ограничениях и ответственно используете ArrayBuffers, все готово.