Главная » Передача данных по ссылке или по значению. Spread оператор (ES6 - ES9)

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


15.03.2021, 22:36
Передача данных по ссылке или по значению

Пример передачи данных по значению:

Код

let a = 5,
b = a; /* => 5 */

b = b + 5;
console.log(b); // => 10

Значение переменной a при этом осталось неизменным (5). Так происходит при работе с примитивными типами данных.

Пробуем сделать копию объекта:

Код

const obj = {
  a: 3,
  b: 5
};

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

copy.a = 5;

console.log(copy); /* => { a: 5, b: 5 } */
console.log(obj); // => { a: 5, b: 5 }

Копии не получилось, поскольку попытка изменить значение свойства а "копии" приводит к изменению и в объекте obj.

Отсюда делаем вывод, что в переменную copy мы сохранили не структуру объекта, а лишь ссылку на объект, лежащий в переменной obj.

При работе с объектами, массивами, функциями передача значений идёт не по значению, а по ссылке.

Создание копий объектов

Пример создания поверхностной копии объекта с помощью цикла:

Код

function copy(mainObj) {
  let objCopy = {

  }; // => сюда будем сохранять копию объекта, переданного в параметр mainObj
}

Далее с помощью цикла for/in проходим по объекту mainObj, переданному в параметр функции copy и копируем его свойства добавлением их в наш объект objCopy.

Код

function copy(mainObj) {
  let objCopy = {

  }; /* => сюда будем сохранять копию объекта, переданного в параметр mainObj */

  let key;

  for (key in mainObj) {
  objCopy[key] = mainObj[key];
  }

  return objCopy; // => выводим содержимое копии наружу
}

Создаём объект, копию которого будем делать:

Код

function copy(mainObj) {
  let objCopy = {

  }; /* => сюда будем сохранять копию объекта, переданного в параметр mainObj */

  let key;

  for (key in mainObj) {
  objCopy[key] = mainObj[key];
  }

  return objCopy; /* => выводим содержимое копии наружу */
}

const numbers = {
  a: 2,
  b: 5,
  c: {
  x: 7,
  y: 4
  }
}; /* => объект, копию которого делаем */

Создаём переменную newNumbers, в неё сохранится результат вызова функции copy, которой в качестве аргумента передаём массив numbers:

Код

function copy(mainObj) {
  let objCopy = {

  }; /* => сюда будем сохранять копию объекта, переданного в параметр mainObj */

  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, оно будет полностью идентичным содержимому объекта numbers:


[Running] node "c:\Users\psstu\Desktop\project\js\tempCodeRunnerFile.js"
{ a: 2, b: 5, c: { x: 7, y: 4 } }
{ a: 2, b: 5, c: { x: 7, y: 4 } }

[Done] exited with code=0 in 0.078 seconds

Изменяем значение свойства b в объекте-копии:

Код

newNumbers.b = 10;

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

И в консоли видим, что в объекте-копии оно изменилось, а в объекте numbers нет:


[Running] node "c:\Users\psstu\Desktop\project\js\tempCodeRunnerFile.js"
{ a: 2, b: 10, c: { x: 7, y: 4 } }
{ a: 2, b: 5, c: { x: 7, y: 4 } }

[Done] exited with code=0 in 0.076 seconds

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

Код

newNumbers.c.x = 10;

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


[Running] node "c:\Users\psstu\Desktop\project\js\tempCodeRunnerFile.js"
{ a: 2, b: 5, c: { x: 10, y: 4 } }
{ a: 2, b: 5, c: { x: 10, y: 4 } }

[Done] exited with code=0 in 0.067 seconds

Метод Object.assign()

Данный метод позволяет скопировать значения всех собственных свойств объекта (или нескольких объектов) в конечный возвращаемый объект.

К примеру, есть два независимых объекта:

Код

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

const add = {
  d: 15,
  e: 12
};

Наша задача поместить свойства объекта add в объект numbers, для этого вызываем метод Object.assign(), где первый параметр будет тот объект, в который копируют, а вторым - из которого копируют:

Код

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

const add = {
  d: 15,
  e: 12
};

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

В консоли получаем результат:


{ a: 2, b: 5, c: { x: 7, y: 4 }, d: 15, e: 12 }

Сейчас мы создали поверхностную копию объектов, которая не зависит от numbers и add.

Этот приём мы можем использовать с пустым объектом и также создать копию нужного нам объекта:

Код

const add = {
  d: 15,
  e: 12
};

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

console.log(clone); // => { d: 15, e: 12 }

Изменим значение свойства d в объекте-копии clone:

Код

const add = {
  d: 15,
  e: 12
};

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

clone.d = 20;

console.log(clone); /* => { d: 20, e: 12 } */
console.log(add); // => { d: 15, e: 12 }

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

Создать поверхностную копию массива можно с помощью метода slice()

Код

const array = [1, 3, 5, 7];

const copyArray = array.slice();

copyArray[0] = 2;

console.log(copyArray); /* => [ 2, 3, 5, 7 ] */
console.log(array); // => [ 1, 3, 5, 7 ]

Метод slice() возвращает срез заданного массива (подмассив). Для метода можно задавать в качестве аргументов начало и конец среза, подлежащего возвращению.

Элемент, указанный первым аргументом, входит в возвращаемый срез, а указанный вторым - нет:

Код

let arr = [1, 3, 5, 7, 9];

console.log(arr.slice(0, 3)); // => [ 1, 3, 5 ]

Если указан один аргумент - возвращаются все элементы, начиная с элемента, указанного в аргументе и до конца исходного массива.

Код

let arr = [1, 3, 5, 7, 9];

console.log(arr.slice(3)); // => [ 7, 9 ]

Метод slice() не изменяет исходного массива.

Оператор разворота (Spread оператор)

Появился в ES6 для массивов и в ES8 для объектов. Его также можно использовать для создания поверхностной копии.

Пример: есть два независимых массива данных, необходимо данные этих двух массивов поместить в третий, в данный момент пустой:

Код

const arr1 = [1, 3, 5];
const arr2 = [6, 8, 10];
const arrSumm = [];

С помощью оператора разворота сделать это довольно просто:

Код

const arr1 = [1, 3, 5];
const arr2 = [6, 8, 10];
const arrSumm =[...arr1, ...arr2];

console.log(arrSumm); // => [ 1, 3, 5, 6, 8, 10 ]

Пример с функцией.
Есть функция с тремя параметрами:

Код

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

И есть массив данных, пришедший, к примеру, с сервера:

Код

const arr = [3, 5, 7];

Как передать данные из массива в виде аргументов для функции?

Мы просто вызываем функцию, передавая в качестве аргумента Spread оператор для массива:

Код

function dataTransfer(a, b, c) {
  console.log(a); /* => 3 */
  console.log(b); /* => 5 */
  console.log(c); /* => 7 */
}

const arr = [3, 5, 7];

dataTransfer(...arr);

Создать поверностную копию массива с помощью Spread оператора очень просто:

Код

const arr = [3, 5, 7];

const copy = [...arr];  

copy[0] = 1;

console.log(arr); /* => [ 3, 5, 7 ] */
console.log(copy); // => [ 1, 5, 7 ]

По аналогии создаётся поверхностная копия объекта:

Код

const obj = {
  a: 5,
  b: 8,
  c: {
  d: 3,
  e: 9
  }
};

const objNew = {...obj}; /* Создаём копию объекта obj */

delete objNew.c; /* Удалим свойство из копии, чтобы убедиться, что оригинал не изменится */

console.log(objNew);
console.log(obj);

Смотрим результат в консоли:


[Running] node "c:\Users\psstu\Desktop\project\js\tempCodeRunnerFile.js"
{ a: 5, b: 8 }
{ a: 5, b: 8, c: { d: 3, e: 9 } }

[Done] exited with code=0 in 0.067 seconds

КОММЕНТАРИИ (0)