데이터 형 검사 예외 사항들 – 완료
데이터 형 검사 예외 사항들
액션스크립트 2.0을 사용하면서, 대부분의 경우 변수 등을 선언할 경우 데이터 형을 명시적으로 해 주는 것이 좋다 .그런데 여기에 몇 가지 예외 사항들이 있다.
첫째, 전역 변수의 경우 데이터 형 선언을 할 수 없다. 전역 변수의 선언은 _global객체에 속성을 추가함으로써 이루어지는데, 다음과 같다.
_global.variableName = value;
이 문법은 액션스크립트 1.0에서부터 온 것으로서, 만약 이 전역변수에 데이터형을 선언하는 다음과 같은 스크립트를 작성하면, 컴파일 타임에 오류가 발생한다.
_global.author:String = “chong”;
이런 경우에 대한 대안은 클래스의 속성을 이용하는 것이다. (자세한 내용은 moock의 Essential ActionScript 2.0의 Chapter 4를 읽고 나서 작성해야 겠다.)
둘째, 스크립트가 타임라인의 프레임에 삽입되는 경우, 무비클립의 속성이나 메소드에 대한 this 키워드의 데이터 형 검사는 수행되지 않는다. 예를 들면, 다음 두 가지 경우를 살펴보자.
_root._y = “chong”;
this._y = “chong”;
이 스크립트는 _y라는 Number형 변수에 문자열인 “chong”을 할당하는 스크립트로 정상적이라면, 컴파일 타임에 데이터 형 오류가 발생해야 한다. 그러나, 첫 번째 스크립트는 컴파일 타임에 데이터 형이 맞지 않는다는 오류를 발생시키지만, 두 번째 스크립트는 this에 대한 데이터 형 검사가 이루어지지 않으므로, 컴파일 타임에 오류를 발생시키지 않는다. 물론, 그렇다고 해서 _y라는 속성에 “chong”이라는 문자열이 저장되는 것은 아니다. 단지 컴파일 타임에 오류가 발생하지 않는 것일 뿐, 의도한 대로 스크립트가 수행되지는 않는다. 그러므로 이런 경우 컴파일 타임에 미리 데이터 형이 맞지 않는다는 오류를 발생시켜주면, 훨씬 도움이 될 것이다. (이런 현상이 발생하는 이유에 대해서는 moock의 Essential ActionScript 2.0에 나오는 내용과 다른 점들이 있으므로, 책에 나오는 이유로는 설명하기 힘들 것같고, 다른 이유를 찾아봐야 할 것같다. 책에서는 위의 예에서 둘 다 에러가 발생하지 않는다고 했는데, 지금은 두 번째의 경우만 에러가 발생하지 않고, 첫 번째의 경우에는 에러를 발생시키기 때문이다.)
솔직히 this 키워드가 아주 유용하긴 하지만, 이런 데이터 형 검사가 이러우지지 않는다면, 곤란한 일이 아닐 수 없다. 그러므로 이런 경우 데이터 형 검사를 수행하도록 하려면 약간 번거롭지만 다음과 같이 스크립트를 작성하여 사용할 수 있다.
Var thisMC:MovieClip = this;
thisMC._y = “chong”;
이렇게 데이터 형 선언을 명시적으로 한 변수를 만들어 주어 this 키워드가 가리키는 객체를 저장하여 사용하면, 데이터 형 검사를 제대로 수행하게 된다. 즉, 위의 스크립트는 두 번째 행에서 데이터 형 오류가 발생하게 되므로, 컴파일 타임에 데이터 형 검사를 제대로 수행함을 알 수 있다.
셋째, 액션스크립트 2.0의 내장 클래스 중에는 XML 클래스가 있다. XML 문서를 다루는 클래스로서, XML 클래스의 인스턴스를 생성하여 XML 문서의 내용을 로드하면, XML 문서의 내용을 트리 형태로 재구성하여 가지고 있게 된다. XML 문서가 계층 형으로 구성되어 있기 때문인데, 다음의 그림을 보면 쉽게 이해가 될 것이다.
여기서 보면, 제일 위에 book이라는 노드가 있고, 그 아래 자식 노드로 title과 author를 갖고 있음을 알 수 있다. 다시 author노드는 자식 노드로서 firstName과 lastName을 가지고 있다. 이런 구조를 재귀적구조라고 하는데, 이런 재귀적 구조를 가진 노드를 나타내기 위해 액션스크립트 2.0에는 XMLNode라는 클래스가 있다. 그러면, XML 클래스와 XMLNode 클래스의 관계는 어떻게 될까? 객체지향프로그래밍의 상속의 개념을 갖고 있다면, 쉽게 유추할 수 있을 것이다. 그렇다. 어느 한쪽이 다른 클래스의 상위 클래스이다. 그러면 어느 쪽이 상위 클래스일까? 클래스 이름을 살펴보면, 좀 더 일반적인 이름이 xML이므로 XML 클래스가 상위 클래스일 것같은 느낌을 준다. 그러면, 다음과 같은 스크립트를 보자.
var xmlDoc:XML = new XML(”<book><title>Essential ActionScript 2.0</title></book>”);
var xmlChild:XML = xmlDoc.firstChild;
이 스크립트를 실행시키면, 먼저 XML 클래스를 생성하고, 그 첫 번째 자식 노드를 다시 XML 데이터 형을 가지는 변수 xmlChild에 할당한다. 아까 앞에서 XML 문서의 노드를 나타내기 위해서 XMLNode라는 클래스가 있다고 했었다. 만약 XML이 상위 클래스라면, 이 스크립트는 문제 없이 수행될 것이다. 그러나, 이 스크립트는 에러를 발생시킨다. 다음과 같이 수정하여 실행시켜보자.
var xmlDoc:XMLNode = new XML(”<book><title>Essential ActionScript 2.0</title></book>”);
var xmlChild:XMLNode = xmlDoc.firstChild;
아무 문제 없이 잘 싱행된다. 즉, XML 클래스와 XMLNode 클래스의 관계는 그 이름이 풍기는 분위기와는 반대로 XML 클래스가 XMLNode 클래스의 하위 클래스인 것이다. 이름에 현혹되지 말자.
넷째, 액션스크립트에서 어떤 객체의 속성이나 메소드에 접근하기 위한 연산자로 ‘.’ 연산자가 있다. 그러나 이 ‘.’ 연산자 외에 또 다른 접근 방법을 액션스크립트는 제공하고 있는데, 바로 [] 연산자이다. [] 연산자를 이용하는 방법은 ‘.’ 연산자와 그다지 다를 바 없다. 단지 속성이나 메소드의 이름이 문자열로 주어진다는 점만 다를 뿐이다. 다음 예를 한 번 보자.
var d:Date = new Date();
var year:String = d.getFullYear();
var year2:String = d[”getFullYear”]();
이 스크립트에서 ‘.’ 연산자를 사용한 두 번째 행은 에러를 발생시키지만, [] 연산자를 사용한 세 번째 행은 에러를 발생시키지 않는다. 함수의 결과 데이터 형에 대한 데이터 형 검사가 이루어 지지 않은 것이다. 그러면, 객체의 속성에 대한 데이터 형 검사도 이루어지지 않을까? 다음 스크립트로 확인해 보자.
var xmlDoc:XML = new XML(”<book><title>Essential ActionScript 2.0</title></book>”);
var xmlFragment:XML = xmlDoc[”firstChild”];
앞서 에러를 발생시켰던 스크립트에서 ‘.’ 연산자를 [] 연산자로 바꿨다. 예상대로 이번에는 에러가 발생하지 않는다. 마지막으로 다음 스크립트를 실행해보자.
var d:Date = new Date();
d.noSuchMethod();
d[”noSuchMethod’]();
이 스크립트에서 d를 Date형 객체로 선언했으므로 d의 속성이나 메소드에 대한 접근이 이루어질 경우 d의 데이터 형을 검사하여 에러 여부를 알려준다. 그러나, ‘.’ 연산자가 아닌 [] 연산자로 접근이 이루어지는 경우에는 비록 d를 Date형 객체로 명시적으로 선언하였어도 데이터 형 검사가 이루어지지 않는다.
정리해보면, ‘.’ 연산자를 이용하는 경우 컴파일러가 제대로 형 검사를 하지만, [] 연산자를 사용하면, 컴파일러가 전혀 형 검사를 하지 않음을 알 수 있다. 속성의 이름이나 메소드의 이름을 문자열 인자로 받아서 사용하는 경우에는 [] 연산자가 편리하겠지만, 이 경우 데이터 형에 대한 주의가 각별히 요구된다. 그리고, 가능하다면, [] 연산자를 사용하기보다는 ‘.’ 연산자를 이용하여 속성이나 메소드에 대한 접근이 이루어지는 것이 바람직하다 하겠다.
마지막으로, 배열에 대해서 살펴보자. 배열의 경우 어떤 원소가 추가 되면 그 원소의 데이터 형을 기억하고 있지 않는다. 어떤 데이터 형의 원소가 추가되든, 그냥 Object 형으로 인식하고 저장해 버린다. 즉, 배열에서 어떤 원소를 꺼내오면, 그 원소의 데이터 형은 Object가 되는 것이다.
이것이 가능한 이유는 액션스크립트에서 Object 클래스는 모든 클래스의 상위 클래스이기 때문이다. 즉 최상위 클래스란 말이 된다. 사용자가 임의로 선언한 클래스라고 해서 예외일 수는 없다. 액션스크립트에서 어떤 클래스이든 상위 클래스를 갖고 있는 경우 그 상우 ㅣ클래스로 데이터 형 변환이 가능하다 했으므로 전혀 문제가 없게 되는 것이다. 그러므로 배열에 객체를 저장했다가 다시 꺼내 오는 경우에는 그 데이터 형을 제대로 다시 변환시켜 주는 작업이 필요하다. 그런데, 다음 스크립트를 한번 보자.
var doc:XML = new XML(”<p>Hello World</p>”);
var items:Array = new Array();
items.push(doc);
var doc2;XML = items[0];
먼저 doc이라는 XML 형의 객체를 생성하였다. 이 객체를 items라는 배열에 넣는다. 이 때, XML 형은 Object형으로 바뀐 채 배열의 0번째 원소로 저장된다. 이 객체를 두 번째 XML형 변수인 doc2에 할당한다. 이 경우 Object 형의 데이터를 XML형의 변수에 할당하므로, 데이터 형 오류가 나야 정상이다. 그런데 이 스크립트를 실행시켜보면 전혀 문제 없이 실행된다. 왜 그럴까?
위의 스크립트에서 배열의 첫 번째 원소에 접근하기 위해서 [] 연산자를 사용했기 때문이다. 앞서 [] 연산자를 사용할 경우 데이터 형 검사가 전혀 이루어지지 않는다고 이야기 했었다. 그 때문에 위의 스크립트는 전혀 아무런 문제도 없이 실행되는 것이다. 위 스크립트의 마지막 행을 다음과 같이 바꿔보자.
var doc2:XML = items.pop();
이제는 XML 형의 변수에 Object형의 데이터가 할당되었다는 에러가 발생한다. 배열 items에 원소들이 Object형으로 저장되어 있음을 알 수 있다. 위와 같이 에러가 발생하는 경우에 메소드의 결과 데이터의 형을 다음과 같이 변환시켜주면 된다.
var doc2:XML = XML(items.pop());
액션스크립트 2.0에서 배열의 원소에 접근하는 메소드는 여러 가지가 있지만, [] 연산자를 대체할 수 있는 메소드는 없다. pop()이나 shift()는 배열에 저장된 원소를 삭제해 버리기 때문에 [] 연산자와는 다른 결과를 발생시킨다. 그러므로 배열을 사용할 경우 항상 [] 연산자를 이용할 수 밖에 없고, 그런 점에서 사용자의 각별한 주의가 필요하다.
참고문헌
- Essential ActionScript 2.0, Colin Moock, O’Reilly