DevGang
Авторизоваться

structuredClone(): Новая эра копирования объектов в JavaScript

Прежде чем погрузиться в детали этой функции, важно понять фундаментальные концепции, лежащие в основе манипулирования объектами в JavaScript. В этой статье мы рассмотрим:

  1. Изменчивость объектов: как и почему объекты могут быть изменены после их создания.
  2. Передачу по ссылке: последствия работы со ссылками, а не со значениями.
  3. Разницу между поверхностным и глубоким копированием.
  4. Традиционные техники копирования объектов и их ограничения.

Эти понятия необходимы для того, чтобы в полной мере оценить мощь и полезность structuredClone(). Эта функция, недавно появившаяся в языке, предлагает элегантное решение многих проблем, которые долгое время не давали покоя разработчикам JavaScript.

Независимо от того, являетесь ли вы начинающим разработчиком, желающим закрепить свои основы, или опытным программистом, стремящимся оптимизировать свою практику, эта статья предоставит вам ценные сведения об управлении объектами в JavaScript. Давайте отправимся в путешествие к сердцу копирования объектов, а конечным пунктом назначения станет функция structuredClone()!

Изменчивость объектов

Определение: Изменчивый объект – это объект, состояние которого может быть изменено после его создания.

В отличие от примитивных типов (таких как числа или строки), объекты можно изменять без создания нового экземпляра.

let obj = { a: 1 };
obj.a = 2; // L'objet est modifié
console.log(obj); // { a: 2 

Последствия изменчивости

  1. Побочные эффекты: изменчивость может привести к неожиданным побочным эффектам, особенно когда объекты совместно используются в разных частях программы.
  2. Сложная отладка: ошибки, связанные с изменчивостью, бывает трудно отследить, поскольку состояние объекта может меняться в нескольких местах кода.
  3. Производительность: Изменчивость часто позволяет ускорить выполнение операций, поскольку не нужно создавать новые объекты для каждой модификации.

Передача по ссылке

Когда объект присваивается переменной или передается в качестве аргумента функции, передается именно ссылка на объект, а не копия его значений. Это означает, что если вы измените этот объект в подфункции, то он будет изменен и во всех остальных.

let obj1 = { x: 10 };
let obj2 = obj1; // obj2 référence le même objet que obj1

obj2.x = 20;
console.log(obj1.x); // 20 - obj1 est également modifié

Поверхностное и глубокое копирование

Чтобы избежать случайного изменения оригинального объекта, можно создавать его копии. Существует два типа копий:

  1. Поверхностное копирование: создается новый объект с теми же свойствами верхнего уровня, что и у оригинала, но вложенные объекты остаются ссылочными.
  2. Глубокое копирование: создает новый объект путем рекурсивного копирования всех свойств, включая вложенные объекты.

Техники копирования объектов

Поверхностное копирование с помощью Object.assign():

let original = { a: 1, b: { c: 2 } };
let copie = Object.assign({}, original);

copie.a = 3;
copie.b.c = 4;

console.log(original); // { a: 1, b: { c: 4 } }
console.log(copie);    // { a: 3, b: { c: 4 } }

Поверхностное копирование с помощью оператора расширения:

Copylet original = { a: 1, b: { c: 2 } };
let copie = { ...original };

// Même résultat qu'avec Object.assign()

Array.slice() для массивов:

let tableauOriginal = [1, 2, [3, 4]];
let copieTablau = tableauOriginal.slice();

Глубокое копирование

Ручная рекурсия:

function deepCopy(obj) {
    if (typeof obj !== 'object' || obj === null) return obj;
    
    let copie = Array.isArray(obj) ? [] : {};
    
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            copie[key] = deepCopy(obj[key]);
        }
    }
    
    return copie;
}

С JSON.parse(JSON.stringify())

Этот метод широко использовался, но у него есть ограничения (потеря методов, неопределенность и т.д.):

let original = { a: 1, b: { c: 2 } };
let copie = JSON.parse(JSON.stringify(original));

copie.b.c = 4;
console.log(original); // { a: 1, b: { c: 2 } }
console.log(copie);    // { a: 1, b: { c: 4 } }

Проблема с JSON.parse(JSON.stringify())

При использовании JSON.parse(JSON.stringify()) для создания глубокой копии объекта, содержащего циклические ссылки, возникает ошибка:

let copie = JSON.parse(JSON.stringify(objA)); 
// Uncaught TypeError: Converting circular structure to JSON

Ограничения JSON.parse(JSON.stringify())

Помимо круговых ссылок, JSON.parse(JSON.stringify()) имеет ряд ограничений:

  • Потеря типов данных, характерных для JavaScript:
  1. undefined преобразуется в null или просто опускается
  2. NaN, Infinity и -Infinity преобразуются в null
  3. Даты преобразуются в строки
  4. Map, Set, WeakMap и WeakSet преобразуются в пустые объекты {}
let obj = {
  a: undefined,
  b: NaN,
  c: new Date(),
  d: new Map([['key', 'value']])
};
let copie = JSON.parse(JSON.stringify(obj));
console.log(copie);
// { b: null, c: "2024-07-29T12:34:56.789Z" }
// 'a' est omis, 'd' est un objet vide {}
  • Потеря методов и прототипов:

Функции и методы полностью игнорируются.

class MaClasse {
  constructor(valeur) {
    this.valeur = valeur;
  }
  maMethode() {
    console.log(this.valeur);
  }
}
let instance = new MaClasse(42);
let copie = JSON.parse(JSON.stringify(instance));
console.log(copie); // { valeur: 42 }
// copie.maMethode() // Erreur : maMethode n'est pas une fonction
  • Игнорируемые символы:

Свойства, определенные с помощью символов, игнорируются.

let sym = Symbol('monSymbole');
let obj = { [sym]: "valeur symbolique" };
let copie = JSON.parse(JSON.stringify(obj));
console.log(copie); // {}

Производительность: для больших объектов сериализация в цепочке JSON с последующей десериализацией может быть дорогостоящей с точки зрения производительности.

Современный метод: structuredClone()

Этот метод, представленный недавно, обеспечивает более надежное и высокопроизводительное глубокое копирование.

let original = { a: 1, b: { c: 2 } };
let copie = structuredClone(original);

copie.b.c = 4;
console.log(original); // { a: 1, b: { c: 2 } }
console.log(copie);    // { a: 1, b: { c: 4 } }

structuredClone() корректно обрабатывает циклические ссылки и поддерживает более широкий спектр типов данных, чем JSON.parse(JSON.stringify()).

Решение с помощью structuredClone()

structuredClone() корректно обрабатывает циклические ссылки:

let copie = structuredClone(objA);
console.log(copie.ref.ref === copie); // true

Заключение

Понимание изменчивости объектов и различных методов копирования очень важно для предотвращения тонких ошибок в ваших JavaScript-приложениях. Метод structuredClone() представляет собой значительное достижение для надежного и эффективного создания глубоких копий.

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

Источник доступен по ссылке.

#JavaScript
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу