Arraycollection通过值而不是flex 3中的引用传递给函数

时间:2011-05-06 22:15:48

标签: flex arraycollection

我想通过flex 3中的函数将arrayCollection#2 =设置为arrayCollection#1。我将两个数组都传递给一个函数并设置arrayCollection#2 = arrayCollection#1。但是,似乎没有通过引用传递arrayCollection#2,因为在函数调用之后,arrayCollection#2没有被更改。我的理解是它应该通过引用和工作传递,我做错了什么?以下是代码:

var AC1:ArrayCollection = new ArrayCollection;
var AC1.addItem(someObject);

var AC2:ArrayCollection = new ArrayCollection;

setAC2(AC1,AC2);
// AC2 is not set to AC1 after the function


private function setAC2(_ac1:ArrayCollection, _ac2:ArrayCollection):void
{
    _ac2 = _ac1;
}

4 个答案:

答案 0 :(得分:6)

请参阅Evaluation Strategy

AS使用“按对象传递”/“通过对象共享传递”。也就是说,传递“对象”(不是复制,克隆或复制),并且对该对象的任何修改都是共享的

但是,赋值_ac2 = _ac1仅更改[function的local]参数变量的值,并且在函数调用期间不会影响任何变量。传入的唯一内容是由函数调用中使用的变量(或任意表达式)的求值产生的值(“对象”)。

这是因为,如上所述,使用的策略是“按对象传递”而不是(因为文档说明“通过引用传递”,这实际上意味着“传递值”引用]“或只是......”通过对象“)。也就是说,术语“通过引用传递”实际上被滥用,因此令人困惑。 (它在许多语言和文档中被滥用。试图达到共同意义是一场艰苦的战斗。)

如果确实是“通过引用传递”,那么为_ac2分配新值会传播出去。 (在发表评论说AS是如何“通过引用传递”之前,请参阅顶部的链接并认为“通过引用传递”涵盖了C#的out/ref,VB的ByRef,TSQL的{{ 1}}和C ++的(引用)output - 这些概念不在AS,Javascript或Java中。但是,正如原始帖子中正确指出的那样(以及其他自我回复),情况并非如此 - 结论: AS不支持“通过引用传递”; 此外,文档(令人困惑的是)使用“通过引用传递”一词来表示“按对象传递”/“通过对象共享传递”。

有几种方法可以传播更改,按(我的)首选项的顺序排序:

  1. 返回新的适用值:&。这通常是最干净的。避免副作用和令人惊讶的代码。如果适当地包装在对象(或数组)中,则可以返回多个值。

  2. 使用闭包:AC2 = doSomeTransformation(AC1),其中doSomeTransformation可能如下所示:doSomeTranformation(AC1, function (newValue) { AC2 = newValue })。我通常只在函数本身的回调“在上下文中运行”或以CPS样式编写代码时才使用它。

  3. 改变一个对象(毕竟AS是“通过对象传递”)。 这非常狡猾,但它会起作用。 function doSomeTransformation(_ac1, finished) { ...; finished(_ac1) }其中doSomeTransformation看起来像var blah = {AC2: null}; doSomeTransformation(ac1, blah); ...; laterOn(blah.AC2)。一般不推荐。

  4. 快乐的编码。


    适用的摘录,来自Evaluation Strategy

    “按引用调用”:(我的主要参数“按引用调用”错误地使用是因为它已经具有明确定义的意义;重载的术语一些语言(如AS和Python)采用的方法只会增加混乱)

      
        

    在call-by-reference评估(也称为pass-by-reference)中,函数接收对用作参数的变量的隐式引用,而不是其值的副本。这通常意味着该函数可以修改用作参数的变量 - 其调用者将看到的内容

      

    “按对象调用”/“通过对象分享调用”:(但请注意它承认这些术语的不一致/本地化的地方;“按引用调用”一词经常被滥用暗示这些语义和“按引用的值调用”在某些上下文中使用也意味着同样的事情)

      
        

    call-by-sharing的语义与call-by-reference的不同之处在于,对函数内的函数参数的赋值对于调用者是不可见的(与by-reference语义不同),例如,如果传递了变量,则无法在调用者范围内模拟该变量的赋值。但是,由于该函数可以访问与调用者相同的对象(不进行复制),因此对于这些对象的突变(如果对象是可变的)在调用者中是可见的,这可能看起来与调用者不同。价值语义。

      

答案 1 :(得分:3)

ActionScript中的函数参数按值传递,而不是按引用传递。它与Java完全相同。您可以阅读详细信息here

答案 2 :(得分:1)

我看到的问题是

var AC1.addItem(someObject);

尝试在函数中添加项目。

var AC1:ArrayCollection = new ArrayCollection;
var AC2:ArrayCollection = new ArrayCollection;

addItemToArrayCollection( AC1 );
setAC2(AC1,AC2);
// AC2 should be pointing to the ArrayCollection that AC1 is pointing to.

private function setAC2(_ac1:ArrayCollection, _ac2:ArrayCollection):void
{
   _ac2 = _ac1;
}

private function addItemToArrayCollection( arrayCollection:ArrayCollection ):void
{
  arrayCollection.addItem( someObject );
}

您可以在分配后添加断点,并查看AC2应与AC1具有相同的对象。

答案 3 :(得分:1)

我相信@Constantiner走在正确的轨道上,但我认为他的解释缺乏细节;所以我将尝试更深入地解释一下;我最了解它。如果我错了,你会纠正我。

如上所述in the docs

  

在ActionScript 3.0中,所有参数都是   通过引用传递,因为所有   值存储为对象。然而,   属于基元的对象   数据类型,包括布尔值,   Number,int,uint和String   制造它们的特殊运营商   表现得好像他们经过了   值。

因此,ArrayCollection绝对是一个对象,而不是一个原始类型,所以它应该通过引用传递,并像通过引用传递一样。但是,您对ArrayCollection的引用变量是什么。从概念上讲,它只是一个指向包含实际Collection数据的内存空间的指针。以下是我对某些ASCII艺术的尝试:

                  |---|
 ac1(variable)--> |   | (ActualArrayCollection1)
                  |---|

                  |---|
 ac2(variable)--> |   | (ActualArrayCollection2)
                  |---|

重复一遍,ac1variable是指向某个内存空间的指针。 ac2variable是指向某些不同内存空间的指针。当您将其中一个作为参数传递给方法时,它将通过引用传递。所以,在方法中,你有这样的东西:

 ac1(variable)--> |---|
 ac1(argument)--> |   | (ActualArrayCollection1)
                  |---|

 ac2(variable)--> |---|
 ac2(argument)--> |   | (ActualArrayCollection2)
                  |---|

因此ac1变量和ac1argument都指向同一个存储空间;因为它们每个都包含相同的指针值。但是,ac1variable和ac1argument实际上持有不同的内存空间。他们不一样。

当该方法运行此行时:

_ac2 = _ac1;

你得到这样的东西:

 ac1(variable)--> |---|
 ac1(argument)--> |   | (ActualArrayCollection1)
 ac2(argument)--> |---|

 ac2(variable)--> |---|
                  |   | (ActualArrayCollection2)
                  |---|

当方法执行结束时,两个参数消失,原始指针变量保持不变。如果要在方法中进行这样的直接赋值,可以使用this关键字访问全局变量。这应该这样做:

   this._ac2 = _ac1;

当然,如果您正在访问类级变量,那么可能会破坏方法中封装的目的。

我肯定是编译器设计的专家,这样的事情会在早餐时吃掉它并吐出来。我希望我的ASCII艺术在多个浏览器/机器/操作系统/等之间保持一致。