在flex 3中,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;
}

请参见评估策略。

AS使用"通过对象传递"/"通过对象共享传递"。也就是说,传递"对象"(不是副本、克隆或副本),并且对对象的任何修改都是共享的

然而,赋值_ac2 = _ac1只改变[函数的局部]参数变量的值,在函数调用期间不会对任何变量产生影响。传入的唯一东西是值("对象"),这些值是由函数调用中使用的变量(或任何任意表达式)的求值产生的。

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

如果确实是"通过引用传递",那么将新值赋给_ac2将传播出去。(在提出评论说AS是如何"通过引用传递"之前,请参阅顶部的链接,并考虑"通过引用传递"涵盖了c#的out/ref, VB的ByRef, TSQL的output和c++的(参考)&的情况-这些概念不在AS, Javascript或Java中)。然而,正如原始帖子(以及额外的自我回复)中正确指出的那样,情况并非如此——结论: as不支持"通过引用传递";此外,文档(令人困惑地)使用术语"通过引用传递"来表示"通过对象传递"/"通过对象共享传递"。

有几种方法可以将更改传播出去,按(我的)偏好排序:

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

  2. 使用闭包:doSomeTranformation(AC1, function (newValue) { AC2 = newValue }),其中doSomeTransformation可能看起来像:function doSomeTransformation(_ac1, finished) { ...; finished(_ac1) }。我通常只在回调"在函数本身的上下文中运行"或以cps风格编写代码时使用它。

  3. 改变一个对象(毕竟AS是"通过对象传递")。这是非常讨厌的,但它会工作。var blah = {AC2: null}; doSomeTransformation(ac1, blah); ...; laterOn(blah.AC2)的doSomeTransformation可能看起来像function doSomeTransformation(_ac1, b) { ...; b.AC2 = _ac1; }。一般不建议使用

幸福的编码。


适用摘录,来自评估策略:

"调用引用":(我对"调用引用" 使用不正确的主要论点是它已经有一个定义良好的含义;某些语言(如as和Python)采用的重载术语只会增加混淆)

在按引用调用求值(也称为按引用传递)中,函数接收对用作参数的变量的隐式引用,而不是其值的副本。这通常意味着函数可以修改用作参数的变量——这将被调用者看到。

"调用对象"/"调用对象共享":(但要注意它承认这些术语的不一致/本地化;术语"按引用调用"经常被误用来暗示这些语义,而"按[引用的]值调用"在某些上下文中也被用来表示相同的含义)

按共享调用的语义与按引用调用的语义不同,在函数内对函数参数的赋值对调用者是不可见的(与按引用语义不同),因此,例如,如果传递了一个变量,在调用者的作用域中不可能模拟对该变量的赋值。然而,由于函数可以访问与调用者相同的对象(没有复制),如果对象是可变的,那么在函数内对这些对象的更改对调用者是可见的,这可能与按值调用语义不同。

ActionScript中的函数参数通过值传递,而不是通过引用传递。这与Java中的完全相同。

我看到的问题是

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相同的Object。

我相信@Constantiner是对的,但我认为他的解释缺乏细节;所以我会试着更深入地解释;据我所知。如果我说错了,你可以纠正我。

如文档中所述:

在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)
                  |---|

所以ac1variable和ac1argument都指向同一个内存空间;因为它们都包含相同的指针值。但是,ac1variable和ac1argument实际上占用了不同的内存空间。它们不一样。

当方法运行这一行时:

_ac2 = _ac1;

你会得到这样的东西:

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

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

   this._ac2 = _ac1;

当然,如果您访问的是类级别的变量,那么这会破坏方法内部封装的目的。

我相信一个编译器设计方面的专家会把这个当成早餐,然后吐出来。我希望我的ASCII艺术是一致的跨多个浏览器/机器/操作系统等。

相关内容

  • 没有找到相关文章

最新更新