Далее на странице...
Передача данных по ссылке и по значению. Что это такое?
На эту тему стоит обратить особое внимание, ее нужно понять.
Также здесь представлен пример функции для клонирования объекта. Как в JavaScript копировать объект? Читайте далее.
Логика или Алогика
Рассмотрим 2 примера. Сначала в обоих случаях пробуем рассуждать логически.
Пример 1.1
let a = 5,
b = a;
b = b + 5;
console.log(b);
console.log(a);
Результат
10
5
1. Создается переменная a = 5.
2. Переменной b присваивается переменная a.
3. Меняем значение переменной b.
4. Значение переменной a остается прежним.
В примере 1.1 код работает правильно. Противоречий нет.
Пример 1.2
const obj = {
a: 5,
b: 1
};
const copy = obj;
copy.a = 10;
console.log(copy);
console.log(obj);
Результат
{ a: 10, b: 1 }
{ a: 10, b: 1 }
1. Создается объект obj. У него два свойства a и b.
2. Создается переменная, в которую заносится объект obj. copy = obj.
По логике copy - это копия объекта obj.
3. Меняем значение свойства a объекта copy.
4. При этом меняется и значение свойства a объекта obj.
В примере 1.2 код работает правильно. Но с точки зрения логики - есть несоответствие. Почему так происходит? Почему код во 2-м примере работает на первый взгляд Алогично.
Простые типы данных - Передача по значению
Простые типы данных: строки, числа, булевы значение - передаются по значению.
То есть в примере 1.1 выражение b = a означает, что переменная b - это копия переменной a.
Поэтому при изменении значения переменной b, значение исходной переменной a - остается прежним.
Объекты - Передача по ссылке
Объекты (смотрим здесь - что к ним относится) - передаются по ссылке.
То есть в примере 1.2 выражение const copy = obj означает, что в переменную copy передается НЕ копия объекта obj, а ссылка на объект (через переменную copy, мы ссылаемся на объект obj).
То есть запись copy.a = 10 означает, что через copy (через ссылку на объект obj) происходит изменение значения свойства a объекта obj.
Так работает JavaScript.
Клонирование объекта
Итак, мы выяснили, что если переменной присвоить объект, то в переменную передается ссылка на объект, но не сам объект.
Но как сделать копию объекта?
В примере 3.1 представлена функция для клонирования объекта.
Пример 3.1
function copy(mainObj) {
let objCopy = {};
let key;
for (key in mainObj){
objCopy[key] = mainObj[key];
}
return objCopy;
}
// Объект для клонирования
const numbers = {
a: 3,
b: 5,
c: 8
};
//Клонирование объекта numbers в переменную newNumbers
const newNumbers = copy(numbers);
// Меняется значение одного из свойства объекта newNumbers
newNumbers.a = 10;
console.log(newNumbers);
console.log(numbers);
Результат
{ a: 10, b: 5, c: 8 }
{ a: 3, b: 5, c: 8 }
1. Функция для клонирования объекта имеет один аргумент mainObj. Таким образом в нее передается объект для клонирования.
2. Внутри функции создается новый (пустой) объект objCopy - в него будут копироваться свойства передаваемого в функцию объекта.
3. Затем при помощи конструкции for-in перебираются все свойства объекта mainObj. При этом они сразу же заносятся (копируются) в новый объект objCopy.
Функция возвращает копию объекта return objCopy.
4. Далее создается тестовый объект для клонирования numbers.
И происходит клонирование: newNumbers = copy(numbers). При этом в функцию copy передается объект numbers.
5. Делаем проверку (нужно убедиться, что не повторится ситуация из примера 1.2): меняем значение свойства a нового объекта newNumbers.
6. В результате видно: значение свойства a исходного объекта numbers осталось неизменным. Значит функция для клонирования объекта работает. И newNumbers - это именно копия объекта numbers.
Поверхностное клонирование - Вложенные объекты
Вернемся к примеру 3.1 и рассмотрим ситуацию, когда одно из свойств объекта для клонирования также является объектом (или массивом).
Что произойдет при клонировании вложенного объекта?
Пример 4.1
function copy(mainObj) {
let objCopy = {};
let key;
for (key in mainObj){
objCopy[key] = mainObj[key];
}
return objCopy;
}
// Объект для клонирования
const numbers = {
a: 3,
b: 5,
c: {
x: 2,
y: 8
}
};
//Клонирование объекта numbers в переменную newNumbers
const newNumbers = copy(numbers);
// Изменение родительского свойства нового (клонированного) объекта
newNumbers.a = 10;
// Изменение вложенного свойства нового (клонированного) объекта
newNumbers.c.x = 13;
console.log(newNumbers);
console.log(numbers);
Результат
{ a: 10, b: 5, c: { x: 13, y: 8 } }
{ a: 3, b: 5, c: { x: 13, y: 8 } }
Как видно из примера: при клонировании вложенного объекта происходит передача данных по ссылке. Что это значит?
В примере 4.1 происходит поверхностное клонирование.
1. При изменении родительских свойств клонированного объекта newNumbers.a = 10, значения свойств исходного объекта остаются прежними.
2. Если же одно из свойств исходного объекта тоже является объектом (массивом), то есть при клонировании вложенной структуры (вложенного объекта, массива) - эта структура имеет ссылочный тип данных.
Из примера видно, что при изменении вложенных свойств клонированного объекта newNumbers.c.x = 13, значения вложенных свойств исходного объекта также изменяются.
Поэтому такое клонирование называется поверхностным.
Глубокого клонирования в рассмотренном примере (клонирования вложенных объектов) НЕ происходит. Вложенные свойства клонированного объекта ссылаются на вложенные свойства исходного объекта.
Глубокое клонирование объекта, когда происходит копирование вложенных структур (вложенных объектов) будет рассматриваться позднее.