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


27

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

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

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

답변:


6

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

JavaScript 와 Classic 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, y과 drawCircle의 어휘 범위에 바인딩Circle
— Raynos

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

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

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

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