← Назад к вопросам

Как передаются параметры функций в JavaScript?

1.6 Junior🔥 291 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как передаются параметры функций в JavaScript

Передача параметров в JavaScript основана на принципе pass-by-value для примитивов и pass-by-reference для объектов. Понимание этого различия критично для избежания неожиданных ошибок.

1. Примитивные типы — передача по значению

Для примитивов (number, string, boolean, null, undefined, symbol, bigint) создаётся копия значения. Изменение параметра внутри функции не влияет на исходную переменную.

function modify(value) {
  value = value * 2;
  console.log('Inside function:', value);  // 20
}

let num = 10;
modify(num);
console.log('Outside function:', num);  // 10 (не изменилось)

Почему? JavaScript создаёт копию значения в стеке памяти:

До вызова:      После вызова:
num = 10        num = 10 (в основном scope)
                value = 10 (копия в scope функции)
                value = 20 (изменение копии)

То же самое с строками и другими примитивами:

function changeString(str) {
  str = str + ' modified';
  return str;
}

let original = 'Hello';
let result = changeString(original);
console.log(original);  // 'Hello' (не изменилось)
console.log(result);    // 'Hello modified'

2. Объекты и массивы — передача по ссылке

Для объектов и массивов передаётся ссылка на объект, а не сама копия. Это означает, что обе переменные указывают на один и тот же объект в памяти.

function modifyObject(obj) {
  obj.name = 'Jane';  // изменяем существующее свойство
  console.log('Inside function:', obj);  // { name: 'Jane', age: 30 }
}

let person = { name: 'John', age: 30 };
modifyObject(person);
console.log('Outside function:', person);  // { name: 'Jane', age: 30 } (изменилось!)

Визуально:

person ──→ { name: 'John', age: 30 }  (объект в памяти)
           ↑
           obj (ссылка указывает на тот же объект)

После модификации:
person ──→ { name: 'Jane', age: 30 }  (объект изменился)
           ↑
           obj (та же ссылка)

3. Важный нюанс: переприсваивание ссылки

Если переприсвоить параметр (создать новую ссылку), это не влияет на исходную переменную:

function reassignObject(obj) {
  obj = { name: 'New Object' };  // переприсваиваем на новый объект
  console.log('Inside function:', obj);  // { name: 'New Object' }
}

let original = { name: 'Original' };
reassignObject(original);
console.log('Outside function:', original);  // { name: 'Original' } (не изменилось)

Почему не изменилось?

Внутри функции: obj = new Object()
                obj теперь указывает на НОВЫЙ объект
                original всё ещё указывает на СТАРЫЙ объект

4. Массивы — то же самое, что объекты

Массивы — это объекты, поэтому передаются по ссылке:

function addToArray(arr) {
  arr.push(4);
  console.log('Inside function:', arr);  // [1, 2, 3, 4]
}

let numbers = [1, 2, 3];
addToArray(numbers);
console.log('Outside function:', numbers);  // [1, 2, 3, 4] (изменилось!)

Но переприсваивание массива не влияет на оригинал:

function reassignArray(arr) {
  arr = [10, 20, 30];  // новый массив
}

let original = [1, 2, 3];
reassignArray(original);
console.log(original);  // [1, 2, 3] (не изменилось)

5. Как защитить от нежелательных изменений

Создание копии

function safeModify(obj) {
  // Поверхностная копия (shallow copy)
  const copy = { ...obj };
  copy.name = 'Modified';
  return copy;
}

const original = { name: 'John', age: 30 };
const modified = safeModify(original);
console.log(original);  // { name: 'John', age: 30 }
console.log(modified);  // { name: 'Modified', age: 30 }

Для массивов

function safeModifyArray(arr) {
  // Создаём копию массива
  const copy = [...arr];
  copy.push(99);
  return copy;
}

const original = [1, 2, 3];
const modified = safeModifyArray(original);
console.log(original);  // [1, 2, 3]
console.log(modified);  // [1, 2, 3, 99]

Глубокая копия (для вложенных объектов)

function deepCopy(obj) {
  return JSON.parse(JSON.stringify(obj));
}

// Или используя structuredClone (экспериментальный)
function modernDeepCopy(obj) {
  return structuredClone(obj);
}

const original = { 
  user: { name: 'John' },
  tags: ['js', 'node']
};

const copy = deepCopy(original);
copy.user.name = 'Jane';
copy.tags.push('backend');

console.log(original);  // не изменилось
console.log(copy);      // изменилось

6. Spread оператор и Object.assign()

function modifyWithSpread(obj) {
  return { ...obj, name: 'Modified' };
}

const original = { name: 'John', age: 30 };
const modified = modifyWithSpread(original);

console.log(original);  // { name: 'John', age: 30 }
console.log(modified);  // { name: 'Modified', age: 30 }

// Object.assign()
function modifyWithAssign(obj) {
  const copy = Object.assign({}, obj);
  copy.name = 'Modified';
  return copy;
}

7. Практические примеры

Ошибка: неожиданное изменение объекта

function updateUser(user) {
  user.lastLogin = new Date();  // изменяет оригинальный объект!
  return user;
}

const userData = { id: 1, name: 'John' };
const returned = updateUser(userData);

console.log(userData);  // { id: 1, name: 'John', lastLogin: Date }
// userData изменился!

Правильно: возвращаем новый объект

function updateUser(user) {
  return {
    ...user,
    lastLogin: new Date()
  };
}

const userData = { id: 1, name: 'John' };
const updated = updateUser(userData);

console.log(userData);  // { id: 1, name: 'John' } (не изменился)
console.log(updated);   // { id: 1, name: 'John', lastLogin: Date }

8. Функции с множественными параметрами

function processData(primitives, obj, arr) {
  // Примитивы — копия
  let num = primitives;  // локальная копия
  
  // Объект — ссылка
  obj.modified = true;   // изменит оригинальный
  
  // Массив — ссылка
  arr.push(99);          // изменит оригинальный
}

let value = 10;
let object = { name: 'test' };
let array = [1, 2, 3];

processData(value, object, array);

console.log(value);    // 10 (не изменился)
console.log(object);   // { name: 'test', modified: true } (изменился!)
console.log(array);    // [1, 2, 3, 99] (изменился!)

9. Параметры по умолчанию и rest параметры

// Параметры по умолчанию
function greet(name = 'Guest', obj = {}) {
  obj.greeted = true;  // изменит переданный объект или новый
}

// Rest параметры (собирают все в массив)
function sum(...numbers) {  // numbers — новый массив
  return numbers.reduce((a, b) => a + b, 0);
}

const nums = [1, 2, 3];
sum(...nums);  // распаковка, но передаются примитивы

10. Деструктуризация параметров

function processUser({ name, email, age = 18 }) {
  // деструктуризирует параметр-объект
  // это поверхностная копия свойств
  name = 'Modified';  // не влияет на исходный
}

const user = { name: 'John', email: 'john@example.com' };
processUser(user);
console.log(user.name);  // 'John' (не изменился)

Сводная таблица

ТипПередачаИзменение влияетПример
numberПо значениюНет10
stringПо значениюНет'hello'
booleanПо значениюНетtrue
null/undefinedПо значениюНетnull
objectПо ссылкеДа (свойства){}
arrayПо ссылкеДа (элементы)[]
functionПо ссылкеДа (вызов)function(){}

Лучшие практики

  1. Помните о ссылках — объекты и массивы изменяют оригиналы
  2. Используйте spread{ ...obj } для копий
  3. Возвращайте новые значения — вместо изменения параметров
  4. Документируйте побочные эффекты — если функция изменяет параметры
  5. Избегайте мутаций — функциональное программирование безопаснее

Заключение

В JavaScript примитивы передаются по значению (копируются), а объекты и массивы — по ссылке (указатель на объект). Это может привести к неожиданным изменениям, если не быть осторожным. Используйте spread оператор, Object.assign() или методы копирования, чтобы защитить исходные данные.