Каков наиболее эффективный способ глубокого клонирования объекта в JavaScript?

Примечание: Корбана в его ответе сначала с краткой версией формата: атрибутам IDL


Хочу отметить, что .clone() включает в себя jQuery . … и это сработает, когда вы сделаете:

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

Дополнительную информацию можно найти в документация jQuery Глядя на вывод

Сброс

Проверьте этот тест: http://jsben.ch/ # / bWfk9

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

JSON.parse(JSON.stringify(obj))

не будет быть самым быстрым способом глубокого клонирования объекта (в общем, jQuery.extend с глубоким флагом, установленным в true на 10-20 %).

jQuery.extend будет довольно быстрым, когда глубокий флаг установлен в false (мелкий клон). Это хороший вариант, потому что он включает некоторую дополнительную логику для проверки типа и не копирует неопределенные свойства и т. Д., Но это также немного замедлит вас.

Если вам известна структура объектов, которые вы пытаетесь клонировать, или можете избежать вложенных массивов, вы можете написать простое свойство for (var i in obj) Объяснение:

Наконец, если вы пытаетесь клонировать известную структуру объекта в горячем цикле, вы можете получить НАМНОГО БОЛЬШЕ ЭФФЕКТИВНОСТИ, просто вставив процедуру клонирования и вручную создав объект.

Механизмы трассировки JavaScript отстают при оптимизации for..in Некоторые люди предлагают конкретные плагины и / или браузеры. Я бы не стал, потому что они только

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

Остерегайтесь, используя JSON.parse(JSON.stringify(obj)) метод включен DateJSON.stringify(new Date()) возвращает строковое представление даты в формате ISO, {{}} Я думаю, что вы ищете, это просто простой объект JavaScript: JSON.parse() не преобразовать обратно в Date объект. Смотрите этот ответ для более подробной информации Глядя на вывод

эта функция принимает произвольную строку и выполняет ее как код JavaScript. Когда запрос кода известен заранее (не определяется во время выполнения), нет причина для использованияeeval (). Если код Динамически генерируемый во время выполнения, часто есть лучший способ достичь цели без eval (). Например, просто использовать квадратную скобку для доступа к динамическим свойствам лучше и проще: этот JSPerf , выполнение нативного клонирования путем создания новой функции почти был бы медленнее, чем при использовании JSON.stringify, который невероятно быстр путь через доску.

структурированном клонировании

Стандарт HTML включает ), тогда вы можете воспользоваться , который может создавать глубокие клоны объектов. Он по-прежнему ограничен определенными встроенными типами, но в дополнение к нескольким типам, поддерживаемым JSON, он также поддерживает Dates, RegExps, Карты, Наборы, BLOB-объекты, FileLists, ImageDatas, разреженные массивы, Typed Arrays и, возможно, больше в будущем. , Он также сохраняет ссылки в клонированных данных, что позволяет поддерживать циклические и рекурсивные структуры, которые могут вызвать ошибки для JSON.

Поддержка в Node.js: экспериментальный 🙂

Переменная v8 совместимость напрямую раскрывает API структурированной сериализации , но эта функциональность по-прежнему помечена как «экспериментальная» и может быть изменена или удалена в будущих версиях. Если вы используете совместимую версию, клонирование объекта так же просто, как:

const v8 = require('v8');

const structuredClone = obj => {
  return v8.deserialize(v8.serialize(obj));
};

Если вы используете

Браузеры в настоящее время не предоставляют прямой интерфейс для алгоритма структурированного клонирования, но глобальный structuredClone() функция обсуждалась в whatwg / html # 793 на GitHub . Как предлагается в настоящее время, использовать его для большинства целей так же просто, как:

const clone = structuredClone(original);

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

Асинхронным Обходным путем: Используемо. 😕

способ с минимальными издержками для создания структурированного Клон с существующими API — это передача данных через один порт MessageChannels . Другой порт выдаст событие message со структурированным клоном присоединенного .data Если вы хотите

class StructuredCloner {
  constructor() {
    this.pendingClones_ = new Map();
    this.nextKey_ = 0;

    const channel = new MessageChannel();
    this.inPort_ = channel.port1;
    this.outPort_ = channel.port2;

    this.outPort_.onmessage = ({data: {key, value}}) => {
      const resolve = this.pendingClones_.get(key);
      resolve(value);
      this.pendingClones_.delete(key);
    };
    this.outPort_.start();
  }

  cloneAsync(value) {
    return new Promise(resolve => {
      const key = this.nextKey_  ;
      this.pendingClones_.set(key, resolve);
      this.inPort_.postMessage({key, value});
    });
  }
}

const structuredCloneAsync = window.structuredCloneAsync =
    StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);

Пример использования:

const main = async () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = await structuredCloneAsync(original);

  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));

  console.log("Assertions complete.");
};

main();

Синхронные обходные пути: Ужасно! 🤢

Нет хороших вариантов для синхронного создания структурированных клонов. Вот пара непрактичных взломов вместо этого.

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

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

Пример использования:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

main();

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

Переменная Notification Конструктор создает структурированный клон связанных с ним данных. Он также пытается отобразить уведомление в браузере для пользователя, но это молча завершится ошибкой, если вы не запросили разрешение на уведомление. Если у вас есть разрешение для других целей, мы немедленно закроем созданное нами уведомление.

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.onshow = n.close.bind(n);
  return n.data;
};

Пример использования:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.close();
  return n.data;
};

main();

Если бы не было встроенного, вы можете попробовать:

function clone(obj) {
    if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
        return obj;

    if (obj instanceof Date)
        var temp = new obj.constructor(); //or new Date(obj);
    else
        var temp = obj.constructor();

    for (var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            obj['isActiveClone'] = null;
            temp[key] = clone(obj[key]);
            delete obj['isActiveClone'];
        }
    }
    return temp;
}

Эффективный способ клонирования (не глубокого клонирования) объекта в одну строку кода

массив Object.assign является частью стандарта ECMAScript 2015 (ES6) и выполняет именно то, что вам нужно.

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

метод Object.assign () используется для копирования значения всех перечисляемых собственных свойств от одного или нескольких исходных объектов до целевого объекта.

Читать дальше …

Переменная polyfill для поддержки старых браузеров:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i  ) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex  ) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

потому что это не итератор, и

// extends 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned
function extend(from, to)
{
    if (from == null || typeof from != "object") return from;
    if (from.constructor != Object && from.constructor != Array) return from;
    if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||
        from.constructor == String || from.constructor == Number || from.constructor == Boolean)
        return new from.constructor(from);

    to = to || new from.constructor();

    for (var name in from)
    {
        to[name] = typeof to[name] == "undefined" ? extend(from[name], null) : to[name];
    }

    return to;
}

Таблица может быть отсортирована, если вы щелкнете по столбцу таблицы.

var obj =
{
    date: new Date(),
    func: function(q) { return 1   q; },
    num: 123,
    text: "asdasd",
    array: [1, "asd"],
    regex: new RegExp(/aaa/i),
    subobj:
    {
        num: 234,
        text: "asdsaD"
    }
}

var clone = extend(obj);

для получения дополнительной информации. ранжировался от лучшего к худшему

  • Переназначение «=» (строковые массивы, только числовые массивы)
  • Number
  • , вы всегда используете его как
  • , а не как свойство
  • jQuery $ .extend
  • Зачем нам нужно кодирование URL:
  • Underscore.js (строковые массивы, только числовые массивы)
  • В Lo-Dash _.cloneDeep

глубокого копирования массива строк или чисел (один уровень — без ссылочных указателей):

Когда массив содержит числа и строки — такие функции, как .slice (), .concat (),. splice (), оператор присваивания «=» и функция клона Underscore.js ; сделают глубокую копию элементов массива.

Где переназначение имеет максимальную производительность:

var arr1 = ['a', 'b', 'c'];
var arr2 = arr1;
arr1 = ['a', 'b', 'c'];

И .slice () имеет лучшую производительность, чем .concat (), http://jsperf.com/duplicate-array-slice-vs-concat/3

var arr1 = ['a', 'b', 'c'];  // Becomes arr1 = ['a', 'b', 'c']
var arr2a = arr1.slice(0);   // Becomes arr2a = ['a', 'b', 'c'] - deep copy
var arr2b = arr1.concat();   // Becomes arr2b = ['a', 'b', 'c'] - deep copy

Глубокое копирование массива объектов (два или более уровня — указатели ссылки):

var arr1 = [{object:'a'}, {object:'b'}];

Запись пользовательская функция (имеет более высокую производительность, чем $ .extend () или JSON.parse):

function copy(o) {
   var out, v, key;
   out = Array.isArray(o) ? [] : {};
   for (key in o) {
       v = o[key];
       out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
   }
   return out;
}

copy(arr1);

Например,

$.extend(true, [], arr1); // Jquery Extend
JSON.parse(arr1);
_.cloneDeep(arr1); // Lo-dash

где jQuery для $ .extend имеет лучшую производительность:

var clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (var i in this) {
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        }
        else
        {
            newObj[i] = this[i];
        }
    }
    return newObj;
}; 

Object.defineProperty( Object.prototype, "clone", {value: clone, enumerable: false});

In объявление переменной только подъемы определения переменной, а не присвоение. Если вы объявите , это довольно хорошо. Он обеспечивает наиболее полное рекурсивное клонирование / копирование произвольных известных мне объектов. Он также поддерживает циклические ссылки, которые пока не охвачены другими ответами.

Вы можете Также интересно наблюдать, насколько Chrome работает с этими функциями массива быстрее, чем firefox. тоже. Может использоваться как для браузера, так и для Node.js.

Вот пример того, как его использовать:

Установите его с движком

npm install clone

или упаковывают их с Ender Глядя на вывод

ender build clone [...]

Вы также можете загрузить исходный код вручную.

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

var clone = require('clone');

var a = { foo: { bar: 'baz' } };  // inital value of a
var b = clone(a);                 // clone a -> b
a.foo.bar = 'foo';                // change a

console.log(a);                   // { foo: { bar: 'foo' } }
console.log(b);                   // { foo: { bar: 'baz' } }

(Отказ от ответственности: я являюсь автором библиотеки.)

Я знаю, что это старый пост, но я подумал, что он может помочь следующему человеку, который спотыкается.

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

var a = function(){
    return {
        father:'zacharias'
    };
},
b = a(),
c = a();
c.father = 'johndoe';
alert(b.father);

Cloning Объект всегда был проблемой в JS, но все это было до ES6, ниже я перечисляю различные способы копирования объекта в JavaScript, представьте, что у вас есть Объект ниже и вы хотели бы иметь его глубокую копию:

var obj = {a:1, b:2, c:3, d:4};

создается новый контекст, поэтому ключевое слово

1) ES5, используя простую функцию, чтобы сделать копию для вас:

function deepCopyObj(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i  ) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }
    throw new Error("Unable to copy obj this object.");
}

2) ES5, используя JSON.parse и JSON.stringify.

var  deepCopyObj = JSON.parse(JSON.stringify(obj));

3) AngularJs:

var  deepCopyObj = angular.copy(obj);

4) jQuery:

var deepCopyObj = jQuery.extend(true, {}, obj);

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

var deepCopyObj = _.cloneDeep(obj); //latest version UndescoreJs makes shallow copy

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

глубокое копирование объектов в JavaScript (я думаю, лучший и самый простой)

1. Использование JSON.parse (JSON.stringify (object)) ;

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = JSON.parse(JSON.stringify(obj));
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

2. Используя созданный метод

function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(obj[i] != null &&  typeof(obj[i])=="object")
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = cloneObject(obj);
obj.b.c = 20;

console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

3. Использование Lo-Dash _.cloneDeep link lodash

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

Для получения дополнительной информации об этом типе кодировки вы можете проверить:

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

НО НЕПРАВИЛЬНО КОГДА

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = Object.assign({}, obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// Note: Properties on the prototype chain and non-enumerable properties cannot be copied.

5.Использование Underscore.js _.clone link Underscore.js

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

НО НЕПРАВИЛЬНО КОГДА

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// (Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated.)

Reference medium.com

JSBEN.CH Performance Benchmarking Playground 1 ~ 3 http://jsben.ch/KVQLd Performance Deep copying objects in JavaScript

Ниже приведен вариант ответа ConroyP, который работает, даже если у конструктора есть обязательные параметры:

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

function deepCopy(obj) {
    if(obj == null || typeof(obj) !== 'object'){
        return obj;
    }
    //make sure the returned object has the same prototype as the original
    var ret = object_create(obj.constructor.prototype);
    for(var key in obj){
        ret[key] = deepCopy(obj[key]);
    }
    return ret;
}

кроме начального значения, замените simpleoo библиотека.

Мы только что выпустили

javascript — Почему конструкторы регулярных выражений должны быть дважды экранированы? — Переполнение стека

/**
 * Deep copy an object (make copies of all its object properties, sub-properties, etc.)
 * An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
 * that doesn't break if the constructor has required parameters
 * 
 * It also borrows some code from http://stackoverflow.com/a/11621004/560114
 */ 
function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {
    if(src === null || typeof(src) !== 'object'){
        return src;
    }

    //Honor native/custom clone methods
    if(typeof src.clone == 'function'){
        return src.clone(true);
    }

    //Special cases:
    //Date
    if(src instanceof Date){
        return new Date(src.getTime());
    }
    //RegExp
    if(src instanceof RegExp){
        return new RegExp(src);
    }
    //DOM Element
    if(src.nodeType && typeof src.cloneNode == 'function'){
        return src.cloneNode(true);
    }

    // Initialize the visited objects arrays if needed.
    // This is used to detect cyclic references.
    if (_visited === undefined){
        _visited = [];
        _copiesVisited = [];
    }

    // Check if this object has already been visited
    var i, len = _visited.length;
    for (i = 0; i < len; i  ) {
        // If so, get the copy we already made
        if (src === _visited[i]) {
            return _copiesVisited[i];
        }
    }

    //Array
    if (Object.prototype.toString.call(src) == '[object Array]') {
        //[].slice() by itself would soft clone
        var ret = src.slice();

        //add it to the visited array
        _visited.push(src);
        _copiesVisited.push(ret);

        var i = ret.length;
        while (i--) {
            ret[i] = deepCopy(ret[i], _visited, _copiesVisited);
        }
        return ret;
    }

    //If we've reached here, we have a regular object

    //make sure the returned object has the same prototype as the original
    var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
    if (!proto) {
        proto = src.constructor.prototype; //this line would probably only be reached by very old browsers 
    }
    var dest = object_create(proto);

    //add this object to the visited array
    _visited.push(src);
    _copiesVisited.push(dest);

    for (var key in src) {
        //Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
        //For an example of how this could be modified to do so, see the singleMixin() function
        dest[key] = deepCopy(src[key], _visited, _copiesVisited);
    }
    return dest;
}

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

Крокфорд предлагает (и я предпочитаю) с помощью этой функции:

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

var newObject = object(oldObject);

Это кратко, работает, как ожидалось, и вам не нужна библиотека.


Мы только что выпустили

Это полифилл для Object.create Определите глобальную функцию, которая обрабатывает привязку в

var newObject = Object.create(oldObject);

Примечание: Если вы используете что-то из этого, вы можете иметь проблемы с некоторой итерацией, которая использует hasOwnProperty. Потому что create создайте новый пустой объект, который наследует oldObject Ладно, ребята, я несколько лет медленно создавал метод catch all для этого, лол! Хитрость заключается в следующем:

Например, если Chrome oldObject.a = 5;

newObject.a; // is 5

, но:

oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false
function clone(obj)
 { var clone = {};
   clone.prototype = obj.prototype;
   for (property in obj) clone[property] = obj[property];
   return clone;
 }

Однострочное копирование с мелким копированием ( ECMAScript 5-е издание ):

var origin = { foo : {} };
var copy = Object.keys(origin).reduce(function(c,k){c[k]=origin[k];return c;},{});

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

и однострочным копированием ( у меня есть два хороших ответа в зависимости от того, является ли ваша цель клонировать «старый старый объект JavaScript» или нет. , 2015):

var origin = { foo : {} };
var copy = Object.assign({}, origin);

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

Я использую

function jQueryClone(obj) {
   return jQuery.extend(true, {}, obj)
}

function JSONClone(obj) {
   return JSON.parse(JSON.stringify(obj))
}

var arrayLikeObj = [[1, "a", "b"], [2, "b", "a"]];
arrayLikeObj.names = ["m", "n", "o"];
var JSONCopy = JSONClone(arrayLikeObj);
var jQueryCopy = jQueryClone(arrayLikeObj);

alert("Is arrayLikeObj an array instance?"   (arrayLikeObj instanceof Array)  
      "nIs the jQueryClone an array instance? "   (jQueryCopy instanceof Array)  
      "nWhat are the arrayLikeObj names? "   arrayLikeObj.names  
      "nAnd what are the JSONClone names? "   JSONCopy.names)

Итак, означает ли это

. Предположим также, что вы намереваетесь создать полный клон без ссылок прототипов на исходный объект. Если вас не интересует полный клон, вы можете использовать многие из подпрограмм Object.clone (), представленных в некоторых других ответах (шаблон Крокфорда).

Обратите внимание, что исходный объект должен быть чистым объектом JSON. То есть все его вложенные свойства должны быть скалярами (например, логическое значение, строка, массив, объект и т. Д.). Любые функции или специальные объекты, такие как RegExp или Date, не будут клонированы.

var clone = JSON.parse(JSON.stringify(obj));

преобразуется в переменную в глобальном пространстве имен? И означает ли это также, что можно использовать это как замену

метод в этих браузерах?

Используйте три функции:

Теперь для непрозрачных объектов JavaScript нет простого ответа. На самом деле, этого не может быть из-за динамической природы функций JavaScript и состояния внутреннего объекта. Глубокое клонирование структуры JSON с функциями внутри требует, чтобы вы воссоздали эти функции и их внутренний контекст. И у JavaScript просто нет стандартизированного способа сделать это.

Используйте этот код, если у вас есть вложенные объекты или если у вас есть вложенный массив obj.

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

http: // davidwalsh. объект name / javascript-clone

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

. Основная идея заключается в том, что вам нужно специально обрабатывать создание ваших функций (или, так сказать, прототипов) для каждого типа. Здесь он предоставил несколько примеров для RegExp и Date.

Итак, что-то вроде следующего будет

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

languageDetector.php

Как правило, это не самое эффективное решение, но оно делает то, что мне нужно. Простые тестовые случаи ниже …

function clone(obj, clones) {
    // Makes a deep copy of 'obj'. Handles cyclic structures by
    // tracking cloned obj's in the 'clones' parameter. Functions 
    // are included, but not cloned. Functions members are cloned.
    var new_obj,
        already_cloned,
        t = typeof obj,
        i = 0,
        l,
        pair; 

    clones = clones || [];

    if (obj === null) {
        return obj;
    }

    if (t === "object" || t === "function") {

        // check to see if we've already cloned obj
        for (i = 0, l = clones.length; i < l; i  ) {
            pair = clones[i];
            if (pair[0] === obj) {
                already_cloned = pair[1];
                break;
            }
        }

        if (already_cloned) {
            return already_cloned; 
        } else {
            if (t === "object") { // create new object
                new_obj = new obj.constructor();
            } else { // Just use functions as is
                new_obj = obj;
            }

            clones.push([obj, new_obj]); // keep track of objects we've cloned

            for (key in obj) { // clone object members
                if (obj.hasOwnProperty(key)) {
                    new_obj[key] = clone(obj[key], clones);
                }
            }
        }
    }
    return new_obj || obj;
}

задать новый вопрос

a = []
a.push("b", "c", a)
aa = clone(a)
aa === a //=> false
aa[2] === a //=> false
aa[2] === a[2] //=> false
aa[2] === aa //=> true

Function test …

f = new Function
f.a = a
ff = clone(f)
ff === f //=> true
ff.a === a //=> false

, могут справиться с этой ситуацией, используя

Ну, если вы используете angular, вы тоже можете это сделать

var newObject = angular.copy(oldObject);

Я не согласен с ответом, набравшим наибольшее количество голосов говорится, что . Функция Below имеет локальную переменную области видимости , Намного быстрее , чем JSON.parse (JSON.stringify (obj)) .

А вот функция для быстрого ознакомления:

function cloneDeep (o) {
  let newO
  let i

  if (typeof o !== 'object') return o

  if (!o) return o

  if (Object.prototype.toString.apply(o) === '[object Array]') {
    newO = []
    for (i = 0; i < o.length; i  = 1) {
      newO[i] = cloneDeep(o[i])
    }
    return newO
  }

  newO = {}
  for (i in o) {
    if (o.hasOwnProperty(i)) {
      newO[i] = cloneDeep(o[i])
    }
  }
  return newO
}
// obj target object, vals source object
var setVals = function (obj, vals) {
    if (obj && vals) {
        for (var x in vals) {
            if (vals.hasOwnProperty(x)) {
                if (obj[x] && typeof vals[x] === 'object') {
                    obj[x] = setVals(obj[x], vals[x]);
                } else {
                    obj[x] = vals[x];
                }
            }
        }
    }
    return obj;
};

Не прямой ответ на ваш вопрос, но не лучше ли, чтобы ваш RPC возвращал некоторую структуру (будь то XML, JSON или что-то еще) с этими данные изображения (URL в вашем примере) внутри этой структуры? JSON.parse(JSON.stringify(obj)) версия, но не теряя объекты Date, вы можете использовать (counter.js): parse — маленький , не Flash, утилита, которая позволяет копировать текстовые или HTML-данные в буфер обмена. Его очень просто использовать, просто включите .js и используйте что-то вроде этого: для преобразования строк обратно в Date:

function clone(obj) {
  var regExp = /^d{4}-d{2}-d{2}Td{2}:d{2}:d{2}.d{3}Z$/;
  return JSON.parse(JSON.stringify(x), function(k, v) {
    if (typeof v === 'string' && regExp.test(v))
      return new Date(v);
    return v;
  });
}

. Вот всеобъемлющий метод clone (), который может клонировать любой объект JavaScript. Он обрабатывает почти все случаи:

function clone(src, deep) {

    var toString = Object.prototype.toString;
    if (!src && typeof src != "object") {
        // Any non-object (Boolean, String, Number), null, undefined, NaN
        return src;
    }

    // Honor native/custom clone methods
    if (src.clone && toString.call(src.clone) == "[object Function]") {
        return src.clone(deep);
    }

    // DOM elements
    if (src.nodeType && toString.call(src.cloneNode) == "[object Function]") {
        return src.cloneNode(deep);
    }

    // Date
    if (toString.call(src) == "[object Date]") {
        return new Date(src.getTime());
    }

    // RegExp
    if (toString.call(src) == "[object RegExp]") {
        return new RegExp(src);
    }

    // Function
    if (toString.call(src) == "[object Function]") {

        //Wrap in another method to make sure == is not true;
        //Note: Huge performance issue due to closures, comment this :)
        return (function(){
            src.apply(this, arguments);
        });
    }

    var ret, index;
    //Array
    if (toString.call(src) == "[object Array]") {
        //[].slice(0) would soft clone
        ret = src.slice();
        if (deep) {
            index = ret.length;
            while (index--) {
                ret[index] = clone(ret[index], true);
            }
        }
    }
    //Object
    else {
        ret = src.constructor ? new src.constructor() : {};
        for (var prop in src) {
            ret[prop] = deep
                ? clone(src[prop], true)
                : src[prop];
        }
    }
    return ret;
};

, несколько абзацев под большой таблицей в начале этого раздела), где говорится:

Только когда вы можете использовать метод prop возвращает логическое значение для отмеченных, выбранных, отключенных, readOnly..etc, а attr возвращает определенную строку. Таким образом, вы можете напрямую использовать .prop («проверил») в условии if. или является тегом Глядя на вывод

Особенности:

  • Не будет вызывать геттер / сеттер при копировании.
  • Сохраняет метод получения / установки.
  • Сохраняет информацию о прототипе.
  • Работает с обоими Object-literal и функционал OO Любые аналогичные конструкции, которые дают вам значение, равное ложному выравниванию, обернутое в правдивый тип

потому что это не итератор, и

function clone(target, source){

    for(let key in source){

        // Use getOwnPropertyDescriptor instead of source[key] to prevent from trigering setter/getter.
        let descriptor = Object.getOwnPropertyDescriptor(source, key);
        if(descriptor.value instanceof String){
            target[key] = new String(descriptor.value);
        }
        else if(descriptor.value instanceof Array){
            target[key] = clone([], descriptor.value);
        }
        else if(descriptor.value instanceof Object){
            let prototype = Reflect.getPrototypeOf(descriptor.value);
            let cloneObject = clone({}, descriptor.value);
            Reflect.setPrototypeOf(cloneObject, prototype);
            target[key] = cloneObject;
        }
        else {
            Object.defineProperty(target, key, descriptor);
        }
    }
    let prototype = Reflect.getPrototypeOf(source);
    Reflect.setPrototypeOf(target, prototype);
    return target;
}

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

   function cloneObject(obj) {
        if (obj === null || typeof(obj) !== 'object')
            return obj;
        var temp = obj.constructor(); // changed
        for (var key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
                obj['isActiveClone'] = null;
                temp[key] = cloneObject(obj[key]);
                delete obj['isActiveClone'];
            }
        }
        return temp;
    }



var b = cloneObject({"a":1,"b":2});   // calling

, что намного лучше и быстрее, чем:

var a = {"a":1,"b":2};
var b = JSON.parse(JSON.stringify(a));  

и

var a = {"a":1,"b":2};

// Deep copy
var newObject = jQuery.extend(true, {}, a);

Я тестировал код, и вы можете проверить результаты говорится, что :

, и обмен результатами: enter image description here Ссылки: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

Я обычно использую метод var newObj = JSON.parse( JSON.stringify(oldObje) ); javascript — обнаружение изменений в DOM

var o = {};

var oo = Object.create(o);

(o === oo); // => false

Смотрите устаревшие браузеры!

клонируют объект с использованием сегодняшнего атрибута JavaScript: ECMAScript 2015 (ранее известный как ECMAScript 6)

var original = {a: 1};

// Method 1: New object with original assigned.
var copy1 = Object.assign({}, original);

// Method 2: New object with spread operator assignment.
var copy2 = {...original};

Старые браузеры могут не поддерживать ECMAScript 2015. Распространенным решением является использование компилятора JavaScript-JavaScript, такого как Babel, для вывода ECMAScript 5 версии вашего кода JavaScript.

В моем В обоих примерах у меня есть функция указал @jim-hall , , это всего лишь мелкая копия . Свойства свойств копируются как ссылки: изменение одного из них приведет к изменению значения в другом объекте / экземпляре.

однострочное решение ECMAScript 6 (специальные типы объектов, такие как Date / Regex, не обрабатываются):

const clone = (o) =>
  typeof o === 'object' && o !== null ?      // only clone objects
  (Array.isArray(o) ?                        // if cloning an array
    o.map(e => clone(e)) :                   // clone each of its elements
    Object.keys(o).reduce(                   // otherwise reduce every key in the object
      (r, k) => (r[k] = clone(o[k]), r), {}  // and save its cloned value into a new object
    )
  ) :
  o;                                         // return non-objects as is

var x = {
  nested: {
    name: 'test'
  }
};

var y = clone(x);

console.log(x.nested !== y.nested);

В Lodash есть функция, которая обрабатывает это для вас.

var foo = {a: 'a', b: {c:'d', e: {f: 'g'}}};

var bar = _.cloneDeep(foo);
// bar = {a: 'a', b: {c:'d', e: {f: 'g'}}} 

Прочитайте документы говорится, что Глядя на вывод

ES 2017:

let objectToCopy = someObj;
let copyOfObject = {};
Object.defineProperties(copyOfObject, Object.getOwnPropertyDescriptors(objectToCopy));
// copyOfObject will now be the same as objectToCopy

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

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

Создан совершенно новый объект.

copyDeleteAndReset:function(namespace,strObjName){
    var obj = namespace[strObjName],
    objNew = {},objOrig = {};
    for(i in obj){
        if(obj.hasOwnProperty(i)){
            objNew[i] = objOrig[i] = obj[i];
            delete obj[i];
        }
    }
    namespace[strObjName] = objOrig;
    return objNew;
}

var namespace = {};
namespace.objOrig = {
    '0':{
        innerObj:{a:0,b:1,c:2}
    }
}

var objNew = copyDeleteAndReset(namespace,'objOrig');
objNew['0'] = 'NEW VALUE';

console.log(objNew['0']) === 'NEW VALUE';
console.log(namespace.objOrig['0']) === innerObj:{a:0,b:1,c:2};

Есть много способов сделать это, но если вы хотите сделать это без какой-либо библиотеки, вы можете использовать следующее:

const cloneObject = (oldObject) => {
  let newObject = oldObject;
  if (oldObject && typeof oldObject === 'object') {
    if(Array.isArray(oldObject)) {
      newObject = [];
    } else if (Object.prototype.toString.call(oldObject) === '[object Date]' && !isNaN(oldObject)) {
      newObject = new Date(oldObject.getTime());
    } else {
      newObject = {};
      for (let i in oldObject) {
        newObject[i] = cloneObject(oldObject[i]);
      }
    }

  }
  return newObject;
}

Дайте мне знать, что вы думаете.

. Я пробовал ES2015 значение по умолчанию и оператор распространения

 const makeDeepCopy = (obj, copy = {}) => {
  for (let item in obj) {
    if (typeof obj[item] === 'object') {
      makeDeepCopy(obj[item], copy)
    }
    if (obj.hasOwnProperty(item)) {
      copy = {
        ...obj
      }
    }
  }
  return copy
}
const testObj = {
  "type": "object",
  "properties": {
    "userId": {
      "type": "string",
      "chance": "guid"
    },
    "emailAddr": {
      "type": "string",
      "chance": {
        "email": {
          "domain": "fake.com"
        }
      },
      "pattern": ". @fake.com"
    }
  },
  "required": [
    "userId",
    "emailAddr"
  ]
}

const makeDeepCopy = (obj, copy = {}) => {
  for (let item in obj) {
    if (typeof obj[item] === 'object') {
      makeDeepCopy(obj[item], copy)
    }
    if (obj.hasOwnProperty(item)) {
      copy = {
        ...obj
      }
    }
  }
  return copy
}

console.log(makeDeepCopy(testObj))

насчет асинхронного клонирования объектов, выполненного Promise?

async function clone(thingy /**/)
{
    if(thingy instanceof Promise)
    {
        throw Error("This function cannot clone Promises.");
    }
    return thingy;
}

Для мелкой копии в стандарте ECMAScript2018 представлен отличный простой метод, включающий использование Оператор распространения :

let obj = {a : "foo", b:"bar" , c:10 , d:true , e:[1,2,3] };

let objClone = { ...obj };

Я проверил это в браузере Chrome, оба объекта хранятся в разных местах, поэтому изменение непосредственных дочерних значений в одном из них не изменит другого. Хотя (в примере) изменение значения в e Вот решение, использующее

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

В JavaScript вы можете написать свое deepCopy Это не требует сортировки или каких-либо сторонних фреймворков. нужны ручные петли. Он работает с каждым значением

function deepCopy(src) {
  let target = Array.isArray(src) ? [] : {};
  for (let prop in src) {
    let value = src[prop];
    if(value && typeof value === 'object') {
      target[prop] = deepCopy(value);
  } else {
      target[prop] = value;
  }
 }
    return target;
}

Есть много ответов, но ни один из них не дал желаемого эффекта, который мне был нужен. Я хотел использовать всю мощь глубокой копии jQuery … Однако, когда он сталкивается с массивом, он просто копирует ссылку на массив и глубоко копирует элементы в нем. Чтобы обойти это, я сделал небольшую рекурсивную функцию, которая автоматически создаст новый массив.

(Он даже проверяет kendo.data.ObservableArray, если вы этого хотите! Тем не менее, убедитесь, что вы вызываете kendo.observable (newItem), если хотите, чтобы массивы снова стали наблюдаемыми.)

. Итак, чтобы полностью скопировать существующий элемент, вы просто делаете это:

var newItem = jQuery.extend(true, {}, oldItem);
createNewArrays(newItem);


function createNewArrays(obj) {
    for (var prop in obj) {
        if ((kendo != null && obj[prop] instanceof kendo.data.ObservableArray) || obj[prop] instanceof Array) {
            var copy = [];
            $.each(obj[prop], function (i, item) {
                var newChild = $.extend(true, {}, item);
                createNewArrays(newChild);
                copy.push(newChild);
            });
            obj[prop] = copy;
        }
    }
}

Я думаю, что это лучшее решение, если вы хотите обобщить алгоритм клонирования объектов.
Его можно использовать как с jQuery, так и без него, хотя я рекомендую не использовать метод extends jQuery, если вы хотите, чтобы клонированный объект имел тот же «класс», что и исходный.

function clone(obj){
    if(typeof(obj) == 'function')//it's a simple function
        return obj;
    //of it's not an object (but could be an array...even if in javascript arrays are objects)
    if(typeof(obj) !=  'object' || obj.constructor.toString().indexOf('Array')!=-1)
        if(JSON != undefined)//if we have the JSON obj
            try{
                return JSON.parse(JSON.stringify(obj));
            }catch(err){
                return JSON.parse('"' JSON.stringify(obj) '"');
            }
        else
            try{
                return eval(uneval(obj));
            }catch(err){
                return eval('"' uneval(obj) '"');
            }
    // I used to rely on jQuery for this, but the "extend" function returns
    //an object similar to the one cloned,
    //but that was not an instance (instanceof) of the cloned class
    /*
    if(jQuery != undefined)//if we use the jQuery plugin
        return jQuery.extend(true,{},obj);
    else//we recursivley clone the object
    */
    return (function _clone(obj){
        if(obj == null || typeof(obj) != 'object')
            return obj;
        function temp () {};
        temp.prototype = obj;
        var F = new temp;
        for(var key in obj)
            F[key] = clone(obj[key]);
        return F;
    })(obj);            
}

Fiddle: fiddle . Надеюсь, это нелепо прояснит ее.

. Использование такое же, как описано в jQuery API:

  • Неглубокий клон: Deep clone: ​​extend(object_dest, object_source);
  • Одна дополнительная функция используется, чтобы определить, подходит ли объект для клонирования. extend(true, object_dest, object_source);

Это выполняется примерно в

/**
 * This is a quasi clone of jQuery's extend() function.
 * by Romain WEEGER for wJs library - www.wexample.com
 * @returns {*|{}}
 */
function extend() {
    // Make a copy of arguments to avoid JavaScript inspector hints.
    var to_add, name, copy_is_array, clone,

    // The target object who receive parameters
    // form other objects.
    target = arguments[0] || {},

    // Index of first argument to mix to target.
    i = 1,

    // Mix target with all function arguments.
    length = arguments.length,

    // Define if we merge object recursively.
    deep = false;

    // Handle a deep copy situation.
    if (typeof target === 'boolean') {
        deep = target;

        // Skip the boolean and the target.
        target = arguments[ i ] || {};

        // Use next object as first added.
        i  ;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if (typeof target !== 'object' && typeof target !== 'function') {
        target = {};
    }

    // Loop trough arguments.
    for (false; i < length; i  = 1) {

        // Only deal with non-null/undefined values
        if ((to_add = arguments[ i ]) !== null) {

            // Extend the base object.
            for (name in to_add) {

                // We do not wrap for loop into hasOwnProperty,
                // to access to all values of object.
                // Prevent never-ending loop.
                if (target === to_add[name]) {
                    continue;
                }

                // Recurse if we're merging plain objects or arrays.
                if (deep && to_add[name] && (is_plain_object(to_add[name]) || (copy_is_array = Array.isArray(to_add[name])))) {
                    if (copy_is_array) {
                        copy_is_array = false;
                        clone = target[name] && Array.isArray(target[name]) ? target[name] : [];
                    }
                    else {
                        clone = target[name] && is_plain_object(target[name]) ? target[name] : {};
                    }

                    // Never move original objects, clone them.
                    target[name] = extend(deep, clone, to_add[name]);
                }

                // Don't bring in undefined values.
                else if (to_add[name] !== undefined) {
                    target[name] = to_add[name];
                }
            }
        }
    }
    return target;
}

/**
 * Check to see if an object is a plain object
 * (created using "{}" or "new Object").
 * Forked from jQuery.
 * @param obj
 * @returns {boolean}
 */
function is_plain_object(obj) {
    // Not plain objects:
    // - Any object or value whose internal [[Class]] property is not "[object Object]"
    // - DOM nodes
    // - window
    if (obj === null || typeof obj !== "object" || obj.nodeType || (obj !== null && obj === obj.window)) {
        return false;
    }
    // Support: Firefox <20
    // The try/catch suppresses exceptions thrown when attempting to access
    // the "constructor" property of certain host objects, i.e. |window.location|
    // https://bugzilla.mozilla.org/show_bug.cgi?id=814622
    try {
        if (obj.constructor && !this.hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) {
            return false;
        }
    }
    catch (e) {
        return false;
    }

    // If the function hasn't returned already, we're confident that
    // |obj| is a plain object, created by {} or constructed with new Object
    return true;
}

Поскольку рекурсия слишком дорога для JavaScript, и большинство ответов, которые я нашел, используют рекурсию, в то время как подход JSON пропускает не-JSON-конвертируемые части (функция и т. Д.). Поэтому я провел небольшое исследование и нашел эту технику батута, чтобы избежать этого. Вот код:

/*
 * Trampoline to avoid recursion in JavaScript, see:
 *     http://www.integralist.co.uk/posts/js-recursion.html
 */
function trampoline() {
    var func = arguments[0];
    var args = [];
    for (var i = 1; i < arguments.length; i  ) {
        args[i - 1] = arguments[i];
    }

    var currentBatch = func.apply(this, args);
    var nextBatch = [];

    while (currentBatch && currentBatch.length > 0) {
        currentBatch.forEach(function(eachFunc) {
            var ret = eachFunc();
            if (ret && ret.length > 0) {
                nextBatch = nextBatch.concat(ret);
            }
        });

        currentBatch = nextBatch;
        nextBatch = [];
    }
};

/*
 *  Deep clone an object using the trampoline technique.
 *
 *  @param target {Object} Object to clone
 *  @return {Object} Cloned object.
 */
function clone(target) {
    if (typeof target !== 'object') {
        return target;
    }
    if (target == null || Object.keys(target).length == 0) {
        return target;
    }

    function _clone(b, a) {
        var nextBatch = [];
        for (var key in b) {
            if (typeof b[key] === 'object' && b[key] !== null) {
                if (b[key] instanceof Array) {
                    a[key] = [];
                }
                else {
                    a[key] = {};
                }
                nextBatch.push(_clone.bind(null, b[key], a[key]));
            }
            else {
                a[key] = b[key];
            }
        }
        return nextBatch;
    };

    var ret = target instanceof Array ? [] : {};
    (trampoline.bind(null, _clone))(target, ret);
    return ret;
};

Source: https://gist.github.com/SeanOceanHu/7594cafbfab682f790eb

включает префикс & суффикс amp ; с маскойJSON.parse(JSON.stringify(obj)). Вот модернизированная рекурсивная копия глубокого объекта Функция, которая может помещаться в одну строку:

function deepCopy(obj) {
  return Object.keys(obj).reduce((v, d) => Object.assign(v, {
    [d]: (obj[d].constructor === Object) ? deepCopy(obj[d]) : obj[d]
  }), {});
}

в 40 раз быстрее JavaScript — В чем разница между JSON и Object Literal Notation? — Метод переполнения стека , чем JSON.parse... цикл для получения перечислимых ключей:

Аналогичная методология могла бы конечно, для создания функций-сеттеров:

deepCopy(object) {
  const getCircularReplacer = () => {
    const seen = new WeakSet();
    return (key, value) => {
      if(typeof value === 'object' && value !== null) {
        if(seen.has(value)) return;
        seen.add(value);
      }
      return value;
    };
  };
  return JSON.parse(JSON.stringify(object, getCircularReplacer()));
}

const theCopy = deepCopy(originalObject);

Использование Object.create() Чтобы получить prototype, как говорят instanceof и используйте for() Требуются новые браузеры, но …

function cloneObject(source) {
    var key,value;
    var clone = Object.create(source);

    for (key in source) {
        if (source.hasOwnProperty(key) === true) {
            value = source[key];

            if (value!==null && typeof value==="object") {
                clone[key] = cloneObject(value);
            } else {
                clone[key] = value;
            }
        }
    }

    return clone;
}

Почему в данном случае это не объект JSON? Только потому, что это не определяется с помощью кавычек?

Давайте расширим нативный объект и получим ES5 также не может быть .extend() ;

Object.defineProperty(Object.prototype, 'extend', {
    enumerable: false,
    value: function(){
        var that = this;

        Array.prototype.slice.call(arguments).map(function(source){
            var props = Object.getOwnPropertyNames(source),
                i = 0, l = props.length,
                prop;

            for(; i < l;   i){
                prop = props[i];

                if(that.hasOwnProperty(prop) && typeof(that[prop]) === 'object'){
                    that[prop] = that[prop].extend(source[prop]);
                }else{
                    Object.defineProperty(that, prop, Object.getOwnPropertyDescriptor(source, prop));
                }
            }
        });

        return this;
    }
});

Просто вставьте это перед любым кодом, который использует .extend () для объекта.

Пример:

var obj1 = {
    node1: '1',
    node2: '2',
    node3: 3
};

var obj2 = {
    node1: '4',
    node2: 5,
    node3: '6'
};

var obj3 = ({}).extend(obj1, obj2);

console.log(obj3);
// Object {node1: "4", node2: 5, node3: "6"}

Для дальнейшего использования можно использовать этот код

obj = {
  a: { b: { c: { d: ['1', '2'] } } },
  e: 'Saeid'
}
const Clone = function (obj) {
  
  const container = Array.isArray(obj) ? [] : {}
  const keys  = Object.keys(obj)
   
  for (let i = 0; i < keys.length; i  ) {
    const key = keys[i]
    if(typeof obj[key] == 'object') {
      container[key] = Clone(obj[key])
    }
    else
      container[key] = obj[key].slice()
  }
  
  return container
}
 console.log(Clone(obj))

ES5:

ES6:

_clone: function(obj){
    let newObj = {};
    for(let i in obj){
        if(typeof(obj[i]) === 'object' && Object.keys(obj[i]).length){
            newObj[i] = clone(obj[i]);
        } else{
            newObj[i] = obj[i];
        }
    }
    return Object.assign({},newObj);
}

Например,

function clone(obj){
let newObj = {};
for(let i in obj){
    if(typeof(obj[i]) === 'object' && Object.keys(obj[i]).length){
        newObj[i] = clone(obj[i]);
    } else{
        newObj[i] = obj[i];
    }
}
return Object.assign({},newObj);

}

Такие форматы обычно не зависят от языка, что означает они могут быть обработаны Java, Python, JavaScript, PHP, вы называете это.

var obj ={a:{b:1,c:3},d:4,e:{f:6}}
var xc = clone(obj);
console.log(obj); //{a:{b:1,c:3},d:4,e:{f:6}}
console.log(xc); //{a:{b:1,c:3},d:4,e:{f:6}}

xc.a.b = 90;
console.log(obj); //{a:{b:1,c:3},d:4,e:{f:6}}
console.log(xc); //{a:{b:90,c:3},d:4,e:{f:6}}
class Handler {
  static deepCopy (obj) {
    if (Object.prototype.toString.call(obj) === '[object Array]') {
      const result = [];
      
      for (let i = 0, len = obj.length; i < len; i  ) {
        result[i] = Handler.deepCopy(obj[i]);
      }
      return result;
    } else if (Object.prototype.toString.call(obj) === '[object Object]') {
      const result = {};
      for (let prop in obj) {
        result[prop] = Handler.deepCopy(obj[prop]);
      }
      return result;
    }
    return obj;
  }
}

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

function objectClone(o){
  var ot = Array.isArray(o);
  return o !== null && typeof o === "object" ? Object.keys(o)
                                                     .reduce((r,k) => o[k] !== null && typeof o[k] === "object" ? (r[k] = objectClone(o[k]),r)
                                                                                                                : (r[k] = o[k],r), ot ? [] : {})
                                             : o;
}
var obj = {a: 1, b: {c: 2, d: {e: 3, f: {g: 4, h: null}}}},
    arr = [1,2,[3,4,[5,6,[7]]]],
    nil = null,
  clobj = objectClone(obj),
  clarr = objectClone(arr),
  clnil = objectClone(nil);
console.log(clobj, obj === clobj);
console.log(clarr, arr === clarr);
console.log(clnil, nil === clnil);
clarr[2][2][2] = "seven";
console.log(arr, clarr);

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

  1. JSON.parse (JSON.stringify (obj )) ;

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

  3. Он расширяет контейнер по горизонтали, а не по вертикали (как макет Pinterest).

  4. будний день:

  5. . JavaScript не имеет ничего подобного.

https://github.com/jinujd/Javascript-Deep-Clone

function deepClone(obj) {
    /*
     * Duplicates an object 
     */

    var ret = null;
    if (obj !== Object(obj)) { // primitive types
        return obj;
    }
    if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) { // string objecs
        ret = obj; // for ex: obj = new String("Spidergap")
    } else if (obj instanceof Date) { // date
        ret = new obj.constructor();
    } else
        ret = Object.create(obj.constructor.prototype);

    var prop = null;
    var allProps = Object.getOwnPropertyNames(obj); //gets non enumerables also


    var props = {};
    for (var i in allProps) {
        prop = allProps[i];
        props[prop] = false;
    }

    for (i in obj) {
        props[i] = i;
    }

    //now props contain both enums and non enums 
    var propDescriptor = null;
    var newPropVal = null; // value of the property in new object
    for (i in props) {
        prop = obj[i];
        propDescriptor = Object.getOwnPropertyDescriptor(obj, i);

        if (Array.isArray(prop)) { //not backward compatible
            prop = prop.slice(); // to copy the array
        } else
        if (prop instanceof Date == true) {
            prop = new prop.constructor();
        } else
        if (prop instanceof Object == true) {
            if (prop instanceof Function == true) { // function
                if (!Function.prototype.clone) {
                    Function.prototype.clone = function() {
                        var that = this;
                        var temp = function tmp() {
                            return that.apply(this, arguments);
                        };
                        for (var ky in this) {
                            temp[ky] = this[ky];
                        }
                        return temp;
                    }
                }
                prop = prop.clone();

            } else // normal object 
            {
                prop = deepClone(prop);
            }

        }

        newPropVal = {
            value: prop
        };
        if (propDescriptor) {
            /*
             * If property descriptors are there, they must be copied
             */
            newPropVal.enumerable = propDescriptor.enumerable;
            newPropVal.writable = propDescriptor.writable;

        }
        if (!ret.hasOwnProperty(i)) // when String or other predefined objects
            Object.defineProperty(ret, i, newPropVal); // non enumerable

    }
    return ret;
}

keys

Когда ваш объект является вложенным и содержит объект данных, другой структурированный объект или некоторый объект свойства и т. Д., Затем используется JSON.parse(JSON.stringify(object)) или Object.assign({}, obj) или $.extend(true, {}, obj) (т.е. последовательность символов, заключенная в двойные кавычки

var obj = {a: 25, b: {a: 1, b: 2}, c: new Date(), d: anotherNestedObject };
var A = _.cloneDeep(obj);

Теперь A будет вашим новым клоном obj без каких-либо ссылок.

, несколько абзацев под большой таблицей в начале этого раздела), где говорится:

Object.assign({},sourceObj) a строка

obj={a:"lol",b:["yes","no","maybe"]}
clonedObj = Object.assign({},obj);

clonedObj.b.push("skip")// changes will reflected to the actual obj as well because of its reference type.
obj.b //will also console => yes,no,maybe,skip

не связаны с

делает

var obj = Json.stringify(yourSourceObj)
var cloned = Json.parse(obj);

Поскольку на этот вопрос уделяется много внимания и есть ответы со ссылкой на встроенные функции, такие как Object.assign или пользовательский код для глубокого клонирования, я хотел бы поделиться некоторыми библиотеками для глубокого клонирования, { *} Пример использования в ES6:

1. esclone

Обычные посетители вашего сайта не будут иметь такого же опыта, как вы. когда вы разрабатываете сайт. Верадж посетитель посещает сайт реже (возможно, только несколько раз в месяц, если вы не являетесь пользователем Google или hi5 Networks), тогда он с меньшей вероятностью будет хранить ваши файлы в кеше, и этого может быть достаточно. Если вы хотите принудительно ввести новую версию в браузер, вы всегда можете добавить строку запроса к запросу и увеличить номер версии при внесении серьезных изменений: Https://www.npmjs.com/package/esclone

Строковые литералы, числовые литералы или имена идентификаторов в качестве ключей (начиная с ES6, ключи теперь также могут быть вычислены, что вводит еще один синтаксис).

import esclone from "esclone";

const rockysGrandFather = {
  name: "Rockys grand father",
  father: "Don't know :("
};
const rockysFather = {
  name: "Rockys Father",
  father: rockysGrandFather
};

const rocky = {
  name: "Rocky",
  father: rockysFather
};

const rockyClone = esclone(rocky);

пример использования в ES5:

var esclone = require("esclone")
var foo = new String("abcd")
var fooClone = esclone.default(foo)
console.log(fooClone)
console.log(foo === fooClone)

Дублирующие ключи дают определенные, определенные результаты (в свободном режиме последнее определение заменяет первое ; в строгом режиме, это ошибка).

npm install deep-copy https://www.npmjs.com/package/deep-copy

Пример:

var dcopy = require('deep-copy')

// deep copy object 
var copy = dcopy({a: {b: [{c: 5}]}})

// deep copy array 
var copy = dcopy([1, 2, {a: {b: 5}}])

, ваш пример не является JSON по двум причинам:

$ npm install —save clone-deep https://www.npmjs.com/package/clone-deep

Пример:

var cloneDeep = require('clone-deep');

var obj = {a: 'b'};
var arr = [obj];

var copy = cloneDeep(arr);
obj.c = 'd';

console.log(copy);
//=> [{a: 'b'}] 

console.log(arr);

Object.fromEntries () , который поддерживается в более новых версиях некоторых браузеров ( , вы не имеете дело с JSON. Возможно, вы получили данные как JSON (например, через ajax или чтение из файла), но как только вы или используемая вами библиотека проанализировали их, это больше не JSON. Только потому, что объектные литералы и JSON выглядят См. Также Как и ожидалось, каждый вызов ). Я хочу внести свой вклад с помощью следующего рекурсивного подхода:

const obj = {
  key1: {key11: "key11", key12: "key12", key13: {key131: 22}},
  key2: {key21: "key21", key22: "key22"},
  key3: "key3",
  key4: [1,2,3, {key: "value"}]
}

const cloneObj = (obj) =>
{
    if (Object(obj) !== obj)
       return obj;
    else if (Array.isArray(obj))
       return obj.map(cloneObj);

    return Object.fromEntries(Object.entries(obj).map(
        ([k,v]) => ([k, cloneObj(v)])
    ));
}

// Clone the original object.
let newObj = cloneObj(obj);

// Make changes on the original object.
obj.key1.key11 = "TEST";
obj.key3 = "TEST";
obj.key1.key13.key131 = "TEST";
obj.key4[1] = "TEST";
obj.key4[3].key = "TEST";

// Display both objects on the console.
console.log("Original object: ", obj);
console.log("Cloned object: ", newObj);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Мой сценарий был немного другим. У меня был объект с вложенными объектами и функциями. Поэтому Object.assign() и JSON.stringify() (то же самое относится и к { *} оператор, таким образом, мы можем прочитать значения свойств объекта как массив.

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

let deepCopy = (target, source) => {
    Object.assign(target, source);
    // check if there's any nested objects
    Object.keys(source).forEach((prop) => {
        /**
          * assign function copies functions and
          * literals (int, strings, etc...)
          * except for objects and arrays, so:
          */
        if (typeof(source[prop]) === 'object') {
            // check if the item is, in fact, an array
            if (Array.isArray(source[prop])) {
                // clear the copied referenece of nested array
                target[prop] = Array();
                // iterate array's item and copy over
                source[prop].forEach((item, index) => {
                    // array's items could be objects too!
                    if (typeof(item) === 'object') {
                        // clear the copied referenece of nested objects
                        target[prop][index] = Object();
                        // and re do the process for nested objects
                        deepCopy(target[prop][index], item);
                    } else {
                        target[prop].push(item);
                    }
                });
            // otherwise, treat it as an object
            } else {
                // clear the copied referenece of nested objects
                target[prop] = Object();
                // and re do the process for nested objects
                deepCopy(target[prop], source[prop]);
            }
        }
    });
};

с гораздо более ограниченным синтаксисом, включая:

let a = {
    name: 'Human', 
    func: () => {
        console.log('Hi!');
    }, 
    prop: {
        age: 21, 
        info: {
            hasShirt: true, 
            hasHat: false
        }
    },
    mark: [89, 92, { exam: [1, 2, 3] }]
};

let b = Object();

deepCopy(b, a);

a.name = 'Alien';
a.func = () => { console.log('Wassup!'); };
a.prop.age = 1024;
a.prop.info.hasShirt = false;
a.mark[0] = 87;
a.mark[1] = 91;
a.mark[2].exam = [4, 5, 6];

console.log(a); // updated props
console.log(b);

объекта с его

function clone(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] = clone(obj[i]);
        }
        return copy;
    }

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

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

Спецификацией JSON является синтаксис для кодирования данные в виде строки. То, что люди называют «объектом JSON» (в javascript), на самом деле является просто обычным объектом javascript, который (вероятно) был десериализован из допустимой строки JSON, nd может быть легко повторно сериализован как допустимая строка JSON. Обычно это означает, что он содержит только данные (а не функции). Это также означает, что даты отсутствуют, потому что JSON не имеет типа даты (вероятно, самая болезненная вещь в JSON ;) JSON.parse(JSON.stringify(obj)) потому что он медленнее, чем следующий метод

Как правильно клонировать объект JavaScript ?

. ключи , но он копирует только с глубиной одного внутреннего -объект, означающий, что когда вам дается что-то вроде values ​​?

function deepClone(o) {
    var keys = Object.keys(o);
    var values = Object.values(o);

    var clone = {};

    keys.forEach(function(key, i) {
        clone[key] = typeof values[i] == 'object' ? Object.create(values[i]) : values[i];
    });

    return clone;
}

Примечание: Этот метод не обязательно делает полные копии JSON является {a: {b: {c: null}}} документации { *}, как предложил @Filix King, я также предлагаю поиграть с deepClone(a.b).c это технически ссылка на a.b.c. Вы можете использовать его, но это усложняет поиск проблем и усложняет работу с людьми, которым может потребоваться внести изменения позже. deepClone(a).b является клоном, не ссылка Глядя на вывод

Если есть object Best метод, также рекомендованный Google. :) constructor. Если у вас нет constructor. В именах файлов JSON используется расширение object ; Мне кажется, вы должны создать constructor ; встроенным Глядя на вывод

OK, теперь клонируем объекты:

function SampleObjectConstructor(config) {
    this.greet = config.greet;
}
// custom-object's prototype method
SampleObjectConstructor.prototype.showGreeting = function(){
  alert(this.greet);
}

var originalObject = new SampleObjectConstructor({greet: 'Hi!'});
var clonedObj = new SampleObjectConstructor(originalObject);

console.log(originalObject); // SampleObjectConstructor {greet: "Hi!"}
console.log('clonedObj : ', clonedObj) // SampleObjectConstructor {greet: "Hi!"}
console.log('cloned successfully?', originalObject !== clonedObj); // cloned successfully? true

для вас. В таком случае вам даже не нужно писать свой собственный . Я не знаю деталей с точки зрения того, насколько хорошо это работает, или что такое «глубокая» копия, но я использую ее, чтобы также объединить атрибуты объекта с другими объектами. Кажется, работает для клонирования, а также. custom object в качестве разделителя (по умолчанию): prototype methods ECMAScript основан на нескольких исходных технологиях, наиболее известными из которых являются object constructor - Object может работать так же хорошо, например, new Object(originalObject) Давайте проверим это … clone the original object, когда мы распределяем массив по отдельным значениям и помещаем его в новый массив с помощью оператора []. constructor Глядя на вывод

var originalObject = {
    foo: 'bar'
}

var clonedObject = new Object(originalObject);

console.log(originalObject); // {foo: "bar"}
console.log(clonedObject); // {foo: "bar"}
console.log(originalObject !== clonedObject); // false

Удачи …

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

let a = {id:1, name:'sample_name'}
let b = {...a};
//  use Object.assign()

const obj = { 
 //whatever your object 
}

const clone = Object.assign({}, obj)

Для моих целей наиболее элегантный способ создать новый объект из существующего (клон) — это использовать объектную функцию JavaScript ‘assign’.

foo = {bar: 10, baz: {quox: 'batman'}};

clonedObject = Object.assign(foo);

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

Лучший и самый современный способ сделать этот клон заключается в следующем:

, используя «…» ES6 spread operatorExample:

var clonedObjArray = [...oldObjArray];

Хотя до 1994 года ECMA была известна как «Европейская ассоциация производителей компьютеров» После 1994 года, когда организация стала глобальной, «торговая марка» «Ecma» сохранилась по историческим причинам.

Диалекты были получены из того же языка. Они очень похожи друг на друга, поскольку они произошли от одного языка, но они претерпели некоторые изменения. Диалект — это разновидность самого языка. Это происходит от одного языка.

let objArray = [ {a:1} , {b:2} ];

let refArray = objArray; // this will just point to the objArray
let clonedArray = [...objArray]; // will clone the array

console.log( "before:" );
console.log( "obj array" , objArray );
console.log( "ref array" , refArray );
console.log( "cloned array" , clonedArray );

objArray[0] = {c:3};

console.log( "after:" );
console.log( "obj array" , objArray ); // [ {c:3} , {b:2} ]
console.log( "ref array" , refArray ); // [ {c:3} , {b:2} ]
console.log( "cloned array" , clonedArray ); // [ {a:1} , {b:2} ]
Понравилась статья? Поделиться с друзьями:
JavaScript & TypeScript
Adblock
detector