IT

플래시 3.0

by 모아레 posted May 14, 2008
?

단축키

Prev이전 문서

Next다음 문서

ESC닫기

크게 작게 위로 아래로 게시글 수정 내역 댓글로 가기 인쇄

네이버 플생사모 - EAS 3.0번역자료

1장
핵심 개념





액션스크립트 코드를 쓰기 위한 툴
액션스크립트 코드는 문자로 쓰여진다. 그러므로 액션스크립트 프로그램은 윈도우즈의 Notepad(메모장), 맥의 TextEdit 같은 간단한 텍스트 편집기로 만들 수 있다. 하지만, 많은 액션스크립트 프로그래머는 액션스크립트 코드를 쓰는데 어도비의 플렉스 빌더 또는 플래시 오소링 툴을 사용한다. 플렉스 빌더는 통합 개발 환경(IDE)이다. IDE는 코드 작성을 관리하고, 인쇄용 문서를 만들기 위한 문서 편집기이다. 개발자들은 플렉스 빌더에서 액션스크립트나 MXML(또는 둘 다)를 사용하여 소프트웨어 애플리케이션, 멀티미디어 컨텐츠를 만들어낸다. MXML은 유저 인터페이스를 기술하기 위한 XML 기반의 언어이다. 대조적으로, 플래시 오소링 툴은 디자인, 애니메이션, 프로그래밍 에디터이다. 개발자들은 플래시 오소링 툴에서 액션스크립트 코드로 직접 그리고, 애니메이션을 만들고, 멀티미디어 컨텐츠를 이용하여 소프트웨어 애플리케이션, 멀티미디어 컨텐츠를 만든다.

AS3.0은 플렉스 빌더2 또는 보다 상위 버전, 플래시 CS3(플래시 오소링 툴의 9번째 버전) 또는 보다 상위 버전에서 지원한다. 플렉스 빌더는 www.adobe.com/products/flex/productinfo/overview/ 에서 플래시 오소링 툴은 http://www.adobe.com/go/flash/ 에서 얻을 수 있다.

이 책에서는 소프트웨어 애플리케이션, 멀티미디어 컨텐츠를 만드는데 대부분 순수한 액션스크립트만을 사용한다. 29장은 플래시 오소링 툴에서 액션스크립트를 사용하는 방법을 포함한다. 이 책은 MXML을 광범위하게 다루고 적용하지 않는다. MXML을 배우고 싶다면 O'really의 Programming Flex 2(Kazoun and Lott, 2007)와 어도비의 플렉스 빌더 문서를 보기 바란다.


플래시 클라이언트 런타임 환경
액션스크립트 프로그램은 세 개의 소프트웨어 애플리케이션에서 실행될 수 있다 : 플래시 플레이어, 플래시 라이트, 어도비 AIR.

플래시 플레이어는 웹 브라우저나 데스크탑에서 액션스크립트 프로그램을 실행한다. 플래시 플레이어는 운영체제의 아주 적은 부분만 접근할 수 있다. (파일을 조작하고, 윈도우를 제어하고, 하드웨어에 접근할 수 없다)

어도비 AIR은 데스크탑에서 액션스크립트 프로그램을 실행하고 데스크탑 운영체제의 모든 부분을 접근할 수 있다. (파일을 조작하고, 윈도우를 제어하고, 하드웨어에 접근할 수 있다)

플래시 라이트는 핸드폰 같은 모바일 장치에서 액션스크립트 프로그램을 실행한다. 이 책이 출판될 때, 플래시 라이트는 AS2.0으로 쓰여진 액션스크립트 프로그램을 실행할 수 있었지만 플래시 플레이어와 AIR이 AS3.0으로 쓰여진 프로그램을 실행시킬 수 있을 때 플래시 라이트는 AS3.0은 불가능했다. 그러므로, 이 책에서 가르치는 기술들을 플래시 플레이어와 AIR에서 쓸 수 있지만 플래시 라이트에서는 AS3.0을 지원하기 전까지는 불가능하다.

일반적으로 플래시 플레이어, AIR, 플래시 라이트는 플래시 클라이언트 런타임 환경이다. 왜냐하면 그들은 자신들이 실행되고 있을 때 액션스크립트 프로그램을 관리하기 때문이다. 액션스크립트 프로그램은 윈도우즈, 맥, 리눅스, 다른 모바일장치에서 수정 없이 이용 가능하다. 왜냐하면 액션스크립트 프로그램은 플래시 런타임에 의해 실행되는데, 하드웨어 장치들에 맞는 런타임 환경이 액션스크립트 프로그램을 실행하기 때문이다. 그러므로 한 액션스크립트 프로그램은 여러 하드웨어로 이식이 가능하다.

액션스크립트 가상 머신(ActionScript Virtual Machine;AVM)은 플래시 플레이어, AIR, 플래시 라이트에 내장되어 있는 소프트웨어 모듈로 액션스크립트 프로그램을 실행시킨다. 하지만 플래시 런타임들은 표시 스크린, 비디오 및 오디오 재생, 다른 운영체제와의 연결 등에서 다른 책임을 가진다. AVM은 두 가지 버전이 있는데, AS1.0과 AS2.0코드를 실행하기 위한 AVM1과 AS3.0코드를 실행하기 위한 AVM2가 있다.

컴파일러
액션스크립트 프로그램이 플래시 런타임에서 실행되기 전에, 그것은 반드시 사람이 이해할 수 있는 AS3.0 코드에서 플래시 런타임이 이해할 수 있는 액션스크립트바이트코드(ABC)로 변환되어야 한다. 하지만 바이트코드는 플래시 런타임에서 혼자 실행할 수 없다. 대신, 그것은 반드시 .swf 파일로 감싸져야 한다. .swf 파일은 바이트코드와 액션스크립트 프로그램이 요구하는 미디어 자산을 포함한다.

액션스크립트 프로그램과 swf 파일을 컴파일 할 때, 우리는 컴파일러라고 알려진 소프트웨어 모듈을 사용한다. 액션스크립트 코드를 컴파일 하는 컴파일러는 액션스크립트 컴파일러다. swf 파일을 만드는 컴파일러는 swf 컴파일러다. 플렉스 빌더 2나 플래시 오소링 툴은 swf 컴파일러를 포함한다. 플렉스 빌더 2와 플래시 오소링 툴은 같은 액션스크립트 컴파일러를 가지나 다른 swf 컴파일러를 가진다. (플렉스 컴파일러, 플래시 컴파일러) 어도비는 mxmlc라는 커맨드라인 환경의 독립된 컴파일러를 제공한다. mxmlc는 어도비에서 무료로 배포하는 플렉스2 SDK에 포함되어 있다. 플렉스2 SDK는 http://www.adobe.com/go/flex2_sdk 에서 얻을 수 있다.

JIT 컴파일러
액션스크립트 프로그램이 실행될 때, 플래시 런타임은 액션스크립트 바이트코드를 그 운영체제의 네이티브 코드로 변환해서 실행한다. 네이티브 코드로 변환하면, 프로그램에는 바이트코드 대신 네이티브 코드가 저장된다. 다음에 다시 실행할 때는 이미 변환되어 있는 네이티브 코드를 실행함으로서 바이트코드를 해석해서 실행하지 않아도 된다.

재검토
이전에 몇몇 페이지들은 진도를 많이 나갔다. 우리가 지금까지 무엇을 배웠는지 다시 검토해보자.

액션스크립트 프로그램은 명령들로 구성되어 있고 플래시 런타임(플래시 플레이어, 어도비 AIR, 플래시 라이트)에 의해 실행된다. 액션스크립트 프로그램은 텍스트 편집기, 플렉스 빌더, 플래시 오소링 툴으로 만들 수 있다.
액션스크립트 프로그램을 실행하기 위해 먼저 액션스크립트 프로그램을 <[플래시 컴파일러를 포함하는 플래시 오소링 툴], [mxmlc] 또는 [플래시 컴파일러] [mxmlc] 둘 다를 포함하는 플렉스 빌더 2와 플렉스 2 SDK 같은
SWF 컴파일러>로 swf 파일로 만든다. 말이 배배 꼬여서 이해하기 난감; 대충 괄호로 묶어놨습니다.

앞으로 나올 개념들은 모두 새로운 것이나 걱정하지 말라. 우리는 아직 900쪽 가량이 남아있다. 지금 시작이다!

클래스와 객체
당신이 비행기를 짓고, 완전히 해체한다고 상상하고, 처리 과정을 생각해 보라. 당신은 용접을 시작한다. 그리고 비행기를 만들기 위한 과정을 상세하게 계획한다. 단지 하나만을 그리는 게 아니라, 비행기의 많은 부분을 계획해야 한다. (바퀴, 날개, 시트, 브레이크 등등..) 각 부분을 개념적으로 묘사하고 각 부분을 조화시켜 비행기를 물리적으로 구체화 한다. 비행기를 지을 때, 각 부분을 일일이 제조하고 하나로 조립할 것이다. 각 부분은 상호연동해서 비행기의 동작을 만들어낼 것이다,

만약 이 모든 소리가 논리적으로 다가온다면, 당신은 액션스크립트 프로그래머가 될 소질을 갖추고 있는 것이다.
하늘을 날아다니는 비행기는 상호연동하는 각 부분들의 그룹이다. 실행되고 있는 액션스크립트 프로그램은 상호연동하는 클래스 기반인 객체들의 그룹이다. 액션스크립트 객체는 프로그램에서 실체있는 것과 실체없는 것 둘 다를 제공한다. 예를 들어, 객체는 숫자 계산, 달력과 시간의 한 지점, 클릭 가능한 버튼, 이미지의 흐림 효과를 제공한다. 객체는 클래스를 구체화 한 것 또는 인스턴스다. (객체와 인스턴스는 같은 뜻으로 쓰인다) 클래스는 객체를 만들기 위한 기반이다.

프로그램을 만들기 위한 첫걸음은 클래스를 만드는 것이다. 클래스는 객체의 동작을 지정한다. 우리는 클래스로 객체를 만들고 객체에게 무엇을 하라고 명령할 수 있다.

클래스와 객체로 프로그램을 만드는 것은 객체지향프로그래밍(OOP)라고 한다.

프로그램을 만들기 전에, 잠깐 네이티브 클래스들에 대해 알아보자.
---------------------------------------------------------
String       문자열 데이터를 제공한다.
Boolean    논리구문인 true(참)과 false(거짓)을 제공한다.
Number     부동소수점 숫자 데이터를 제공한다. (소수점 이하의 값을 가질 수 있음)
int            0과 정수를 제공한다.
uint          0과 양의 정수를 제공한다.
Array        배열(정돈된 목록)을 제공한다.
Error         프로그램 에러를 제공한다.
Date          날짜, 시간을 제공한다.
Math         수학 관련(삼각함수, 랜덤, 라디안..)을 제공한다.
RegExp     정규표현식을 제공한다.
Function   재사용 할 수 있는 명령묶음을 제공한다.
Object     액션스크립트의 모든 객체의 기반을 정의한다.
---------------------------------------------------------

이제 클래스와 객체를 사용해서 간단한 프로그램을 만들어보자. 만들어 볼 프로그램은 가상 동물이 있는 동물원 시뮬레이션이다.

플래시 오소링 툴에선 타임라인에 코드를 입력해서 클래스를 만들지 않고도 액션스크립트 프로그램을 만들 수 있다. (29장) 하지만, 당신이 혼자 클래스를 만들 수 있을 거라고 기대하지 않아도 이 장에서 그렇게 하는 법을 배울 수 있을 것이다. 클래스를 어떻게 만드는지 아는 것은 당신에게 액션스크립트를 더욱 깊게 이해시킬 것이고 당신을 훌륭한 프로그래머로 만들 것이다.

프로그램 만들기
액션스크립트 프로그램은 클래스로 구성되어진다. 각 클래스는 이름, 특징, 역할을 가진다. 하나의 클래스는 특별한 메인 클래스로 지정해야 한다. 메인 클래스는 애플리케이션의 시작점을 제공한다. 프로그램을 시작하면, 플래시 런타임은 자동적으로 메인 클래스의 객체를 하나 만든다.

가상 동물원 프로그램을 위해 메인 클래스의 이름을 VirtualZoo라고 할 것이다. 프로그램을 만드는 첫번째 단계로 우리는 virtualzoo라는 폴더를 하나 만들 것이다. 그 폴더에 모든 소스 파일(.as)가 저장되는 src라는 이름의 하위 폴더를 만들 것이다.

메인 클래스는 반드시 자신이 저장된 파일의 이름과 일치해야 한다. src에 VirtualZoo.as 라는 빈 파일을 만든다.

virtualzoo
ㄴsrc
 ㄴVirualZoo.as

VirtualZoo.as 파일이 만들어졌으니 이제 VirualZoo클래스를 쓰기 시작할 수 있다. 하지만, 먼저, 발생 가능한 문제들 - 만약 우리가 선택한 메인 클래스의 이름이 액션스크립트의 내장된 클래스의 이름과 충돌한다면 우리의 클래스는 만들어지지 않을 것이고, 우리의 프로그램도 시작이 가능하지 않을 것이다. 우리의 프로그램에서 일어날 수도 있는 이름 충돌을 막기 위해서, 우리는 패키지를 사용한다.

진도를 많이 나갔다. 우리는 7장에서 실제로 우리의 프로그램을 컴파일 해 볼 것이다. 만약 건너뛰기로 결정하고, 1장~6장에서 제공되는 예제들을 컴파일하려 한다면 당신은 여러 경고와 에러에 맞닥뜨리게 될 것이다. 7장 후에는 모든 예제를 에러 없이 컴파일 할 수 있을 것이다.

패키지
패키지라는 이름이 암시하듯, 패키지는 클래스 그룹의 개념적인 컨테이너이며, 나중에 배우겠지만 프로그램의 다른 것을 위한 것이다. 패키지 범위는 프로그램의 어떤 영역을 위한 범위고, 영역에 패키지 이름이라고 불리는 범위를 준다. 관습적으로, 패키지 이름의 첫글자는 소문자로, 클래스 이름의 첫글자는 대문자로 쓴다. 이 것은 패키지 이름과 클래스 이름을 구별하는데 도움을 준다.

클래스 소스 코드가 패키지 안에 있을 때, 클래스는 자식이 부모의 이름을 물려받는 것 처럼 자동적으로 패키지의 이름을 자신의 이름에 포함시킨다. 예를 들어, game패키지에 들어있는 Player클래스의 이름은 game.Player가 된다. 패키지 이름은 처음에 오고, 클래스 이름과 .(점)캐릭터로 연결된다. (캐릭터는 편지, 숫자, 구두점, 기타 등등..을 위한 간단한 프로그래밍 용어이다.) 패키지 이름은 game.Player클래스와 다른 Player클래스를 구별할 수 있게 도와준다. 이렇게 이름 충돌을 막았다.

패키지를 만들기 위해 우리는 패키지 정의 지시문을 사용한다. 상세히 해부해보자. 액션스크립트에서, 모든 프로그램 명령은 일반적으로 지시문을 이용한다. 정의는 패키지나 클래스 같은 것을 만들거나 정의하기 위한 지시문의 한 종류다. 이 경우, 패키지를 정의하고자 하므로, 패키지 정의 지시문을 사용한다.

정의는 프로그램에서 어떤 것을 만든다고 선언하는 것이다. 정의는 어떤 것을 참조할 수 있게 하는 선언이다.

여기 일반적인 패키지 정의 지시문이 있다.

package packageName{
}

모든 패키지 정의는 package 키워드로 시작한다. 키워드는 액션스크립트 언어에서 예악되어 있는 명령 이름이다. 이 경우, package 키워드는 액션스크립트에게 패키지를 만들라고 말한다. 물론 패키지의 이름을 적는 packageName부분은 프로그래머에 의해 변경될 것이다. 다음으로, 패키지의 시작점과 끝점을 나타내는 중괄호를 표시했다. 클래스를 추가할 때는, 이 중괄호 사이에 작성해야 한다.

package packageName{
 클래스 소스 코드를 여기에
}

중괄호는 블록 구문이다. 블록 구문은 지시문들을 논리적으로 묶어서 처리한다. 패키지 정의의 블록은 패키지 블록 또는 패키지 몸체로 불린다.

액션스크립트 구문 목록은 10장에서 볼 수 있다.

관습에 의해서(물론 강제는 아니고), 패키지 이름은 다음 규칙을 따른다.
○ 단체의 도메인 이름을 뒤집어 사용한다
○ 점(.)으로 구분한다
○ 목적에 맞는 이름을 사용한다
예를 들어, Acme라는 회사에서 맵핑 애플리케이션을 만들기 위한 클래스가 들어있는 패키지가 있다. 이 회사의 도메인 이름은 acme.com이다. 패키지 이름은 이 걸 뒤집고 map을 붙여서 com.acme.map이라고 이름짓는다. 다음과 같이 나타낸다.

package com.acme.map{
}

com이 acme보다 앞장섰다. (패키지 이름에서는 도메인 이름을 뒤집는다)

도메인 이름은 인정받은 시스템의 유일무이한 개런티다. 당신의 패키지 이름과 도메인이 다른 단체의 도메인과 충돌하지 않도록 피해가라.

우리의 가상 동물원 프로그램에서 패키지를 사용해보자. 예제에서 우리는 다른 도메인 이름 없이 zoo라는 패키지 이름을 사용할 것이다. zoo 패키지를 정의하고, 우리는 그에 따른 코드를 VirtualZoo.as에 추가할 것이다.

package zoo{
}

이제 우리는 VirtualZoo.as를 zoo패키지에 추가해야 한다. 반드시 폴더 이름과 패키지 이름을 맞춰야 한다. 예를 들어, com.gamecompany.zoo라는 패키지는 com폴더 안의 gamecompany폴더 안의 zoo라는 폴더에 들어있어야 한다. 따라서, 우리는 zoo라는 새로운 폴더를 만들고 VirtualZoo.as를 그 곳으로 이동시켜야 한다.

virtualzoo
ㄴsrc
 ㄴzoo
  ㄴVirtualZoo.as

패키지 정의를 가지게 되었다. VirtualZoo 클래스를 추가해보자.

클래스 정의하기
클래스를 만들기 위해, 클래스 정의를 사용할 것이다.

class ClassName{
}

클래스 정의는 class 키워드로 시작한다. 그리고 ClassName 부분에는 클래스의 이름을 쓴다. 클래스의 이름은 공백이나 대쉬(-, 마이너스문자)를 포함하거나 숫자로 시작하면 안 된다. 클래스 이름은 관습적으로 첫글자와 이름의 다음 단어를 대문자로 쓴다. (Date, TextField; TextField는 텍스트를 보여주기 위한 플래시 런타임의 내장 클래스이다.) 중괄호{} 는 패키지의 중괄호와 마찬가지로 ClassName 다음에 온다. 클래스 정의의 중괄호(클래스 블록)도 클래스 블록 또는 클래스 몸체로 불린다.

여기 동물원 게임을 위한 main클래스인 VirtualZoo의 간단한 정의가 있다. 우리는 이 코드를 VirtualZoo.as 파일에 넣을 것이다 :

package zoo {
 class VirtualZoo {
 }
}

VirtualZoo 클래스는 zoo 패키지 안에 있으므로 클래스의 풀네임은 zoo.VirtualZoo 가 된다. 하지만 우리는 계속 VirtualZoo 클래스라고 부를 것이다. 이제 우리의 프로그램을 위한 메인 클래스 정의를 가지게 되었다. VirtualPet이라는 다른 클래스를 만들어보자. VirtualPet 클래스로, 우리는 동물원에 펫 객체를 만들 것이다. VirtualZoo 클래스처럼, VirtualPet 클래스도 zoo패키지에 위치할 것이다. zoo 폴더에 VirtualPet.as 라는 이름으로 파일을 만들고 다음 코드를 쓴다.

package zoo {
 class VirtualPet {
 }
}

패키지는 여러 소스 파일을 가질 수 있다. VirualZoo와 VirtualPet은 다른 as파일에 저장되어 있고, 같은 zoo패키지에 있다. 어떤 클래스를 가진 어떤 파일이라도 zoo패키지에 위치시키고 zoo패키지의 일원이 되도록 할 수 있다. 대조적으로, 클래스 정의는 여러 파일에 이루어질 수 없다. 임의의 클래스는 오직 하나의 파일에, 한 번만 쓰여질 수 있다.

클래스를 위한 접근제어자
기본적으로, 패키지의 클래스는 오직 그 패키지에 안에서만 사용 가능하다. 패키지 밖에서 패키지의 클래스를 사용하기 위해서는 클래스의 접근제어자를 public으로 정의하여야 한다. 접근제어자는 class 키워드 이전에 온다.

접근제어자 class ClassName{
}

예를 들어, VirtualPet에 public을 추가하면 다음과 같다.

package zoo {
 public class VirtualPet {
 }
}

하지만, 이 경우 VirtualPet은 VirtualZoo클래스에서만 쓰이고, VirtualZoo는 VirtualPet과 같은 패키지에 있기 때문에 (같은 패키지의 클래스는 같은 패키지의 다른 클래스에서 항상 접근 가능하다. 잊지말라) VirtualPet의 public 제어자는 불필요하다. 그러니까 VirtualPet의 원래 정의로 돌아가자.

package zoo {
 class VirtualPet {
 }
}

만약 VirtualPet을 같은 패키지에서만 접근할 수 있게 하고자 한다면, 우리는 internal 접근 제어자를 쓸 수 있다 :

package zoo {
 internal class VirtualPet {
 }
}

internal 접근 제어자를 가진 클래스는 같은 패키지에서만 접근할 수 있다. internal 접근 제어자를 쓰는 것은 클래스에 아무 접근제어자도 쓰지 않은 것과 동일하다. (즉, 아무 접근제어자를 쓰지 않으면 클래스의 접근제어자는 자동으로 internal 이 된다) internal 제어자를 쓰는 것은 프로그래머의 목적을 명확하게 나타낸다.

internal과 public은 클래스의 접근제어자인데, 클래스에 접근 가능한 범위를 결정하기 때문이다.

VirtualPet과 다르게, 메인 클래스인 VirtualZoo는 반드시 public을 써야 한다.

컴파일러는 public클래스들에서 애플리케이션의 main클래스를 찾는다

VirtualZoo클래스를 업데이트하자.

package zoo {
 public class VirtualZoo {
 }
}

가상 동물원 재검토
우리의 게임은 이제 두 개의 클래스를 가졌다. (VirtualZoo : main클래스, VirtualPet : 게임의 펫을 위한 클래스) 액션스크립트 컴파일러의 요구대로, 애플리케이션의 메인 클래스인 VirtualZoo 는 public 접근제어자를 가지게 되었다. VirtualPet은 internal 접근제어자를 가졌으므로 zoo 패키지 안에서만 접근할 수 있다. 예제1-1 은 지금까지의 코드를 보여준다. 또한 예제는 주석이라는 새로운 것을 소개한다. 주석은 오직 프로그래머가 코드를 이해하기 쉽게하기 위해 쓴 것으로, 컴파일러는 주석을 완전히 무시한다. 액션스크립트 주석은 두 가지가 있다. 그 줄만 주석으로 바꾸고 싶다면 // 를 사용한다. 여러 줄을 주석으로 바꾸고 싶다면 시작부분에 /* 를, 끝부분에 */ 를 쓴다.

이 것은 한 줄 주석이다.

// 오직 프로그래머만을 위해


이 것은 여러 줄 주석이다.
/*
 오직 프로그래머만을 위해
*/

여기 동물원 게임을 위한 지금까지의 코드가 있다.

예제1-1. 동물원 게임

// VirtualZoo 클래스
package zoo {
 public class VirtualZoo {
 }
}

// VirtualPet 클래스
package zoo {
 internal class VirtualPet {
 }
}

이제 우리의 프로그램을 만들기 위해 메인 클래스인 VirtualZoo 클래스의 생성자(constructor) 메서드를 정의해보자.

생성자 메서드
생성자 메서드(짧게 말하면 생성자)는 클래스의 인스턴스를 만드는데 사용된다. 생성자를 만들기 위해, 클래스 블록 사이에 함수 정의를 사용한다.

class SomeClass {
 function SomeClass ( ) {
 }
}

function 키워드로 생성자 메서드 정의를 시작한다. 다음으로는 생성자의 이름이 온다. 생성자의 이름은 클래스의 이름과 같아야 한다(중요하다!). 생성자의 이름 뒤에는 생성자의 매개변수를 포함하는 둥근괄호()가 따라온다. 매개변수에 대해서는 나중에 배울 것이다. 둥근괄호 뒤에는 중괄호{}가 따라온다. 생성자 메서드의 블록 구문{}은 생성자 몸체로 불린다. 생성자 몸체에는 인스턴스를 초기화하는 것에 대한 내용이 들어있다. 클래스의 인스턴스를 만들 때는 언제나 그 클래스의 생성자가 실행된다.

생성자 메서드는 function 키워드로 만드는데, 생성자 메서드가 함수의 한 종류이기 때문이다. 함수에 대해서는 5장에서 배울 것이다.

클래스에 생성자를 정의하지 않았을 때, 액션스크립트는 아무 동작도 하지 않는 빈 생성자를 자동적으로 만들어낸다. 이런 편리에도 불구하고, 최선의 방법은 항상 생성자를 넣는 것이다. (생성자의 몸체에 아무 내용이 없다 해도) 빈 생성자는 클래스에서 생성자에 아무 초기화도 요구하지 않는다고 나타낸다.

class SomeClass {
 // 빈 생성자. 이 클래스는 초기화를 요구하지 않음
 function SomeClass ( ) {
 }
}

생성자에는 접근제어자를 사용할 수 없다. AS3.0에서, 모든 생성자의 접근제어자는 public이다. (액션스크립트의 이전 버전에서는 public 이 아닌 접근제어자를 허용했었다) 이 책에서는 생성자는 반드시 public이여야 한다는 것을 강조하기 위해 생성자에 항상 public 접근제어자를 붙일 것이다.

class SomeClass {
 public function SomeClass ( ) {
 }
}

생성자는 반드시 public 이여야 한다는 규칙은 ECMAscript4 언어 사양을 따른 것이다. 자세한 것은 Sho Kuwamoto의 다음 글을 참조한다. http://kuwamoto.org/2006/04/05/as3-on-the-lack-ofprivate-and-protected-constructors  (sho는 어도비 플렉스 빌더2 개발팀의 리더다)

메인 클래스의 생성자는 프로그램에서 특별한 역할을 한다. 생성자는 애플리케이션이 시작되고 곧바로 실행된다. 그러므로 메인클래스의 생성자는 프로그램의 시작점인 셈이다.

여기 VirtualZoo 클래스에 생성자를 추가한 코드가 있다 :

package zoo {
 public class VirtualZoo {
  public function VirtualZoo ( ) {
  }
 }
}

우리의 애플리케이션은 공식 시작점을 가지게 되었다. 애플리케이션이 시작되면, 플래시 런타임은 자동으로 VirtualZoo의 인스턴스를 만들고 생성자를 실행할 것이다. VirtualZoo의 생성자는 VirtualPet의 객체를 만들게 될 것이다. 다음에는 객체를 만드는 방법을 알아보자.

객체 만들기
클래스의 객체를 만들기 위해서는 new 키워드를 사용한다.
new 키워드의 사용법은 다음과 같다.

new 클래스이름

예를 들어, VirtualPet클래스의 객체를 만들기 위해서는 다음과 같이 쓴다.

new VirtualPet

한 클래스에서 여러 객체를 만들어낼 수 있다. 다음 코드는 VirtualPet의 객체를 두 번 만든다.

new VirtualPet
new VirtualPet

리터럴 구문
방금 새로운 객체를 만드는 일반적인 방법을 알아보았다. 그것은 다음과 같았다.

new 클래스이름

이 구문은 내장된 클래스와 직접 만든(커스텀) 클래스 양쪽에 똑같이 쓰인다. 예를 들어, 내장된 클래스인 Date의 객체는 다음과 같은 방법으로 만든다.

new Date

하지만, 몇 가지 내장 클래스를 위해 액션스크립트는 그 클래스의 객체를 만드는 다른 방법을 제공한다. 이 것은 리터럴 구문이라고 불린다. 예를 들어, 25.4라는 숫자를 제공하는 Number인스턴스는 리터럴을 사용해서 다음과 같이 만들고 나타낼 수 있다.

25.4

마찬가지로, hello라는 문자열을 제공하는 String인스턴스는 다음과 같이 나타낼 수 있다 :

"hello"

마지막으로, 논리값인 true(참)과 false(거짓)을 제공하는 Boolean인스턴스는 다음과 같이 표기한다 :

true
false

또한 Object, Function, RegExp, XML클래스를 위한 리터럴 구문들도 있다. (Object는 객체를 의미하는게 아닙니다. 주의) 우리는 Object의 리터럴 구문을 15장에서 배울 것이다. Function의 리터럴 구문은 5장에서 배울 것이다. XML의 리터럴 구문은 18장에서 배울 것이다. RegExp의 리터럴 구문에 대해서는 어도비의 문서를 참고하라. (이 책은 RegExp에 대해서는 다루지 않습니다)

객체 생성 : 동물원에 펫 추가하기
우리는 이제 클래스의 객체를 만드는 법을 알았다. 우리는 zoo 프로그램에 VirtualPet의 객체를 넣을 수 있다.

package zoo {
 public class VirtualZoo {
  public function VirtualZoo ( ) {
   new VirtualPet
  }
 }
}

VirtualPet의 풀네임은 zoo.VirtualPet이 되기 때문에 VirtualPet 만 쓰는 것은 부정확한 이름이지만, 같은 패키지에서는 클래스의 이름만 써도 정확하게 그 클래스에 접근할 것이다.

하지만, 한 패키지에서는 다른 패키지의 public 클래스에 그냥 접근할 수 없다. 다른 패키지의 public 클래스에 접근하기 위해서는 import 키워드를 사용해야 한다.

import packageName.className

packageName 은 접근하려는 클래스의 패키지 이름이다. clasName 은 접근하려는 public 클래스의 이름이다.
만약 접근하려는 클래스가 public이 아니라면, import 는 실패할 것이다. 여기 내장 클래스인 flash.media.Sound클래스를 import 하고 객체를 만드는 예제가 있다.

import flash.media.Sound
new Sound

클래스를 import하는 것은 패키지몸체에서 이루어진다. 클래스의 인스턴스를 만드는 것은 메서드에서 이루어진다.

package zoo {
 import flash.media.Sound

 public class VirtualZoo {
  public function VirtualZoo ( ) {
   new Sound
  }
 }
}

만약 현재 클래스의 이름이 다른 패키지에서 불러온 클래스의 이름과 충돌한다면? 예를 들어, zoo패키지에 Sound클래스를 새로 만들었는데 내장 클래스인 flash.media.Sound와 이름이 충돌한다고 가정한다. 그러면 컴파일 시간에 에러가 나는데, 이것을 컴파일 에러(compile time error) 라고 한다.

어떤 패키지의 모든 public 클래스를 불러오고 싶을 때는 다음과 같이 한다.

import packageName.*

예를 들어, flash.media 패키지의 모든 public 클래스를 불러오고 싶으면 다음과 같이 쓴다.

import flash.media.*

이름을 넣지 않은 패키지는 이름없는 패키지라고 한다. 이름없는 패키지의 클래스들은 import 없이 사용 가능하다.

package {
 // 여기 정의한 클래스는
 // 프로그램의 어디서든지 즉시 사용 가능
}

하지만, 다른 클래스(또는 다른 종류의 정의)와 충돌할 가능성이 있기 때문에 최선의 방법은 이름없는 패키지를 피하는 것이다.

기술적인 수준에서, import 지시문은 현재 스코프와 모든 nested 스코프를 위한 특별한 패키지의 public 네임스페이스를 연다. 하지만 액션스크립트가 처음이라면 당신은 import 지시문의 세부 기술에 대해 걱정하지 않아도 된다. 우리는 이 장에서 당신이 필요한 지식을 모두 검토 할 것이다.

가상 동물원 프로그램에서 객체를 만드는 것으로 돌아가자. 어떻게 VirtualPet의 객체를 만들어냈는지 생각해내라.

package zoo {
 public class VirtualZoo {
  public function VirtualZoo ( ) {
   new VirtualPet
  }
 }
}

이 코드는 VirtualPet의 객체를 성공적으로 만든다. 하지만 문제가 하나 생기는데, 이 객체가 만들어진 후, 프로그램은 이 것에 접근할 방법이 없다는 것이다. 결국, 우리 프로그램은 새로운 펫을 제어할 수 없다. VirtualPet 객체에 접근하기 위해, 우리는 변수를 사용한다.

변수와 값
액션스크립트에서 모든 객체는 값이라고 불리는 데이터의 조각을 가지고 있다. 액션스크립트의 객체들에서 값을 가지지 않는 것은 "값 없음"을 나타내는 null과 undefined가 유일하다. 변수는 값들의 식별자다. 예를 들어, 변수가 submitBtn이라는 버튼 객체의 식별자라고 하자. 아니면, 변수가 productionDescription이라는 String객체의 식별자라고 하자.

변수는 프로그램에서 정보의 흔적을 저장해서 우리에게 만들어진 객체의 참조를 제공한다.

변수는 네 가지 종류가 있다 : 지역변수, 인스턴스 변수, 동적 인스턴스변수, 정적 변수. 지금은 지역변수, 인스턴스 변수를 알아볼 것이다. 나머지 두 개는 나중에 알아볼 것이다.

지역 변수
지역 변수는 메서드 안에서 정보의 흔적을 임시적으로 저장한다. 지금은 생성자 메서드 안의 지역 변수에 초점을 맞추겠다.

생성자 메서드에 지역 변수를 만들기 위해, 변수 정의를 사용한다. var 키워드로 변수 정의를 시작함을 통고한다.
그리고, 모든 지시문을 쓴 후에는 관습적으로 세미콜론(;)으로 끝낸다. (변수 정의에 블록 구문{}은 들어가지 않는다)

class SomeClass {
 public function SomeClass ( ) {
  var varName = value;
 }
}

varName 은 지역변수의 이름이고, value 는 변수의 값이다. 등호(=)와 value는 변수 초기화자(者)인데, 변수의 최초의 값을 결정시키기 때문이다.

변수에 값을 넣는 것은 할당, 설정, 쓰기 등을 연상시킨다.

변수 초기화자를 생략할 땐, 액션스크립트는 변수에 자동적으로 기본값을 할당시킨다. 변수의 기본값은 8장에서 볼 수 있다.

지역변수는 자신을 가지는 메서드 또는 함수 안에서만 사용할 수 있다. 메서드나 함수의 실행이 끝났을 때, 지역 변수는 파기되고 더 이상 프로그램에 남아있지 않는다.

VirtualZoo 생성자에서 만들었던 VirtualPet 객체를 참조하는 지역변수를 만들자. 지역변수의 이름은 pet 으로, VirtualPet 객체를 참조하도록 초기화 할 것이다.

package zoo {
 public class VirtualZoo {
  public function VirtualZoo ( ) {
   var pet = new VirtualPet;
  }
 }
}

지역변수 pet이 VirtualPet객체를 참조하게 되었다. 이제 우리는 이 객체를 pet 을 통해 제어할 수 있다. 하지만, 현재 VirtualPet 객체는 실제로 아무 것도 할 수 없는데, 어떤 기능을 할 수 있도록 프로그램하지 않았기 때문이다. 다음 부분에서 펫이 별명을 가지도록 수정할 것이다.

인스턴스 변수
앞에서 클래스를 만들고 객체를 만드는 것을 알아봤다. OOP에서 "특징적인"은 가로길이, 속도, 색깔 등 객체의 어떤 모양을 나타내는 특별한 정보를 말한다. 객체의 특징을 저장하기 위해 우리는 인스턴스변수를 사용한다. 인스턴스변수는 객체에 붙여진 특별한 변수이다. 일반적으로, 인스턴스 변수는 객체의 어떤 특징을 묘사한다. 예를 들어, 이름이 width고 값이 150인 인스턴스변수는 버튼 객체의 넓이를 나타내기 위한 것으로 연상된다. 이름이 shippingAddress이고 값이 "34 Somewhere St"인 인스턴스변수는 운반물의 목적지를 연상시킨다.

인스턴스 변수는 클래스몸체에 변수 정의를 이용해서 만든다 :

class SomeClass {
 var varName = value;
}

클래스정의 안에 인스턴스변수 정의를 넣으면 그 변수는 그 클래스의 인스턴스를 만들 때 자동으로 붙여진다.

VirtualPet클래스에 별명을 나타내기 위해 petName이라는 변수를 추가하자.

package zoo {
 internal class VirtualPet {
  var petName = "Unnamed Pet";
 }
}

VirtualPet 클래스의 인스턴스를 만들면, petName 은 그 인스턴스에 붙여진다. 모든 VirtualPet 의 인스턴스의 petName 의 기본값은 "Unnamed Pet"이다. 하지만, VirtualPet 의 인스턴스는 자신의 petName의 값을 수정할 수 있다. 인스턴스변수에 새 값을 할당하기 위해서는 다음과 같이 쓴다.

someObject.instanceVariable = value

위에서 someObject 는 인스턴스변수를 가지는 객체를 의미한다. instanceVariable 은 객체가 가지고 있는 인스턴스변수를 의미한다. value 은 할당될 값을 의미한다.

VirtualZoo 생성자에서 VirtualPet 의 객체의 petName 의 값을 수정해보자. 여기 지금까지 써온 VirtualZoo 코드가 있다 :

package zoo {
 public class VirtualZoo {
  public function VirtualZoo ( ) {
   var pet = new VirtualPet;
  }
 }
}

인스턴스변수에 새 값을 할당시키기 위해 우선 객체부터 쓴다.

pet

그리고 점을 찍는다.

pet.

그리고, 인스턴스변수의 이름을 쓴다.

pet.petName

마지막으로, 등호(=)를 쓰고, 할당할 값을 쓴다.

pet.petName = "스탠"

귀엽지 않은가? 펫은 이름을 가지게 되었다.

package zoo {
 public class VirtualZoo {
  public function VirtualZoo ( ) {
   var pet = new VirtualPet;
   pet.petName = "스탠";
  }
 }
}

VirtualZoo 에서, VirtualPet 에 정의한 petName 을 가지는 VirtualPet 인스턴스의 인스턴스변수인 petName 의 값을 수정했다. petName 은 외부에서 수정 가능한, [접근 가능한 인스턴스변수]인 셈이다. 이 장의 나중에서, 우리는 caloriesPerSecond라는 인스턴스변수를 만들고 펫이 초마다 소화하는 속도를 나타낼 것이다. 만약 caloriesPerSecond에 너무 적거나 너무 큰 값이 들어가면, 펫은 굶어죽거나 배고픔을 모르고 자랄 것이다. 클래스 외부에서 caloriesPerSecond에 접근하고 값을 바꾸는 것을 막기 위해, 우리는 외부에서 caloriesPerSecond에 접근하지 못 하게 해야한다. 그러기 위해, 접근제어자를 사용할 것이다.

인스턴스 변수를 위한 접근제어자
인스턴스 변수의 접근제어자는 변수에 대한 접근가능성을 제어한다. 인스턴스 변수를 위한 접근제어자는 public, internal, protected, private이 있다. public과 internal은 클래스에 썼던 것과 마찬가지의 효과를 가진다. (public이면 패키지의 내부,외부 양쪽에서 접근 가능하고 internal이면 오직 패키지 내부에서만 접근 가능하다) protected와 private은 internal 보다 많은 제한을 둔다. protected이면 그 클래스 또는 그 클래스를 상속하는 클래스에서만 접근 가능하다. (우리는 아직 상속에 대해 배우지 않았다. 당신이 OOP를 깨우친다면, protected에 대해 바로, 간단하게 알 수 있을 것이다) private이면 그 클래스에서만 접근할 수 있다. 아무 접근제어자도 쓰지 않으면, internal이 사용된다.

표1-2. 인스턴스변수의 접근제어자에 따른 접근 가능성
─────────────────────────────────────
                     제어자
코드 위치         public  internal  protected  private
─────────────────────────────────────
변수가 정의된      허락됨   허락됨   허락됨   허락됨
클래스의 안쪽

변수가 정의된 클래스와 허락됨   허락됨   허락됨   거절됨
그 클래스의 자손

같은 패키지의      허락됨   허락됨   거절됨   거절됨
다른 클래스

다른 패키지에서의 접근 허락됨   거절됨   거절됨   거절됨
─────────────────────────────────────

VirtualPet 의 petName 은 VirtualZoo 에서 사용된다. 그러므로 petName 의 접근제어자를 internal 로 하자.

package zoo {
 internal class VirtualPet {
  internal var petName = "Unnamed Pet";
 }
}

internal 이 기본값이기 때문에 접근제어자를 쓰지 않은 것과 동일하다.

이 책의 나머지 예제들은 더 많은 인스턴스변수를 가진다. 가상 동물원 프로그램 개발의 다음 단계로 넘어가자.

지금까지 VirtualPet 클래스의 petName 을 직접 수정했다. 하지만 모든 펫에게 이름을 공급하기 위한 개런티를 원한다면, 생성자 매개변수를 사용할 수 있다. 다음 부분에서 알아볼 것이다.

 

 

 

생성자 매개변수(인자)와 인수
생성자 매개변수는 생성자 정의의 특별한 지역변수다.
일반 지역변수와 달리, 생성자 매개변수의 초기값은
새로운 객체를 만들 때(어떤 경우에는 반드시) 외부에서 공급할 수 있다.

class SomeClass {
 function SomeClass (식별자 = 값) {
 }
}

[식별자]는 매개변수의 이름이고, [값]은 매개변수의 초기값이다.
생성자 메서드를 위해 한 개 이상의 매개변수를 만들려면
콤마(,)로 구분해서 매개변수를 연속적으로 적는다.

class SomeClass {
 function SomeClass (식별자1 = 값1,
           식별자2 = 값2,
           식별자3 = 값3) {
 }
}

기본적으로, 매개변수의 값은 객체를 만들 때 공급받는다.
new SomeClass(값1, 값2, 값3)
값1,2,3은 생성자 인수라고 불리고, SomeClass의 생성자의 매개변수들에 할당된다.
생성자 인수를 사용해 생성자 매개변수에 값을 공급하는 것은 passing이라고 불린다.

생성자 매개변수 정의가 초기값을 포함하지 않을 때,
매개변수의 값은 반드시 인수에서 공급되어야 한다.

class SomeClass {
 function SomeClass (requiredParameter) {
 }
}

SomeClass의 객체를 만들 때는 반드시 requireParameter에 값을 공급해야 한다.
new SomeClass(값)
기본값이 없는 매개변수에 인수를 공급하지 않으면
엄격한 컴파일 모드일 시 컴파일 할 때 에러가 발생하고
기본 컴파일 모드일 시 프로그램이 실행되면 에러가 발생한다.
컴파일의 두 가지 모드 엄격한 컴파일과 기본 컴파일은 7장에서 배울 것이다.

어떤 객체를 생성자 인수 없이 만들 때,
어떤 프로그래머들은 인수를 넣는 괄호를 유지하기도 한다.
new VirtualPet( )
지금까지는 이렇게 써왔다.
new VirtualPet
액션스크립트는 두 형식 모두 지원한다.
하지만, 액션스크립트 프로그래밍 포럼에서는 괄호를 쓰는 것을 선호한다.
그러므로 이 책에서는 앞으로 객체의 매개변수가 없는 생성자에 괄호를 붙일 것이다.


매개변수를 추가하는 일반적인 방법을 알았으니,
VirtualPet의 생성자에 name이라는 [요구되는] 매개변수를 추가해보자.
우리는 name의 값을 petName의 값에 넣는 용도로 사용할 것이다.
여기 name은 추가했지만, 아직 생성자 몸체에서는 아무것도 하지 않은 코드가 있다.

package zoo {
 internal class VirtualPet {
  internal var petName = "Unnamed Pet";

  public function VirtualPet (name) {
  }
 }
}

name은 [요구되는 매개변수]이기 때문에, 외부에서 반드시 공급받아야 한다.
따라서, VirtualZoo의 생성자에서 VirtualPet의 객체를 만드는 이 코드를 수정해야 한다.

package zoo {
 public class VirtualZoo {
  public function VirtualZoo ( ) {
   var pet = new VirtualPet;
   pet.petName = "Stan";
  }
 }
}

여기 수정된 코드가 있다.

package zoo {
 public class VirtualZoo {
  public function VirtualZoo ( ) {
   var pet = new VirtualPet("스탠");
  }
 }
}

인수로 들어간 "스탠"은 petName의 값으로 쓰일 것이다.
VirtualPet의 생성자가 실행될 때, "스탠"은 생성자의 name 매개변수에 공급된다.
우리는 공급받은 "스탠"을 petName의 값으로 할당하는데 쓸 수 있다.
우리는 식별자 표현식을 사용하는데 petName의 값이 필요하다.
다음 섹션에서 표현식과 식별자 표현식에 대해 알아볼 것이다.

표현식
액션스크립트 프로그램에서 값을 쓰는 것은 표현식이라고 한다.
예를 들어, 다음 코드는 Date클래스의 새로운 객체를 나타내는 new표현식이다.

new Date()

마찬가지로, 다음 코드는 2.5라는 값을 가지는 Number클래스를 나타내는 리터럴 표현식이다.

2.5

각각의 표현식은 프로그램이 실행될 때 연산자를 이용한 복합표현식으로 묶일 수 있다.
연산자는 값을 묶고, 조종하고, 변형시키는 내장된 커맨드이다.
(연산자는 수학에서의 연산자만을 말하는 것이 아니다)
연산자는 심벌(+)이나 키워드(instanceof)를 이용해 쓴다.
예를 들어, 곱하기 연산자는 별표(*)를 이용해서 쓰며, 두 숫자를 곱한다.
다음 코드는 4와 2.5를 곱하는 것을 보여준다.

4 * 2.5

이 코드가 실행되면 컴파일 시간에 액션스크립트는 4와 2.5를 곱하는 연산을 한다.
그리고 4*2.5는 연산된 결과(10)으로 대체된다.

액션스크립트의 연산자 목록은 10장에서 볼 수 있다.

만약 연산에 변수를 사용한다면, 그 값은 컴파일 시간에 계산되지 않고,
프로그램이 실행될 때 계산된다.
예를 들어, 이 복합표현식은 quantity와 price의 값을 곱한다.

quantity * price

quantity의 값은 2이고, price의 값은 4.99라고 가정한다.

액션스크립트는 quantity와 price의 자리에 그들의 값을 대신 대치시킨다.

2 * 4.99

그리고 최종적인 값 표현식은 다음과 같다.

9.98

quantity같은 오직 이름만을 가지는 표현식을 식별자 표현식이라고 한다.

우리의 가상 동물 프로그램에서 식별자 표현식을 사용해보자.

한 변수의 값을 다른 것에 할당시키기
여기 지금까지 해온 VirtualPet과 VirtualZoo클래스가 있다.

// VirtualPet 클래스
package zoo {
 internal class VirtualPet {
  internal var petName = "Unnamed Pet";
   public function VirtualPet (name) {
  }
 }
}
// VirtualZoo 클래스
package zoo {
 public class VirtualZoo {
  public function VirtualZoo ( ) {
   var pet = new VirtualPet("Stan");
  }
 }
}

이제 우리는 표현식에서 어떻게 변수를 사용하는지 알고 있다.
잠깐 인스턴스변수의 값을 외부에서 어떻게 바꿨는지 기억해보자.

객체.인스턴스변수 = 값

인스턴스변수에 접근하기 위해 객체부터 참조해야 했다.
이 경우 객체는 VirtualPet의 인스턴스다.
객체 내부에서 자신의 인스턴스변수에 접근하기 위해서, this키워드를 사용한다.

클래스에서 그 클래스의 인스턴스에 접근하기 위해서 우리는 this키워드를 사용한다.

this를 쓴 후에는 점(.)을 쓰고, 참조하길 원하는 인스턴스변수를 쓴다.

this.petName

마지막으로, 등호(=) 기호를 쓰고, 할당할 값을 쓴다.

this.petName = 값

우리는 petName에 매개변수 name의 값을 할당하길 원한다.
그러므로, [값]부분에 name을 쓰자.

this.petName = name

런타임 때, 액션스크립트는 name 부분을
VirtualPet의 생성자의 인수로 들어간 값으로 대체한다.
그리고 petName의 값에 대체된 값을 할당한다.

package zoo {
 internal class VirtualPet {
  internal var petName = "Unnamed Pet";

  public function VirtualPet (name) {
   this.petName = name;
  }
 }
}

VirtualPet의 생성자에서 petName에 할당할 값이 제공되니,
우리는 petName의 정의에서 초기값인 "Unnamed Pet"을 뺄 수 있다.

internal var petName = "Unnamed Pet";

"Unanmed Pet"을 뺀 코드는 다음과 같다.

package zoo {
 internal class VirtualPet {
  internal var petName;

  public function VirtualPet (name) {
   this.petName = name;
  }
 }
}

this.petName = name 같은 변수에 값을 할당하는 표현식은 할당 표현식이다.
할당 표현식에서 등호(=) 기호는 할당 연산자라고 불린다.


복사와 참조
이전 섹션에서 우리는 한 변수의 값을 다른 변수에 할당하는 법, 특히,
인스턴스변수인 petName에 매개변수 name의 값을 할당하는 법을 배웠다.

this.petName = name;

한 변수의 값을 다른 변수에 할당하는 것의 결과는 할당된 값의 타입에 의존한다.

제공된 변수의 값이 Sring,Boolean,Number,int,uint의 인스턴스이면
액션스크립트는 그 값을 복사해서 값이 할당될 변수에 복사된 값을 할당한다.
할당후에는, 원래 값은 시스템 메모리에서 두 가지로 분리된다-
원래 값과 원래 값의 복사된 값.

대조적으로, 제공된 변수의 값이 커스텀클래스 또는
String,Boolean,Number,int,uint가 아닌 다른 내장된 클래스의 인스턴스이면
할당될 변수의 값은 원래 변수의 값을 참조한다.
할당후에는, 오직 하나의 값이 메모리에 있고, 두 변수가 그 값을 참조한다.
이 경우, 첫 번째 변수의 값이 바뀌면 두 번째 변수의 값에 그대로 반영된다.
예를 들어, 여기 a,b 두 지역 변수가 있고, b에는 a의 값이 할당되었다.

var a = new VirtualPet("스탠");
var b = a;

첫번째 줄에서 액션스크립트는 메모리에 VirtualPet의 새로운 객체를 만들고,
지역변수 a는 그 객체의 주소를 참조한다.
두번째 줄이 실행되면, 액션스크립트는 지역변수b에 이미 a가 참조하고 있는
VirtualPet의 객체의 주소를 할당시킨다.
예를 들어, b.petName = "톰" 이라는 코드로 petName에 값을 할당하면
a.petName 역시 "톰" 이다.
또는, a.petName = "켄" 이라는 코드를 사용하면 b.petName 역시 "켄" 이다.

변수는 객체를 자신에게 저장하지 않는다. 다만, 그 객체를 참조한다.
객체는 액션스크립트에 의해 내부적으로 시스템 메모리에 있다.


앞에서, 우리는 메서드나 함수의 실행이 끝나면 인스턴스변수가 파기된다고 배웠다.
VirtualPet의 인스턴스를 VirtualZoo의 생성자가 끝난 후에도 살리기 위해서
VirtualZoo클래스를 업데이트 하자.
VirtualPet객체를 지역변수로 선언하는 대신, 인스턴스변수 pet으로 바꾸자.
pet을 VirtualZoo클래스 안에서만 접근할 수 있게 하기 위해 private을 쓰자.

package zoo {
 public class VirtualZoo {
  private var pet;

  public function VirtualZoo ( ) {
   this.pet = new VirtualPet("Stan");
  }
 }
}

몇 전 섹션에서 우리는 클래스의 객체에 특징을 주기 위해
인스턴스 변수를 주는 법을 배웠다.
이제 클래스의 객체에 특별한 동작을 주기 위해 인스턴스 메서드를 알아보자.

인스턴스 메서드
인스턴스 메서드는 객체가 무엇인가를 할 수 있게 한다.
예를 들어, 내장된 Sound클래스에는 사운드를 재생할 수 있는
play라는 인스턴스 메서드가 정의되어 있다.
내장된 TextField 클래스에는 setSection이라는 메서드를 사용해서
텍스트필드에서 선택될 수 있는 텍스트의 양을 조절할 수 있다.

인스턴스 메서드를 만들기 위해, 우리는 클래스 몸체에서 함수 정의문을 사용한다.

class SomeClass {
 function identifier ( ) {
 }
}

function키워드는 인스턴스 메서드의 시작이다.
다음에는 인스턴스 메서드의 이름(identifier)이 온다.
(식별자는 공백,대쉬(-)문자를 가질 수 없고 숫자로 시작할 수 없음을 기억하자)
메서드 이름 다음에는 나중에 배울 메서드 매개변수를 포함하는 괄호()가 온다.
매개변수 목록 다음에는 블록 구문인 중괄호{}가 온다.
인스턴스 메서드의 블록 구문은 메서드 몸체라고 한다.
메서드 몸체는 무엇인가를 할 수 있는 지시문들이 들어간다.

인스턴스 메서드는 function키워드로 시작하는데, 함수의 한 종류이기 때문이다.
함수는 5장에서 배울 것이다.


인스턴스 메서드를 실행하기 위해 우리는 호출 표현식을 사용한다.
객체.메서드이름()
[메서드이름]은 실행될 메서드의 이름이다.
객체는 해당 메서드를 가지는 대상이다.
인스턴스 메서드를 실행하기 위해 호출 표현식을 사용하는 것은
객체의 메서드 호출이라고 불린다.
(또는 객체를 통해 메서드 호출하기, 객체의 메서드 호출하기라고도 불린다)

인스턴스메서드와 변수를 구분하기 위해 앞으로는
인스턴스메서드의 이름을 쓴 후 ()를 붙이겠다.

우리의 펫에 먹는 기능을 추가하기 위해, VirtualPet 클래스에
새로운 인스턴스변수와 새로운 인스턴스메서드를 추가하자.
새로운 인스턴스변수는 currentCalories로,
펫이 먹은 음식의 양을 나타내는 숫자값이다.
새로운 인스턴스메서드는 eat()으로, 이 메서드는
사용자가 펫에게 먹이를 먹이는 동작을 할 것이다.

여기 currentCalories 변수를 정의하는 코드가 있다.
VirtualPet의 외부에서 currentCalories에 접근하는 것을 막기 위해,
currentCalories의 접근제어자는 private으로 할 것이다.
새로운 VirtualPet의 인스턴스는 1000칼로리를 가지고 시작한다.

package zoo {
 internal class VirtualPet {
  internal var petName;
  private var currentCalories = 1000;
  public function VirtualPet (name) {
   this.petName = name;
  }
 }
}

여기 eat() 메서드 정의의 기본 골격이 있다.

package zoo {
 internal class VirtualPet {
  internal var petName;
  private var currentCalories = 1000;
  public function VirtualPet (name) {
   this.petName = name;
  }
  function eat ( ) {
  }
 }
}

eat()메서드는 아직 아무 코드도 가지지 않지만, eat()메서드를 호출할 수는 있다.
VirtualZoo클래스를 업데이트하자.

package zoo {
 public class VirtualZoo {
  private var pet;
  public function VirtualZoo ( ) {
   this.pet = new VirtualPet("Stan");
   this.pet.eat( );
  }
 }
}

우리는 메서드 eat()이 호출되면 currentCalories에 100을 더하길 원한다.
currentCalories에 100을 더하기 위해서는 두 단계를 거쳐야 한다.
첫번째로, 변수와 숫자값을 더한 값을 변수에 할당한다.
어떤변수 = 어떤변수 + 숫자값
메서드 eat()에서 currentCalories에 100을 더하는 코드는 다음과 같다.

this.currentCalories = this.currentCalories + 100;

코드를 짧게 쓰기 위해, 액션스크립트는 축약 더하기 연산자(+=)를 지원한다.
왼쪽에는 변수를, 오른쪽에는 더할 숫자를 쓴다.

this.currentCalories += 100;

여기 수정된 VirtualPet클래스가 있다.

package zoo {
 internal class VirtualPet {
  internal var petName;
  private var currentCalories = 1000;
  public function VirtualPet (name) {
   this.petName = name;
  }
  function eat ( ) {
   this.currentCalories += 100;
  }

 }
}

VirtualPet인스턴스의 메서드 eat()이 호출되면,
그 인스턴스의 currentCalories는 100이 증가한다.

예를 들어, 이 경우 pet의 currentCalories는 1100이 된다.
this.pet = new VirtualPet("스탠");
this.pet.eat( );

currentCalories는 외부에서 접근할 수 없으므로 eat()만을 통해 수정된다.
하지만, 종종 인스턴스메서드도 private일 필요가 있다.
인스턴스메서드의 접근가능성을 제어하기 위해 접근제어자를 사용한다.

인스턴스메서드를 위한 접근제어자
인스턴스메서드의 접근제어자는 인스턴스변수와 마찬가지로 다음과 같다.
(public, internal, protected, private)
인스턴스메서드가 public이면 내부,외부 양쪽에서 접근 가능하다.
internal이면 같은 패키지에서만 접근할 수 있다.
protected이면 그 클래스와 상속한 클래스에서만 접근할 수 있다.
(우리는 아직 상속에 대해 배우지 않았다. 만약 OOP가 처음이라면,
 지금은 protected에 대해 무시해도 좋다.)
private이라면 그 클래스 내부에서만 접근할 수 있다.
아무 접근제어자도 없으면, internal이 사용된다.

클래스의 메서드에 접근제어자를 추가할 때, 우리는 "블랙 박스" 원칙을 고수한다.
OOP에서, 각 객체는 손잡이에 의해 제어되는 블랙박스로 생각할 수 있다.
(블랙박스는 제어공학용어로, 어떤 입력을 주면 그에 맞는 출력을 주는 장치입니다.
 장치의 내용, 실태는 문제삼지 않고
 입력과 출력의 관계만을 논하는 추상적 개념으로 사용됩니다)


객체의 내부 움직임은 알 수 없(또한 별로 중요하지 않)다.
객체를 조종하는게 중요할 뿐이다.
객체의 public 인스턴스 메서드는 프로그래머에 의해 실행된다.
객체의 public이 아닌 메서드는 다른 내부 명령에 의해 실행된다.
따라서, public메서드만이 클래스와 외부를 통신 가능케 하는 매체인 셈이다.
private,protected,internal로 정의된 메서드는 내부 실행에 필요하다.
객체를 자동차에 빗대서 생각하라.
운전자는 객체를 사용하는 프로그래머다. 그리고,
자동차를 만든 사람은 클래스로 객체를 만드는 프로그래머다.
자동차를 운전하는데, 운전자는 자동차의 엔진의 역할을 몰라도 된다.
드라이버는 자동차를 페달으로 가속하고 핸들로 회전시킬 뿐이다.
운전자가 페달을 밟으면 자동차가 가속되게 하는 것은
운전자가 아니라 제작자의 관심사다.

당신의 클래스를 제작할 때, 내부의 동작에 초점을 맞춰라.
당신이 "운전자의 좌석"에 앉아있다고 상상해보라.
클래스의 구조를 바꿀 땐, 클래스의 외관-(즉, public메서드들)은
아주 조금, 또는 완전히 수정하지 않고, 클래스의 내부를 변형시켜야 한다.
비유적으로, 자동차에 새로운 엔진을 넣어도 운전자가 페달을 밟으면 움직여야 한다.

객체지향에서, 클래스의 public인스턴스메서드와 public인스턴스변수는 가끔,
합쳐서 클래스의 바깥세계에 대한 클래스의 인터페이스라고 불린다.
또는, 클래스의 (Application Programming Interface;API) 라고 불린다.

API는 또한 클래스의 그룹에 대한 집합적인 서비스를 의미한다.
예를 들어, 화면에 무언가를 표시하는
플래시 런타임의 내장 클래스들은 display API라고 불린다.
3D를 표현할 수 있는, 누군가가 만든 3D엔진은 "3D API"라고 불린다.
게다가, API는 다른 프로그램의 정의에 들어갈 수 있다.

액션스크립트에서, 인터페이스는 또 다른 전문적인 의미를 가진다.
(9장에서 볼 수 있다)
혼란을 막기 위해, 이 책은 객체의 public메서드와 public변수를 일컫는데
"인터페이스"라는 용어를 사용하지 않는다.

우리의 가상 동물원 프로그램으로 돌아오자.
VirtualPet클래스의 eat() 메서드에 접근제어자를 붙여보자.
외부에서 VirtualPet객체를 수정할 수 있게 하기 위한 메서드이므로 public을 붙인다.

package zoo {
 internal class VirtualPet {
  internal var petName;
  private var currentCalories = 1000;
  public function VirtualPet (name) {
   this.petName = name;
  }
  public function eat ( ) {
   this.currentCalories += 100;
  }
 }
}

eat()메서드는 호출될 때 마다 currentCalories에
매번 똑같은 값을 더하기 때문에 유연하지 않다.
사용자는 주는 음식에 따라서 칼로리에 더하는 양을 다르게 주는 것을 원할 것이다.
그래서, 우리는 메서드 매개변수가 필요하다.

메서드 매개변수와 인수
생성자 매개변수와 마찬가지로, 메서드 매개변수는 지역 변수의 특별한 한 종류이다.
메서드 매개변수를 정의하기 위해, 일반적으로 다음과 같은 코드를 쓴다.
메서드 매개변수 정의는 생성자 매개변수 정의의 구조와 같다.

function 메서드이름(식별자1 = 값1,
          식별자2 = 값2,
          ...
          식별자n = 값n) {
}

식별자1=값1,식별자2=값2,...식별자n=값n은
메서드 매개변수의 이름과 초기값의 목록이다.
기본적으로, 메서드 매개변수의 초기값에는 매개변수 정의의 값이 공급된다.
하지만, 메서드 매개변수의 값은 외부에서 공급받을 수 있다.

theMethod(값1, 값2, ... 값n)

[theMethod]는 호출할 메서드에 대한 참조고,
값1,값2,...값n은 [theMethod]의 매개변수 목록에 할당될 값이다.
메서드 매개변수에 공급되는 값들은 메서드 인수라고 한다.
메서드 인수를 메서드 매개변수에 공급하는 것은 passing이라고 한다.

생성자와 마찬가지로, 매개변수 정의에 초기값이 들어있지 않은 경우에는
반드시 메서드가 호출될 때 메서드 인수로 공급되어야 한다.
이런 매개변수는 요구되는 메서드 매개변수라고 한다.
다음 코드는 요구되는 메서드 매개변수를 만드는 예제이다.

function methodName (requiredParameter) {
}

요구되는 매개변수가 있는 메서드를 호출할 때는
반드시 메서드가 호출될 때 인수로 공급받아야 한다.

theMethod(value)

함수를 호출하는데 인수를 넣지 않으면, 컴파일이
엄격한 모드이면 컴파일 때 에러가 발생한다.
컴파일이 기본 모드이면 프로그램이 실행될 때 에러가 발생한다.

이제 VirtualPet클래스의 메서드 eat()이
요구되는 매개변수 numberofCalories를 가지도록 업데이트하자.
eat()이 호출되면, currentCalories의 값에 numberOfCalories를 더할 것이다.
여기 수정된 eat() 메서드가 있다.

package zoo {
 internal class VirtualPet {
  internal var petName;
  private var currentCalories = 1000;
  public function VirtualPet (name) {
   this.petName = name;
  }
  public function eat (numberOfCalories) {
   this.currentCalories += numberOfCalories;
  }
 }
}

numberOfCalories는 요구되는 매개변수이기 때문에,
eat()이 호출될 때 반드시 외부에서 공급받아야 한다.
VirtualZoo 생성자에서 만든 VirtualPet 객체에게 실험해보자.
그 전에, VirtualZoo 클래스의 코드를 보자.

package zoo {
 public class VirtualZoo {
  private var pet;
  public function VirtualZoo ( ) {
   this.pet = new VirtualPet("Stan");
   this.pet.eat( );
  }
 }
}

여기 업데이트된 코드가 있다. eat()에 50을 인수로 준다.

package zoo {
 public class VirtualZoo {
  private var pet;
  public function VirtualZoo ( ) {
   this.pet = new VirtualPet("Stan");
   this.pet.eat(50);
  }
 }
}

인수로 50을 줬으므로, pet의 currentCalories는 1050이 된다.

메서드의 반환값
메서드는 반환값을 제공할 수 있다.
메서드에서 값을 반환하기 위해서는 return구문을 사용한다.

function methodName ( ) {
 return 값;
}

메서드가 반환한 값은 메서드의 반환값 또는 메서드의 결과라고 한다.

메서드가 실행되면, 메서드의 반환값은 호출 표현식의 값이 된다.

메서드의 반환값을 설명하기 위해, VirtualPet클래스에
펫의 나이를 계산해서 반환하는 메서드를 추가하겠다.
인스턴스가 만들어진 시간을 계산하기 위해선
Date클래스에 대한 지식이 약간 필요하다.
Date의 인스턴스를 만들기 위해서 다음과 같은 코드를 쓴다.

new Date()

Date의 인스턴스는 1970년 1월 1일 자정부터
지금까지 경과한 시간을 밀리초로 반환하는 메서드가 있다.
예를 들어, 1970년 1월 1일 1초 후는 1000으로 표현된다.
1970년 1월 2일 자정은 85400000으로 표현된다
(하루는 1000밀리초 * 60초 * 60분 * 24시간).
기본적으로, Date의 객체는 로컬 시스템의 시간을 이용한다.

Date가 제공하는 1970년부터 지금까지의 밀리초를 얻기 위해서
우리는 인스턴스 변수 time을 사용한다.

new Date().time;

메서드가 실행되면, 메서드의 반환값은 호출 표현식의 값이 된다.
2007년 1월 24일 오후 5시 20분 지금, new Date().time이 나타내는 값은 다음과 같다.
1169677183875
이 값은 1970년 1월 1일 자정과
2007년 1월 24일 오후 5시 20분 사이를 밀리초로 변환한 값이다.

VirtualPet클래스로 돌아가자.
VirtualPet객체의 나이를 계산하기 위해 우리는 객체가 만들어질 때의 시간을 기억해야 한다.
그러기 위해서 VirtualPet의 생성자에서 내장된 클래스인 Date클래스를 사용할 것이다.
그리고 시간을 저장하기 위해 creationTime이라는 인스턴스 변수를 추가하겠다.

package zoo {
 internal class VirtualPet {
  internal var petName;
  private var currentCalories = 1000;
  private var creationTime;
  public function VirtualPet (name) {
   this.creationTime = new Date( );
   this.petName = name;
  }
  public function eat (numberOfCalories) {
   this.currentCalories += numberOfCalories;
  }
 }
}

나이를 계산하기 위해 getAge()라는 메서드를 추가하겠다.

public function getAge ( ) {
 var currentTime = new Date( );
 var age = currentTime.time - this.creationTime.time;
}

age를 반환하기 위해 return 구문을 사용한다.

public function getAge ( ) {
 var currentTime = new Date( );
 var age = currentTime.time - this.creationTime.time;

 return age;
}

여기 getAge()를 추가한 코드가 있다.

package zoo {
 internal class VirtualPet {
  internal var petName;
  private var currentCalories = 1000;
  private var creationTime;
  public function VirtualPet (name) {
   this.creationTime = new Date( );
   this.petName = name;
  }
  public function eat (numberOfCalories) {
   this.currentCalories += numberOfCalories;
  }
  public function getAge ( ) {
   var currentTime = new Date( );
   var age = currentTime.time - this.creationTime.time;
   return age;
  }

 }
}

VirtualZoo의 생성자에서 getAge()의 반환값을 사용하자.

package zoo {
 public class VirtualZoo {
  private var pet;
  public function VirtualZoo ( ) {
   this.pet = new VirtualPet("Stan");
   this.pet.getAge( );
  }
 }
}

나중에도 이 값을 참조할 수 있게 하기 위해 변수를 만들고 값을 할당하겠다.

package zoo {
 public class VirtualZoo {
  private var pet;
  public function VirtualZoo ( ) {
   this.pet = new VirtualPet("Stan");
   var age = this.pet.getAge( );
  }
 }
}

가상 동물원 프로그램의 마지막 버전에서는
사용자가 나이를 볼 수 있게 age를 화면에 표시할 것이다.

메서드의 반환값은 OOP의 높은 수준의 개념이다.
반환값은 이 책의 처음부터 끝까지 광범위하게 쓰일 것이다.

호출 표현식은 연산자를 이용해서 다른 표현식과 결합시킬 수 있다.
예를 들어, 이 코드는 pet의 나이를 반절로 나눈다.

pet.getAge() / 2

다음 코드는 VirtualPet의 객체를 두 개 만들고,
둘의 나이를 더해서 totalAge라는 지역변수에 할당시킨다.

package zoo {
 public class VirtualZoo {
  private var pet1;
  private var pet2;
  public function VirtualZoo ( ) {
   this.pet1 = new VirtualPet("Sarah");
   this.pet2 = new VirtualPet("Lois");
   var totalAge = this.pet1.getAge() + this.pet2.getAge( );
  }
 }
}

return 구문이 아무 값도 반환하지 않을 땐,
간단하게 메서드의 실행을 강제로 종료한다.

public function someMethod ( ) {
 // 이 곳의 코드는 실행된다
 return;
 // 이 곳의 코드는 실행되지 않는다
}

return구문이 아무 값도 반환하지 않으면(또는 return구문이 쓰이지 않으면)
메서드는 특별한 값인 undefined를 반환한다.

메서드 시그네쳐
OOP에서, 메서드의 이름, 매개변수 목록은 때때로 메서드의 시그네쳐라 불린다.
액션스크립트에서, 매개변수의 데이터타입과 메서드의 반환값도 시그네쳐에 포함된다.
매개변수의 데이터타입과 메서드의 반환값타입은 8장에 나온다.

예를 들어, eat() 메서드의 시그네쳐는 다음과 같다.
eat(numberOfCalories)

getAge() 메서드의 시그네쳐는 간단하다.
getAge()

우리는 지금 인스턴스 메서드의 기본을 배우고 있다.
이 장을 끝내기 전에, 우리는 액션스크립트 문법과 관련된
이슈를 하나 배울 것이다.

멤버와 속성
AS3.0에서, 객체의 변수와 메서드는 속성이라고 불린다.
속성은 "값 또는 메서드의 이름" 을 뜻한다.
당황스럽게도, 다른 액션스크립트 문서에선 (특히, 어도비의 액션스크립트 언어 레퍼런스)
속성이 "인스턴스 변수"를 지칭하는데도 쓰인다.
혼란을 피하기 위해, 이 책에서는 "속성"이라는 표현을 피하겠다.

그 대신, 클래스의 인스턴스 메서드와 인스턴스 변수를
이 책에서는 OOP의 전통적인 용어인 인스턴스 멤버(간단하게는 멤버)라고 부를 것이다.
예를 들어, "반지름은 상자의 멤버가 아니다"는
Box클래스에는 radius라는 변수나 메서드가 정의되지 않은 것을 의미한다.

가상 동물원 재검토
우리의 가상 동물원 프로그램은 두 가지 클래스를 가지고 있다 :
VirtualZoo(main클래스), VirtualPet(동물원의 펫을 나타냄)

우리 프로그램이 실행되면, 플래시 런타임은 자동적으로 VirtualZoo의 인스턴스를 만든다
(VirtualZoo가 애플리케이션의 main클래스이기 때문이다).
VirtualZoo의 인스턴스를 만들기 위해 VirtualZoo의 생성자가 실행된다.
VirtualZoo의 생성자는 VirtualPet의 인스턴스를 만든다.
VirtualPet의 인스턴스를 만드는데는 "스탠" 이라는 인수가 쓰였다.

VirtualPet 클래스에는 세 가지 인스턴스 변수를 정의한다.
petName, currentCalories, creationTime
세 인스턴스 변수는 펫의 별명, 칼로리, 나이를 나타낸다.
VirtualPet의 새로운 객체를 위해 currentCalories의 초기값은 1000이다.
creationTime의 초기값은 VirtualPet의 객체가 만들어질 떄 Date객체가 제공한다.
VirtualPet의 객체가 만들어질 때,
petName의 값에는 name이라는 요구되는 매개변수가 할당된다.
name은 new표현식으로 VirtualPet의 객체가 만들어질 때
VirtualPet의 생성자 인수에 의해 공급받는다.

그리고 VirtualPet클래스는 두 인스턴스 메서드를 정의한다.
eat(), getAge()
eat()메서드는 currentCalories의 값을 증가시킨다.
getAge()는 펫의 현재 나이를 밀리초로 계산해서 반환한다.

[예제 1-2]는 동물원 프로그램의 현재 전체 코드이다.

[예제 1-2 동물원 프로그램]
// VirtualPet class
package zoo {
 internal class VirtualPet {
  internal var petName;
  private var currentCalories = 1000;
  private var creationTime;
  public function VirtualPet (name) {
   this.creationTime = new Date( );
   this.petName = name;
  }
  public function eat (numberOfCalories) {
   this.currentCalories += numberOfCalories;
  }
  public function getAge ( ) {
   var currentTime = new Date( );
   var age = currentTime.time - this.creationTime.time;
   return age;
  }
 }
}
// VirtualZoo class
package zoo {
 public class VirtualZoo {
  private var pet;
  public function VirtualZoo ( ) {
   this.pet = new VirtualPet("Stan");
  }
 }
}

 

휴식 시간!
우리는 이 장에서 진도를 많이 나갔다.
아직 배울게 많이 남아있지만, 휴식 시간을 가지자.
AS3.0의 기초를 배울 준비가 되어 있다면, 다음 장으로 넘어가자.