JavaScript 의 클래스 계승

7879 단어 상속
JavaScript Inheritance
DouglasCrockford www.crockford.com
And you think you're so clever and classless and free--John Lennon
JavaScript 는 클래스 가 없 는 대상 을 대상 으로 하 는 언어 로 클래스 계승 대신 원형 계승 을 사용 합 니 다.이것 은 전통 적 인 대상 언어(예 를 들 어 C++와 자바)훈련 을 받 은 프로그래머 에 게 약간 혼 란 스 러 울 수 있다.자 바스 크 립 트 의 원형 계승 은 클래스 계승 보다 더 강 한 표 현 력 을 가지 고 있 으 니 이제 살 펴 보 자.
Java
JavaScript
강 한 유형
약 한 유형
정적
동태
클래스 기반
원형 기반
종류
함수.
구조 기
함수.
방법.
함수.
그런데 우선 왜 우 리 는 상속 에 관심 이 많 을 까?주로 두 가지 이유 가 있다.첫 번 째 는 유형 이 유리 하 다.우 리 는 언어 시스템 이 유사 한 유형의 인용 변환 캐 스 트 를 자동 으로 진행 할 수 있 기 를 바란다.작은 유형의 보안 은 프로그램 이 대상 이 참조 하 는 형식 시스템 을 표시 하도록 요구 하 는 형식 시스템 에서 얻 을 수 있 습 니 다.이것 은 강 한 유형 언어의 가장 관건 적 인 요점 이지 만,이것 은 자 바스 크 립 트 와 같은 약 한 유형 언어 에 대해 서 는 무관 하 며,자 바스 크 립 트 의 클래스 인용 은 강제 적 으로 변환 할 필요 가 없다.
두 번 째 이 유 는 코드 의 재 활용 을 위 한 것 이다.프로그램 에 서 는 많은 대상 이 같은 방법 을 실현 하 는 것 을 자주 발견 할 수 있다.클래스 는 단일 한 정 의 를 만 들 고 대상 을 집중 적 으로 만 드 는 것 을 가능 하 게 합 니 다.대상 에 다른 대상 도 포 함 된 대상 을 포함 하 는 것 도 흔 하지만 차이 점 은 작은 방법의 추가 나 수정 에 불과 하 다.클래스 계승 은 이것 에 매우 유용 하지만 원형 계승 은 심지어 더욱 유용 하 다.
이 점 을 보 여 주 려 면,우 리 는 우리 가 일반적인 언어 처럼 코드 를 쓸 수 있 는 작은 디저트 를 소개 해 야 한다.우 리 는 그런 후에 언어 에 없 는 유용 한 모델 을 보 여줄 것 이다.마지막 으로 우 리 는 이 디저트 들 을 설명 할 것 이다.클래스 계승 우선,우 리 는 Parenizor 클래스 를 만 듭 니 다.멤버 value 의 get 과 set 방법 이 있 고,value 를 괄호 안에 포장 하 는 toString 방법 도 있 습 니 다
 
function Parenizor(value) {
this.setValue(value);
}
Parenizor.method('setValue', function (value) {
this.value = value;
return this;
});
Parenizor.method('getValue', function () {
return this.value;
});
Parenizor.method('toString', function () {
return '(' + this.getValue() + ')';
});
이 문법 은 쓸모 가 없 을 수도 있 지만 그 중의 유형 을 쉽게 알 수 있다.method 방법 은 방법 이름과 함 수 를 받 아들 이 고 클래스 에 넣 는 것 을 공공 방법 으로 합 니 다.이제 우 리 는
 
myParenizor = new Parenizor(0);
myString = myParenizor.toString();
기대 한 바 와 같이 마 이 스 트 링 은'(0)'이 라 고 쓸 수 있다.이제 우 리 는 Parenizor 에서 계승 하 는 다른 종 류 를 만 들 려 고 합 니 다.이 종 류 는 기본적으로 똑 같 습 니 다.toString 방법 을 제외 하고'-0-'이 생 길 것 입 니 다.value 가 0 이거 나 비어 있 으 면..
 
function ZParenizor(value) {
this.setValue(value);
}
ZParenizor.inherits(Parenizor);
ZParenizor.method("e;toString"e;, function () {
if (this.getValue()) {
return this.uber('toString');
}
return "-0-";
});
inherits 방법 은 자바 의 extends 와 유사 하 다.uber 방법 은 자바 의 슈퍼 와 유사 하 다.부모 클래스 를 호출 하 는 방법 입 니 다.우 리 는 이렇게 쓸 수 있다
 
myZParenizor = new ZParenizor(0);
myString = myZParenizor.toString();
이번에 my String 은"-0-"이다.자바 스 크 립 트 는 클래스 가 없 지만 우 리 는 이 목적 을 달성 할 수 있다.다 중 계승 은 함수 하 나 를 조작 하 는 prototype 대상 을 통 해 다 중 계승 을 실현 할 수 있 습 니 다.혼합 다 상속 은 실현 되 기 어렵 고 명칭 충돌 의 위험 에 처 할 수 있다.우 리 는 자 바스 크 립 트 에서 혼합 다 중 계승 을 실현 할 수 있 지만,이 예 는 스위스 계승 SwissI nheritance 라 고 불 리 는 비교적 규범 화 된 형식 을 사용 할 것 입 니 다.만약 NumberValue 류 에 setValue 방법 이 있다 고 가정 하면 value 가 지 정 된 범위 내의 한 수 인지 확인 하고 적당 한 시기 에 이상 을 던 집 니 다.우 리 는 그것 의 setValue 와 setRange 방법 을 우리 의 ZParenizor 에 게 주기 만 하면 된다.우 리 는 당연히 그것 의 toString 방법 을 원 하지 않 는 다.이렇게 해서 우 리 는
 
ZParenizor.swiss(NumberValue, 'setValue', 'setRange');
이것 은 필요 한 방법 만 추가 할 것 이 라 고 썼 다.기생 계승 은 또 다른 ZParenizor 류 를 쓰 는 방법 이다.Parenizor 에서 계승 하지 않 고 Parenizor 구조 기 를 호출 한 구조 기 를 썼 으 며 결과 수정 을 마지막 으로 이 결 과 를 되 돌려 주 었 습 니 다.이 구조 기 는 공공 적 인 방법 이 아니 라 특권 적 인 방법 을 추가 합 니 다
 
function ZParenizor2(value) {
var self = new Parenizor(value);
self.toString = function () {
if (this.getValue()) {
return this.uber('toString');
}
return "-0-"
};
return self;
}
상속 은'예...'의 관계 이 고 기생 상속 은'원래................................................................구조 기 는 대상 의 구조 에서 대량의 역할 을 맡 았 다.uber(슈퍼 키 대신)는 특권 방법 에 유효 합 니 다.클래스 확장 자 바스 크 립 트 의 동태 성 은 기 존의 클래스 를 추가 하거나 교체 할 수 있 습 니 다.우 리 는 언제든지 방법 을 호출 할 수 있다.우 리 는 수시로 한 종 류 를 확장 할 수 있다.계승 은 이런 방식 이 아니다.그래서 우 리 는 이러한 상황 을'클래스 확장'이 라 고 부 르 며 자바 의 extends-확장 이 라 고도 부 르 지만 헷 갈 리 지 않 습 니 다.대상 은 정적 대상 언어 로 확장 되 어 있 습 니 다.대상 과 다른 대상 을 구별 하려 면 클래스 를 새로 만들어 야 합 니 다.그러나 자바 스 크 립 트 에 서 는 새 클래스 대신 단독 대상 에 방법 을 추가 할 수 있 습 니 다.이것 은 커 다란 에 너 지 를 가 질 수 있다.왜냐하면 너 는 가능 한 한 적은 종 류 를 쓸 수 있 고,종류 도 더욱 간단하게 쓸 수 있 기 때문이다.자 바스 크 립 트 의 대상 을 생각하면 해시 표 와 같다.너 는 언제든지 새로운 값 을 추가 할 수 있다.만약 이 값 이 함수 라면 그 는 하나의 방법 이 될 것 이다.이렇게 위의 예 에서 나 는 ZParenizor 류 가 전혀 필요 없다.나 는 단지 나의 실례 를 간단하게 수정 하기 만 하면 된다
 
myParenizor = new Parenizor(0);
myParenizor.toString = function () {
if (this.getValue()) {
return this.uber('toString');
}
return "-0-";
};
myString = myParenizor.toString();
우 리 는 my Parenizor 인 스 턴 스 에 toString 방법 을 추가 하여 어떠한 계승 도 사용 하지 않 았 다.우 리 는 이 언어 가 유형 이 없 기 때문에 단독 실례 를 진화 시 킬 수 있다.디저트 는 위의 예 를 실행 시 켜 야 한다.나 는 디저트 방법 네 가 지 를 썼 다.우선,method 방법 은 하나의 인 스 턴 스 방법 을 하나의 클래스 에 추가 할 수 있 습 니 다
 
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
이것 은 Function.prototype 에 공공 방법 을 추가 하여 클래스 를 통 해 모든 함 수 를 확장 할 수 있 습 니 다.그것 은 이름과 함 수 를 매개 변수 로 해 야 한다.이것 은 this 로 돌아 갑 니 다.내 가 값 을 되 돌려 주지 않 는 방법 을 쓸 때,나 는 보통 그것 을 this 로 되 돌려 준다.이렇게 하면 체인 문 구 를 형성 할 수 있다.다음은 inherits 방법 입 니 다.한 종 류 는 다른 종 류 를 계승 하 는 것 이 라 고 지적 할 것 입 니 다.그것 은 두 가지 유형 이 모두 정 의 된 후에 야 정 의 를 내 릴 수 있 지만 방법 이 계승 되 기 전에 호출 해 야 한다
 
Function.method('inherits', function (parent) {
var d = 0, p = (this.prototype = new parent());
this.method('uber', function uber(name) {
var f, r, t = d, v = parent.prototype;
if (t) {
while (t) {
v = v.constructor.prototype;
t -= 1;
}
f = v[name];
} else {
f = p[name];
if (f == this[name]) {
f = v[name];
}
}
d += 1;
r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));
d -= 1;
return r;
});
return this;
});
다시,우 리 는 Function 류 를 확장 합 니 다.우 리 는 parent 류 의 인 스 턴 스 를 추가 하고 그것 을 새로운 prototype 으로 만 듭 니 다.우 리 는 또한 constructor 필드 를 수정 해 야 하 며,동시에 uber 방법 에 가입 해 야 합 니 다.uber 방법 은 자신의 prototype 에서 어떤 방법 을 찾 을 것 입 니 다.이것 은 기생 계승 이나 클래스 확장 의 한 상황 이다.만약 우리 가 클래스 계승 이 라면,우 리 는 parent 의 prototype 중의 함 수 를 찾 아야 한다.return 문 구 는 함수 의 apply 방법 을 호출 하여 이 함 수 를 호출 하 는 동시에 this 를 표시 하고 파 라 메 터 를 전달 합 니 다.인자(있 으 면)는 arguments 배열 에서 얻 을 수 있 습 니 다.불 행 히 도 arguments 배열 은 진정한 배열 이 아니 기 때문에 우 리 는 apply 를 사용 하여 배열 의 slice 방법 을 호출 해 야 합 니 다.마지막 으로 swiss 방법
 
Function.method('swiss', function (parent) {
for (var i = 1; i < arguments.length; i += 1) {
var name = arguments[i];
this.prototype[name] = parent.prototype[name];
}
return this;
});
The swiss 방법 은 모든 매개 변 수 를 순환 합 니 다.모든 이름 은 parent 의 원형 에 있 는 구성원 을 새로운 종류의 prototype 에 복사 합 니 다.자바 스 크 립 트 는 클래스 언어 처럼 사용 할 수 있 지만 매우 독특한 표현 차원 도 있다.우 리 는 이미 상속,스위스 상속,기생 상속,클래스 확장 과 대상 확장 을 보 았 다.이 같은 일련의 코드 재 활용 모델 은 모두 작 고 간단 한 자바 스 크 립 트 언어 로 여 겨 져 왔 다.클래스 대상 은'딱딱 한'에 속한다.'딱딱 한'대상 에 멤버 를 추가 하 는 유일한 방법 은 새로운 종 류 를 만 드 는 것 이다.자 바스 크 립 트 에서 대상 은'소프트'입 니 다.'소프트'대상 에 멤버 를 추가 하려 면 간단 한 할당 만 하면 됩 니 다.자 바스 크 립 트 의 클래스 가 이렇게 유연 하기 때문에 더 복잡 한 클래스 계승 을 생각 할 수도 있 습 니 다.깊이 있 는 계승 은 적절 하지 않다.얕 은 계승 은 비교적 효과 적 이 고 표현 하기 쉽다.

좋은 웹페이지 즐겨찾기