Что такое передача переменной по значению?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Передача переменной по значению
Передача по значению (Pass by Value) — это механизм, при котором функция получает копию значения переменной, а не саму переменную. Изменение параметра внутри функции не влияет на исходную переменную. Это фундаментальное понимание, необходимое для избежания неожиданных ошибок в JavaScript.
Базовое понимание
В JavaScript есть два типа данных:
- Примитивные типы — передаются по значению
- Сложные типы (объекты) — передаются по ссылке
Примитивные типы (по значению)
let a = 5;
let b = a; // копируется значение 5
b = 10;
console.log(a); // 5 (не изменилось)
console.log(b); // 10
// Визуально:
// a -> [5] (ячейка памяти 1)
// b -> [10] (ячейка памяти 2, отдельная копия)
Когда ты присваиваешь let b = a, JavaScript копирует значение из переменной a в новую переменную b. Они не связаны друг с другом.
Передача примитивов в функции
function increment(num) {
num = num + 1;
console.log("Внутри функции:", num); // 6
}
let value = 5;
increment(value);
console.log("Снаружи функции:", value); // 5 (не изменилось!)
Даже когда ты передаёшь параметр в функцию, JavaScript копирует значение. Изменение копии не влияет на исходную переменную.
Все примитивные типы
// Number
let num = 42;
let num2 = num;
num2 = 100;
console.log(num); // 42
// String
let str = "hello";
let str2 = str;
str2 = "world";
console.log(str); // "hello"
// Boolean
let bool = true;
let bool2 = bool;
bool2 = false;
console.log(bool); // true
// undefined
let x = undefined;
let y = x;
y = 10;
console.log(x); // undefined
// null
let a = null;
let b = a;
b = 5;
console.log(a); // null
Все примитивные типы передаются по значению — копируется их значение.
Объекты передаются по ссылке (важная тонкость!)
У сложных типов (объекты, массивы, функции) ситуация иная:
// ❌ Это НЕ передача по значению
let obj1 = { name: "Alice", age: 25 };
let obj2 = obj1; // копируется ссылка на объект, НЕ сам объект
obj2.name = "Bob";
console.log(obj1.name); // "Bob" - изменилось!
console.log(obj2.name); // "Bob"
// Почему?
// obj1 -> [ссылка на объект в памяти] <- obj2
// Обе переменные указывают на ОДИН И ТОТ ЖЕ объект
То есть JavaScript правильнее назвать "pass by sharing" — объекты передаются по ссылке, примитивы по значению.
Объекты в функциях
function modifyUser(user) {
user.name = "Charlie"; // изменяет оригинальный объект
}
let person = { name: "Alice" };
modifyUser(person);
console.log(person.name); // "Charlie" - изменилось!
// Но если переназначить сам объект:
function reassignUser(user) {
user = { name: "David" }; // создаёт новый объект
}
let person = { name: "Alice" };
reassignUser(person);
console.log(person.name); // "Alice" - не изменилось!
Это ключевое различие: ты можешь изменять свойства объекта, но если переназначить саму переменную, это не повлияет на исходный объект.
Визуальное объяснение
// Примитив (по значению)
let a = 5;
let b = a;
// a: [5]
// b: [5] (отдельная копия)
// Объект (по ссылке)
let obj1 = { x: 10 };
let obj2 = obj1;
// obj1: --->
// |
// obj2: ---+---> { x: 10 } (один объект в памяти)
Частая ошибка: изменение параметра
// ❌ Проблема
function processArray(arr) {
arr.push(4); // изменяет оригинальный массив!
}
let numbers = [1, 2, 3];
processArray(numbers);
console.log(numbers); // [1, 2, 3, 4] - неожиданно изменилось!
// ✅ Решение 1: создай копию
function processArray(arr) {
const copy = [...arr]; // создаём копию
copy.push(4);
return copy;
}
let numbers = [1, 2, 3];
const result = processArray(numbers);
console.log(numbers); // [1, 2, 3]
console.log(result); // [1, 2, 3, 4]
// ✅ Решение 2: не изменяй входные параметры
function processArray(arr) {
const newArray = arr.slice();
newArray.push(4);
return newArray;
}
Как создавать копии
// Поверхностная копия (shallow copy)
const arr1 = [1, 2, 3];
const arr2 = [...arr1]; // новый массив
const obj1 = { name: "Alice" };
const obj2 = { ...obj1 }; // новый объект
// Глубокая копия (deep copy) для вложенных объектов
const deepCopy = JSON.parse(JSON.stringify(obj1));
// Или использовать структурированное клонирование
const deepCopy2 = structuredClone(obj1);
// Проблема с поверхностной копией
const user1 = { name: "Alice", address: { city: "NYC" } };
const user2 = { ...user1 }; // поверхностная копия
user2.address.city = "LA"; // изменит и user1!
console.log(user1.address.city); // "LA" - неожиданно изменилось!
// Нужна глубокая копия
const user3 = structuredClone(user1);
user3.address.city = "LA"; // user1 не изменится
Передача по значению в TypeScript
// Явная типизация помогает избежать ошибок
function updateUser(user: User): void {
// ясно, что User — объект
user.name = "Bob"; // может изменить оригинал
}
function createUser(userData: User): User {
// возвращаем новый объект, не изменяя входной
return { ...userData, id: generateId() };
}
Практический пример из React
// ❌ Проблема: мутируем состояние
function UserProfile() {
const [user, setUser] = useState({ name: "Alice", scores: [10, 20] });
const addScore = (score: number) => {
user.scores.push(score); // мутирует существующий объект!
setUser(user); // React не заметит изменение
};
}
// ✅ Правильно: создаём новый объект
function UserProfile() {
const [user, setUser] = useState({ name: "Alice", scores: [10, 20] });
const addScore = (score: number) => {
// создаём новый объект с новым массивом
setUser({
...user,
scores: [...user.scores, score]
});
};
}
Иммутабельность (Immutability)
Добрая практика — не изменять переданные параметры:
// ❌ Плохо: мутирует параметр
function processData(data: DataType[]): void {
data.sort();
data.map(item => item.value * 2);
}
// ✅ Хорошо: возвращает новый результат
function processData(data: DataType[]): DataType[] {
return data
.slice() // копия
.sort()
.map(item => ({ ...item, value: item.value * 2 }));
}
Резюме
- Примитивные типы (число, строка, boolean и т.д.) передаются по значению — копируется их значение
- Объекты передаются по ссылке — обе переменные указывают на один объект в памяти
- Изменение объекта внутри функции влияет на оригинальный объект — нужно создавать копии
- Избегай мутирования параметров — это делает код непредсказуемым
- Используй иммутабельность — особенно в React, где это критично для обновления состояния