Изменения одной переменной распространяются на другую

Например, у меня есть две коллекции ArrayCollection - firstAC и secondAC. Если я сделаю secondAC = firstAC, а затем внесу изменения в secondAC (возможно, добавлю к нему функцию фильтрации), он каким-то образом перейдет в firstAC, может ли кто-нибудь мне сказать, почему это происходит в Flex или Actionscript 3?

Что я могу сделать, если я хочу, чтобы secondAC получал все данные только из firstAC, но затем, когда я вношу изменения в secondAC, они не отображаются в firstAC?

Спасибо за ответы! Ладислав


person Ladislav    schedule 08.12.2009    source источник


Ответы (4)


В языках ECMAScript (AS1-3, JavaScript и др.) При использовании

var foo = //some value which is not a String or a Number

на самом деле вы говорите «foo теперь указывает на тот же объект, что и другая переменная». Это означает, что в этой ситуации оба массива будут иметь одинаковое значение:

var foo:Array = [ 1, 2, 3 ];
foo = bar;
bar.push( 4 );
trace( foo ); // 1, 2, 3, 4

Это также работает для функций:

var foo:Array = [ 1, 2, 3 ];
adder( foo );
function adder( bar:Array ):void {
    bar.push( 4 );
}

trace( foo ); // 1, 2, 3, 4

и он даже работает с XML:

var xml:XML = <root><foo/></root>;
var bar:XML = xml;
bar.children()[ 0 ].@bar = 1;
trace( xml.toXMLString() ); // <root><foo bar="1"/></root>

Это называется «передачей по ссылке» вместо «передачей по значению» или «передачей по копии». Это означает, что каждый раз при ссылке на элемент каждая переменная будет указывать на один и тот же объект.

Есть много способов обойти это, и большинство из них зависит от вашего контекста. Для массивов мне больше всего нравится Array.concat (), который возвращает буквальный клон массива. Это означает, что все, что я делаю с возвращаемым значением, никоим образом не повлияет на оригинал. Однако если я имею дело с XML, я сделаю что-то вроде: var xml2:XML = XML( xml.toXMLString() );.

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

var secondAC:ArrayCollection = new ArrayCollection( firstAC.source.concat() );

Это имеет основные преимущества не только в том, что он быстрее (он основан на скомпилированном коде вместо кода Flex SDK, и он также не создает сначала экземпляр нового массива, а затем повторно заполняет его), но также имеет явное преимущество - доступность в более старые версии SDK Flex 3 - он полностью обратно совместим.

person cwallenpoole    schedule 10.12.2009
comment
Большое спасибо за этот ответ, очень хорошие примеры ... спасибо за ваше время! Ладислав - person Ladislav; 11.12.2009

Когда вы пишете secondAC = firstAC, вы просто указываете, что secondAC и firstAC являются ссылками на одну и ту же коллекцию массивов.

Вы хотите клонировать первую коллекцию (например, копировать все элементы по одному).

У вас должно получиться что-то вроде:

secondAC = new ArrayCollection();
secondAC.addAll(firstAC); 
person phtrivier    schedule 08.12.2009
comment
Большое спасибо за объяснение, что происходит - person Ladislav; 09.12.2009

Я понятия не имею о Flex или Actionscript, но похоже, что firstAC и secondAC указывают на один и тот же массив, поэтому этого и следовало ожидать.

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

person Ariel    schedule 08.12.2009

Вместо secondAC = firstAC можно попробовать secondAC.addAll(firstAC).

person Wesley Petrowski    schedule 08.12.2009