В этом руководстве вы узнаете о двух разных типах значений в JavaScript, включая примитивные и ссылочные значения.
JavaScript имеет два разных типа значений:
- Примитивные значения;
- Ссылочные значения.
Примитивные значения — это атомарные фрагменты данных, а ссылочные значения — это объекты, которые могут состоять из нескольких значений.
Стек и куча памяти
Когда вы объявляете переменные, механизм JavaScript выделяет для них память в двух местах памяти: в стеке и в куче.
Статические данные — это данные, размер которых фиксируется во время компиляции. Статические данные включают в себя:
- Примитивные значения (null, undefined, boolean, number, string, symbol и BigInt)
- Ссылочные значения, которые относятся к объектам.
Поскольку размер статических данных не меняется, механизм JavaScript выделяет фиксированный объем памяти для статических данных и сохраняет их в стеке.
Например, в следующем примере объявляются две переменные и инициализируются их значения буквальной строкой и числом:
let name = 'John'; let age = 25;
Поскольку name
и age
являются примитивными значениями, движок JavaScript сохраняет эти переменные в стеке, как показано на следующем рисунке:
Обратите внимание, что строки являются объектами во многих языках программирования, включая Java и C#. Однако строки являются примитивными значениями в JavaScript.
В отличие от стека, JavaScript хранит объекты (и функции) в куче. Движок JavaScript не выделяет фиксированный объем памяти для этих объектов. Вместо этого он будет выделять больше места по мере необходимости.
В следующем примере определяются переменные name
, age
и person
:
let name = 'John'; let age = 25; let person = { name: 'John', age: 25, };
Внутри движок JavaScript выделяет память, как показано на следующем рисунке:
На этом рисунке JavaScript выделяет память в стеке для трех переменных name
, age
и person
.
Движок JavaScript создает новый объект в куче памяти. Кроме того, он связывает переменную person
в памяти стека с объектом в памяти кучи.
По этой причине мы говорим, что переменная person
является ссылкой на объект.
Динамические свойства
Ссылочное значение позволяет добавлять, изменять или удалять свойства в любое время. Например:
let person = { name: 'John', age: 25, }; // add the ssn property person.ssn = '123-45-6789'; // change the name person.name = 'John Doe'; // delete the age property delete person.age; console.log(person);
Выход:
{ name: 'John Doe', ssn: '123-45-6789' }
В отличие от ссылочного значения, примитивное значение не может иметь свойств. Это означает, что вы не можете добавить свойство к примитивному значению.
JavaScript позволяет добавлять свойство к примитивному значению. Однако никакого эффекта это не даст. Например:
let name = 'John'; name.alias = 'Knight'; console.log(name.alias); // undefined
Выход:
undefined
В этом примере мы добавляем свойство alias
к примитивному значению name
. Но когда мы обращаемся к свойству alias
через примитивное значение name
, оно возвращает undefined
.
Копирование значений
Когда вы присваиваете примитивное значение одной переменной другой, механизм JavaScript создает копию этого значения и присваивает его переменной. Например:
let age = 25; let newAge = age;
В этом примере:
- Во-первых, объявите новую переменную
age
и инициализируйте ее значение25
. - Во-вторых, объявите еще одну переменную
newAge
и присвойтеage
переменнойnewAge
.
В фоновом режиме механизм JavaScript создает копию примитивного значения 25
и присваивает его переменной newAge
.
На следующем рисунке показана память стека после присваивания:
В памяти стека newAge
и age
являются отдельными переменными. Если вы измените значение одной переменной, это не повлияет на другую.
Например:
let age = 25; let newAge = age; newAge = newAge + 1; console.log(age, newAge);
Когда вы присваиваете ссылочное значение одной переменной другой, механизм JavaScript создает ссылку, чтобы обе переменные ссылались на один и тот же объект в куче памяти. Это означает, что если вы измените одну переменную, это повлияет на другую.
Например:
let person = { name: 'John', age: 25, }; let member = person; member.age = 26; console.log(person); console.log(member);
Как это работает.
Во-первых, объявите переменную person
и инициализируйте ее значение с помощью объекта с двумя свойствами: name
и age
.
Во-вторых, назначьте переменную person
переменной- member
. В памяти обе переменные ссылаются на один и тот же объект, как показано на следующем рисунке:
В-третьих, измените свойство age
объекта с помощью переменной- member
:
Поскольку и переменные person
и переменные- member
ссылаются на один и тот же объект, изменение объекта через переменную- member
также отражается в переменной person
.
Заключение
- Javascript имеет два типа значений: примитивные и ссылочные.
- Вы можете добавлять, изменять или удалять свойства ссылочного значения, но не можете делать это с примитивным значением.
- При копировании примитивного значения из одной переменной в другую создается отдельная копия значения. Это говорит о том, что изменение значения одной переменной не влияет на другую.
- Копирование ссылки из одной переменной в другую создает ссылку, так что две переменные ссылаются на один и тот же объект. Это означает, что изменение объекта через одну переменную отражается в другой переменной.