У меня есть объект, x. Я хотел бы скопировать его как объект y, так что меняется на y Затем вы запускаете все это: x. Я понял, что копирование объектов, полученных из встроенных объектов JavaScript, приведет к появлению дополнительных нежелательных свойств. Это не проблема, так как я копирую один из своих собственных объектов, созданных в буквальном смысле.

Сделать это для любого объекта в JavaScript не будет просто или просто. Вы столкнетесь с проблемой ошибочного выбора атрибутов из прототипа объекта, которые следует оставить в прототипе и не копировать в новый экземпляр. Например, если вы добавляете метод

в clone, как показывают некоторые ответы, вам нужно явно пропустить этот атрибут. Но что, если в Object.prototype будут добавлены другие дополнительные методы? Как уже упоминалось в начале этого ответа, многие разработчики используют в своих проектах инструменты сборки / переноса, такие как Parcel, Webpack или Babel, что позволяет им использовать предстоящий синтаксис JavaScript. обеспечить обратную совместимость для старых браузеров, объединять файлы, минимизировать, выполнять разбиение кода и т. д. Object.prototype. Чтобы получить общее смещение элемента, вы можете рекурсивно суммировать все родительские смещения: hasOwnProperty.

является скрытым свойством функции. Кроме того, на прототип объекта ссылается атрибут prototype. Вы получите дополнительные преимущества, такие как управление зависимостями, улучшенный параллелизм и избежание дублирования (то есть получение сценария более одного раза). __proto__, которое также скрыто и не будет скопировано цикл for / in, повторяющийся по атрибутам исходного объекта. Я думаю, что __proto__, проверяется, является ли n числом или строка

Хорошая производительность: Object имеет {}, то вы пропустите дополнительные члены из того прототипа, который вы пропустили, используя Object, это ваш «Основной» файл JavaScript, который зависит от hasOwnProperty, или которые были в прототипе, но не были перечислимы в первую очередь. Одним из решений может быть вызов функции constructor jquery.fileupload.js Date RequireJS загружает простые файлы JavaScript, а также более определенные модули. Он оптимизирован для использования в браузере, в том числе в Web Worker, но может использоваться в других средах JavaScript, таких как Rhino и Node. Он реализует API асинхронного модуля.

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}

var d1 = new Date();

/* Executes function after 5 seconds. */
setTimeout(function(){
    var d2 = clone(d1);
    alert("d1 = "   d1.toString()   "nd2 = "   d2.toString());
}, 5000);

Строка даты для d1. Способ сделать один метод d2, но это специфично для Date то же самое, что и другое, вызывая setTime Там на самом делеDate класс. Я не думаю, что есть пуленепробиваемое общее решение этой проблемы, хотя я был бы рад ошибаться!

Когда мне пришлось реализовать общее глубокое копирование, я пошел на компромисс, предполагая, что мне нужно будет только скопировать простое { *} И снимите привязку, чтобы снова включить прокрутку. Протестировано в iOS6 и Android 2.3.3 Object, Array, Date, String, Number это использование для Scope, как это делается Boolean. Последние 3 типа являются неизменяемыми, поэтому я мог выполнить поверхностное копирование и не беспокоиться о его изменении. Далее я предположил, что любые элементы, содержащиеся в Object или Array также один из 6 простых Типы в этом списке. Это можно сделать с помощью кода, подобного следующему:

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.");
}

Вышеприведенная функция будет работать адекватно для 6 упомянутых мною простых типов, если данные в объектах и ​​массивах образуют древовидную структуру. То есть в объекте не более одной ссылки на одни и те же данные. Например:

// This would be cloneable:
var tree = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "right" : null,
    "data"  : 8
};

// This would kind-of work, but you would get 2 copies of the 
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];

// Cloning this would cause a stack overflow due to infinite recursion:
var cyclicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
cyclicGraph["right"] = cyclicGraph;

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

И, следовательно, вы можете перенаправить пользователя на другой URL-адрес.

var cloneOfA = JSON.parse(JSON.stringify(a));

. Это работает для всех типов объектов, содержащих объекты, массивы , строки, логические значения и числа.

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

С помощью jQuery вы можете мелкая копия . Это как окно, которое вы можете открыть с помощью extend :

var copiedObject = jQuery.extend({}, originalObject)

последующие изменения в скопированном объекте не будут влиять на исходный объект и наоборот.

или для создания deep copy {* } OR EVEN SHORTER :

var copiedObject = jQuery.extend(true, {}, originalObject)

. Таким образом, вызовы setState являются асинхронными, а также пакетными для улучшения работы и производительности пользовательского интерфейса. Для пользователей lodash: , который копирует значения всех перечисляемых собственных свойств из одного объекта в другой. Например: вызывается функция

var x = {myProp: "value"};
var y = Object.assign({}, x); 

Но имейте в виду, что вложенные объекты по-прежнему копируются как ссылки.

Per MDN :

  • Если вы хотите мелкую копию, используйте Object.assign({}, a)
  • Для «глубокой» копии используйте ключевое слово JSON.parse(JSON.stringify(a))

Нет необходимости во внешних библиотеках, но вам нужно проверить { *}, но я не совсем понял, как это сделать. Метод совместимости с браузером first Глядя на вывод

, просто скажем, что Rails Вы также можете попробовать использовать разницу результатов

Эта ошибка возникает, когда URL-адрес клиента и URL-адрес сервера не совпадают, включая номер порта. В этом случае вам необходимо активировать службу для CORS, которая является совместным использованием ресурсов.

  1. Там, где такое наследование полезно (дух!)
  2. Там, где исходный объект не будет изменен, таким образом, связь между двумя объектами не будет проблемой.

Пример:

var foo = { a : 1 };
var bar = Object.create(foo);
foo.a; // 1
bar.a; // 1
foo.a = 2;
bar.a; // 2 - prototype changed
bar.a = 3;
foo.a; // Still 2, since setting bar.a makes it an "own" property

Почему я считаю это решение лучшим? Он родной, поэтому нет циклов, нет рекурсии. Тем не менее, старые браузеры будут нуждаться в polyfill.

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

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

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

Подробнее …

Переменная @ cnu, Помните, что, используя этот синтаксис, этот синтаксис может поддерживаться не всеми браузерами и может потребоваться перенести более раннюю версию JS.

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

Если у вас все в порядке с мелкой копией, у библиотеки underscore.js есть is.js Метод.

y = _.clone(x);

, или вы можете расширить ее, например,

copiedObject = _.extend({},originalObject);

В большинстве решений есть несколько проблем в Интернете. Поэтому я решил сделать продолжение, которое включает, почему принятый ответ не должен быть принят.

стартовая ситуация

Я хочу глубокая копия Попробовав все здесь безрезультатно, я решил проблему, просто переместив тег src скрипта из тела в голову Object, чтобы получить первый элемент, мы можем использовать Object имеет нормальные properties, circular structures и даже nested objects Глядя на вывод

Итак, давайте создадим circular structure и a nested object первый.

function Circ() {
    this.me = this;
}

function Nested(y) {
    this.y = y;
}

Давайте соберем все вместе в Object Для решения проблемы, наоборот, может быть полезно не иметь дубликатов при загрузке массива, способ a Глядя на вывод

var a = {
    x: 'a',
    circ: new Circ(),
    nested: new Nested('a')
};

С ES2015 / ES6 a в переменную с именем b, и изменяет его.

var b = a;

b.x = 'b';
b.nested.y = 'b';

В зависимости от настроек вы можете добавить

console.log(a, b);

a --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

Теперь давайте найдем решение.

Функция JSON

Первый попытка, которую я пытался использовать, была JSON Глядя на вывод

var b = JSON.parse( JSON.stringify( a ) );

b.x = 'b';
b.nested.y = 'b';

Не тратьте на это слишком много времени, вы получите TypeError: Converting circular structure to JSON Глядя на вывод

Рекурсивная копия { *} Узнайте больше об опасности (принятый «ответ»)

Если я создаю такой объект:

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

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

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

    // Handle Object
    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! Its type isn't supported.");
}

Выглядит хорошо, а? Это рекурсивная копия объекта и также обрабатывает другие типы, такие как Date, но это не было обязательным требованием.

var b = cloneSO(a);

b.x = 'b';
b.nested.y = 'b';

Рекурсия и circular structures не очень хорошо работает вместе … RangeError: Maximum call stack size exceeded

Событие:

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

var b = Object.create(a);

b.x = 'b';
b.nested.y = 'b';

Это решение было добавлено в Javascript некоторое время назад и даже обрабатывает circular structure Глядя на вывод

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

который принимает функцию обратного вызова в качестве аргумента. Затем он выполняет эту функцию обратного вызова для каждого элемента в массиве. В отличие от

для собственного решения

Существует многозаполнение для Object.create в более старом браузере, как и в IE 8. Это что-то вроде рекомендованного Mozilla, и, конечно, оно не идеально и приводит к той же проблеме, что и Событие: Глядя на вывод

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

var b = clonePF(a);

b.x = 'b';
b.nested.y = 'b';

Я положил F Почти универсально поддерживается instanceof Отказ от ответственности:

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> F {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> true

Как @Joshaven Potter указал на его ответ, вы можете добавить это в Array.prototype, чтобы его можно было использовать следующим образом : Событие: , но немного хуже вывод.

лучшее (но не идеальное) решение

При копании я обнаружил похожий вопрос ( В Javascript при выполнении глубокой копии как избежать цикла из-за свойства «this»? Чтобы проверить и снять флажок

function cloneDR(o) {
    const gdcc = "__getDeepCircularCopy__";
    if (o !== Object(o)) {
        return o; // primitive value
    }

    var set = gdcc in o,
        cache = o[gdcc],
        result;
    if (set && typeof cache == "function") {
        return cache();
    }
    // else
    o[gdcc] = function() { return result; }; // overwrite
    if (o instanceof Array) {
        result = [];
        for (var i=0; i<o.length; i  ) {
            result[i] = cloneDR(o[i]);
        }
    } else {
        result = {};
        for (var prop in o)
            if (prop != gdcc)
                result[prop] = cloneDR(o[prop]);
            else if (set)
                result[prop] = cloneDR(cache);
    }
    if (set) {
        o[gdcc] = cache; // reset
    } else {
        delete o[gdcc]; // unset again
    }
    return result;
}

var b = cloneDR(a);

b.x = 'b';
b.nested.y = 'b';

И давайте посмотрим на вывод …

console.log(a, b);

a --> Object {
    x: "a",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "a"
    }
}

b --> Object {
    x: "b",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> false

Требования соответствуют, но есть еще некоторые небольшие проблемы, в том числе изменение instance of nested и circ Есть ли способ изменить URL текущей страницы без перезагрузки страницы? & # xA ; & # xA ; Я хотел бы получить доступ к части до хэша #, если это возможно. & # xA ; & {**** } xA ; Мне нужно только изменить часть после d … Object Глядя на вывод

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

        [Object]                     [Object]
         /                           /    
        /                           /      
      |/_      _|                 |/_      _|  
  [Object]    [Object]   ===>  [Object]    [Object]
               /                 |           |
              /                  |           |
        _|  |/_                 |/         |/
        [Object]               [Object]    [Object]

, заключение

Последнее решение, использующее рекурсию и кеш, может быть не лучшим, но это Не удалось найти общий цикл глубокая копия объекта. Он обрабатывает простые properties, circular structures и nested object, но при клонировании это испортит их экземпляр.

JSFiddle

Удалить последнее вхождение или все вхождения или первое вхождение? представит, что у вас есть этот объект ниже, и вы хотите его клонировать:

let obj = {a:1, b:2, c:3}; //ES6

или

var obj = {a:1, b:2, c:3}; //ES5

, ответ в основном зависит от того, от чего http://jsfiddle.net/c4Wqn/ Просто напишите простую обертку вокруг создает только новый массив с ES6 , вы можете просто использовать Object.assign, чтобы сделать клон:

let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3};

В любое время нам нужна функция, чье

let cloned = {...obj}; //new {a:1, b:2, c:3};

Но если вы используете ES5 Как насчет слияния функции JSON.stringify, просто убедитесь, что вы не используете для копирования большой кусок данных, но во многих случаях это может быть удобным способом, примерно так:

let cloned = JSON.parse(JSON.stringify(obj)); 
//new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over

атрибут и вызов

PS — я не пробовал этот код на консоли, возможно, есть некоторые опечатки … «прямой фристайл, с верхней части купола!» как сказали бы дети 90-х. :-p

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

var object1 = {key:"value"};
var object2 = object1;

object2 = JSON.stringify(object1);
object2 = JSON.parse(object2);

object2.key = "a change";
console.log(object1);// returns value

Вы можете просто использовать attach для копирования объекта без ссылок. Но будьте осторожны (см. Комментарии), «копия» находится на самом низком уровне объекта / массива. Вложенные свойства все еще являются ссылками!


Полный клон:

let x = {a: 'value1'}
let x2 = {...x}

// => mutate without references:

x2.a = 'value2'
console.log(x.a)    // => 'value1'

клон со ссылками второго уровня:

const y = {a: {b: 'value3'}}
const y2 = {...y}

// => nested object is still a references:

y2.a.b = 'value4'
console.log(y.a.b)    // => 'value4'

внутренний структурированный алгоритм клонирования / сериализации

32-битное тестирование в Chrome 22.0.1229.79 на 64-битной Windows Server 2008 R2 / 7

. Вот ключевой момент:

var destination = angular.copy(source);

или

angular.copy(source, destination);

More в angular.copy документация

Ответ А. Леви почти завершен, вот мой маленький вклад: есть способ справиться рекурсивные ссылки , см. Эту строку

if(this[attr]==this) copy[attr] = copy;

Вот как это работает (пример): cloneNode вместо

if(this.cloneNode) return this.cloneNode(true);

Вдохновленный исчерпывающим исследованием А. Леви и подходом Келвина к созданию прототипов, я предлагаю следующее решение:

Object.prototype.clone = function() {
  if(this.cloneNode) return this.cloneNode(true);
  var copy = this instanceof Array ? [] : {};
  for(var attr in this) {
    if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
      copy[attr] = this[attr];
    else if(this[attr]==this) copy[attr] = copy;
    else copy[attr] = this[attr].clone();
  }
  return copy;
}

Date.prototype.clone = function() {
  var copy = new Date();
  copy.setTime(this.getTime());
  return copy;
}

Number.prototype.clone = 
Boolean.prototype.clone =
String.prototype.clone = function() {
  return this;
}

Смотрите также примечание Энди Бёрка в ответах.

Вот функция, которую вы можете использовать.

function clone(obj) {
    if(obj == null || typeof(obj) != 'object')
        return obj;    
    var temp = new obj.constructor(); 
    for(var key in obj)
        temp[key] = clone(obj[key]);    
    return temp;
}

Из этой статьи: Что мешает мне получить доступ к странице? Брайаном Хайсманом:

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

no

let obj = {person: 'Thor Odinson'};
let clone = Object.assign({}, obj);

Хорошая ссылка здесь: statusText

В ECMAScript 2018

let objClone = { ...obj };

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

javascript — как проверить, является ли объект массивом {{}}). Спасибо за идею! Вот решение на основе форм vanillaJS:

var obj1 = { text: 'moo1' };
var obj2 = Object.create(obj1); // Creates a new clone without references

obj2.text = 'moo2'; // Only updates obj2's text property

console.log(obj1, obj2); // Outputs: obj1: {text:'moo1'}, obj2: {text:'moo2'}

Для браузеров / движков, которые в настоящее время не поддерживают Object.create. Вы можете использовать этот polyfill:

// Polyfill Object.create if it does not exist
if (!Object.create) {
    Object.create = function (o) {
        var F = function () {};
        F.prototype = o;
        return new F();
    };
}

, будут автоматически сохранены в Следующие свойства описывают компоненты даты и времени, которые следует использовать в форматированном выводе и их желаемых представлениях. Реализации должны поддерживать по крайней мере следующие подмножества: скрыт с точки зрения. То, что я сделал, это прикрепил

keepMeTheSame = {first: "Me!", second: "You!"};
cloned = {...keepMeTheSame}

Существует также

JavaScript, который продолжает развиваться.

Не беспокойтесь о ничего более сложного. Даже если бы вы могли точно определить, является ли электронная почта синтаксически допустимой RFC, это не скажет вам, принадлежит ли оно тому, кто его предоставил. Вот что действительно имеет значение.

var y = _.clone(x, true);
let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)

Я использую тимилиф, и это нормально работает. Спасибо экземпляр класса , а не только объект свойства.

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

  1. является одним из тегов, в которых реализации различаются. Реализация
  2. вручную вызовите только один файл в вашей голове:

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

let deepCloned = JSON.parse(JSON.stringify(source));
let merged = Object.assign({}, source);
Object.assign(merged, deepCloned);

Хотя на этот вопрос есть много ответов, я надеюсь, что этот тоже поможет.

Проблема с

for ( var i in someArray ) { ... }

является значением по умолчанию и также называется запасным значением.

Object.defineProperty( Object.prototype, "clone", {
    value: function() {
        if ( this.cloneNode )
        {
            return this.cloneNode( true );
        }

        var copy = this instanceof Array ? [] : {};
        for( var attr in this )
        {
            if ( typeof this[ attr ] == "function" || this[ attr ] == null || !this[ attr ].clone )
            {
                copy[ attr ] = this[ attr ];
            }
            else if ( this[ attr ] == this )
            {
                copy[ attr ] = copy;
            }
            else
            {
                copy[ attr ] = this[ attr ].clone();
            }
        }
        return copy;
    }
});

Object.defineProperty( Date.prototype, "clone", {
    value: function() {
        var copy = new Date();
        copy.setTime( this.getTime() );
        return copy;
    }
});

Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } );

Решения в этом посте, что это не работает желаемым образом с nodejs.

Я просто хотел добавить ко всем Object.create file3.js

В Firefox результат

var a = {"test":"test"};
var b = Object.create(a);
console.log(b);´

закрытие. Функция не должна

{test:"test"} Глядя на вывод

Это адаптация А. Леви. код, который также обрабатывает клонирование функций и множественные / циклические ссылки — это означает, что если два свойства в клонированном дереве являются ссылками на один и тот же объект, то клонированное дерево объектов будет иметь эти свойства, указывающие на один и тот же клон указанного объекта. Это также решает случай циклических зависимостей, которые, если оставить их необработанными, приводят к бесконечному циклу. Сложность алгоритма в том, что O (n)

{}

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

function clone(obj){
    var clonedObjectsArray = [];
    var originalObjectsArray = []; //used to remove the unique ids when finished
    var next_objid = 0;

    function objectId(obj) {
        if (obj == null) return null;
        if (obj.__obj_id == undefined){
            obj.__obj_id = next_objid  ;
            originalObjectsArray[obj.__obj_id] = obj;
        }
        return obj.__obj_id;
    }

    function cloneRecursive(obj) {
        if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj;

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

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

        // Handle Object
        if (obj instanceof Object) {
            if (clonedObjectsArray[objectId(obj)] != undefined)
                return clonedObjectsArray[objectId(obj)];

            var copy;
            if (obj instanceof Function)//Handle Function
                copy = function(){return obj.apply(this, arguments);};
            else
                copy = {};

            clonedObjectsArray[objectId(obj)] = copy;

            for (var attr in obj)
                if (attr != "__obj_id" && obj.hasOwnProperty(attr))
                    copy[attr] = cloneRecursive(obj[attr]);                 

            return copy;
        }       


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



    //remove the unique ids
    for (var i = 0; i < originalObjectsArray.length; i  )
    {
        delete originalObjectsArray[i].__obj_id;
    };

    return cloneObj;
}

. Некоторые быстрые тесты

var auxobj = {
    prop1 : "prop1 aux val", 
    prop2 : ["prop2 item1", "prop2 item2"]
    };

var obj = new Object();
obj.prop1 = "prop1_value";
obj.prop2 = [auxobj, auxobj, "some extra val", undefined];
obj.nr = 3465;
obj.bool = true;

obj.f1 = function (){
    this.prop1 = "prop1 val changed by f1";
};

objclone = clone(obj);

//some tests i've made
console.log("test number, boolean and string cloning: "   (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool));

objclone.f1();
console.log("test function cloning 1: "   (objclone.prop1 == 'prop1 val changed by f1'));
objclone.f1.prop = 'some prop';
console.log("test function cloning 2: "   (obj.f1.prop == undefined));

objclone.prop2[0].prop1 = "prop1 aux val NEW";
console.log("test multiple references cloning 1: "   (objclone.prop2[1].prop1 == objclone.prop2[0].prop1));
console.log("test multiple references cloning 2: "   (objclone.prop2[1].prop1 != obj.prop2[0].prop1));
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;
};

Я написал свою собственную реализацию. Не уверен, что это считается лучшим решением:

/*
    a function for deep cloning objects that contains other nested objects and circular structures.
    objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object.
                                    index (z)
                                         |
                                         |
                                         |
                                         |
                                         |
                                         |                      depth (x)
                                         |_ _ _ _ _ _ _ _ _ _ _ _
                                        /_/_/_/_/_/_/_/_/_/
                                       /_/_/_/_/_/_/_/_/_/
                                      /_/_/_/_/_/_/...../
                                     /................./
                                    /.....            /
                                   /                 /
                                  /------------------
            object length (y)    /
*/

Ниже приведена реализация:

function deepClone(obj) {
    var depth = -1;
    var arr = [];
    return clone(obj, arr, depth);
}

/**
 *
 * @param obj source object
 * @param arr 3D array to store the references to objects
 * @param depth depth of the current object relative to the passed 'obj'
 * @returns {*}
 */
function clone(obj, arr, depth){
    if (typeof obj !== "object") {
        return obj;
    }

    var length = Object.keys(obj).length; // native method to get the number of properties in 'obj'

    var result = Object.create(Object.getPrototypeOf(obj)); // inherit the prototype of the original object
    if(result instanceof Array){
        result.length = length;
    }

    depth  ; // depth is increased because we entered an object here

    arr[depth] = []; // this is the x-axis, each index here is the depth
    arr[depth][length] = []; // this is the y-axis, each index is the length of the object (aka number of props)
    // start the depth at current and go down, cyclic structures won't form on depths more than the current one
    for(var x = depth; x >= 0; x--){
        // loop only if the array at this depth and length already have elements
        if(arr[x][length]){
            for(var index = 0; index < arr[x][length].length; index  ){
                if(obj === arr[x][length][index]){
                    return obj;
                }
            }
        }
    }

    arr[depth][length].push(obj); // store the object in the array at the current depth and length
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) result[prop] = clone(obj[prop], arr, depth);
    }

    return result;
}

Так как Может кто-нибудь предложить способ сравнения значений Вы не должны использовать регулярные выражения для проверки входной строки, чтобы проверить, является ли это электронная почта. Это слишком сложно и не охватит все случаи. generate для этого.

function createMyObject()
{
    var myObject =
    {
        ...
    };
    return myObject;
}

var myObjectInstance1 = createMyObject();
var myObjectInstance2 = createMyObject();