Один важливий концепт, який варто освіжити перед тим, як зануритися в задачі з алгоритмів — це розуміння того, як JavaScript обробляє аргументи функцій з примітивними типами та об'єктами. У інших мовах програмування ви можете зустріти терміни "Pass by Value" (передача за значенням) та "Pass by Reference" (передача за посиланням). Однак, у JavaScript все передається за значенням. Однак цей процес має нюанси, коли мова йде про складні типи, такі як об'єкти та масиви.
Примітка: термін "передача за посиланням" часто неправильно розуміється. JavaScript завжди передає аргументи за значенням; для об'єктів це значення є посиланням, яке дозволяє спільний доступ до даних об'єкта.
Примітивні типи в JavaScript:
- String (Рядок)
- Number (Число)
- Boolean (Булевий тип)
- Undefined (Не визначено)
- Null
- ES6 Symbols (Символи ES6)
Складні типи в JavaScript:
- Об'єкти (включаючи масиви)
- Функції
Поведінка примітивних і складних типів
Примітивні типи:
У JavaScript для примітивних змінних фактичне значення, яке зберігається в змінній, передається іншій змінній або функції, створюючи нову копію. Це означає, що зміни параметра всередині функції не впливають на оригінальну змінну.
let originalFruit = 'Apple';
let newFruit = originalFruit;
newFruit = 'Pineapple';
// originalFruit залишиться 'Apple', тому що копія була передана в newFruit
console.log(originalFruit); // Apple
console.log(newFruit); // Pineapple
Складні типи:
Коли ви присвоюєте або передаєте складні значення, такі як об'єкти чи масиви, JavaScript передає копію посилання за значенням. Це означає, що як оригінальна, так і нова змінна посилаються на один і той самий об'єкт в пам'яті.
Тому зміни в об'єкті через нову змінну впливають на оригінальний об'єкт.
let originalFruitBasket = ['Apple'];
let newFruitBasket = originalFruitBasket; //['Apple']
newFruitBasket[0] = 'Orange';
// Обидва посилання вказують на той самий об'єкт, тому originalFruitBasket оновлюється
console.log(originalFruitBasket); // ['Orange']
console.log(newFruitBasket); // ['Orange']
newFruitBasket = ['Banana'];
// Переназначення порушує посилання; originalFruitBasket залишається незмінним
console.log(originalFruitBasket); // ['Orange']
console.log(newFruitBasket); // ['Banana']
Розуміння посилань:
Якщо змінна зберігає посилання на об'єкт, будь-яка модифікація властивостей об'єкта через це посилання також відображатиметься на оригінальному об'єкті.
let originalList = [1, 2];
let newList = originalList; // newList тепер зберігає копію посилання
newList.push(3);
// Зміни в newList впливають на originalList
// тому що вони мають одне й те саме посилання
console.log(originalList); // [1, 2, 3]
console.log(newList); // [1, 2, 3]
Якщо ми хочемо створити новий масив з тими самими значеннями, а не спільне посилання, ми можемо використати метод .slice()
.
let originalList = [1, 2];
let newList = originalList.slice(); // Створює новий масив, порушуючи посилання
// або let newList = [...originalList]
newList.push(3);
// Зміни в newList не впливають на originalList
console.log(originalList); // [1, 2]
console.log(newList); // [1, 2, 3]
Передача значень у функції
Передача примітивних значень:
Зверніть увагу, що значення оригінального примітиву залишаються незмінними.
let age = 25;
function addYears(age) {
age += 5;
return age;
}
let newAge = addYears(age);
console.log(age); // 25
console.log(newAge); // 30
Передача складних значень:
Передається посилання на складне значення, тому зміни впливають на оригінальний об'єкт.
let ageList = [25];
function addYearsToList(list) {
list.push(30);
return list;
}
let newAgeList = addYearsToList(ageList);
console.log(ageList); // [25, 30]
console.log(newAgeList); // [25, 30]
// ageList і newAgeList вказують на один і той самий масив
Важливо, що переназначення параметра на новий об'єкт чи масив усередині функції не змінює оригінальне посилання поза функцією.
let ageList = [1, 2, 3];
function modifyArray(arr) {
// Це змінює вміст масиву, впливаючи на оригінальний масив
arr.push(4);
console.log('Всередині функції після push:', arr); // [1, 2, 3, 4]
// *** Переназначення параметра на новий масив ***
arr = [5, 6, 7];
console.log('Всередині функції після переназначення:', arr); // [5, 6, 7]
}
modifyArray(ageList);
console.log('Поза функцією:', ageList); // [1, 2, 3, 4]
arr.push(4)
: Модифікація властивостей або елементів у функції впливає на оригінальний об'єкт чи масив, оскільки обидва посилання вказують на одну й ту саму пам'ятну локацію.arr = [5, 6, 7]
: Переназначення параметра всередині функції не впливає на оригінальне посилання поза функцією, оскільки переназначення змінює лише локальну копію посилання в межах області видимості функції.
Оператори рівності та PBV:
Оператор строгого порівняння ===
порівнює складні значення за посиланням, а не за значенням.
let numbers1 = [1, 2, 3];
let numbers2 = [1, 2, 3];
console.log(numbers1 === numbers2); // false (не ті самі посилання)
let numbers3 = numbers1;
console.log(numbers1 === numbers3); // true (ті самі посилання)
Висновок:
У JavaScript усі аргументи функцій передаються за значенням.
Однак для складних типів, таких як об'єкти та масиви, це значення насправді є посиланням на об'єкт або масив у пам'яті. Це означає, що, хоча ви можете змінювати властивості об'єкта або елементи масиву всередині функції (тим самим впливаючи на оригінальний об'єкт чи масив), переназначення параметра на новий об'єкт чи масив усередині функції не змінює оригінальне посилання поза функцією. Розуміння цієї різниці є важливим для написання ефективного та безпомилкового коду.
Дякую! Успішного кодування!
Перекладено з: Pass by Value (PBV) in JavaScript: Understanding Primitive Types and Objects