Все мы знаем что в 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/
Добавить комментарий