리스너 함수 만들기는 ActionScript 3.0 이벤트 모델이 DOM 이벤트 모델과 다른 부분 중 하나입니다. DOM 이벤트 모델에서는 이벤트 리스너와 리스너 함수 간의 차이가 명확합니다. 이벤트 리스너는 EventListener 인터페이스를 구현하는 클래스의 인스턴스이고 리스너 함수는 handleEvent()라는 클래스의 메서드입니다. 또한 DOM 이벤트 모델에서는 실제 리스너 함수가 아니라 리스너 함수를 포함하는 클래스 인스턴스를 등록합니다.
반면에 ActionScript 3.0 이벤트 모델에서는 이벤트 리스너와 리스너 함수 간에 차이가 없습니다. ActionScript 3.0에는 EventListener 인터페이스가 없으며 리스너 함수를 클래스 외부에 또는 클래스의 일부로 정의할 수 있습니다. 또한 리스너 함수의 이름을 handleEvent()로 지정할 필요가 없으며 유효한 식별자를 사용하여 명명할 수 있습니다. ActionScript 3.0에서는 실제 리스너 함수의 이름을 등록한다는 것도 DOM 이벤트 모델과 다릅니다.
클래스 외부에 정의되는 리스너 함수
다음 코드에서는 빨간색 정사각형 모양을 표시하는 간단한 SWF 파일을 만듭니다. 여기에서 클래스 외부에 정의된 clickHandler() 리스너 함수는 빨간색 정사각형에서 마우스 클릭 이벤트를 수신합니다.
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, clickHandler);
}
}
function clickHandler(event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
사용자가 사각형을 클릭하여 그 결과 나타나는 SWF 파일과 상호 작용하면 Flash Player 또는 AIR에서 다음과 같은 추적 출력이 생성됩니다.
clickHandler detected an event of type: click
the this keyword refers to: [object global]
이벤트 객체는 clickHandler()에 인수로 전달됩니다. 이를 통해 리스너 함수에서 이벤트 객체를 검토할 수 있습니다. 이 예제에서는 이벤트 객체의 type 속성을 사용하여 이벤트가 click 이벤트인지 확인합니다.
또한 이 예제에서는 this 키워드의 값도 확인합니다. 이 경우에는 함수가 사용자 정의 클래스 또는 객체의 외부에 정의되므로 this가 전역 객체를 나타냅니다.
클래스 메서드로 정의되는 리스너 함수
다음 예제는 clickHandler() 함수가 ChildSprite 클래스의 메서드로 정의된다는 것만 제외하면 ClickExample 클래스를 정의하는 위의 예제와 같습니다.
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, clickHandler);
}
private function clickHandler(event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
}
사용자가 빨간색 사각형을 클릭하여 그 결과로 나타나는 SWF 파일에 대해 작업을 처리하면 Flash Player 또는 AIR에서 다음과 같은 추적 출력이 생성됩니다.
clickHandler detected an event of type: click
the this keyword refers to: [object ChildSprite]
여기에서 this 키워드는 child라는 ChildSprite 인스턴스를 참조하는데, 이는 ActionScript 2.0의 비헤이비어와 비교하여 달라진 점입니다. ActionScript 2.0 구성 요소를 사용한 경우, 클래스 메서드를 UIEventDispatcher.addEventListener()에 전달하면 메서드 범위가 리스너 메서드가 정의된 클래스 대신 이벤트를 브로드캐스팅하는 구성 요소에 바인딩되었음을 유념해야 합니다. 즉, ActionScript 2.0에서 이 방법을 사용한 경우에는 this 키워드가 ChildSprite 인스턴스 대신 이벤트를 브로드캐스팅하는 구성 요소를 참조합니다.
이렇게 되면 리스너 메서드를 포함하는 클래스의 다른 메서드 및 속성에 액세스할 수 없으므로 일부 프로그래머에게는 이것이 중요한 문제였고 이를 해결하기 위해 ActionScript 2.0 프로그래머는 mx.util.Delegate 클래스를 사용하여 리스너 메서드의 범위를 변경할 수 있었습니다. 그러나 ActionScript 3.0에서는 addEventListener()가 호출될 때 바인딩 메서드를 만들기 때문에 이 방법이 더 이상 필요하지 않습니다. 결과적으로 this 키워드는 child라는 ChildSprite 인스턴스를 참조하고 프로그래머는 ChildSprite 클래스의 다른 메서드와 속성에 액세스할 수 있습니다.
사용할 수 없는 이벤트 리스너
동적으로 지정된 리스너 함수를 가리키는 속성으로 일반 객체를 만드는 제 3의 방법이 있지만 사용하지 않는 것이 좋습니다. 이 방법은 ActionScript 2.0에서 일반적으로 사용되었기 때문에 여기에서 설명하지만 ActionScript 3.0에서는 사용하지 않아야 합니다. 이 방법을 사용하면 this 키워드가 리스너 객체 대신 전역 객체를 참조하므로, 권장할만한 방법은 아닙니다.
다음 예제는 리스너 함수가 myListenerObj라는 일반 객체의 일부로 정의된다는 것만 제외하면 위에 나오는 ClickExample 클래스 예제와 같습니다.
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, myListenerObj.clickHandler);
}
}
var myListenerObj:Object = new Object();
myListenerObj.clickHandler = function (event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
추적 결과는 다음과 같습니다.
clickHandler detected an event of type: click
the this keyword refers to: [object global]
this 키워드가 myListenerObj를 참조하고 추적 출력이 [object Object]로 표시된다고 예상할 수 있지만 실제로는 전역 객체를 참조합니다. 동적 속성 이름을 addEventListener()에 인수로 전달하면 Flash Player 또는 AIR에서 바인딩 메서드를 만들 수 없습니다. 이는 listener 매개 변수로 전달하는 대상이 리스너 함수의 메모리 주소이고 Flash Player 및 AIR에서는 해당 메모리 주소를 myListenerObj 인스턴스에 링크할 수 없기 때문입니다.