Точно клонируйте объект в JavaScript

Я пытался точно клонировать объект в JavaScript. Я знаю следующее решение с помощью jQuery:

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

но проблема с то есть, что тип объектов теряется:

var MyClass = function(param1, param2) {
    alert(param1.a + param2.a);
};
var myObj = new MyClass({a: 1},{a: 2});
var myObjClone = jQuery.extend(true, {}, myObj);
alert(myObj instanceof MyClass);      // => true
alert(myObjClone instanceof MyClass); // => false

Там какое-либо решение состоит в том, чтобы стать верным на втором предупреждении?

20
задан Tom 14 February 2010 в 18:10
поделиться

3 ответа

jQuery.extend не ожидает от вас использования оператора instanceof. Это великолепно сложная копия, а не настоящий клон. Недостаточно перебирать элементы. Кроме того, вызов конструктора - не лучший вариант, потому что вы потеряете свои аргументы. Попробуйте следующее:

var MyClass = function(param1, param2) {
    alert(param1.a + param2.a);
    this.p1 = param1;
    this.p2 = param2;
};

function Clone() { }
function clone(obj) {
    Clone.prototype = obj;
    return new Clone();
}

var myObj = new MyClass({a: 1},{a: 2});
var myObjClone = clone(myObj);
alert(myObj instanceof MyClass);      // => true
alert(myObjClone instanceof MyClass); // => true
console.log(myObj);       //note they are
console.log(myObjClone)   //exactly the same

Имейте в виду, что, поскольку ваш прототип теперь указывает на исходный объект (myObj), любые изменения в myObj будут отражаться в myObjClone. Прототипное наследование в Javascript довольно сложно. Вы должны быть уверены, что ваш новый объект имеет правильный прототип и, следовательно, правильный конструктор.

По общему признанию, у меня болит голова от Javascript. Тем не менее, я думаю, что я правильно понял из спецификации языка ECMAScript :

13.2.2 [[Construct]]
Когда [[Construct]] внутренний Для объекта Function F вызывается с возможно пустым списком аргументов, предпринимаются следующие шаги:

  1. Пусть obj будет вновь созданным собственным объектом ECMAScript.
  2. Установите все внутренние методы obj, как указано в 8.12.
  3. Установите для внутреннего свойства [[Class]] объекта obj значение «Object».
  4. Установите для внутреннего свойства [[Extensible]] объекта obj значение true.
  5. Пусть proto будет значением вызова внутреннего свойства [[Get]] для F с аргументом> "прототип".
  6. Если Type (proto) - Object, установите внутреннему свойству [[Prototype]] объекта obj значение proto.
  7. Если Тип (прототип) не является Объектом, установите внутреннее свойство [[Prototype]] объекта obj равным> стандартному встроенному объекту-прототипу Object, как описано в 15.2.4.
  8. Пусть result будет результатом вызова внутреннего свойства [[Call]] объекта F, предоставления> obj в качестве значения this и предоставления списка аргументов, переданных в [[Construct]] в качестве аргументов.
  9. Если Тип (результат) - Объект, то вернуть результат.
  10. Вернуть объект.

Этот человек , кажется, понимает эту концепцию намного лучше меня. K, я сейчас возвращаюсь в java, где я больше плаваю, чем тону :).

12
ответ дан 30 November 2019 в 01:10
поделиться

Вы не думали использовать функцию clone предложенную здесь?

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

var MyClass = function(param1, param2) {};
var myObj = new MyClass(1,2);
var myObjClone = clone(myObj);
alert(myObj instanceof MyClass);      // => true
alert(myObjClone instanceof MyClass); // => true
4
ответ дан 30 November 2019 в 01:10
поделиться
function clone( obj ) {  
    var target = new obj.constructor();  
    for ( var key in target ) { delete target[key]; }  
    return $.extend( true, target, obj );  
}  

$. Extend не может скопировать все внутренние свойства, которые не видны (некоторые из них видны в firefox), но если obj.constructor является правильным и не будет работать без аргументов, внутренние свойства могут быть установлены с помощью new obj.constructor () . Если вы выполняете наследование с помощью чего-то вроде Derived.prototype = new Base () , вам также необходимо выполнить наследование с помощью Derived.prototype.constructor = Derived , чтобы конструктор был правильным.

Вы могли бы сделать $.extend (true, new obj.constructor (), obj) , но возможно, что конструктор создает свойства, которые позже были удалены - даже если вы могли правильно получить аргументы конструктора - вот почему свойства должны быть удалены перед делая расширение. Не имеет значения, что аргументы конструктора неверны, поскольку эффекты исходных аргументов конструктора - плюс все остальное, что произошло с объектом с тех пор - находятся в объекте, который мы клонируем.

1
ответ дан 30 November 2019 в 01:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: