Я пытался точно клонировать объект в 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
Там какое-либо решение состоит в том, чтобы стать верным на втором предупреждении?
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 вызывается с возможно пустым списком аргументов, предпринимаются следующие шаги:
- Пусть obj будет вновь созданным собственным объектом ECMAScript.
- Установите все внутренние методы obj, как указано в 8.12.
- Установите для внутреннего свойства [[Class]] объекта obj значение «Object».
- Установите для внутреннего свойства [[Extensible]] объекта obj значение true.
- Пусть proto будет значением вызова внутреннего свойства [[Get]] для F с аргументом> "прототип".
- Если Type (proto) - Object, установите внутреннему свойству [[Prototype]] объекта obj значение proto.
- Если Тип (прототип) не является Объектом, установите внутреннее свойство [[Prototype]] объекта obj равным> стандартному встроенному объекту-прототипу Object, как описано в 15.2.4.
- Пусть result будет результатом вызова внутреннего свойства [[Call]] объекта F, предоставления> obj в качестве значения this и предоставления списка аргументов, переданных в [[Construct]] в качестве аргументов.
- Если Тип (результат) - Объект, то вернуть результат.
- Вернуть объект.
Этот человек , кажется, понимает эту концепцию намного лучше меня. K, я сейчас возвращаюсь в java, где я больше плаваю, чем тону :).
Вы не думали использовать функцию 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
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)
, но возможно, что конструктор создает свойства, которые позже были удалены - даже если вы могли правильно получить аргументы конструктора - вот почему свойства должны быть удалены перед делая расширение. Не имеет значения, что аргументы конструктора неверны, поскольку эффекты исходных аргументов конструктора - плюс все остальное, что произошло с объектом с тех пор - находятся в объекте, который мы клонируем.