Примитивы в JavaScript — это миф?

от автора

Все мы знаем что в JavaScript есть ссылочные (Object), присваивающиеся по ссылке и примитивные типы данных (String, Number, Null и тд), присваивающиеся по значению. Но так ли это на самом деле? В этой статье с помощью небольшого эксперимента мы убедимся, что это не совсем так и посмотрим как «примитивные» типы данных на самом деле хранятся в памяти.

Создадим небольшой HTML файл:

<!DOCTYPE html> <html lang="en"> <head>   <meta charset="UTF-8">   <meta http-equiv="X-UA-Compatible" content="IE=edge">   <meta name="viewport" content="width=device-width, initial-scale=1.0">   <title>Document</title> </head> <a class="la1"></a> <body>   <script>     var word = "word".repeat(1000000);     document.querySelector('.a1').innerHTML = word;   </script> </body> </html>

Мы создаем переменную word в которой хранится строка, содержащая 1 миллион повторений слова «word»
Сделаем snapshot во вкладке Memory в браузере Chrome и посмотрим на память

Мы видим что наша огромная строка занимает 4Мб памяти

Далее добавим в наш HTML файл немного кода

<!DOCTYPE html> <html lang="en"> <head>   <meta charset="UTF-8">   <meta http-equiv="X-UA-Compatible" content="IE=edge">   <meta name="viewport" content="width=device-width, initial-scale=1.0">   <title>Document</title> </head> <a class="a1"></a> <a class="a2"></a> <body>   <script>     var word = "word".repeat(1000000);     // Добавляем переменную word2     var word2 = word;     document.querySelector('.a1').innerHTML = word;     // Отрисовываем ее значение во вторую ссылку      document.querySelector('.a2').innerHTML = word;   </script> </body> </html>

Как мы все много раз слышали, примитивные типы передаются по значению, соответственно в переменную word2 должна попасть полная копия значения, которое лежит в переменной word и составляет 4Мб. В итоге мы ожидаем увидеть увеличение памяти в 2 раза.

Давайте смотреть!

Но как так! Память, занимаемая строками не то что не увеличилась в 2 раза, она вообще не изменилась! И мы не наблюдаем второй строки, переменная word2 ссылается на тот же участок памяти, что и переменная word. Никакой копии не произошло. Попробуем по-другому.

Давайте создадим массив и добавим туда несколько значений

<!DOCTYPE html> <html lang="en"> <head>   <meta charset="UTF-8">   <meta http-equiv="X-UA-Compatible" content="IE=edge">   <meta name="viewport" content="width=device-width, initial-scale=1.0">   <title>Document</title> </head> <a class="a1"></a> <body>   <script>     var word = "word".repeat(1000000)     var arr = [word, word, word, word, word]     for (let i = 0; i < arr.length - 1; i++) {         document.querySelector('.a1').innerHTML += word;     }   </script> </body> </html>

Как мы видим, снова ничего не изменилось. Все 5 элементов массива ссылаются на один и тот же участок памяти.

Мы можем взглянуть на сам массив и увидеть его Shallow Size — объем памяти, непосредственно занимаемый объектом, который не включает память, занимаемую другими объектами, на которые этот объект ссылается.

Вывод

JavaScript движки оптимизируют использование памяти, храня данные в одном месте и создавая ссылки на одну и ту же строку для всех переменных, которые на неё ссылаются.
Однако, если одна из переменных, ссылающихся на одну и ту же строку, изменяется, движок создаст новую строку, которая будет занимать соответствующий объем памяти.
Это позволяет эффективно использовать память и избегать её ненужного увеличения.


ссылка на оригинал статьи https://habr.com/ru/articles/824614/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *