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

каков наиболее эффективный способ клонирования объекта JavaScript? Я видел obj = eval(uneval(o)); используется, но это нестандартно и поддерживается только Firefox.

я делал такие вещи, как obj = JSON.parse(JSON.stringify(o)); но вопрос эффективности.

Я также видел рекурсивные функции копирования с различных недостатков.
Я удивлен, что канонического решения не существует.

30 ответов


Примечание: Это ответ на другой ответ, а не правильный ответ на этот вопрос. Если вы хотите иметь быстрое клонирование объекта, пожалуйста, следуйте совет Корбана в их ответе на этот вопрос.


Я хочу отметить, что .clone() метод jQuery только клоны элементов DOM. Чтобы клонировать объекты JavaScript, вы должны сделать:

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

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

больше информации можно найти в документация jQuery.

Я также хочу отметить, что глубокая копия на самом деле намного умнее, чем показано выше, – она способна избежать многих ловушек (например, пытаясь глубоко расширить элемент DOM). Он часто используется в ядре jQuery и в плагинах с большим эффектом.


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

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

JSON.parse(JSON.stringify(obj))

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

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

если вы знаете структуру объектов, которые вы пытаетесь клонировать, или можете избежать глубоких вложенных массивов, вы можете написать простой for (var i in obj) цикл для клонирования объекта при проверке hasOwnProperty, и это будет намного быстрее, чем jQuery.

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

JavaScript трассировки двигатели сосать при оптимизации for..in петли и проверка hasOwnProperty также замедлит вас. Ручной клон, когда скорость является абсолютной необходимостью.

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

остерегайтесь, используя JSON.parse(JSON.stringify(obj)) метод on Date объекты - JSON.stringify(new Date()) возвращает строковое представление даты в формате ISO, который JSON.parse() не преобразовать обратно в


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

var newObject = JSON.parse(JSON.stringify(oldObject));

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

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;
}

Структурированные Клонирования

в HTML5 определяет внутренний "структурированный" алгоритм клонирования который может создавать глубокие клоны объектов. Он по-прежнему ограничен определенными встроенными типами, но в дополнение к нескольким типам, поддерживаемым JSON, он также поддерживает даты, регулярные выражения, карты, наборы, Blobs, FileLists, ImageDatas, разреженные массивы,Типизированные Массивы, и, вероятно, больше в будущем. Он также сохраняет ссылки в клонированных данных, позволяя он поддерживает циклические и рекурсивные структуры, которые вызывают ошибки для JSON.

прямая поддержка в браузерах: скоро?

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


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

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

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

Объект.методом 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;
}

Это то, что я использую:

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

глубокая копия по производительности: Рейтинг от лучшего до худшего

  • переназначение " = " (массивы строк, только массивы чисел)
  • Slice (строковые массивы, только числовые массивы)
  • конкатенация (массивы строк, только массивы чисел)
  • пользовательская функция: for-loop или рекурсивная копия
  • $jQuery.продлить
  • в формате JSON.разобрать (строки, массивы, числа массивы, массивы объектов - только)
  • подчеркивания.js ' s _.clone (строковые массивы, только числовые массивы)
  • Ло-Дэша _.cloneDeep

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

когда массив содержит числа и строки - функции, такие как .ломтик. ,)(concat (),.splice (), оператор присваивания " = " и подчеркивание.функция клонирования 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});

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

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

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

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

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

установить ему с

npm install clone

или пакет с Эндер.

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' } }

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


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.синтаксический анализ и формат JSON.преобразовать в строки.

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

3) AngularJs:

var  deepCopyObj = angular.copy(obj);

4) jQuery:

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

5) UnderscoreJs & Loadash:

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

надеюсь, что это поможет...


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

var newObject = _.clone(oldObject);

вот версия ответа 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;
}

эта функция также доступна в my simpleoo библиотека.

Edit:

вот более надежная версия (благодаря Джастину Маккэндлессу это теперь также поддерживает циклические ссылки):

/**
 * 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();
    };
}

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

var objToCreate = JSON.parse(JSON.stringify(cloneThis));

function clone(obj)
 { var clone = {};
   clone.prototype = obj.prototype;
   for (property in obj) clone[property] = obj[property];
   return clone;
 }

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

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

var newObject = object(oldObject);

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


EDIT:

это polyfill для Object.create, так что вы можете также использовать это.

var newObject = Object.create(oldObject);

Примечание: если вы используете некоторые из этого, у вас могут возникнуть проблемы с некоторыми итерации, которые используют hasOwnProperty. Так, create создать новый пустой объект, который наследует oldObject. Но это все еще полезно и практично для клонирования объектов.

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

newObject.a; // is 5

но:

oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false

Lodash имеет хороший _.cloneDeep(значение) способ:

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

мелкий экземпляр ОДН-вкладыш (ECMAScript 5th edition):

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

и мелкий экземпляр ОДН-вкладыш (6-е издание ECMAScript, 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

только потому, что я не видел AngularJS упомянул и подумал, что люди могут захотеть знать...

angular.copy также предлагается способ глубокого копирования объектов и массивов.


там, кажется, нет идеальных глубоких оператор клон, но для массивов объектов. Как показано в приведенном ниже коде, клонер jQuery Джона Ресига превращает массивы с нечисловыми свойствами в объекты, которые не являются массивами, а клонер JSON RegDwight отбрасывает нечисловые свойства. Следующие тесты иллюстрируют эти моменты в нескольких браузерах:

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)

У меня есть два хороших ответа в зависимости от того, является ли ваша цель клонировать "простой старый объект JavaScript" или нет.

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

для простых старых объектов JavaScript, проверенный и истинный хорошо способ клонирования объекта в современных средах выполнения довольно прост:

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

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

эффективно ли это? Черт возьми, да. Мы пробовали все виды методов клонирования, и это работает лучше всего. Я уверен, что некоторые ниндзя могли бы придумать более быстрый метод. Но я подозреваю, мы говорим о предельной прибыли.

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

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

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

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

http://davidwalsh.name/javascript-clone

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

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

этот код не только краткий, но и очень читаемый. Его довольно легко расширить.

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

Итак, поехали. Два подхода. На мой взгляд, оба метода эффективны.


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

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

протестировать функции...

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

AngularJS

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

var newObject = angular.copy(oldObject);

Я не согласен с ответом с наибольшим количество голосов здесь. А Рекурсивный Глубокий Клон is быстрее, чем в формате JSON.разобрать(в формате 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;
};

вот всеобъемлющий метод 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;
};

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

function clone(obj) {
  var regExp = /^\d{4}-\d{2}-\d{2}T\d{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;
  });
}

Я обычно использую var newObj = JSON.parse( JSON.stringify(oldObje) ); но, вот более правильно:

var o = {};

var oo = Object.create(o);

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

посмотреть устаревших браузеров!