sitelink1 http://www.graphittie.org/blog/entry/def...nheritance 
sitelink2  
sitelink3  
sitelink4 http://1 
extra_vars4 ko 
extra_vars5  
extra_vars6 sitelink1 

Attention for this document이 문서의 이용시 주의사항

이 페이지는 Prototype 공식 홈페이지의 "Defining classes and inheritance" 문서를 한국어로 번역한 문서입니다. 번역 오류정보 및 기타 제안사항은 제안 및 문의사항 페이지를 통해 보내주시기 바랍니다. 이 문서는 원저작자의 공유 조건인 Creative Commons 저작자표시-동일조건변경허락 3.0 Unported에 따라 이용하실 수 있습니다.

Content본문

Prototype에서 클래스 생성의 기반은 여전히 Class.create() 메소드이다. 프레임워크의 새로운 버전에서도 사용자의 클래스 기반 코드는 전처럼 동작할 것이다. 단지 이제는 직접적으로 객체의 prototype을 다룰 필요가 없어졌으며 속성을 복사하기 위해 Object.extend()를 사용할 필요도 없다.

Example예제

Prototype에서 클래스를 생성하고 상속하는 새로운 방법과 이전 방법을 비교해 보자.

 
var Person = Class.create();
Person.prototype = {
initialize: function(name) {
this.name = name;
},
say: function(message) {
return this.name + ': ' + message;
}
};
 
var guy = new Person('Miro');
guy.say('hi');
 
var Pirate = Class.create();
Pirate.prototype = Object.extend(new Person(), {
say: function(message) {
return this.name + ': ' + message + ', yarr!';
}
});
 
var john = new Pirate('Long John');
john.say('ahoy matey');

클래스의 prototype과 직접적으로 연동되는 부분과 Object.extend()를 사용하는 어색한 상속 테크닉에 주목하라. Person say() 메소드를 재정의하는 Pirate에서는 클래스 기반 상속을 지원하는 다른 프로그래밍 언어와는 다르게, 오버라이딩된(overriden) 메소드를 호출할 방법이 없다.

이 문제는 개선되었다. 다음과 위 예제를 비교해보라:

 
var Person = Class.create({
initialize: function(name) {
this.name = name;
},
say: function(message) {
return this.name + ': ' + message;
}
});
 
var Pirate = Class.create(Person, {
say: function($super, message) {
return $super(message) + ', yarr!';
}
});
 
var john = new Pirate('Long John');
john.say('ahoy matey');

더이상 직접적으로 prototype을 해킹할 필요가 없어졌기 때문에 클래스와 서브클래스가 모두 더 짧아진 것을 확인할 수 있다. 또한 위 예제에는 "수퍼콜(supercall)"이라 불리는 새로운 기능의 데모도 포함되어 있다. (Ruby에서 사용하는 특별한 키워드인 super를 사용하여) Pirate#say가 오버라이딩한(overriden) 메소드를 호출하는 것이다.

How to mix-in modules모듈과 함께 사용하는 법

지금까지는 Class.create의 일반적인 사용법을 보았다.

var Pirate = Class.create(Person, {  });

그러나 사실상 Class.create가 받는 인수의 갯수는 자의적으로 변한다. (첫번째 인수가 다른 클래스인 경우) 새로 생성되는 클래스는 첫번째 인수를 상속한다. 이외의 모든 경우는 인스턴스 메소드(instance method)로서 추가되는데, 내부적으로는 addMethods에 의해 호출된다(다음 예제를 보라). 이 방식은 모듈을 통합하기에 편리하다.

var Vulnerable = {
wound: function(hp) {
this.health -= hp;
if (this.health < 0) this.kill();
},
kill: function() {
this.dead = true;
}
};
 
var Person = Class.create(Vulnerable, {
initialize: function() {
this.health = 100;
this.dead = false;
}
});
 
var bruce = new Person;
bruce.wound(55);
bruce.health; 

The $super argument in method definitions메소드 정의에서 $super 인수

서브클래스에서 메소드를 오버라이딩하되(override) 원본 메소드 역시 계속 해서 호출할 수 있기를 원한다면, 메소드에 레퍼런스를 부여할 필요가 있다. 메소드 정의에서 인수의 처음에 임시 인수 $super를 부여하면 레퍼런스를 지정할 수 있다. Prototype은 이를 인식하여 이 인수를 통해 사용자가 필요로 하는 메소드를 덧씌우게 된다(overriden). 그러나 외부에서 볼 때 Pirate#say 메소드는 여전히 하나의 인수를 갖는 것으로 취급되는데, 사용자는 이러한 세부 구현에 신경쓰지 않고 이전처럼 코드를 작성하면 된다.

Types of inheritance in programming languages프로그래밍 언어에서 상속의 타입

일반적으로 클래스 기반 상속과 프로토타입 상속으로 구별되는데, 자바스크립트는 후자의 케이스이다. 곧 나올 자바스크립트 2.0은 진정한 의미의 클래스 정의를 지원할 예정이지만, 최신 브라우저에 구현되어 있는 자바스크립트 언어의 현재 버전은 프로토타입 상속에 제한되어 있다.

물론, 프로토타입 상속은 매우 유용한 기능이기는 하지만 실제로 객체를 생성하기에는 다소 장황한 면이 있기도 하다. 이 점이 내부적으로 프로토타입 상속을 통해 (Ruby와 비슷한) 클래스 기반 상속을 흉내내는 이유이다. 이것은 암시하는 바가 있다. 예를 들어, PHP(PHP: Hypertext Preprocessor)에서는 인스턴스 변수에 초기값을 정의할 수 있다.

class Logger {
public $log = array();
 
function write($message) {
$this->log[] = $message;
}
}
 
$logger = new Logger;
$logger->write('foo');
$logger->write('bar');
$logger->log; 

Prototype에서도 같은 시도를 해볼 수 있다.

var Logger = Class.create({
initialize: function() { },
log: [],
write: function(message) {
this.log.push(message);
}
});
 
var logger = new Logger;
logger.log; 
logger.write('foo');
logger.write('bar');
logger.log; 

동작은 할 것이다. 허나 Logger의 또 다른 인스턴스를 생성하려 한다면 어쩔 것인가?

var logger2 = new Logger;
logger2.log; 
 

볼 수 있는 것처럼, 새로운 인스턴스에서 빈 배열이 예상되지만 이전에 생성된 logger의 값이 존재한다. 사실상 모든 logger 객체는 값이 아니라 레퍼런스에 의해 복제되었기 때문에 하나의 배열 객체를 공유하게 된다.올바른 방법은 인스턴스마다 디폴트 값으로 초기화하는 것이다.

var Logger = Class.create({
initialize: function() {
this.log = [];
},
write: function(message) {
this.log.push(message);
}
});

Defining class methods클래스 메소드 정의

Prototype 1.6.0에서는 클래스 메소드에 대한 특별한 지원은 없다. 단순히 존재하는 클래스에 정의하기만 하면 된다.

Pirate.allHandsOnDeck = function(n) {
var voices = [];
n.times(function(i) {
voices.push(new Pirate('Sea dog').say(i + 1));
});
return voices;
}
 
Pirate.allHandsOnDeck(3);

한 번에 여러 메소드를 정의할 필요가 있다면 그냥 다음처럼 Object.extend를 사용하라:

Object.extend(Pirate, {
song: function(pirates) { ... },
sail: function(crew) { ... },
booze: ['grog', 'rum']
});

Pirate를 상속할 때 클래스 메소드는 상속되지 않는다. 이 기능은 Prototype의 이후 버전에서 추가될 예정이다. 그때까지는 수동으로 메소드를 복사하되 다음처럼 하지는 말도록:

var Captain = Class.create(Pirate, {});
Object.extend(Captain, Pirate);

클래스 생성자는 함수 객체인데 이는 단순히 어떤 클래스에서 다른 클래스로 모든 것을 복사하려 할 경우 문제의 여지가 있다. 운이 좋다면 Captain superclass subclasses 속성을 오버라이드할 수 있을지도 모르지만, 이는 좋은 방법은 아니다.

Special class properties특수 클래스 속성

Prototype 1.6.0은 두 가지 특별한 클래스 속성인 subclasses, superclass를 정의하고 있다. 역할은 이름이 묘사하는 것과 같아서 각각 현재 클래스의 수퍼클래스와 서브클래스의 레퍼런스이다.

Person.superclass
Person.subclasses.length
Person.subclasses.first() == Pirate
Pirate.superclass == Person
Captain.superclass == Pirate
Captain.superclass == Person

이 속성은 손쉽게 클래스 내부를 돌아보도록 하기 위한 것이다.

Adding methods on-the-fly with Class#addMethods동작중에 Class#addMethods로 메소드를 추가하기

Class#addMethods는 Prototype 1.6 RC0에서는 Class.extend로 불렸다. 이에 따라 코드를 적절히 업데이트 하라.

임시 메소드를 추가하고 싶은 클래스가 이미 정의되어 있다고 가정하자. 당연히 해당 메소드를 서브클래스와 메모리에 존재하는 모든 인스턴스에서 바로 사용하길 원하고 있다. 이것은 prototype 체인(chain)에 속성을 주입함으로써 이뤄지게 되는데, Prototype에서 이를 구현하는 가장 안전한 방법은 Class#addMethods를 사용하는 것이다.

var john = new Pirate('Long John');
john.sleep();
 
Person.addMethods({
sleep: function() {
return this.say('ZzZ');
}
});
 
john.sleep();

sleep 메소드는 새롭게 생성될 Person 인스턴스에서 뿐만 아니라 Person의 서브클래스 및 현재 메모리에 존재하는 인스턴스에서도 바로 사용할 수 있다.

번호 제목 글쓴이 날짜 조회 수
30 상속과 Super 로의 접근 황제낙엽 2012.09.18 64
29 inherits() 를 이용한 상속 황제낙엽 2012.07.18 129
» Defining classes and inheritance (클래스 정의와 상속) 황제낙엽 2011.03.24 392
27 JavaScript Closures for Dummies 황제낙엽 2009.04.08 227
26 체인 생성자(생성자 체인), 프로토타입 체인 그리고 생성자 재지정 황제낙엽 2009.08.12 55
25 [펌] TAEYO.NET - Js OOP - 나만의 프레임워크 만들기 황제낙엽 2009.04.02 18
24 [펌] TAEYO.NET - Js OOP - 사용자 정의 객체. 그리고 상속과 재사용 황제낙엽 2009.04.02 16
23 [펌] TAEYO.NET - JavaScript OOP 코어객체와 prototype를 사용한 객체확장 황제낙엽 2009.04.02 21
22 [펌] 아사페릴의 사생활 - 싱글톤 패턴을 지향한 Javascript Module Pattern 황제낙엽 2009.04.02 90
21 [펌] 아사페릴의 사생활 - Code Conventions for the JavaScript Programming Language 황제낙엽 2009.04.02 194
20 [펌] 아사페릴의 사생활 - __proto__ 와 construct 와 prototype 황제낙엽 2009.04.02 23
19 [펌] 아사페릴의 사생활 - prototype과 __proto__ 와 constructor 황제낙엽 2009.04.02 41
18 [펌] 아사페릴의 사생활 - __proto__ 와 prototype에 대해.. 황제낙엽 2009.04.02 15
17 [펌] 아사페릴의 사생활 - Javascript의 클래스에 관한 이야기 황제낙엽 2009.04.02 17
16 [펌] 아사페릴의 사생활 - Javascript의 constructor 와 prototype 황제낙엽 2009.04.02 156
15 [펌] prototype (2) 황제낙엽 2009.04.02 9
14 [펌] prototype (1) 황제낙엽 2009.04.02 12
13 [key:value] 형태로 object를 저장할 수 있는 Static영역의 해쉬맵 클래스 (Map) 황제낙엽 2008.11.04 46
12 함수와 인자값 (arguments) 황제낙엽 2008.08.12 15
11 중첩 함수, 함수 클로저 황제낙엽 2008.08.12 820