Как выполнить глубокое клонирование в javascript


105

Как глубоко клонировать объект Javascript?

Я знаю, что существуют различные функции, основанные на таких фреймворках, как JSON.parse(JSON.stringify(o))и, $.extend(true, {}, o)но я не хочу использовать такой фреймворк.

Каков самый элегантный или эффективный способ создания глубокого клона.

Мы заботимся о крайних случаях, таких как массив клонирования. Не нарушать цепочки прототипов, имея дело с самореференциями

Мы не заботимся о поддержке копирования объектов DOM и т.п., потому что .cloneNodeсуществует по этой причине.

Поскольку я в основном хочу использовать глубокие клоны при node.jsиспользовании функций ES5 двигателя V8, это приемлемо.

[Редактировать]

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

[Дальнейшее редактирование]

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

var o = (function() {
     var magic = 42;

     var magicContainer = function() {
          this.get = function() { return magic; };
          this.set = function(i) { magic = i; };
     }

      return new magicContainer;
}());

var n = clone(o); // how to implement clone to support closures

Есть ли способ написать функцию клонирования, которая клонирует объект, имеет то же состояние во время клонирования, но не может изменить состояние oбез написания парсера JS в JS.

В такой функции больше не должно быть реальной потребности. Это чисто академический интерес.


2
Прежде чем он будет отмечен как дубликат, я просмотрел stackoverflow.com/questions/122102/… и не нашел ответа, который касался бы всех крайних случаев.
Raynos

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

Сегодня вечером я много читал об этом, и среди ресурсов, которые я нашел, был этот уродливый пост в блоге, который включает в себя пару приемов для доступа к алгоритму структурированного клонирования в браузере: dassur.ma/things/deep-copy
Cat

Ответы:


67

Это действительно зависит от того, что вы хотите клонировать. Это действительно объект JSON или просто любой объект в JavaScript? Если вы захотите сделать какой-нибудь клон, это может вызвать у вас проблемы. Какая проблема? Я объясню это ниже, но сначала приведу пример кода, который клонирует литералы объектов, любые примитивы, массивы и узлы DOM.

function clone(item) {
    if (!item) { return item; } // null, undefined values check

    var types = [ Number, String, Boolean ], 
        result;

    // normalizing primitives if someone did new String('aaa'), or new Number('444');
    types.forEach(function(type) {
        if (item instanceof type) {
            result = type( item );
        }
    });

    if (typeof result == "undefined") {
        if (Object.prototype.toString.call( item ) === "[object Array]") {
            result = [];
            item.forEach(function(child, index, array) { 
                result[index] = clone( child );
            });
        } else if (typeof item == "object") {
            // testing that this is DOM
            if (item.nodeType && typeof item.cloneNode == "function") {
                result = item.cloneNode( true );    
            } else if (!item.prototype) { // check that this is a literal
                if (item instanceof Date) {
                    result = new Date(item);
                } else {
                    // it is an object literal
                    result = {};
                    for (var i in item) {
                        result[i] = clone( item[i] );
                    }
                }
            } else {
                // depending what you would like here,
                // just keep the reference, or create new object
                if (false && item.constructor) {
                    // would not advice to do that, reason? Read below
                    result = new item.constructor();
                } else {
                    result = item;
                }
            }
        } else {
            result = item;
        }
    }

    return result;
}

var copy = clone({
    one : {
        'one-one' : new String("hello"),
        'one-two' : [
            "one", "two", true, "four"
        ]
    },
    two : document.createElement("div"),
    three : [
        {
            name : "three-one",
            number : new Number("100"),
            obj : new function() {
                this.name = "Object test";
            }   
        }
    ]
})

А теперь поговорим о проблемах, которые могут возникнуть при клонировании РЕАЛЬНЫХ объектов. Я говорю сейчас об объектах, которые вы создаете, делая что-то вроде

var User = function(){}
var newuser = new User();

Конечно, вы можете клонировать их, это не проблема, каждый объект имеет свойство конструктора, и вы можете использовать его для клонирования объектов, но это не всегда будет работать. Вы также можете делать простые for inс этими объектами, но это идет в том же направлении - неприятности. Я также включил в код функцию клонирования, но она исключена if( false )оператором.

Итак, почему клонирование может быть проблемой? Во-первых, у каждого объекта / экземпляра может быть какое-то состояние. Вы никогда не можете быть уверены, что ваши объекты не имеют, например, частных переменных, и если это так, клонируя объект, вы просто нарушаете состояние.

Представьте, что государства нет, это нормально. Тогда у нас осталась еще одна проблема. Клонирование с помощью метода «конструктор» создаст нам еще одно препятствие. Это зависимость аргументов. Никогда нельзя быть уверенным в том, что кто-то, создавший этот объект, не делал каких-то

new User({
   bike : someBikeInstance
});

Если это так, вам не повезло, someBikeInstance, вероятно, был создан в каком-то контексте, и этот контекст неизвестен для метода clone.

Так что делать? Вы по-прежнему можете for inрешать такие задачи и обращаться с такими объектами как с обычными объектными литералами, но, может быть, это идея вообще не клонировать такие объекты, а просто передать ссылку на этот объект?

Другое решение - вы можете установить соглашение, согласно которому все объекты, которые должны быть клонированы, должны реализовывать эту часть самостоятельно и предоставлять соответствующий метод API (например, cloneObject). Что-то, что cloneNodeделает для DOM.

Вам решать.


Я столкнулся с препятствием, когда имел дело с объектами, которые используют замыкания, чтобы скрыть состояние. Как можно клонировать объект и все его состояние, но при этом гарантировать, что клон не может сам изменить исходное состояние? Говоря о result = new item.constructor();плохом, можно сказать , что с учетом функции конструктора и объекта элемента вы должны иметь возможность RE любые параметры, переданные в конструктор.
Raynos

7
@Raynos: если объекты используют замыкания, чтобы скрыть состояние, вы не можете их клонировать. Отсюда и термин «закрытие». Как говорит nemisj в конце, лучший способ - реализовать метод API для клонирования (или сериализации / десериализации), если это возможно.
Michiel Kalkman

@MichielKalkman У меня такое ощущение. Хотя у кого-то могло быть действительно умное решение для этого.
Raynos

Каков эффект false && item.constructor? Разве это не ifбесполезно?
Габриэль Петровай

2
@GabrielPetrovay Это if«бесполезно» с функциональной точки зрения, потому что оно никогда не запустится, но оно имеет академическую цель - показать гипотетическую реализацию, которую можно попытаться использовать, которую автор не дает по причинам, объясненным позже. Итак, да, он будет запускать elseпредложение каждый раз, когда оценивается условие, и все же есть причина для того, чтобы код был там.
Ги Имамура

156

Очень простой способ, может быть, слишком простой:

var cloned = JSON.parse(JSON.stringify(objectToClone));

12
Отлично, если значение объекта не является функцией, и тогда вам придется использовать что-то вроде принятого ответа. Или используйте вспомогательную функцию, как cloneDeepв Lodash.
matthoiland 03

31
Если значение объекта является функцией, объект не является JSON.
Жос де Йонг,

6
Какой вариант использования может оправдать клонирование функции, а не просто ее использование?
G. Ghez

3
Если я правильно помню, это также преобразует даты в строки.
Питер

3
@ G.Ghez, если вы клонируете объект, содержащий функцию, эта функция будет потеряна ..
Питер

38

JSON.parse(JSON.stringify())Сочетание глубокого копирования объектов Javascript является неэффективным хак, как это было предназначено для данных JSON. Он не поддерживает значения undefinedили function () {}и просто игнорирует их (или nullих) при «преобразовании» (маршалинге) объекта Javascript в JSON.

Лучшее решение - использовать функцию глубокого копирования. Функция ниже выполняет глубокое копирование объектов и не требует сторонней библиотеки (jQuery, LoDash и т. Д.).

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

7
За исключением случаев, когда aObject (или другой объект, который он содержит) содержит ссылку на себя ... stackoverflow ™!
e2-e4

@ ringø - Можете ли вы предоставить несколько тестовых примеров для самопроверки?
tfmontague

4
var o = { a:1, b:2 } ; o["oo"] = { c:3, m:o };
e2-e4

4
Мне нравится это решение. Единственное исправление для меня bObject[k] = (v === null) ? null : (typeof v === "object") ? copy(v) : v;
Дэвид Киркланд

2
Эта функция проста, понятна и улавливает практически все случаи. В мире JavaScript это почти то же самое, что и вы.
icc97

22

Вот функция ES6, которая также будет работать для объектов с циклическими ссылками:

function deepClone(obj, hash = new WeakMap()) {
    if (Object(obj) !== obj) return obj; // primitives
    if (hash.has(obj)) return hash.get(obj); // cyclic reference
    const result = obj instanceof Set ? new Set(obj) // See note about this!
                 : obj instanceof Map ? new Map(Array.from(obj, ([key, val]) => 
                                        [key, deepClone(val, hash)])) 
                 : obj instanceof Date ? new Date(obj)
                 : obj instanceof RegExp ? new RegExp(obj.source, obj.flags)
                 // ... add here any specific treatment for other classes ...
                 // and finally a catch-all:
                 : obj.constructor ? new obj.constructor() 
                 : Object.create(null);
    hash.set(obj, result);
    return Object.assign(result, ...Object.keys(obj).map(
        key => ({ [key]: deepClone(obj[key], hash) }) ));
}

// Sample data
var p = {
  data: 1,
  children: [{
    data: 2,
    parent: null
  }]
};
p.children[0].parent = p;

var q = deepClone(p);

console.log(q.children[0].parent.data); // 1

Примечание о наборах и картах

Спорный вопрос, как обращаться с ключами наборов и карт: эти ключи часто являются примитивами (в этом случае нет споров), но они также могут быть объектами. В этом случае возникает вопрос: нужно ли клонировать эти ключи?

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

С другой стороны, хотелось бы, чтобы если Set / Map has ключа это должно было быть истинным как в оригинале, так и в копии - по крайней мере, до того, как в любой из них будут внесены какие-либо изменения. Было бы странно, если бы копия была Set / Map с ключами, которые никогда не встречались ранее (поскольку они были созданы в процессе клонирования): конечно, это не очень полезно для любого кода, который должен знать, является ли данный объект введите этот Set / Map или нет.

Как вы заметили, я придерживаюсь второго мнения: ключи наборов и карт - это значения (возможно, ссылки ), которые должны оставаться неизменными.

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


не обрабатывает дату и регулярное выражение
mkeremguc

1
@mkeremguc, спасибо за ваш комментарий. Я обновил код для поддержки даты и регулярного выражения.
trincot

Хорошее решение, включая карту. Просто отсутствует поддержка клонирования наборов es6.
Роберт Биггс

Если я не ошибаюсь, вы, вероятно, можете добавить поддержку Sets с помощью:if (object instanceof Set) Array.from(object, val => result.add(deepClone(val, hash)));
Роберт Биггс

@RobertBiggs, это одна из возможностей, но, на мой взгляд, если у Set есть определенный ключ, это также должно быть верно в клонированной версии этого Set. С вашим предложенным кодом это не будет выполняться, если ключи являются объектами. Поэтому я бы предложил не клонировать ключи - я действительно думаю, что тогда он будет вести себя более ожидаемым образом. См. Обновление моего ответа по этому поводу.
trincot

10

В библиотеке библиотеки Contrib Underscore.js есть функция, называемая моментальным снимком, которая глубоко клонирует объект.

фрагмент из источника:

snapshot: function(obj) {
  if(obj == null || typeof(obj) != 'object') {
    return obj;
  }

  var temp = new obj.constructor();

  for(var key in obj) {
    if (obj.hasOwnProperty(key)) {
      temp[key] = _.snapshot(obj[key]);
    }
  }

  return temp;
}

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

_.snapshot(object);

4
хорошее решение, просто запомните: клон и оригинал имеют один и тот же прототип. если это проблема, можно добавить «temp .__ proto__ = .snapshot (obj .__ proto_ );» прямо над «return temp», и для поддержки встроенных классов со свойствами, помеченными как «no enumerate», вы можете выполнять итерацию в getOwnPropertyNames () вместо «for (var key in obj)»
Ронен Несс

3

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

function deepClone (obj) {
    var _out = new obj.constructor;

    var getType = function (n) {
        return Object.prototype.toString.call(n).slice(8, -1);
    }

    for (var _key in obj) {
        if (obj.hasOwnProperty(_key)) {
            _out[_key] = getType(obj[_key]) === 'Object' || getType(obj[_key]) === 'Array' ? deepClone(obj[_key]) : obj[_key];
        }
    }
    return _out;
}

3

Как отмечали другие по этому и подобным вопросам, клонирование «объекта» в общем смысле сомнительно в JavaScript.

Однако существует класс объектов, которые я называю объектами «данных», то есть объекты, построенные просто из { ... }литералов и / или простых присвоений свойств или десериализованные из JSON, для которых разумно захотеть клонировать. Как раз сегодня я хотел искусственно увеличить данные, полученные от сервера, в 5 раз, чтобы проверить, что происходит с большим набором данных, но объект (массив) и его дочерние элементы должны были быть отдельными объектами, чтобы все работало правильно. Клонирование позволило мне сделать это для увеличения набора данных:

return dta.concat(clone(dta),clone(dta),clone(dta),clone(dta));

Другое место, где я часто заканчиваю клонирование объектов данных, - это отправка данных обратно на хост, где я хочу удалить поля состояния из объекта в модели данных перед его отправкой. Например, я могу удалить все поля, начинающиеся с «_», из объекта, когда он клонируется.

Это код, который я написал, чтобы сделать это в общих чертах, включая вспомогательные массивы и селектор для выбора элементов для клонирования (который использует строку «путь» для определения контекста):

function clone(obj,sel) {
    return (obj ? _clone("",obj,sel) : obj);
    }

function _clone(pth,src,sel) {
    var ret=(src instanceof Array ? [] : {});

    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }

        var val=src[key], sub;

        if(sel) {
            sub+=pth+"/"+key;
            if(!sel(sub,key,val)) { continue; }
            }

        if(val && typeof(val)=='object') {
            if     (val instanceof Boolean) { val=Boolean(val);        }
            else if(val instanceof Number ) { val=Number (val);        }
            else if(val instanceof String ) { val=String (val);        }
            else                            { val=_clone(sub,val,sel); }
            }
        ret[key]=val;
        }
    return ret;
    }

Простейшее разумное решение с глубоким клонированием, предполагающее ненулевой корневой объект и без выбора членов:

function clone(src) {
    var ret=(src instanceof Array ? [] : {});
    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }
        var val=src[key];
        if(val && typeof(val)=='object') { val=clone(val);  }
        ret[key]=val;
        }
    return ret;
    }

2

Lo-Dash , теперь расширенный набор Underscore.js , имеет несколько функций глубокого клонирования:

Из ответа самого автора :

lodash underscore build предоставляется для обеспечения совместимости с последней стабильной версией Underscore.


в вопросе сказано: «Я не хочу использовать библиотеки»
Femi Oni

@FemiOni в вопросе нет ничего о библиотеках (даже в его старых редакциях) ... Несколько других ответов здесь также используют ту или иную библиотеку.
CPHPython

Ответ @FemiOni был отклонен вчера. Интересно ... В любом случае, это место для обучения, и на тот случай, если кто-то действительно собирается реализовать сам глубокий клон, исходный код lodashbaseClone может дать некоторые идеи.
CPHPython

@FemiOni объект JSON не является ни библиотекой, ни фреймворком ... Если вы собираетесь реализовать функцию, я предлагаю заглянуть в одну из библиотек с открытым исходным кодом и использовать те части, которые вам нужны (многие из них были проверены годами). Это позволит избежать ошибок и упущенных замечаний в долгосрочной перспективе.
CPHPython

2

Приведенная ниже функция является наиболее эффективным способом глубокого клонирования объектов javascript.

function deepCopy(obj){
    if (!obj || typeof obj !== "object") return obj;

    var retObj = {};

    for (var attr in obj){
        var type = obj[attr];

        switch(true){
            case (type instanceof Date):
                var _d = new Date();
                _d.setDate(type.getDate())
                retObj[attr]= _d;
                break;

            case (type instanceof Function):
                retObj[attr]= obj[attr];
                break;

            case (type instanceof Array):
                var _a =[];
                for (var e of type){
                    //_a.push(e);
                    _a.push(deepCopy(e));
                }
                retObj[attr]= _a;
                break;

            case (type instanceof Object):
                var _o ={};
                for (var e in type){
                    //_o[e] = type[e];
                    _o[e] = deepCopy(type[e]);
                }
                retObj[attr]= _o;
                break;

            default:
                retObj[attr]= obj[attr];
        }
    }
    return retObj;
}

var obj = {
    string: 'test',
    array: ['1'],
    date: new Date(),
    object:{c: 2, d:{e: 3}},
    function: function(){
        return this.date;
    }
};

var copyObj = deepCopy(obj);

console.log('object comparison', copyObj === obj); //false
console.log('string check', copyObj.string === obj.string); //true
console.log('array check', copyObj.array === obj.array); //false
console.log('date check', copyObj2.date === obj.date); //false
console.log('object check', copyObj.object === obj.object); //false
console.log('function check', copyObj.function() === obj.function()); //true

2
Есть ли у вас какие-либо аргументы в поддержку своего утверждения?
Фабиан фон Эллертс

Я привел пример под функцией. Есть сомнения?
Kooldandy

Эти примеры показывают, что функция работает, и это круто, но почему это «самый эффективный способ»?
Фабиан фон Эллертс

Потому что он рекурсивно копирует атрибуты объекта в одном цикле. Также правильно обрабатываются дата, функция, объект, массив, число, строка. Есть ли у вас другой способ?
Kooldandy

2

В такой функции больше не должно быть реальной потребности. Это чисто академический интерес.

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

const cloner = (x) => {
    const recurseObj = x => (typeof x === 'object') ? cloner(x) : x
    const cloneObj = (y, k) => {
        y[k] = recurseObj(x[k])
        return y
    }
    // Guard blocks
    // Add extra for Date / RegExp if you want
    if (!x) {
        return x
    }
    if (Array.isArray(x)) {
        return x.map(recurseObj)
    }
    return Object.keys(x).reduce(cloneObj, {})
}
const tests = [
    null,
    [],
    {},
    [1,2,3],
    [1,2,3, null],
    [1,2,3, null, {}],
    [new Date('2001-01-01')], // FAIL doesn't work with Date
    {x:'', y: {yx: 'zz', yy: null}, z: [1,2,3,null]},
    {
        obj : new function() {
            this.name = "Object test";
        }
    } // FAIL doesn't handle functions
]
tests.map((x,i) => console.log(i, cloner(x)))


1

Я заметил, что Map требует особого обращения, поэтому со всеми предложениями в этой ветке код будет:

function deepClone( obj ) {
    if( !obj || true == obj ) //this also handles boolean as true and false
        return obj;
    var objType = typeof( obj );
    if( "number" == objType || "string" == objType ) // add your immutables here
        return obj;
    var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
    if( obj instanceof Map )
        for( var key of obj.keys() )
            result.set( key, deepClone( obj.get( key ) ) );
    for( var key in obj )
        if( obj.hasOwnProperty( key ) )
            result[key] = deepClone( obj[ key ] );
    return result;
}

1

мое дополнение ко всем ответам

deepCopy = arr => {
  if (typeof arr !== 'object') return arr
  if(arr.pop) return [...arr].map(deepCopy)
  const copy = {}
  for (let prop in arr)
    copy[prop] = deepCopy(arr[prop])
  return copy
}

0

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

const deepClone = (objOrArray) => {

  const copyArray = (arr) => {
    let arrayResult = [];
    arr.forEach(el => {
        arrayResult.push(cloneObjOrArray(el));
    });
    return arrayResult;
  }

  const copyObj = (obj) => {
    let objResult = {};
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        objResult[key] = cloneObjOrArray(obj[key]);
      }
    }
    return objResult;
  }

  const cloneObjOrArray = (el) => {
    if (Array.isArray(el)) {
      return copyArray(el);
    } else if (typeof el === 'object') {
      return copyObj(el);
    } else {
      return el;
    }
  }

  return cloneObjOrArray(objOrArray);
}

0

Мы можем использовать рекурсию для создания deepCopy. Он может создавать копию массива, объекта, массива объекта, объекта с функцией. при желании вы можете добавить функцию для другого типа структуры данных, например карты и т. д.

function deepClone(obj) {
         var retObj;
        _assignProps = function(obj, keyIndex, retObj) {
               var subType = Object.prototype.toString.call(obj[keyIndex]);
               if(subType === "[object Object]" || subType === "[object Array]") {
                    retObj[keyIndex] = deepClone(obj[keyIndex]);
               }
               else {
                     retObj[keyIndex] = obj[keyIndex];
               }
        };

        if(Object.prototype.toString.call(obj) === "[object Object]") {
           retObj = {};
           for(key in obj) {
               this._assignProps(obj, key, retObj);
           }
        }
        else if(Object.prototype.toString.call(obj) == "[object Array]") {
           retObj = [];
           for(var i = 0; i< obj.length; i++) {
              this._assignProps(obj, i, retObj);
            }
        };

        return retObj;
    };

0

Используйте immutableJS

import { fromJS } from 'immutable';

// An object we want to clone
let objA = { 
   a: { deep: 'value1', moreDeep: {key: 'value2'} } 
};

let immB = fromJS(objA); // Create immutable Map
let objB = immB.toJS(); // Convert to plain JS object

console.log(objA); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }
console.log(objB); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }

// objA and objB are equalent, but now they and their inner objects are undependent
console.log(objA === objB); // false
console.log(objA.a === objB.a); // false
console.log(objA.moreDeep === objB.moreDeep); // false

Или lodash / merge

import merge from 'lodash/merge'

var objA = {
    a: [{ 'b': 2 }, { 'd': 4 }]
};
// New deeply cloned object:
merge({}, objA ); 

// We can also create new object from several objects by deep merge:
var objB = {
    a: [{ 'c': 3 }, { 'e': 5 }]
};
merge({}, objA , objB ); // Object { a: [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }

0

Этот, использующий круговую ссылку, работает для меня

 //a test-object with circular reference :
 var n1 = {   id:0,   text:"aaaaa",   parent:undefined} 
 var n2 = {  id:1,   text:"zzzzz",   parent:undefined } 
 var o = { arr:[n1,n2],   parent:undefined } 
 n1.parent = n2.parent = o;
 var obj = {   a:1,   b:2,   o:o }
 o.parent = obj;

 function deepClone(o,output){ 

     if(!output) output = {};  
     if(o.______clone) return o.______clone;
     o.______clone = output.______clone = output;

   for(var z in o){

     var obj = o[z];
     if(typeof(obj) == "object") output[z] = deepClone(obj)
     else output[z] = obj; 
    }

   return output;
}

console.log(deepClone(obj));

0

var newDate = новая дата (this.oldDate); Я передавал oldDate для работы и генерировал newDate из this.oldDate, но он также менял this.oldDate, поэтому я использовал это решение, и оно сработало.


0

Это решение позволит избежать проблем с рекурсией при использовании [... target] или {... target}

function shallowClone(target) {
  if (typeof a == 'array') return [...target]
  if (typeof a == 'object') return {...target}
  return target
}

/* set skipRecursion to avoid throwing an exception on recursive references */
/* no need to specify refs, or path -- they are used interally */
function deepClone(target, skipRecursion, refs, path) {
  if (!refs) refs = []
  if (!path) path = ''
  if (refs.indexOf(target) > -1) {
    if (skipRecursion) return null
    throw('Recursive reference at ' + path)
  }
  refs.push(target)
  let clone = shallowCopy(target)
  for (i in target) target[i] = deepClone(target, refs, path + '.' + i)
  return clone
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.