машинопись - клонирование объекта

188

У меня есть класс супер , который является родительским ( Entity) для многих подкласса ( Customer, Product, ProductCategory...)

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

В примере: у Customerкоторого есть разные, у Productкого естьProductCategory

var cust:Customer  = new Customer ();

cust.name = "someName";
cust.products.push(new Product(someId1));
cust.products.push(new Product(someId2));

Для клонирования всего дерева объекта я создал функцию в Entity

public clone():any {
    var cloneObj = new this.constructor();
    for (var attribut in this) {
        if(typeof this[attribut] === "object"){
           cloneObj[attribut] = this.clone();
        } else {
           cloneObj[attribut] = this[attribut];
        }
    }
    return cloneObj;
}

newПоднимается следующее сообщение об ошибке , когда он transpiled в JavaScript:error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.

Хотя скрипт работает, я хотел бы избавиться от трансплантированной ошибки

Дэвид Лаберже
источник

Ответы:

255

Решение конкретной проблемы

Вы можете использовать утверждение типа, чтобы сообщить компилятору, что вы знаете лучше:

public clone(): any {
    var cloneObj = new (this.constructor() as any);
    for (var attribut in this) {
        if (typeof this[attribut] === "object") {
            cloneObj[attribut] = this[attribut].clone();
        } else {
            cloneObj[attribut] = this[attribut];
        }
    }
    return cloneObj;
}

клонирование

Имейте в виду, что иногда лучше написать собственное отображение, чем быть полностью динамичным. Тем не менее, есть несколько приемов «клонирования», которые вы можете использовать, которые дают вам эффекты разницы.

Я буду использовать следующий код для всех последующих примеров:

class Example {
  constructor(public type: string) {

  }
}

class Customer {
  constructor(public name: string, public example: Example) {

  }

  greet() {
    return 'Hello ' + this.name;
  }
}

var customer = new Customer('David', new Example('DavidType'));

Вариант 1: распространение

Свойства: Да
Методы: Нет
Глубокая копия: Нет

var clone = { ...customer };

alert(clone.name + ' ' + clone.example.type); // David DavidType
//alert(clone.greet()); // Not OK

clone.name = 'Steve';
clone.example.type = 'SteveType';

alert(customer.name + ' ' + customer.example.type); // David SteveType

Вариант 2: Object.assign

Свойства: Да
Методы: Нет
Глубокая копия: Нет

var clone = Object.assign({}, customer);

alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // Not OK, although compiler won't spot it

clone.name = 'Steve';
clone.example.type = 'SteveType';

alert(customer.name + ' ' + customer.example.type); // David SteveType

Вариант 3: Object.create

Свойства: унаследованные
методы: унаследованный
Deep Copy: мелкий унаследованный (глубокие изменения влияют как на оригинал, так и на клон)

var clone = Object.create(customer);

alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // OK

customer.name = 'Misha';
customer.example = new Example("MishaType");

// clone sees changes to original 
alert(clone.name + ' ' + clone.example.type); // Misha MishaType

clone.name = 'Steve';
clone.example.type = 'SteveType';

// original sees changes to clone
alert(customer.name + ' ' + customer.example.type); // Misha SteveType

Вариант 4: функция глубокого копирования

Свойства: Да
Методы: Нет
Глубокая копия: Да

function deepCopy(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = deepCopy(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = deepCopy(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

var clone = deepCopy(customer) as Customer;

alert(clone.name + ' ' + clone.example.type); // David DavidType
// alert(clone.greet()); // Not OK - not really a customer

clone.name = 'Steve';
clone.example.type = 'SteveType';

alert(customer.name + ' ' + customer.example.type); // David DavidType
Фентон
источник
Близко, транспиляция перестала жаловаться с машинописью 1.3, но однажды в javascript она выдаст ошибку Машинопись 1.4.1, не отпустит.
Дэвид Лаберже
1
Не могли бы вы уточнить, как именно вы это используете? Я включил в качестве метода моего объекта, а затем получил ошибку, говоря, что это не функция ...
megalucio
1
Я получаю следующую ошибку: «ОШИБКА TypeError: this.constructor (...) не является конструктором»
michali
3
Вы только что сделали публичный пример из этого клиента?
Блэр Коннолли
1
Может кто - то TL; DR для меня , который , какие из решений , указанных в все ответы сохраняют тип ОО клона, то есть cloned instanceof MyClass === true?
Щепан Холышевский
177

1. Используйте спред оператора

const obj1 = { param: "value" };
const obj2 = { ...obj1 };

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

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

2.Object.assign ()

const obj1={ param: "value" };
const obj2:any = Object.assign({}, obj1);

Object.assign создает реальную копию, но только собственные свойства, поэтому свойства в прототипе не будут существовать в скопированном объекте. Это также мелкая копия.


3.Object.create ()

const obj1={ param: "value" };
const obj2:any = Object.create(obj1);

Object.create не занимается реальным клонированием , а создает объект из прототипа. Поэтому используйте его, если объект должен клонировать свойства основного типа, потому что назначение свойств основного типа не выполняется по ссылке.

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


Несколько вещей о мелкой копии

Мелкая копия помещает в новый объект все поля старого, но это также означает, что если исходный объект имеет поля составного типа (объект, массивы и т. Д.), То эти поля помещаются в новый объект с теми же ссылками. Мутация такого поля в исходном объекте будет отражена в новом объекте.

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


Глубокая копия

Оператор спреда может быть полезен для глубокого копирования.

const obj1 = { param: "value", complex: { name: "John"}}
const obj2 = { ...obj1, complex: {...obj1.complex}};

Выше кода создана глубокая копия obj1. Составное поле «комплекс» также было скопировано в obj2. Мутация поля «сложный» не будет отражать копию.

Мацей Сикора
источник
8
Я не думаю, что это совершенно правильно. Object.create(obj1)создает новый объект и назначает obj1 в качестве прототипа. Ни одно из полей в obj1 не копируется и не клонируется. Таким образом, изменения в obj1 без изменения obj2 будут видны, так как он по существу не имеет свойств. Если вы сначала измените obj2, то прототип не будет виден для поля, которое вы определяете, так как поле obj2 с именем находится ближе в иерархии.
Кен Римпл
3
Вы также увидите, что ES2015 и разработчики машинописи делают это вместо этого, что создает объект из 1-го параметра (в моем случае это пустой) и копирует свойства из второго и последующих параметров): let b = Object.assign({}, a);
Кен Римпл
@KenRimple Вы на 100% правы, я добавил еще немного информации.
Мацей Сикора
может быть полезно => developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Эммануэль Тузери
5
Object.assign создаст проблемы для глубоких объектов. Например, {name: 'x', values: ['a', 'b', 'c']}. После использования Object.assign для клонирования оба объекта совместно используют массив значений, поэтому обновление одного влияет на другой. См .: developer.mozilla.org/en/docs/Web/JavaScript/Reference/… (раздел «Предупреждение для глубокого клона»). В нем говорится: для глубокого клонирования нам нужно использовать другие альтернативы. Это связано с тем, что Object.assign () копирует ссылку на свойство, когда назначаемое свойство является объектом.
Меир
48

Попробуй это:

let copy = (JSON.parse(JSON.stringify(objectToCopy)));

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

Чтобы сохранить безопасность типов, вы можете использовать функцию копирования в классе, из которого вы хотите делать копии:

getCopy(): YourClassName{
    return (JSON.parse(JSON.stringify(this)));
}

или статическим способом:

static createCopy(objectToCopy: YourClassName): YourClassName{
    return (JSON.parse(JSON.stringify(objectToCopy)));
}
Lars
источник
5
Это нормально, но вы должны помнить, что при сериализации / разборе вы потеряете информацию о прототипах и все типы, не поддерживаемые в json.
Станислав Евгеньевич Говоров
1
Также это кажется менее эффективным по сравнению с функцией deepCopy, представленной выше .
Мойтаба
У меня есть эта ошибка: "Преобразование круговой структуры в JSON", когда я использую "(JSON.parse (JSON.stringify (objectToCopy))))"
Седрик
Работает только в 98% случаев. Может привести к отсутствию ключей со undefinedзначением, по крайней мере. если objectToCopy = { x : undefined};после запуска ваш код Object.keys(objectToCopy).lengthесть 1, то пока Object.keys(copy).lengthесть 0.
Айдин
33

TypeScript / JavaScript имеет свой собственный оператор для мелкого клонирования:

let shallowClone = { ...original };
Лука С.
источник
15

Легко получить поверхностную копию с помощью «Object Spread», представленного в TypeScript 2.1

этот TypeScript: let copy = { ...original };

производит этот JavaScript:

var __assign = (this && this.__assign) || Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
        s = arguments[i];
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
            t[p] = s[p];
    }
    return t;
};
var copy = __assign({}, original);

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

Homer
источник
2
Примечание: это создаст мелкую копию
Джимми Кейн
11

Для сериализуемого глубокого клона, с информацией о типе

export function clone<T>(a: T): T {
  return JSON.parse(JSON.stringify(a));
}
Сополи
источник
1
Это может изменить порядок реквизита. Просто предупреждение для некоторых людей. Также он не обрабатывает даты должным образом.
Пангамма
Это может изменить порядок реквизита - возможно, попробуйте npmjs.com/package/es6-json-stable-stringify вместоJSON.stringify
Polv
@Polv, если кто-то полагается на порядок ключей в объекте, я думаю, что у них есть большая проблема, чем clone. :)
Айдин
Это решение может пропустить ключи со undefinedзначением. См. Мой комментарий к аналогичному ответу выше: stackoverflow.com/questions/28150967/typescript-cloning-object/…
Aidin
7

Мой взгляд на это:

Object.assign(...) только копирует свойства и мы теряем прототип и методы.

Object.create(...) не копирует свойства для меня, а просто создает прототип.

Для меня сработало создание прототипа с использованием Object.create(...)и копирование свойств в него с помощью Object.assign(...):

Итак, для объекта fooсделайте клон следующим образом:

Object.assign(Object.create(foo), foo)
Мухаммед Али
источник
Здесь происходит очень тонкая вещь. Вы фактически fooстановитесь прототипом родителя clonedFoo(нового объекта). Хотя это может звучать нормально, вы должны иметь в виду, что пропущенное свойство будет найдено в цепочке прототипов, поэтому const a = { x: 8 }; const c = Object.assign(Object.create(a), a); delete c.x; console.log(c.x);выводит 8, а должно быть undefined! (Ссылка REPL: repl.it/repls/CompetitivePreemptiveKeygen )
Айдин
Кроме того, если вы позже добавите свойство foo, оно автоматически отобразится для clonedFoo! например foo.y = 9; console.log(clonedFoo.y), распечатает 9вместо undefined. Очень вероятно, что это не то, что вы просите!
Айдин
@Aidin Так как обеспечить глубокую копию?
Мухаммед Али
Любое другое решение в этом вопросе, которое делает рекурсивное копирование по значению (например, stackoverflow.com/a/53025968 by marckassay), гарантирует, что в исходном объекте нет ссылки на исходный объект.
Айдин
5

Вы также можете иметь что-то вроде этого:

class Entity {
    id: number;

    constructor(id: number) {
        this.id = id;
    }

    clone(): this {
        return new (this.constructor as typeof Entity)(this.id) as this;
    }
}

class Customer extends Entity {
    name: string;

    constructor(id: number, name: string) {
        super(id);
        this.name = name;
    }

    clone(): this {
        return new (this.constructor as typeof Customer)(this.id, this.name) as this;
    }
}

Просто убедитесь, что вы переопределяете cloneметод во всех Entityподклассах, иначе вы получите частичные клоны.

Тип возвращаемого значения thisвсегда будет соответствовать типу экземпляра.

Десятилетие Луны
источник
4

Добавьте "lodash.clonedeep": "^4.5.0"к своему package.json. Тогда используйте как это:

import * as _ from 'lodash';

...

const copy = _.cloneDeep(original)
user2878850
источник
3

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

   let deepClone = <T>(source: T): { [k: string]: any } => {
      let results: { [k: string]: any } = {};
      for (let P in source) {
        if (typeof source[P] === 'object') {
          results[P] = deepClone(source[P]);
        } else {
          results[P] = source[P];
        }
      }
      return results;
    };
marckassay
источник
1
Работает довольно хорошо, насколько я вижу. Тем не менее, typeof nullэто также объект, поэтому запрос должен быть if (source[P] !== null && typeof source[P] === 'object')вместо. В противном случае ваши нулевые значения превратятся в пустой объект.
MortenMoulder
3

Если вы получили эту ошибку:

TypeError: this.constructor(...) is not a function

Это правильный сценарий:

public clone(): any {
    var cloneObj = new (<any>this.constructor)(); // line fixed
    for (var attribut in this) {
        if (typeof this[attribut] === "object") {
            cloneObj[attribut] = this[attribut].clone();
        } else {
            cloneObj[attribut] = this[attribut];
        }
    }
    return cloneObj;
}
pablorsk
источник
4
Правильно cloneObj[attribut] = this.clone();? или вы имеете в видуcloneObj[attribut] = this[attribut].clone();
Сержиньо
2

Сам столкнулся с этой проблемой и в конце написал небольшую библиотеку cloneable-ts, которая предоставляет абстрактный класс, который добавляет метод клонирования к любому классу, расширяющему его. Абстрактный класс заимствует функцию Deep Copy , описанную в общепринятом ответе на Фентоне только замену copy = {};с , copy = Object.create(originalObj)чтобы сохранить класс исходного объекта. Вот пример использования класса.

import {Cloneable, CloneableArgs} from 'cloneable-ts';

// Interface that will be used as named arguments to initialize and clone an object
interface PersonArgs {
    readonly name: string;
    readonly age: number;
}

// Cloneable abstract class initializes the object with super method and adds the clone method
// CloneableArgs interface ensures that all properties defined in the argument interface are defined in class
class Person extends Cloneable<TestArgs>  implements CloneableArgs<PersonArgs> {
    readonly name: string;
    readonly age: number;

    constructor(args: TestArgs) {
        super(args);
    }
}

const a = new Person({name: 'Alice', age: 28});
const b = a.clone({name: 'Bob'})
a.name // Alice
b.name // Bob
b.age // 28

Или вы можете просто использовать Cloneable.cloneвспомогательный метод:

import {Cloneable} from 'cloneable-ts';

interface Person {
    readonly name: string;
    readonly age: number;
}

const a: Person = {name: 'Alice', age: 28};
const b = Cloneable.clone(a, {name: 'Bob'})
a.name // Alice
b.name // Bob
b.age // 28    
Тим Осадчий
источник
1

Поскольку выпущен TypeScript 3.7, теперь поддерживаются рекурсивные псевдонимы типов , и это позволяет нам определять функцию безопасного типа deepCopy():

// DeepCopy type can be easily extended by other types,
// like Set & Map if the implementation supports them.
type DeepCopy<T> =
    T extends undefined | null | boolean | string | number ? T :
    T extends Function | Set<any> | Map<any, any> ? unknown :
    T extends ReadonlyArray<infer U> ? Array<DeepCopy<U>> :
    { [K in keyof T]: DeepCopy<T[K]> };

function deepCopy<T>(obj: T): DeepCopy<T> {
    // implementation doesn't matter, just use the simplest
    return JSON.parse(JSON.stringify(obj));
}

interface User {
    name: string,
    achievements: readonly string[],
    extras?: {
        city: string;
    }
}

type UncopiableUser = User & {
    delete: () => void
};

declare const user: User;
const userCopy: User = deepCopy(user); // no errors

declare const uncopiableUser: UncopiableUser;
const uncopiableUserCopy: UncopiableUser = deepCopy(uncopiableUser); // compile time error

Игровая площадка

Валерий Катков
источник
0

Для простого клонирования содержимого объекта дыры я просто строжайся и анализирую экземпляр:

let cloneObject = JSON.parse(JSON.stringify(objectToClone))

В то время как я изменяю данные в дереве objectToClone, в cloneObject нет никаких изменений. Это было мое требование.

Надеюсь, это поможет

Ferhatos
источник
1
Может пропустить ключи со undefinedзначением. См. Мой комментарий к аналогичному ответу выше: stackoverflow.com/questions/28150967/typescript-cloning-object/…
Aidin
0

Я закончил тем, что сделал:

public clone(): any {
  const result = new (<any>this.constructor);

  // some deserialization code I hade in place already...
  // which deep copies all serialized properties of the
  // object graph
  // result.deserialize(this)

  // you could use any of the usggestions in the other answers to
  // copy over all the desired fields / properties

  return result;
}

Так как:

var cloneObj = new (<any>this.constructor());

от @Fenton дал ошибки во время выполнения.

Версия машинописного текста: 2.4.2

Бернулли ИТ
источник
0

Как насчет старого доброго jQuery ?! Вот глубокий клон:

var clone = $.extend(true, {}, sourceObject);
alehro
источник
Этот вопрос не был помечен как JQuery, и JQuery не был упомянут в этом вопросе. Также было бы очень сложно включить JQuery в проект просто для глубокого клонирования.
LewisM
Это достаточно справедливо, но ОП не о том, как клонировать, а о том, чтобы идентифицировать проблему в предоставленном им коде, и вы ответили способом клонирования jQuery, не ответив на вопрос. Я не тот, кто отказал тебе в голосовании, но я верю, что это может быть причиной твоего отказа.
LewisM
0

Я попытался создать общий сервис копирования / клонирования, который сохраняет типы для вложенных объектов. Хотелось бы получить обратную связь, если я делаю что-то не так, но, похоже, до сих пор работает ...

import { Injectable } from '@angular/core';

@Injectable()
export class CopyService {

  public deepCopy<T>(objectToClone: T): T {
    // If it's a simple type or null, just return it.
    if (typeof objectToClone === 'string' ||
      typeof objectToClone === 'number' ||
      typeof objectToClone === 'undefined' ||
      typeof objectToClone === 'symbol' ||
      typeof objectToClone === 'function' ||
      typeof objectToClone === 'boolean' ||
      objectToClone === null
    ) {
      return objectToClone;
    }

    // Otherwise, check if it has a constructor we can use to properly instantiate it...
    let ctor = Object.getPrototypeOf(objectToClone).constructor;
    if (ctor) {
      let clone = new ctor();

      // Once we've instantiated the correct type, assign the child properties with deep copies of the values
      Object.keys(objectToClone).forEach(key => {
        if (Array.isArray(objectToClone[key]))
          clone[key] = objectToClone[key].map(item => this.deepCopy(item));
        else
          clone[key] = this.deepCopy(objectToClone[key]);
      });

      if (JSON.stringify(objectToClone) !== JSON.stringify(clone))
        console.warn('object cloned, but doesnt match exactly...\nobject: ' + JSON.stringify(objectToClone) + "\nclone: " + JSON.stringify(clone))

      // return our cloned object...
      return clone;
    }
    else {
      //not sure this will ever get hit, but figured I'd have a catch call.
      console.log('deep copy found something it didnt know: ' + JSON.stringify(objectToClone));
      return objectToClone;
    }
  }
}
patrickbadley
источник
0

В typeScript я тестирую с angular, и все нормально

deepCopy(obj) {


        var copy;

        // Handle the 3 simple types, and null or undefined
        if (null == obj || "object" != typeof obj) return obj;

        // Handle Date
        if (obj instanceof Date) {
            copy = new Date();
            copy.setTime(obj.getTime());
            return copy;
        }

        // Handle Array
        if (obj instanceof Array) {
            copy = [];
            for (var i = 0, len = obj.length; i < len; i++) {
                copy[i] = this.deepCopy(obj[i]);
            }
            return copy;
        }

        // Handle Object
        if (obj instanceof Object) {
            copy = {};
            for (var attr in obj) {
                if (obj.hasOwnProperty(attr)) copy[attr] = this.deepCopy(obj[attr]);
            }
            return copy;
        }

        throw new Error("Unable to copy obj! Its type isn't supported.");
    }
Мати Хименес
источник
0

Для глубокого клонирования объекта, который может содержать другие объекты, массивы и т. Д., Я использую:

const clone = <T>(source: T): T => {
  if (source === null) return source

  if (source instanceof Date) return new Date(source.getTime()) as any

  if (source instanceof Array) return source.map((item: any) => clone<any>(item)) as any

  if (typeof source === 'object' && source !== {}) {
    const clonnedObj = { ...(source as { [key: string]: any }) } as { [key: string]: any }
    Object.keys(clonnedObj).forEach(prop => {
      clonnedObj[prop] = clone<any>(clonnedObj[prop])
    })

    return clonnedObj as T
  }

  return source
}

Использование:

const obj = {a: [1,2], b: 's', c: () => { return 'h'; }, d: null, e: {a:['x'] }}
const objClone = clone(obj)
ZiiMakc
источник
0

Вы можете использовать деструктурирующее присваивание с расширенным синтаксисом :

var obj = {id = 1, name = 'product1'};
var clonedObject = {...obj};
СУВИК САХА
источник
1
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и / или почему он решает проблему, улучшит долгосрочную ценность ответа.
Leopal
0

Вот современная реализация, которая учитывает Setи то и Mapдругое:

export function deepClone<T extends object>(value: T): T {
  if (typeof value !== 'object' || value === null) {
    return value;
  }

  if (value instanceof Set) {
    return new Set(Array.from(value, deepClone)) as T;
  }

  if (value instanceof Map) {
    return new Map(Array.from(value, ([k, v]) => [k, deepClone(v)])) as T;
  }

  if (value instanceof Date) {
    return new Date(value) as T;
  }

  if (value instanceof RegExp) {
    return new RegExp(value.source, value.flags) as T;
  }

  return Object.keys(value).reduce((acc, key) => {
    return Object.assign(acc, { [key]: deepClone(value[key]) });
  }, (Array.isArray(value) ? [] : {}) as T);
}

Опробовать это:

deepClone({
  test1: { '1': 1, '2': {}, '3': [1, 2, 3] },
  test2: [1, 2, 3],
  test3: new Set([1, 2, [1, 2, 3]]),
  test4: new Map([['1', 1], ['2', 2], ['3', 3]])
});

test1:
  1: 1
  2: {}
  3: [1, 2, 3]

test2: Array(3)
  0: 1
  1: 2
  2: 3

test3: Set(3)
  0: 1
  1: 2
  2: [1, 2, 3]

test4: Map(3)
  0: {"1" => 1}
  1: {"2" => 2}
  2: {"3" => 3}
Блид
источник
-2

Если у вас уже есть целевой объект, поэтому вы не хотите создавать его заново (как, например, при обновлении массива), вы должны скопировать свойства.
Если сделали это так:

Object.keys(source).forEach((key) => {
    copy[key] = source[key]
})

Хвала должная. (посмотрите на заголовок "версия 2")

LosManos
источник
Функции? Массивы? Дата объектов? Сохранение типов? И конечно как насчет объектов? Если вышеприведенная функция встречает любой из вышеперечисленных типов, она не сможет выполнить глубокое клонирование. Вы скопируете ссылки на те же данные. Когда они перейдут к редактированию дочерних свойств клонированного объекта, они также завершат редактирование исходного объекта.
Пангамма