После замыканий важно разобраться, что именно хранится в переменных и почему одинаково выглядящий код иногда ведёт себя по-разному. Это напрямую связано с типами данных и тем, как JavaScript работает с ними в памяти.
Многие ошибки возникают не из-за синтаксиса, а из-за неправильного понимания различий между типами.
Два больших типа данных
В JavaScript все значения делятся на две группы:
- Примитивы
- Объекты
Это деление принципиально важно.
Примитивные типы
К примитивам относятся:
- number
- string
- boolean
- null
- undefined
- symbol
- bigint
Начнём с простого примера.
let a = 10;
let b = a;
b = 20;
console.log(a); // 10
console.log(b); // 20
Здесь:
- в a лежит значение 10
- в b копируется само значение
- изменение b никак не влияет на a
Это поведение называется передача по значению.
Строки ведут себя так же
let firstName = 'Anna';
let secondName = firstName;
secondName = 'Maria';
console.log(firstName); // Anna
console.log(secondName); // Maria
Строки — тоже примитивы.
Каждая переменная хранит собственное значение.
Объекты — другое поведение
Теперь рассмотрим объект.
const userA = {
name: 'Alex'
};
const userB = userA;
userB.name = 'John';
console.log(userA.name); // John
console.log(userB.name); // John
Здесь происходит неочевидная для многих вещь:
- в userA хранится не сам объект, а ссылка на него
- в userB копируется эта же ссылка
- обе переменные указывают на один и тот же объект
Это называется передача по ссылке.
Почему это важно понимать
На первый взгляд код выглядит безопасно:
function updateUser(user) {
user.isActive = true;
}
const currentUser = { name: 'Alex' };
updateUser(currentUser);
console.log(currentUser.isActive); // true
Функция изменила объект, хотя формально ничего не возвращала.
Это нормальное поведение для объектов.
Примитивы так не работают
function updateCount(count) {
count = count + 1;
}
let total = 5;
updateCount(total);
console.log(total); // 5
Здесь:
- count — копия значения
- изменение не влияет на исходную переменную
Почему это связано с замыканиями
Рассмотрим замыкание с примитивом:
function createCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
count:
- примитив
- но хранится внутри замыкания
- живёт между вызовами функции
Теперь тот же принцип с объектом:
function createSettings() {
const settings = { theme: 'dark' };
return function () {
settings.theme = 'light';
return settings;
};
}
Объект остаётся тем же самым, но его содержимое меняется.
Сравнение примитивов и объектов
console.log(5 === 5); // true
console.log('a' === 'a'); // true
С примитивами всё просто.
console.log({} === {}); // false
Каждый объект — это новая ссылка, даже если содержимое одинаковое.
Частая логическая ошибка
const a = { value: 1 };
const b = { value: 1 };
if (a === b) {
console.log('Equal');
}
Этот код никогда не выполнится, потому что:
- сравниваются ссылки
- а не содержимое объектов
Как это влияет на копирование
const original = { name: 'Alex' };
const copy = original;
copy.name = 'John';
console.log(original.name); // John
Это не копия, а вторая ссылка.
Поверхностное копирование
const original = { name: 'Alex' };
const copy = { ...original };
copy.name = 'John';
console.log(original.name); // Alex
Теперь:
- создан новый объект
- верхний уровень скопирован
Но важно понимать ограничение.
Вложенные объекты
const user = {
name: 'Alex',
settings: {
theme: 'dark'
}
};
const copy = { ...user };
copy.settings.theme = 'light';
console.log(user.settings.theme); // light
Вложенный объект всё ещё общий.
Это поверхностное копирование, а не глубокое.
Практический вывод
На этом этапе важно чётко понимать:
- Примитивы копируются по значению
- Объекты передаются по ссылке
- Изменение объекта влияет на все ссылки
- Поверхностное копирование не изолирует вложенные структуры
В следующей статье логично перейти к работе с объектами глубже: свойствам, мутациям и тому, как писать код, который не ломается из-за неожиданных изменений данных.
21.01.2026
0
18
Комментарии
0