Вот альтернатива методу, описанному poke:
Сначала я хотел бы сделать несколько замечаний по поводу сообщения poke.
"Определите свою собственную функцию клонадля этого конкретного объекта. Не существует специальной функции, которая делает это автоматически для любого произвольного объекта. "Ложь.ActionScript имеет встроенный метод сериализации, называемый AMF (ActionScript Message Format).AMF может использоваться для выполнения копирования не примитивных объектов.
«Использование пользовательского метода клонирования имеет большое преимущество в том, что вы можете точно решить, что будет копироваться и как он будет копироваться ...» Это именно то, что вы делаете, когдавы сериализуете объект, так что нет особого преимущества вашего пользовательского метода клонирования по сравнению с сериализацией.
"... и что тип возвращаемого значения правильный (т.е.надо лить)Вам также не нужно приводить сериализованный объект.Но сериализация имеет дополнительное преимущество: она универсальна, делает функцию копирования динамической, а не ограничивается конкретными типами.
"[реализация интерфейса] (что было бы крайне неуместно, учитываяэтот клон возвращает объект специального типа) «Необходимость определения возвращаемого типа делает процесс статичным, что привязывает вас к использованию определенных типов.Если мы используем динамические атрибуты языка, мы можем сделать общий метод клонирования и не заботиться о типе.В этом нет ничего неуместного.
«То, что вы получаете копию объекта, если дважды сериализуете сериализованный объект, является лишь дополнительным эффектом сериализации».Тот факт, что вы получаете копию массива, вызывая slice () или concat () без каких-либо аргументов, является лишь побочным эффектом этих методов.Я действительно не вижу твоей точки зрения здесь.Кроме того, в основе сериализации лежит копирование.Акт сериализации, а затем десериализации - это процесс создания копии.Как-то не получается вернуть ту же самую память со ссылками и без изменений.
И у меня есть один вопрос: как бы вы справились с вложенными не примитивными типами в вашем методе клонирования??
В своем вопросе вы утверждаете: «Может ли кто-нибудь помочь мне понять, как копировать, например, массив, по значению (не по ссылке)? Я думаю, что при копировании объектов важно знатьразница между мелкими и глубокими копиями.
мелкими копиями
Решения, представленные здесь (Array.slice () и Array.concat ()) известны как мелкие копии.То, что вы получаете, является копией массива.Если содержимое массива является примитивным типом (передаваемым по значению, а не по ссылке), то у вас есть два уникальных объекта: оригинал и копия.Однако, если ваш массив содержит объекты, которые передаются по ссылке, то и оригинал, и копия массива будут иметь одинаковое содержимое.Если вы внесете изменения в объект в исходном массиве, изменения будут отражены в скопированном массиве.Хотя иногда это может быть тем, что вам нужно, но не всегда.
Глубокие копии
Глубокая копия будет проходить по иерархии объекта, который вы хотите скопировать, и делать копии любого найденного объекта.,После этого вам будет разрешено внести любые изменения в скопированный объект без изменений, отраженных в оригинале.
Если вы хотите определить пользовательский метод клонирования, как предлагает poke, то копирование непечатных типов становится слишком сложным.Вам нужно будет просмотреть свойства объекта и вызвать пользовательский метод clone () для любого не примитивного типа.Однако, если вы столкнулись со встроенным не примитивным типом, таким как Array или Dictionary, тогда вам придется воссоздать объект, просмотреть его содержимое и начать все заново, проверив, не является ли он примитивным, вызвав его clone ().метод, если он есть, или работа с массивами и словарями.Это становится слишком сложным.Подводя итог, этот метод имеет две проблемы: вам приходится иметь дело с массивами и словарями (и любыми встроенными не примитивными типами) самостоятельно;Вы должны специально вызывать метод clone для вложенных объектов (и знать, что у них определен метод clone).
Другой метод заключается в использовании AMF для сериализации, а затем десериализации объекта, что дает вам глубокую копию,Это работает прямо из коробки для массивов, словарей и любых не примитивов, которые зависят от общедоступных свойств.
var t:Array = [];
t[0] = [1, 2, 3];
t[1] = new Dictionary();
t[1]['hello'] = 'world';
t[2] = {'my': 'object'}
trace(t, t[1]['hello'], t[2]['my']); // [trace] 1,2,3,[object Dictionary],[object Object] world object
var t2:Array = clone(t);
trace(t2, t2[1]['hello'], t2[2]['my']); // [trace] 1,2,3,[object Dictionary],[object Object] world object
t[0] = [4, 5, 6];
t[1]['hello'] = 'earth';
t[2]['my'] = 'other object';
trace('modified values'); // [trace] modified values
trace(t, t[1]['hello'], t[2]['my']); // [trace] 4,5,6,[object Dictionary],[object Object] earth other object
trace(t2, t2[1]['hello'], t2[2]['my']); // [trace] 1,2,3,[object Dictionary],[object Object] world object
function clone(source:*):* {
var b:ByteArray = new ByteArray();
b.writeObject(source);
b.position = 0;
return(b.readObject());
}
Это охватывает первую проблему с пользовательским методом клонирования и пункт 1 выше.Как вы можете видеть, все объекты и их содержимое были скопированы с использованием встроенных методов.
Я показал реализацию того, как создать метод clone, здесь, но вы можете найти его в: mx.utils.ObjectUtil.
Если вы хотите глубоко копировать объект, который хранит свои данные в частном порядке, то вам нужно реализовать интерфейс IExternalizable.Это заставит вас реализовать два метода:
public function writeExternal(output:IDataOutput):void
public function readExternal(input:IDataInput):void
Внутри этих функций вы записываете свои закрытые переменные в выходной объект, а затем читаете их из ввода в свои закрытые переменные.Затем, когда вы вызываете клон, вы получите полную копию вашего объекта.Не забудьте сделать это для всех вложенных объектов.
Вот простой пример реализации с двумя классами:
package {
import flash.utils.IExternalizable;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.net.registerClassAlias;
public class Car implements IExternalizable {
private var type:String;
private var contents:Array;
public function Car() {
registerClassAlias("Car", Car);
}
public function setVars(type:String, contents:Array):void {
this.type = type;
this.contents = contents;
}
public function setType(type:String):void {
this.type = type;
}
public function writeExternal(output:IDataOutput):void {
output.writeUTF(type);
output.writeObject(contents);
}
public function readExternal(input:IDataInput):void {
type = input.readUTF();
contents = input.readObject();
}
public function toString():String {
return "[Car type = " + type + ", contents = " + contents + "]";
}
}
}
И:
package {
import flash.utils.IExternalizable;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.net.registerClassAlias;
public class Person implements IExternalizable {
private var firstName:String;
private var secondName:String;
public function Person() {
registerClassAlias("Person", Person);
}
public function setVars(firstName:String, secondName:String):void {
this.firstName = firstName;
this.secondName = secondName;
}
public function writeExternal(output:IDataOutput):void {
output.writeUTF(firstName);
output.writeUTF(secondName);
}
public function readExternal(input:IDataInput):void {
firstName = input.readUTF();
secondName = input.readUTF();
}
public function toString():String {
return "[Person firstName = " + firstName + ", secondName = " + secondName + "]";
}
}
}
Чтобы проверить их:
package {
import flash.display.Sprite;
import flash.utils.ByteArray;
import flash.utils.Dictionary;
public class Serial extends Sprite {
public function Serial() {
var person0:Person = new Person();
person0.setVars("John", "Doe");
var person1:Person = new Person();
person1.setVars("Jane", "Doe");
var car0:Car = new Car();
car0.setVars("Ford", [person0, person1]);
var person2:Person = new Person();
person2.setVars("Joe", "Bloggs");
var car1:Car = new Car();
car1.setVars("Vauxhall", [person2]);
var street:Array = [car0, car1];
trace("street = " + street); // [trace] street = [Car type = Ford, contents = [Person firstName = John, secondName = Doe],[Person firstName = Jane, secondName = Doe]],[Car type = Vauxhall, contents = [Person firstName = Joe, secondName = Bloggs]]
var street2:Array = clone(street);
trace("street2 = " + street2); // [trace] street2 = [Car type = Ford, contents = [Person firstName = John, secondName = Doe],[Person firstName = Jane, secondName = Doe]],[Car type = Vauxhall, contents = [Person firstName = Joe, secondName = Bloggs]]
person0.setVars("Max", "Headroom");
person1.setVars("Simon", "Le Bon");
car0.setType("Mini");
person2.setVars("Harry", "Wotsit");
car1.setType("Austin");
trace("modified values of street"); // [trace] modified values of street
trace("street = " + street); // [trace] street = [Car type = Mini, contents = [Person firstName = Max, secondName = Headroom],[Person firstName = Simon, secondName = Le Bon]],[Car type = Austin, contents = [Person firstName = Harry, secondName = Wotsit]]
trace("street2 = " + street2); // [trace] street2 = [Car type = Ford, contents = [Person firstName = John, secondName = Doe],[Person firstName = Jane, secondName = Doe]],[Car type = Vauxhall, contents = [Person firstName = Joe, secondName = Bloggs]]
}
private function clone(source:*):* {
var b:ByteArray = new ByteArray();
b.writeObject(source);
b.position = 0;
return(b.readObject());
}
}
}
Это покрывает вторую проблему с помощью пользовательского метода клонирования.Как вы можете видеть, нам не нужно было беспокоиться о вызове каких-либо методов клонирования, об этом все позаботились о нас.
Я не говорю, что это не лишено недостатков, но это обеспечиваетнекоторые функции для глубокого копирования объектов.
Некоторые недостатки включают в себя:
- В конструкторе не должно быть никаких обязательных параметров.
- Он не хранит справочные данные,поэтому, если два объекта содержат одну и ту же ссылку, вы получите два разных объекта обратно.
- Куда поместить метод клонирования.Я думаю, что это действительно относится к объекту, возможно, к прототипу.Это даст дополнительное преимущество, заключающееся в том, что каждый объект будет копироваться, и при желании вы можете точно указать, как копируется ваш объект.
См. Точку зрения Adobe на копирование массивов: http://livedocs.adobe.com/flex/3/html/help.html?content=10_Lists_of_data_6.html
Также обратите внимание, что Adobe украла эту технику из Java.