Что получится в результате передачи объекта как аргумента в функцию и выполнения кода?
Есть блок кода:
var obj = {};
function func(x) {
x = 1;
return x;
}
console.log(func(obj)); // Первый
console.log(obj); // Второй
Какие результаты будут в консоле?
Теория по задаче
Разберём эту задачу с фундаментальной точки зрения. Это классический вопрос на понимание модели выполнения JavaScript, передачи аргументов и различия типов данных.
Фундамент: Типы данных в JavaScript
JavaScript имеет две категории типов данных, которые ведут себя принципиально по-разному:
Примитивные типы (Primitive Types):
undefined,null,boolean,number,string,symbol,bigint- Хранятся по значению (by value)
- Неизменяемы (immutable) - при "изменении" создаётся новое значение
- Сравниваются по значению:
5 === 5→true
Объектные типы (Object Types)
Object,Array,Function,Date,RegExpи др.- Хранятся по ссылке (by reference)
- Изменяемы (mutable) - можно менять содержимое
- Сравниваются по ссылке:
{} === {}→false
Ключевая концепция: передача аргументов в функции
JavaScript всегда передаёт аргументы ПО ЗНАЧЕНИЮ (pass-by-value) НО: Для объектов это значение ссылки.
Аналогия:
Представь, что у тебя есть:
- Дом (объект) по адресу 0x123
- Визитная карточка (переменная) с этим адресом
let house = { color: "blue" }; // Визитка с адресом 0x123
Кейс 1: Передача примитива (pass-by-value):
function changePrimitive(a) {
a = 10; // Создаётся НОВОЕ значение 10
// Старое значение (5) не меняется
}
let num = 5;
changePrimitive(num);
console.log(num); // 5 - оригинал не изменился
Что происходит:
- Создаётся копия значения
5 - Копия передаётся в параметр
a a = 10меняет локальную копию- Оригинальная переменная
numне затронута
Кейс 2: Передача объекта (pass-by-value-of-reference):
function changeObject(obj) {
obj.color = "red"; // Меняем содержимое ДОМА по адресу
}
let myHouse = { color: "blue" }; // Визитка: адрес 0x123
changeObject(myHouse);
console.log(myHouse.color); // "red" - дом изменился!
Что происходит:
- Создаётся копия ссылки (адреса
0x123) - Копия ссылки передаётся в параметр
obj obj.color = "red"идёт по адресу и меняет сам дом- Оригинальная
myHouseвсё ещё указывает на тот же изменённый дом
Кейс 3: Переприсваивание ссылки (текущая задача):
function reassignReference(obj) {
obj = { color: "green" }; // Создаём НОВЫЙ дом, меняем адрес на визитке
}
let house = { color: "blue" }; // Визитка: адрес 0x123
reassignReference(house);
console.log(house.color); // "blue" - старый дом не изменился!
Что происходит:
- Параметр
objполучает копию ссылки на адрес0x123 obj = { color: "green" }:- Создаётся новый объект (новый дом по адресу
0x456) - Локальная переменная
objтеперь хранит адрес0x456
- Создаётся новый объект (новый дом по адресу
- Оригинальная
houseпродолжает хранить старый адрес0x123
Пошаговый разбор текущей задачи
var obj = {}; // Шаг 1: Создаётся объект, obj хранит ссылку на него
function func(x) { // Шаг 3: x получает КОПИЮ ссылки от obj
x = 1; // Шаг 4: x теперь хранит примитив 1, связь с объектом разорвана
return x; // Шаг 5: возвращается 1
}
console.log(func(obj)); // Шаг 2 и 6: вызов функции -> 1
console.log(obj); // Шаг 7: исходный объект остался {}
Визуализация в памяти:
До вызова функции:
[Глобальная область видимости]
obj: ref1 → { } (Объект #1 в куче)
В момент вызова func(obj):
[Глобальная область видимости]
obj: ref1 → { } (Объект #1)
[Область видимости func]
x: ref1 → { } (КОПИЯ ссылки на тот же объект)
После x = 1:
[Глобальная область видимости]
obj: ref1 → { } (Объект #1) ← НЕ ИЗМЕНЁН!
[Область видимости func]
x: 1 (теперь хранит примитив, не ссылку)
Почему это так важно на практике?
Распространённая ошибка:
function clearArray(arr) {
arr = []; // Не очистит переданный массив!
}
let items = [1, 2, 3];
clearArray(items);
console.log(items); // [1, 2, 3] - массив не очищен!
Правильный подход:
function clearArray(arr) {
arr.length = 0; // Изменяет существующий объект
// или arr.splice(0, arr.length);
}
Как запомнить раз и навсегда?
Простое правило:
- Присваивание (
=) переменной нового значения → меняет только эту переменную - Изменение свойства (
obj.key = value) → меняет сам объект, если переменная на него ссылается
ES6+ особенности
Деструктуризация не меняет правила:
function update({ data }) {
data = 42; // Меняет только локальный параметр
}
let obj = { data: 10 };
update(obj);
console.log(obj.data); // 10
Spread оператор создаёт поверхностную копию:
function update(arr) {
arr[0] = 100; // Изменит и оригинал!
}
let numbers = [1, 2, 3];
update([...numbers]); // Передаётся копия массива, но элементы те же
console.log(numbers); // [1, 2, 3] - не изменился
// Но если бы элементы были объектами - их изменения отразились бы!
Итого
1. Два типа данных в JS
- Примитивы (числа, строки и др.) — хранятся и передаются по значению
- Объекты (включая массивы, функции) — хранятся и передаются по значению ссылки
2. JavaScript всегда передаёт аргументы по значению
- Для объектов передаётся копия ссылки, а не сам объект
- Параметр функции становится локальной переменной
3. Критическая разница в операциях
x = 1— переприсваивание (меняет, на что ссылается переменнаяx)x.property = 1— мутация (меняет содержимое объекта, на который ссылаетсяx)