Поверхневе копіювання

Поверхнева копія об'єкта – це копія, чиї властивості поділяють ті самі посилання (вказують на ті самі значення), що й властивості вихідного об'єкта, котрий було скопійовано. Як наслідок, при зміні як вихідного об'єкта, так і копії, може статися видозміна обох об'єктів. Ця логіка відрізняється від логіки глибокого копіювання, при якому вихідний об'єкт і копія є цілковито незалежними.

Більш формально висловлюючись, два об'єкти o1 і o2 є поверхневими копіями одне одного, якщо:

  1. Вони не одним і тим же об'єктом (o1 !== o2).
  2. Властивості o1 і o2 мають однакові імена в однаковому порядку.
  3. Значення їхніх властивостей – рівні.
  4. Їхні ланцюжки прототипів – рівні.

Дивіться також визначення структурної рівносильності.

Копія об'єкта, в котрого всі властивості мають примітивні значення, відповідає і визначенню глибокої копії, і визначенню поверхневої. Проте дещо безглуздо говорити про глибину такої копії, адже вона не має вкладених властивостей, а про глибоке копіювання зазвичай говорять в контексті внесення змін до таких вкладених властивостей.

При поверхневому копіюванні копіюються лише властивості найвищого рівня, але не значення вкладених об'єктів. Таким чином:

  • Повторне присвоєння властивостей копії найвищого рівня не впливає на вихідний об'єкт.
  • Повторне присвоєння властивостей вкладених у копію об'єктів впливає на вихідний об'єкт.

У JavaScript усі стандартні вбудовані операції копіювання об'єктів (синтаксис розгортання, Array.prototype.concat(), Array.prototype.slice(), Array.from() і Object.assign()) утворюють поверхневі копії, а не глибокі.

Для прикладу – наступний приклад, у якому створюється об'єкт-масив ingredientsList, а потім шляхом копіювання цього об'єкта ingredientsList створюється об'єкт ingredientsListCopy.

const ingredientsList = ["локшина", { list: ["яйця", "борошно", "вода"] }];

const ingredientsListCopy = Array.from(ingredientsList);
console.log(ingredientsListCopy);
// ["локшина",{"list":["яйця","борошно","вода"]}]

Повторне присвоєння значення вкладеної властивості буде помітно на обох об'єктах.

ingredientsListCopy[1].list = ["рисове борошно", "вода"];
console.log(ingredientsList[1].list);
// Array [ "рисове борошно", "вода" ]

Повторне присвоєння значення властивості найвищого рівня (у цьому випадку – індексові 0) буде помітно лише на зміненому об'єкті.

ingredientsListCopy[0] = "рисова локшина";
console.log(ingredientsList[0]);
console.log(JSON.stringify(ingredientsListCopy));
// ["рисова локшина",{"list":["рисове борошно","вода"]}]
console.log(JSON.stringify(ingredientsList));
// ["локшина",{"list":["рисове борошно","вода"]}]

Дивіться також