프로토 타입 상속은 클래식 상속과 실제로 어떻게 다른가요?


27

상속, 다형성 및 캡슐화는 OOP의 가장 뚜렷하고 중요한 세 가지 기능이며, 그로부터 상속은 요즘 높은 사용 통계를 가지고 있습니다. 저는 JavaScript를 배우고 있으며 여기에서 모두 프로토 타입 상속이 있다고 말하고 모든 사람들 이 클래식 상속 전혀 다르다고 말합니다 .

그러나 실제 사용 시점과의 차이점이 무엇인지 이해할 수 없습니까? 다시 말해, 기본 클래스 (프로토 타입)를 정의한 다음 그로부터 일부 서브 클래스를 파생 시키면 둘 다 기본 클래스의 기능에 액세스 할 수 있으며 파생 클래스의 함수를 보강 할 수 있습니다. 우리가 내가 의도 한 상속 결과라고 말한 것을 고려한다면 왜 프로토 타입이나 클래식 버전을 사용하고 있는지 관심을 가져야합니까?

좀 더 명확하게하기 위해 프로토 타입과 클래식 상속의 유용성과 사용 패턴에 차이가없는 것으로 보입니다. OOAD와 같은 결과를 가져 오기 때문에 왜 그들이 다른지 배우는 데 관심이 없습니다. 실제적으로 (이론적으로는) 프로토 타입 상속이 고전 상속과 어떻게 다른가?

답변:


6

JS OO에 관한 최근 블로그 게시물

JavaScriptClassic OO의 고전 OO 에뮬레이션 이 무엇인지 비교할 수 있으며 물론 차이점을 볼 수 없습니다.

면책 조항 : "prototypal OO"에 대한 모든 참조를 "JavaScript의 prototypal OO"로 바꾸십시오. 나는 Self 또는 다른 구현의 특성을 모른다.

그러나 프로토 타입 OO는 다릅니다. 프로토 타입을 사용하면 객체 만 있고 다른 객체 프로토 타입 체인에만 객체를 주입 할 수 있습니다. 객체의 속성에 액세스 할 때마다 해당 객체와 프로토 타입 체인의 모든 객체를 검색합니다.

프로토 타입 OO의 경우 캡슐화 개념이 없습니다. 캡슐화는 범위, 클로저 및 일류 함수의 기능이지만 프로토 타입 OO와는 아무 관련이 없습니다. 상속이라는 개념도 없습니다. 사람들이 "상속"이라고 부르는 것은 실제로는 다형성입니다.

그러나 다형성이 있습니다.

예를 들어

var Dog = {
  walk: function() { console.log("walks"); }
}

var d = Object.create(Dog);
d.walk();

d방법에 분명히 접근 할 수 Dog.walk있으며 이것은 다형성을 나타낸다.

실제로 큰 차이가 있습니다. 다형성 만 있습니다.

그러나 언급했듯이 (원하는 이유는 모르겠습니다) JavaScript에서 클래식 OO를 에뮬레이션 하고 캡슐화 및 상속에 액세스 할 수 있습니다 .


1
프로토 타입 상속을 위한 Google @Rayons를 사용 하면 프로토 타입 상속 이 나타납니다. 야후!
Saeed Neamati

@Saeed 상속은 모호한 용어이며 일반적으로 잘못 사용됩니다. "상속"이라는 의미는 "다형성"이라고 표시합니다. 정의가 너무 모호합니다.
Raynos

아니 @Rayons, 나는 단어의 의미 프로토 타입이 올바른 용어는 아니다 원형 . 나는 상속에 대해 이야기하지 않았다 :)
Saeed Neamati

1
@Saeed 그것은 내 마음이 비워지는 오타 중 하나입니다. 나는 그것에주의를 기울이지 않습니다
Raynos

1
흠 .. 용어. ick. 자바 스크립트 객체가 프로토 타입 "위임"과 관련되는 방식을 호출합니다. 다형성은 주어진 이름이 다른 객체에 대한 다른 코드를 가리킬 수 있다는 사실에 근거하여 저수준 관심사 인 것 같습니다.
Sean McMillan

15

클래식 상속은 상태가없는 상태에서 부모 클래스의 동작을 상속합니다. 객체가 인스턴스화되는 순간의 동작을 상속합니다.

프로토 타입 상속은 상위 오브젝트에서 동작 및 상태를 상속합니다. 객체가 호출되는 순간의 동작과 상태를 상속합니다. 부모 개체가 런타임에 변경되면 자식 개체의 상태와 동작이 영향을받습니다.

프로토 타입 상속의 "이점"은 모든 객체가 인스턴스화 된 후 상태와 동작을 "패치"할 수 있다는 것입니다. 예를 들어 Ext JS 프레임 워크에서는 프레임 워크가 인스턴스화 된 후에 프레임 워크의 핵심 구성 요소를 패치하는 "재정의"를로드하는 것이 일반적입니다.


4
실제로, 당신이 국가를 물려받는다면, 당신은 상처의 세계에 자신을 설정하고 있습니다. 상속 된 상태가 다른 객체에 있으면 공유됩니다.
Sean McMillan

1
자바 스크립트에는 실제로 상태와 분리 된 행동 개념이 없다는 것이 나에게 발생합니다. 생성자 함수 외에도 모든 상태는 다른 상태와 마찬가지로 객체 생성 후 할당 / 수정 될 수 있습니다.
Joeri Sebrechts

그렇다면 파이썬에는 고전적인 상속이 없습니까? 내가 가지고 class C(object): def m(self, x): return x*2있고 instance = C()실행하면 instance.m(3)내가 얻을 수 6있습니다. 그러나 내가 C그렇게 변경 C.m = lambda s, x: x*x하고 실행 instance.m(3)하면 이제 얻을 수 9있습니다. 내가 class D(C)메소드를 만들고 변경 하면 변경된 메소드를받는 C인스턴스 D도 마찬가지입니다. 내가 오해하거나 파이썬이 당신의 정의에 따라 고전 상속을받지 않는다는 것을 의미합니까?
mVChr

@ mVChr : 여전히 고전적인 상속을 가리키는 동작을 상속하고 있지만 상태를 나타내지 않지만 "개체가 인스턴스화되는 순간의 동작을 상속합니다"라는 내 정의에 문제가 있음을 나타냅니다. 정의를 수정하는 방법을 잘 모르겠습니다.
Joeri Sebrechts

9

첫째, 대부분의 경우 객체를 사용하고 정의하지 않고 객체를 사용하는 것은 두 패러다임에서 동일합니다.

둘째 : 대부분의 프로토 타입 환경은 클래스 기반 환경과 동일한 종류의 분할을 사용합니다. 즉 인스턴스에서 변경 가능한 데이터, 메서드가 상속됩니다. 다시 한번 차이가 거의 없습니다. ( 이 스택 오버플로 질문에 대한 나의 대답클래스가없는 자체 용지 구성 프로그램 참조하십시오 . PDF 버전Citeseer를 참조하십시오 .)

셋째 : 자바 스크립트의 동적 인 특성은 상속의 종류보다 훨씬 큰 영향을 미칩니다. 기본 객체에 유형을 지정하여 유형의 모든 인스턴스에 새 메소드를 추가 할 수 있다는 사실은 깔끔하지만 루비에서도 클래스를 다시 열어서 동일한 방법을 사용할 수 있습니다.

넷째, 사용에 잊어의 실제 문제가있는 동안 실제적인 차이는, 작은 new훨씬 더 큰 것입니다 - 즉 당신이 누락에 의해 훨씬 더 가능성이 영향을받을 것입니다 new당신이 프로토 타입 클래식 코드의 차이에 의해 영향을받는 것으로보다 .

그러나 프로토 타입과 클래식 상속의 실질적인 차이점은 보유하고있는 것들 (클래스)이 보유하고있는 데이터 (인스턴스)와 동일하다는 것입니다. 이는 클래스를 구성 할 수 있음을 의미합니다. 모든 인스턴스에서 사용하는 것과 동일한 객체 조작 도구를 모두 사용합니다. (실제로 이것은 모든 클래스 에뮬레이션 라이브러리가 수행하는 방식입니다. 다른 방법이 아닌 다른 방법은 Traits.js보십시오 ). 이것은 메타 프로그래밍중인 경우 주로 흥미 롭습니다.


예, 최고의 답변 IMO!
Aivar

0

JavaScript의 프로토 타입 상속은 다음과 같은 중요한 점에서 클래스와 다릅니다.

생성자는 단순히 다음없이 호출 할 수있는 함수입니다 new.

function Circle (r, x, y) { 
  //stuff here
}
Var c = new Circle();
Circle.call(c, x, y, z); //This works and you can do it over and over again.

개인 변수 또는 메소드는 없으며 최선을 다하면됩니다.

function Circle (r, x, y) {
  var color = 'red';
  function drawCircle () {
    //some code here with x, y and r
  }
  drawCircle();
  this.setX = function (x_) {
    x = x_;
    drawCircle();
  }

}
Circle.prototype.getX = function () {
   //Can't access x!
}

위의 예에서는 가짜 개인 변수 및 메소드에 의지하는 경우 클래스를 의미있게 확장 할 수 없으며 선언 한 공개 메소드는 새 인스턴스가 작성 될 때마다 다시 작성됩니다.


"클래스"를 의미있게 확장 할 수 있습니다. 당신은 지역 변수에 액세스 할 수 없습니다 color, r, x, ydrawCircle의 어휘 범위에 바인딩Circle
Raynos

사실은 가능하지만 인스턴스를 생성 할 때마다 생성되는 컨텍스트에 추가 된 많은 '공개'메소드를 작성하지 않으면 수행 할 수 없습니다.
Bjorn

이것은 당신이 거기에서 사용하는 매우 이상한 패턴입니다. Circle.call()생성자로? "기능적 객체"(잘못된 이름 ...)를 설명하려는 것 같습니다.
Sean McMillan

그것은 내가 한 일이 아니며, JavaScript를 사용하여 생성자를 반복해서 호출 할 수는 있지만 전통적인 클래스가있는 언어로는 불가능하다고 말하고 있습니다.
Bjorn

1
그러나 이러한 차이는 어떻게 '중요'합니까? '신규'를 '중요'로 사용하지 않고 구문 차이가 작은 함수를 호출하여 객체를 구성하는 것을 볼 수 없습니다. 마찬가지로 개인 변수가 없다는 것은 근본적으로 다르지 않고 약간의 차이입니다. 또한 설명하는 방식으로 (개인 변수와 비슷한) 개인 변수를 가질 있습니다.
Roel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.