Moje dwa centy ... Tak to rozumiem. (Możesz mnie poprawić, jeśli się mylę)
Czas wyrzucić wszystko, co wiesz o przekazywaniu według wartości / referencji.
Ponieważ w JavaScript nie ma znaczenia, czy jest przekazywany przez wartość, przez referencję czy cokolwiek innego. Liczy się mutacja vs. przypisanie parametrów przekazanych do funkcji.
OK, pozwól, że zrobię co w mojej mocy, aby wyjaśnić, co mam na myśli. Powiedzmy, że masz kilka obiektów.
var object1 = {};
var object2 = {};
To, co zrobiliśmy, to „przypisanie” ... Przypisaliśmy 2 oddzielne puste obiekty do zmiennych „object1” i „object2”.
Powiedzmy, że bardziej lubimy obiekt1 ... Więc „przypisujemy” nową zmienną.
var favoriteObject = object1;
Następnie, z jakiegokolwiek powodu, decydujemy, że obiekt 2 bardziej nam się podoba. Więc po prostu wykonujemy małe przeniesienie.
favoriteObject = object2;
Nic się nie stało z obiektem1 lub obiektem2. Nie zmieniliśmy żadnych danych. Wszystko, co zrobiliśmy, to ponowne przypisanie tego, co jest naszym ulubionym przedmiotem. Ważne jest, aby wiedzieć, że zarówno obiekt2, jak i ulubiony obiekt są przypisane do tego samego obiektu. Możemy zmienić ten obiekt za pomocą jednej z tych zmiennych.
object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe
OK, teraz spójrzmy na prymitywy takie jak na przykład łańcuchy
var string1 = 'Hello world';
var string2 = 'Goodbye world';
Ponownie wybieramy ulubionego.
var favoriteString = string1;
Zarówno nasze ulubione zmienne ciąg, jak i łańcuch1 są przypisane do „Hello world”. A co jeśli chcemy zmienić nasz ulubiony ciąg ??? Co się stanie???
favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'
Uh oh .... Co się stało. Nie mogliśmy zmienić string1, zmieniając ulubiony ciąg ... Dlaczego? Ponieważ nie zmieniliśmy naszego obiektu ciągu . Wszystko, co zrobiliśmy, to „RE ASSIGN” zmienna favoriteString do nowego ciągu. To zasadniczo odłączyło go od string1. W poprzednim przykładzie, kiedy zmieniliśmy nazwę naszego obiektu, nie przypisaliśmy niczego. (Cóż, nie do samej zmiennej ... jednak przypisaliśmy właściwość name do nowego ciągu.) Zamiast tego po prostu zmutowaliśmy obiekt, który utrzymuje połączenia między 2 zmiennymi a obiektami leżącymi u ich podstaw. (Nawet jeśli chcieliśmy zmodyfikować lub zmutować sam obiekt łańcuchowy, nie mogliśmy tego zrobić, ponieważ w JavaScript są ciągi niezmienne.)
Teraz do funkcji i przekazywania parametrów .... Kiedy wywołujesz funkcję i przekazujesz parametr, to, co zasadniczo robisz, to „przypisanie” do nowej zmiennej, i działa dokładnie tak samo, jakbyś po prostu przypisał za pomocą znak równości (=).
Weź te przykłady.
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'
Teraz to samo, ale z funkcją
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'
OK, teraz podajmy kilka przykładów z użyciem obiektów zamiast ... najpierw, bez funkcji.
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';
Teraz to samo, ale z wywołaniem funkcji
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
OK, jeśli przeczytasz cały ten post, być może lepiej rozumiesz, jak wywołania funkcji działają w JavaScript. Nie ma znaczenia, czy coś jest przekazywane przez odniesienie, czy przez wartość ... Liczy się przypisanie vs mutacja.
Za każdym razem, gdy przekazujesz zmienną do funkcji, „przypisujesz” do dowolnej nazwy zmiennej parametru, tak jak w przypadku użycia znaku równości (=).
Zawsze pamiętaj, że znak równości (=) oznacza przypisanie. Zawsze pamiętaj, że przekazanie parametru do funkcji w JavaScript oznacza również przypisanie. Są takie same, a dwie zmienne są połączone dokładnie w ten sam sposób (to znaczy tak nie jest, chyba że policzysz, że są przypisane do tego samego obiektu).
Jedyny moment, w którym „modyfikowanie zmiennej” wpływa na inną zmienną, następuje po zmutowaniu obiektu leżącego u podstaw (w którym to przypadku nie zmodyfikowano zmiennej, ale sam obiekt.
Nie ma sensu wprowadzać rozróżnienia między obiektami a prymitywami, ponieważ działa on tak samo dokładnie, jakbyś nie miał funkcji, a jedynie użył znaku równości do przypisania nowej zmiennej.
Jedynym gotcha jest to, że nazwa zmiennej, którą przekazujesz do funkcji, jest taka sama jak nazwa parametru funkcji. Kiedy tak się dzieje, musisz traktować parametr wewnątrz funkcji tak, jakby była to zupełnie nowa zmienna prywatna dla funkcji (ponieważ tak jest)
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'