Мои два цента ... Я так понимаю. (Не стесняйтесь поправлять меня, если я ошибаюсь)
Пришло время выбросить все, что вы знаете о передаче по значению / ссылке.
Потому что в JavaScript не имеет значения, передается ли он по значению, по ссылке или как угодно. Важна мутация против присвоения параметров, переданных в функцию.
Хорошо, позвольте мне сделать все возможное, чтобы объяснить, что я имею в виду. Допустим, у вас есть несколько объектов.
var object1 = {};
var object2 = {};
Что мы сделали, так это «присваивание» ... Мы присвоили 2 отдельных пустых объекта переменным «object1» и «object2».
Теперь предположим, что нам нравится object1 лучше ... Итак, мы «назначаем» новую переменную.
var favoriteObject = object1;
Затем, по какой-либо причине, мы решаем, что нам нравится объект 2 лучше. Итак, мы просто делаем небольшое переназначение.
favoriteObject = object2;
Ничего не случилось с object1 или object2. Мы не изменили никаких данных вообще. Все, что мы сделали, это переназначили наш любимый объект. Важно знать, что object2 и FavoritesObject назначены одному и тому же объекту. Мы можем изменить этот объект с помощью любой из этих переменных.
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;
Обе переменные favouriteString и string1 присвоены «Hello world». А что если мы захотим изменить нашу любимую строку ??? Что случится???
favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'
Э-э-э ... Что случилось? Мы не могли изменить string1, изменив favourString ... Почему ?? Потому что мы не изменили наш строковый объект . Все, что мы сделали, это «RE ASSIGN» переменную favourString для новой строки. Это по существу отключило его от string1. В предыдущем примере, когда мы переименовали наш объект, мы ничего не назначали. (Ну, не для самой переменной , но мы присвоили свойство name новой строке.) Вместо этого мы просто мутировали объект, который поддерживает связи между двумя переменными и базовыми объектами. (Даже если бы мы хотели изменить или мутировать строку объект сам, мы не могли бы, потому что строки на самом деле неизменяемы в 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 также означает присваивание. Они одинаковы, и эти две переменные связаны одинаково (то есть они не связаны, если только вы не считаете, что они назначены одному и тому же объекту).
Единственный раз, когда «изменение переменной» влияет на другую переменную, - это когда мутирует базовый объект (в этом случае вы изменяете не переменную, а сам объект).
Нет никакого смысла проводить различие между объектами и примитивами, потому что это работает точно так же, как если бы у вас не было функции, а просто использовали знак равенства для присвоения новой переменной.
Единственная ошибка, когда имя переменной, которую вы передаете в функцию, совпадает с именем параметра функции. Когда это происходит, вы должны обрабатывать параметр внутри функции, как если бы это была целая новая переменная, приватная для функции (потому что это так)
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'