Мої два центи ... Це те, як я це розумію. (Не соромтеся виправити мене, якщо я помиляюся)
Настав час викинути все, що ви знаєте про прохідне значення / посилання.
Оскільки в JavaScript це не має значення, передається він за значенням, за посиланням чи іншим. Важливим є мутація проти присвоєння параметрів, переданих у функції.
Добре, дозвольте зробити все можливе, щоб пояснити, що я маю на увазі. Скажімо, у вас є кілька об’єктів.
var object1 = {};
var object2 = {};
Що ми зробили - це "присвоєння" ... Ми присвоїли 2 окремі порожні об'єкти змінним "object1" та "object2".
Тепер скажімо, що нам подобається object1 краще ... Отже, ми «присвоюємо» нову змінну.
var favoriteObject = object1;
Далі, з будь-якої причини, ми вирішуємо, що нам подобається об’єкт 2 краще. Отже, ми просто робимо невелике перепризначення.
favoriteObject = object2;
Нічого не сталося з об’єктом1 або з об’єктом2. Ми взагалі не змінили жодних даних. Все, що ми зробили, було перепризначити те, що наш улюблений об’єкт. Важливо знати, що object2 та favoriteObject обидва присвоєні одному об'єкту. Ми можемо змінити цей об’єкт за допомогою будь-якої з цих змінних.
object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe
Гаразд, тепер давайте подивимося на примітиви, як, наприклад, рядки
var string1 = 'Hello world';
var string2 = 'Goodbye world';
Знову ми вибираємо фаворита.
var favoriteString = string1;
І наші змінні favoriteString, і string1 призначені для "Hello world". А що робити, якщо ми хочемо змінити свою улюбленуString ??? Що станеться???
favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'
Ух о .... Що сталося. Ми не могли змінити string1, змінивши favoriteString ... Чому ?? Тому що ми не змінили наш рядковий об'єкт . Все, що ми зробили, було "RE ASSIGN" змінною FavorString в нову рядок. Це по суті від'єднало його від string1. У попередньому прикладі, коли ми перейменували наш об’єкт, ми нічого не призначили. (Ну, а не самої змінної , ... ми, однак, призначили властивість імені новому рядку.) Натомість ми просто мутували об'єкт, який зберігає зв'язки між двома змінними та основними об'єктами. (Навіть якщо б ми хотіли змінити або мутувати рядок об'єкт сам, ми не могли цього зробити, оскільки рядки насправді незмінні в JavaScript.)
Тепер, до функцій та передачі параметрів .... Коли ви викликаєте функцію та передаєте параметр, то, що ви по суті робите, це "присвоєння" новій змінній, і вона працює точно так само, як якщо б ви просто призначили за допомогою знак рівності (=)
Візьміть ці приклади.
var myString = 'hello';
// Assign to a new variable (just like when you pass to a function)
var param1 = myString;
param1 = 'world'; // Re assignment
console.log(myString); // Logs 'hello'
console.log(param1); // Logs 'world'
Тепер те саме, але з функцією
function myFunc(param1) {
param1 = 'world';
console.log(param1); // Logs 'world'
}
var myString = 'hello';
// Calls myFunc and assigns param1 to myString just like param1 = myString
myFunc(myString);
console.log(myString); // logs 'hello'
Добре, тепер давайте кілька прикладів, використовуючи замість них об'єкти ... по-перше, без функції.
var myObject = {
firstName: 'Joe',
lastName: 'Smith'
};
// Assign to a new variable (just like when you pass to a function)
var otherObj = myObject;
// Let's mutate our object
otherObj.firstName = 'Sue'; // I guess Joe decided to be a girl
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Sue'
// Now, let's reassign the variable
otherObj = {
firstName: 'Jack',
lastName: 'Frost'
};
// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object has no influence on the other
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Jack';
Тепер те саме, але з викликом функції
function myFunc(otherObj) {
// Let's mutate our object
otherObj.firstName = 'Sue';
console.log(otherObj.firstName); // Logs 'Sue'
// Now let's re-assign
otherObj = {
firstName: 'Jack',
lastName: 'Frost'
};
console.log(otherObj.firstName); // Logs 'Jack'
// Again, otherObj and myObject are assigned to 2 very different objects
// And mutating one object doesn't magically mutate the other
}
var myObject = {
firstName: 'Joe',
lastName: 'Smith'
};
// Calls myFunc and assigns otherObj to myObject just like otherObj = myObject
myFunc(myObject);
console.log(myObject.firstName); // Logs 'Sue', just like before
Гаразд, якщо ви читаєте весь цей пост, можливо, тепер ви краще розумієте, як функціонують дзвінки в JavaScript. Не має значення, передається щось за посиланням чи за значенням ... Важливим є присвоєння проти мутації.
Кожен раз, коли ви передаєте змінну функції, ви "присвоюєте" будь-яку назву змінної параметра, як і якщо ви використовували знак рівності (=).
Завжди пам’ятайте, що знак рівності (=) означає присвоєння. Завжди пам’ятайте, що передача параметра до функції в JavaScript також означає призначення. Вони однакові, і дві змінні з'єднані абсолютно однаково (що означає, що вони не є, якщо не порахувати, що вони призначені одному і тому ж об'єкту).
Єдиний раз, коли "модифікація змінної" впливає на іншу змінну - це коли мутація основного об'єкта (у цьому випадку ви змінили не змінну, а сам об'єкт.
Немає сенсу проводити розмежування між об'єктами та примітивами, оскільки це працює так само, як якщо б у вас не було функції, а просто використовується знак рівності для присвоєння новій змінній.
Єдиний gotcha - це те, коли ім'я змінної, яку ви передаєте у функцію, є такою ж, як і ім'я параметра функції. Коли це відбувається, ви повинні ставитися до параметра всередині функції так, ніби це абсолютно нова змінна, приватна для функції (тому що вона є)
function myFunc(myString) {
// myString is private and does not affect the outer variable
myString = 'hello';
}
var myString = 'test';
myString = myString; // Does nothing, myString is still 'test';
myFunc(myString);
console.log(myString); // Logs 'test'