我想通过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;
}
答案 0 :(得分:6)
AS使用“按对象传递”/“通过对象共享传递”。也就是说,传递“对象”(不是复制,克隆或复制),并且对该对象的任何修改都是共享的。
但是,赋值_ac2 = _ac1
仅更改[function的local]参数变量的值,并且在函数调用期间不会影响任何变量。传入的唯一内容是由函数调用中使用的变量(或任意表达式)的求值产生的值(“对象”)。
这是因为,如上所述,使用的策略是“按对象传递”而不是(因为文档说明“通过引用传递”,这实际上意味着“传递值”引用]“或只是......”通过对象“)。也就是说,术语“通过引用传递”实际上被滥用,因此令人困惑。 (它在许多语言和文档中被滥用。试图达到共同意义是一场艰苦的战斗。)
如果确实是“通过引用传递”,那么为_ac2
分配新值会传播出去。 (在发表评论说AS是如何“通过引用传递”之前,请参阅顶部的链接并认为“通过引用传递”涵盖了C#的out/ref
,VB的ByRef
,TSQL的{{ 1}}和C ++的(引用)output
- 这些概念不在AS,Javascript或Java中。但是,正如原始帖子中正确指出的那样(以及其他自我回复),情况并非如此 - 结论: AS不支持“通过引用传递”; 此外,文档(令人困惑的是)使用“通过引用传递”一词来表示“按对象传递”/“通过对象共享传递”。
有几种方法可以传播更改,按(我的)首选项的顺序排序:
返回新的适用值:&
。这通常是最干净的。避免副作用和令人惊讶的代码。如果适当地包装在对象(或数组)中,则可以返回多个值。
使用闭包:AC2 = doSomeTransformation(AC1)
,其中doSomeTransformation可能如下所示:doSomeTranformation(AC1, function (newValue) { AC2 = newValue })
。我通常只在函数本身的回调“在上下文中运行”或以CPS样式编写代码时才使用它。
改变一个对象(毕竟AS是“通过对象传递”)。 这非常狡猾,但它会起作用。
function doSomeTransformation(_ac1, finished) { ...; finished(_ac1) }
其中doSomeTransformation看起来像var blah = {AC2: null}; doSomeTransformation(ac1, blah); ...; laterOn(blah.AC2)
。一般不推荐。
快乐的编码。
适用的摘录,来自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艺术在多个浏览器/机器/操作系统/等之间保持一致。