AS3:访问函数外的变量

AS3: Access variable outside of function

这个问题快把我逼疯了,我不知道我错过了什么。这是我的代码:

package  {
 
 import flash.display.*;
 import flash.text.*;
 import flash.events.*;
 import flash.net.*;
 import flash.xml.*; 
 
 public class PopUp extends Sprite {
  
  public var container:Array = new Array();

  public function PopUp() {
   
   var contentXML:XML = new XML(); 
   var XML_URL:String = "./content/content.xml"; 
   var contentXMLURL:URLRequest = new URLRequest(XML_URL); 
   var contentLoader:URLLoader = new URLLoader(contentXMLURL); 
   contentLoader.addEventListener("complete", FuncXML);
   
   function FuncXML(event:Event):void { 
    contentXML = XML(contentLoader.data);
    for each (var item in contentXML.item) {
     
     var txtbox:Sprite = new Sprite();
     txtbox.graphics.beginFill(0x444444, 0.9);
     txtbox.graphics.drawRoundRect(0, 0, 100, 100, 15, 15)
     txtbox.graphics.endFill();
     txtbox.name = "txtbox_"+item.settings.target;
     addChild(txtbox);
     container.push(txtbox);
    }
    trace(container.length); // Returns 2
   }
  trace(container.length); // Returns 0
  }

 }
 
}

此代码的最终版本应根据 xml 文件的内容创建文本框,但我无法从函数 "FuncXML" 中获取内容。我用痕迹试过了。函数内的trace returns 正确的长度是"container",也就是2。函数外的trace returns 0。请问这里有什么问题吗?

正如其他答案中所解释的那样,您的第二个跟踪将在内部函数中的第一个跟踪之前执行。我碰巧是因为 URLLoader 不是即时的,加载数据需要一些时间。所以你必须等到它完成工作。您可以等待本文档中描述的特定事件:URLLoader Adobe Help。 下面我可以建议一些您可能想要做的基本示例:

public class PopUp extends Sprite {

    public var container:Array = new Array();
    // Class constructor       
    public function PopUp() {

    }

    public function prepareAndLoad():void {
        var XML_URL:String = "./content/content.xml"; 
        var contentXMLURL:URLRequest = new URLRequest(XML_URL); 
        var contentLoader:URLLoader = new URLLoader(); 
        contentLoader.addEventListener(Event.COMPLETE, onXMLLoadComplete);
        // good practice here would be to expect errors as well:
        contentLoader.addEventListener(IOErrorEvent.IO_ERROR, onError);
        contentLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);

        contentLoader.load(contentXMLURL);
    }
    private function onError(e:ErrorEvent):void {
        trace("Error");
        // maybe you want to handle this situation somehow.
    }

    private function onXMLLoadComplete(event:Event):void { 
        var contentXML:XML = XML(event.target.data);
        for each (var item in contentXML.item) {
            var txtbox:Sprite = new Sprite();
            txtbox.graphics.beginFill(0x444444, 0.9);
            txtbox.graphics.drawRoundRect(0, 0, 100, 100, 15, 15)
            txtbox.graphics.endFill();
            txtbox.name = "txtbox_"+item.settings.target;
            addChild(txtbox);
            container.push(txtbox);
        }
        trace(container.length);
        // here your XML is loaded and processed. Dispatch an event to notify that job is done and container is not empty.
        dispatchEvent(new Event(Event.COMPLETE));
    }
}

您可以在项目的某处创建此弹出窗口的实例:

//...
var popUp:PopUp = new PopUp();
popUp.addEventListener(Event.COMPLETE, onPopUpReady);
popUp.prepareAndLoad();
//...
private function onPopUpReady(e:Event):void {
    var popUp:PopUp = e.target as PopUp;
    trace(popUp.container.length); // Ready and loaded.
} 
//...

阅读你的代码我可以看到第二个 trace(container.length); returns 0 只是因为它被称为 before "first" trace(container.length);.

如果您看到函数 FuncXML 仅在第二次跟踪之前被声明并添加为侦听器回调(或处理程序),您就可以理解它,但是由于您处于 异步 上下文你永远不会知道 FuncXML 内容是否会在第二个 "trace" 调用之前执行。

特别是您有两个并行运行的函数流:PopUpFuncXML 流,但您假设它们是相应的。

希望对您有所帮助

如前所述,您正在查找项目,然后才加载它们。
您应该等到它们加载并准备就绪,然后在舞台上或其他地方处理它们。

我会这样处理这种情况:
在您的主文件上:

var newTxt:PopUp = new PopUp({
    onReady_func: handlePopUp //pass the function to PopUp class as a parameter
}); 

// this function will be called whenever PopUp is ready
function handlePopUp(){
    trace(newTxt.container.length);
}

在弹出窗口中 class:

...
// the $config object contains setup parameters 
public function PopUp($config) {
    ...
    function FuncXML(event:Event):void { 
       ...
       //  Everything is ready. Lets tell them.
       $config.onReady_func(); // this call should be in the last line of funcXML
    }