hellojs.ru
Главная - Основы JavaScript - Передача по ссылке или по значению, Spread оператор (ES6-ES9)

Передача по ссылке или по значению, Spread оператор (ES6-ES9)

Размещено в категории "Основы JavaScript"
27.09.2024 / просмотров: 39 / комментариев: 0
Ресурсы:

Статья про клонирование
Object.assign()
Spread оператор




Ожидаемое поведение:
Код

let a = 5,
b = a;

b = b + 5;

console.log(b); // 10
console.log(a); // 5

Теперь рассмотрим на примере с объектами, создадим какой-нибудь объект obj и переменную copy, в которую положим значение объекта obj
Код

const obj = {
  a: 5,
  b: 1
}

const copy = obj;  

Изменяем значение свойства a в объекте copy и выведем в консоль содержимое обоих объектов:
Код

const obj = {
  a: 5,
  b: 1
}

const copy = obj; // здесь передаётся ссылка на объект obj

copy.a = 10;

console.log(obj); // { a: 10, b: 1 }
console.log(copy); // { a: 10, b: 1 }

Как видно, значение свойства a поменялось также и в объекте obj. Происходит это потому, что в данном случае идёт передача по ссылке, то есть в переменной copy мы сохранили не копию значения объекта obj, а ссылку на этот объект, именно поэтому, внося изменения в объект copy, мы вносим также изменения в объект obj

Как же создаются копии объектов, массивов и прочего?

Использование цикла для создания копии



Напишем функцию, которая будет как аргумент принимать наш объект и создавать новый objCopy, перебирая свойства первоначального объекта
Код

function copy(mainObj) {
  let objCopy = {};

  let key; // вариант объявления переменной вне цикла
  for (key in mainObj) {
  objCopy[key] = mainObj[key];
  }

  return objCopy;
}  

Теперь добавим какой-нибудь объект, который будем передавать в нашу функцию в качестве аргумента
Код

const numbers = {
  a: 2,
  b: 5,
  c: {
  x: 7,
  y: 4
  }
};

Теперь создадим переменную и в неё сохраним наш новый объект, копию объекта, переданного в функцию
Код

const newNumbers = copy(numbers);

Пробуем теперь изменить значение какого-то свойства в новом объекте, копии первоначального, и затем выведем оба объекта в консоль
Код

function copy(mainObj) {
  let objCopy = {};

  let key; // вариант объявления переменной вне цикла
  for (key in mainObj) {
  objCopy[key] = mainObj[key];
  }

  return objCopy;
}

const numbers = {
  a: 2,
  b: 5,
  c: {
  x: 7,
  y: 4
  }
};

const newNumbers = copy(numbers);

newNumbers.a = 10;

console.log(numbers);
console.log(newNumbers);

Цитата

{ a: 2, b: 5, c: { x: 7, y: 4 } } // значение a не изменилось
{ a: 10, b: 5, c: { x: 7, y: 4 } } // значение a изменилось

Но,если поменять значение свойства c в копии объекта
Код

newNumbers.c.x = 10;

То оно поменяется и в первоначальном объекте
Цитата

{ a: 2, b: 5, c: { x: 10, y: 4 } }
{ a: 2, b: 5, c: { x: 10, y: 4 } }

Всё дело в том, что есть глубокие и поверхностные копии объектов, и в данном случае мы сделали поверхностную копию объекта.

В ней на первом уровне вложенности копия отрабатывает нормально, но на втором уровне вложенности в объекте опять работает ссылочный тип данных.

Создание копии объекта с помощью метода Object.assign()



Метод Object.assign() используется для копирования значений всех собственных перечисляемых свойств из одного или более исходных объектов в целевой объект. После копирования он возвращает целевой объект.

Синтаксис метода:
Код

Object.assign(target, ...sources)

target - это объект, в который мы хотим поместить значения свойств нужных объектов

sources - необходимые объекты
Код

const numbers = {
  a: 2,
  b: 5,
  c: {
  x: 7,
  y: 4
  }
};

const add = {
  d: 17,
  e: 20
};

console.log(Object.assign(numbers, add));

Цитата

{ a: 2, b: 5, c: { x: 7, y: 4 }, d: 17, e: 20 }

И в данном случае мы опять получили независимую поверхностную копию объекта. Тоже самое можно проделать и с пустым объектом, чтобы просто создать копию нужного объекта.
Код

const add = {
  d: 17,
  e: 20
};

const clone = Object.assign({}, add);

clone.d = 20;

console.log(add);
console.log(clone);  

Цитата

{ d: 17, e: 20 } { d: 20, e: 20 }


Создание копии массива



Если написать так, то в newArray мы получим ссылку на первоначальный массив, а не копию
Код

const oldArray = ['a', 'b', 'c'];

const newArray = oldArray;

Вместо этого воспользуемся методом slice(), чтобы получить поверхностную копию массива
Код

const newArray = oldArray.slice();
console.log(newArray); // ['a', 'b', 'c']

Метод slice() возвращает новый массив, содержащий копию части исходного массива.

Синтаксис метода:
Код

arr.slice([begin[, end]])

begin - необязательный параметр

Индекс (счёт начинается с нуля), по которому начинать извлечение.

Если индекс отрицательный, begin указывает смещение от конца последовательности. Вызов slice(-2) извлечёт два последних элемента последовательности.

Если begin не определён, slice() начинает работать с индекса 0.

Если begin больше длины последовательности, вернётся пустой массив.

end - необязательный параметр

Индекс (счёт начинается с нуля), по которому заканчивать извлечение. Метод slice() извлекает элементы с индексом меньше end.

Вызов slice(1, 4) извлечёт элементы со второго по четвёртый (элементы по индексам 1, 2 и 3).

Если индекс отрицательный, end указывает смещение от конца последовательности. Вызов slice(2, -1) извлечёт из последовательности элементы начиная с третьего элемента с начала и заканчивая вторым с конца.

Если end опущен, slice() извлекает все элементы до конца последовательности (arr.length).
Код

const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

console.log(animals.slice(2));
// Expected output: Array ["camel", "duck", "elephant"]

console.log(animals.slice(2, 4));
// Expected output: Array ["camel", "duck"]

console.log(animals.slice(1, 5));
// Expected output: Array ["bison", "camel", "duck", "elephant"]

console.log(animals.slice(-2));
// Expected output: Array ["duck", "elephant"]

console.log(animals.slice(2, -1));
// Expected output: Array ["camel", "duck"]

console.log(animals.slice());
// Expected output: Array ["ant", "bison", "camel", "duck", "elephant"]


Spread оператор



Код

const video = ['youtube', 'vimeo', 'rutube'];
const blogs = ['wordpress', 'livejournal', 'blogger'];
const internet = [];

Задача перенести данные из первых двух массивов в третий.

Используем для этого spread оператор (...), который разворачивает структуру массивов на отдельные значения.
Код

const video = ['youtube', 'vimeo', 'rutube'];
const blogs = ['wordpress', 'livejournal', 'blogger'];
const internet = [...video, ...blogs, 'vk', 'facebook'];

console.log(internet);

Цитата

[
'youtube',
'vimeo',
'rutube',
'wordpress',
'livejournal',
'blogger',
'vk',
'facebook'
]

Пример посложнее:
Код

function log(a, b, c) {
  console.log(a);
  console.log(b);
  console.log(c);
}

const num = [2, 5, 7];

log(...num);

Так как при вызове функции spread оператор развернет массив на отдельные составляющие, то они попадут как аргументы в переменные a, b, c
Цитата

2
5
7

Похожим образом мы можем создать поверхностную копию массива или объекта
Код

const arr = ['a', 'b', 'c'];
const newArr = [...arr];

const obj = {
  one: 1,
  two: 2
};

const newObj = { ...obj };
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
Сайт управляется системой uCoz