Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Передача аргументів за значенням і за посиланням». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**JavaScript завжди копіює аргумент під час виклику функції, але результат залежить від типу даних: примітиви копіюються цілком (за значенням), а для об'єктів, масивів і функцій копіюється посилання на них, тому функція працює з тим самим об'єктом у пам'яті.** Через це зміна властивості всередині функції видно ззовні, а перепризначення самого параметра, ні. ```javascript let count = 10; const user = { name: "Alice" }; function change(x, obj) { x = 20; // змінюється лише копія примітива obj.name = "Bob"; // змінюється спільний об'єкт } change(count, user); console.log(count, user.name); // 10 "Bob" ``` **Ключове:** технічно JavaScript передає все за значенням, просто для об'єктів цим значенням є посилання, тобто передається копія посилання.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Коли ми передаємо аргументи у функцію, JavaScript копіює їх, а те, як саме копіює, залежить від типу даних: примітиви копіюються за значенням, а об'єкти, масиви і функції передаються за посиланням, точніше за копією посилання.** Саме тому одні зміни всередині функції видно ззовні, а інші зникають разом із викликом. ## Теорія ### TL;DR - Примітиви (`number`, `string`, `boolean`, `null`, `undefined`, `symbol`, `bigint`) передаються **за значенням**: у параметр лягає повна копія. - Об'єкти, масиви і функції передаються **за посиланням**, тобто у параметр лягає копія посилання на ту саму ділянку пам'яті. - Зміна **вмісту** об'єкта всередині функції (`obj.name = "Bob"`, `arr.push(4)`) видно в оригіналі. - **Перепризначення** параметра (`obj = {...}`, `arr = [...]`) оригінал не зачіпає, бо змінюється лише локальна копія посилання. - Строго кажучи, JavaScript завжди передає за значенням: для об'єктів цим значенням є посилання. ### Швидкий приклад ```javascript let a = 10; function changeValue(x) { x = 20; // змінюємо копію } changeValue(a); console.log(a); // 10 ``` Значення `a` не змінилося, бо у `x` записалася лише його копія. ### Передача за значенням Примітиви, тобто числа, рядки, булеві значення, `null`, `undefined`, `symbol` і `bigint`, копіюються **повністю**. | Тип даних | Як передається | | --- | --- | | Примітиви (числа, рядки, булеві, `null`, `undefined`, `symbol`, `bigint`) | **за значенням** | | Об'єкти, масиви, функції | **за посиланням (точніше, за копією посилання)** | Пояснення на прикладі вище: - У `x` записується **копія** значення `a`. - Зміна `x` жодним чином не впливає на `a`. У пам'яті це виглядає так: ```text a -> 10 x -> 10 (копія) ``` ### Передача за посиланням Об'єкти, масиви і функції не копіюються цілком. Замість цього передається **посилання на їхню адресу в пам'яті**. ```javascript const user = { name: "Alice" }; function rename(obj) { obj.name = "Bob"; } rename(user); console.log(user.name); // "Bob" ``` Пояснення: - Змінна `user` зберігає **посилання** на об'єкт у пам'яті. - У `obj` копіюється це саме посилання, тож обидві змінні вказують на один і той самий об'єкт. - Зміни через `obj` видно і через `user`. У пам'яті це виглядає так: ```text user --+ v { name: "Bob" } ^ obj ---+ ``` ### Перепризначення посилання всередині функції Якщо всередині функції змінити саме посилання, оригінал залишиться недоторканим. ```javascript const user = { name: "Alice" }; function reassign(obj) { obj = { name: "Charlie" }; // нове посилання } reassign(user); console.log(user.name); // "Alice" ``` Що тут відбувається: - У `obj` спочатку копіюється посилання на `user`. - Потім `obj` перенаправляється на **новий об'єкт**, але оригінальне посилання (`user`) залишається тим самим. Це і є доказ того, що передається копія посилання, а не сам слот змінної. ### Приклад з масивом Масив це теж об'єкт, тому діють ті самі правила. Зміна вмісту видно ззовні: ```javascript const numbers = [1, 2, 3]; function modify(arr) { arr.push(4); // змінюємо вміст } modify(numbers); console.log(numbers); // [1, 2, 3, 4] ``` А ось перепризначення посилання, ні: ```javascript function modify(arr) { arr = [9, 9, 9]; // створюємо новий масив } modify(numbers); console.log(numbers); // [1, 2, 3] ``` ### Підсумок і проста аналогія | Тип даних | Як передається | Чи впливає зміна всередині функції на оригінал? | | --- | --- | --- | | Примітиви (`number`, `string`, `boolean`, `null`, `undefined`, `symbol`, `bigint`) | **За значенням** | Ні | | Об'єкти, масиви, функції | **За посиланням (копією посилання)** | Так, якщо змінюється вміст | | Перепризначення параметра всередині функції | Локальна копія | Ні | Аналогія, яка добре лягає на співбесіді: - **За значенням** це як передати копію аркуша паперу: якщо ви щось напишете на своїй копії, оригінал не зміниться. - **За посиланням** це як передати адресу сейфа: обидва можете відкрити той самий сейф і змінити те, що всередині. ### Типові помилки - **Вважати, що JavaScript має справжню передачу за посиланням.** Її немає: функція не може перепризначити змінну, яку їй передали. Правильне формулювання це «передача копії посилання», або, як кажуть англійською, call by sharing. - **Плутати мутацію з перепризначенням.** `obj.name = "Bob"` змінює спільний об'єкт, `obj = {...}` змінює лише локальний параметр. - **Думати, що `const` захищає від змін.** `const user = {...}` забороняє перепризначити `user`, але не забороняє змінювати його властивості всередині функції. Для захисту потрібен `Object.freeze` або копія. - **Розраховувати, що поверхнева копія рятує повністю.** `{ ...user }` і `structuredClone` поводяться по-різному: спред копіює лише верхній рівень, тож вкладені об'єкти залишаються спільними. - **Забувати, що рядок незмінний.** Метод на кшталт `str.toUpperCase()` не змінює аргумент, а повертає новий рядок, який треба присвоїти.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.