프로토 타입 기반 대 클래스 기반 상속


208

JavaScript에서 모든 객체는 동시에 인스턴스와 클래스입니다. 상속을 위해 모든 객체 인스턴스를 프로토 타입으로 사용할 수 있습니다.

파이썬, C ++ 등에서는 별도의 개념으로 클래스와 인스턴스가 있습니다. 상속을 수행하려면 기본 클래스를 사용하여 새 클래스를 작성해야하며,이를 사용하여 파생 인스턴스를 생성 할 수 있습니다.

JavaScript가 왜이 방향으로 진행 되었습니까 (프로토 타입 기반 객체 방향)? 기존의 클래스 기반 OO와 관련하여 프로토 타입 기반 OO의 장점과 단점은 무엇입니까?


10
JavaScript는 프로토 타입 상속을 가진 첫 번째 언어 인 Self의 영향을 받았습니다. 그 당시 고전 상속은 시뮬 라에서 처음 소개 된 모든 분노였습니다. 그러나 고전 상속은 너무 복잡했습니다. 그런 다음 David Ungar와 Randall Smith는 GEB를 읽은 후 주현절을 겪었습니다. "가장 구체적인 사건은 일련의 사건의 일반적인 예가 될 수 있습니다." 그들은 객체 지향 프로그래밍에 클래스가 필요하지 않다는 것을 깨달았습니다. 그러므로 자아가 태어났다. 프로토 타입 상속이 클래식 상속보다 더 나은지 알기 위해 이것을 읽으십시오 : stackoverflow.com/a/16872315/783743 =)
Aadit M Shah

@AaditMShah 무엇입니까 GEB?
Alex

3
@Alex GEB는 Douglas Hofstadter가 쓴 책입니다. Gödel Escher Bach의 약자입니다. 커트 고델은 수학자였습니다. 에셔는 예술가였습니다. 바흐는 피아니스트였습니다.
Aadit M Shah

답변:


201

여기에는 약 100 가지의 용어 문제가 있으며, 대부분 자신의 아이디어를 '최고'처럼 들리려고하는 사람을 중심으로 구축되었습니다.

모든 객체 지향 언어는 몇 가지 개념을 처리 할 수 ​​있어야합니다.

  1. 특히 데이터 멤버 및 멤버 함수 또는 데이터 및 방법으로 알려진 데이터에 대한 관련 작업과 함께 데이터를 캡슐화합니다.
  2. 상속, 이러한 객체가 이러한 변경을 제외하고 다른 객체 세트와 같다고 말할 수있는 능력
  3. 다형성 ( "다양한 형태") : 객체가 어떤 메소드를 실행할 것인지 스스로 결정하므로 언어에 따라 요청을 올바르게 라우팅 할 수 있습니다.

이제 비교하자면 다음과 같습니다.

첫 번째는 전체 "클래스"대 "시제품"질문입니다. 이 아이디어는 원래 Simula에서 시작되었으며, 클래스 기반 방법으로 각 클래스는 동일한 상태 공간 ( "가능한 값"을 읽음)과 동일한 작업을 공유하여 동등 클래스를 형성하는 일련의 객체를 나타 냈습니다. Smalltalk를 다시 살펴보면 클래스를 열고 메소드를 추가 할 수 있기 때문에 Javascript에서 수행 할 수있는 것과 사실상 동일합니다.

이후의 OO 언어는 정적 유형 검사를 사용할 수 있기를 원했기 때문에 컴파일 타임에 고정 클래스 세트라는 개념을 얻었습니다. 오픈 클래스 버전에서는 더 많은 유연성이있었습니다. 최신 버전에서는 컴파일러에서 테스트가 필요한 몇 가지 정확성을 검사 할 수있었습니다.

"클래스 기반"언어에서 해당 복사는 컴파일 타임에 발생합니다. 프로토 타입 언어에서 작업은 프로토 타입 데이터 구조에 저장되며 런타임시 복사 및 수정됩니다. 그러나 추상적으로 클래스는 여전히 동일한 상태 공간 및 메소드를 공유하는 모든 오브젝트의 동등 클래스입니다. 프로토 타입에 메소드를 추가하면 새로운 동등성 클래스의 요소를 효과적으로 만들 수 있습니다.

왜 그렇게합니까? 주로 런타임에 단순하고 논리적이며 우아한 메커니즘을 만들기 때문입니다. 이제, 새로운 객체를 만들 거나 새로운 클래스를 만들려면, 당신은 단순히 데이터와 프로토 타입의 데이터 구조를 모두 복사 깊은 복사를 수행해야합니다. 상속과 다형성은 어느 정도 무료로 제공됩니다. 메소드 조회는 항상 이름별로 메소드 구현을위한 사전을 요청하는 것으로 구성됩니다.

Javascript / ECMA 스크립트로 끝나는 이유는 기본적으로 10 년 전에 시작했을 때 훨씬 덜 강력한 컴퓨터와 훨씬 덜 정교한 브라우저를 다루고 있었기 때문입니다. 프로토 타입 기반 방법을 선택하면 원하는 객체 방향 속성을 유지하면서 인터프리터가 매우 간단 할 수 있습니다.


1
맞아, 그 paragaph는 내가 달리 의미하는 것처럼 읽습니까? Dahl와 Nyqvist는 동일한 메소드 서명을 가진 것들의 모음으로 "클래스"를 고안했습니다.
Charlie Martin

1
그 변화가 더 잘 말하는가?
Charlie Martin

2
아니요, 죄송합니다. CLOS는 1980 년대 후반 dreamsongs.com/CLOS.html 스몰 토크 (1980 년부터) en.wikipedia.org/wiki/Smalltalk 및 Simula에서 1967-68까지의 전체 객체 방향 en.wikipedia.org/wiki/Simula
Charlie Martin

3
@Stephano, Python, Ruby, Smalltalk는 메소드 검색에 사전을 사용하고 javascript 및 Self에는 클래스가 있습니다. 어느 정도 차이가 있다고한다면 프로토 타입 지향 언어가 구현을 노출하고 있다는 것입니다. 따라서 큰 거래로 만들지 않는 것이 좋을 것입니다. EMACS와 vi 사이의 논쟁과 비슷할 것입니다.
Charlie Martin

21
유용한 답변 . 댓글에 쓸모없는 정크 +1 CLOS 또는 스몰 토크가 처음인지에 차이가 있습니까? 어쨌든 대부분의 사람들은 역사가가 아닙니다.
Adam Arold

40

프로토 타입 기반 접근 방식에 약간 편향된 비교는 Self : The Simplicity 의 논문에서 찾을 수 있습니다 . 이 논문은 프로토 타입을 위해 다음과 같은 주장을한다.

복사하여 작성 . 프로토 타입에서 새로운 객체를 생성하는 것은 간단한 생물학적 은유 복제와 함께 간단한 조작, 복사로 이루어집니다. 클래스에서 새 객체를 생성하는 것은 인스턴스화를 통해 이루어지며 여기에는 클래스의 형식 정보 해석이 포함됩니다. 인스턴스화는 계획에서 집을 짓는 것과 비슷합니다. 복사는 인스턴스화보다 단순한 은유로 우리에게 호소합니다.

기존 모듈의 예 . 프로토 타입은 형식과 초기화에 대한 설명이 아니라 객체의 예이므로 클래스보다 더 구체적입니다. 이 예제는 사용자가 이해하기 쉽도록 모듈을 재사용하는 데 도움이 될 수 있습니다. 프로토 타입 기반 시스템을 통해 사용자는 설명을 이해하도록 요구하지 않고 일반적인 담당자를 조사 할 수 있습니다.

독특한 객체 지원 . 자체는 고유 한 동작을 가진 고유 한 객체를 쉽게 포함 할 수있는 프레임 워크를 제공합니다. 각 객체에는 이름이 지정된 슬롯이 있고 슬롯은 상태 또는 동작을 보유 할 수 있으므로 모든 객체는 고유 한 슬롯 또는 동작을 가질 수 있습니다. 클래스 기반 시스템은 동일한 동작을 가진 많은 객체가있는 상황을 위해 설계되었습니다. 객체가 자신의 고유 한 행동을 갖도록 언어 적으로 지원하는 것은 없으며, 싱글턴 패턴을 생각하는 인스턴스가 하나만 보장되는 클래스를 만드는 것은 어색합니다 . 자아는 이러한 단점 중 어느 것도 겪지 않습니다. 모든 객체는 자체 동작으로 사용자 정의 할 수 있습니다. 고유 한 개체는 고유 한 동작을 보유 할 수 있으며 별도의 "인스턴스"가 필요하지 않습니다.

메타 회귀 제거 . 클래스 기반 시스템의 어떤 개체도 자급 자족 할 수 없습니다. 구조와 동작을 표현하기 위해서는 다른 객체 (클래스)가 필요합니다. 이것은 개념적으로 무한한 메타 회귀로 이어진다 : a point는 class Point의 인스턴스이며 Point, 이것은 metametaclass의 인스턴스 인 Pointad infinitum 인 metaclass 의 인스턴스이다 . 반면, 프로토 타입 기반 시스템에서 객체는 자체 동작을 포함 할 수 있습니다. 생명을 불어 넣는 데 다른 물체가 필요하지 않습니다. 프로토 타입은 메타 회귀를 제거합니다.

Self 는 아마도 프로토 타입을 구현 한 최초의 언어 일 것입니다 (JIT와 같은 다른 흥미로운 기술을 개척하여 나중에 JVM에 도입했습니다). 따라서 다른 Self 논문 도 읽는 것이 유익해야합니다.


5
RE : 메타-회귀 제거 : 클래스 기반의 Common Lisp Object System에서 a point는 class의 인스턴스이며 Point,이 클래스 는 메타 클래스 standard-class의 인스턴스이며 자체 인스턴스 인 ad finitum입니다.
Max Nanasy

자체 용지에 대한 링크가 죽었습니다. 작업 링크 : 자기 : 단순성의 힘 | 자가 서지
user1201917

24

Douglas Crockford의 JavaScript 에 대한 훌륭한 책을 확인해야합니다 . JavaScript 작성자가 내린 일부 디자인 결정에 대해 아주 잘 설명합니다.

JavaScript의 중요한 디자인 측면 중 하나는 프로토 타입 상속 시스템입니다. 객체는 JavaScript에서 일류 시민이므로 일반 함수도 객체 ( 'Function'객체는 정확함)로 구현됩니다. 제 생각에는 브라우저 내부에서 실행되도록 설계되었을 때 많은 단일 객체를 만드는 데 사용되었습니다. 브라우저 DOM에는 해당 창, 문서 등 모든 단일 객체가 있습니다. 또한 JavaScript는 느슨하게 형식화 된 동적 언어 (강력한 형식의 Python과 달리 동적 언어)와 달리 'prototype'속성을 사용하여 객체 확장 개념을 구현했습니다.

따라서 JavaScript로 구현 된 프로토 타입 기반 OO에 대한 전문가가 있다고 생각합니다.

  1. 느슨한 유형의 환경에 적합하며 명시 적 유형을 정의 할 필요가 없습니다.
  2. 싱글 톤 패턴을 구현하기가 엄청나게 쉽습니다 (이 점에서 JavaScript와 Java를 비교하면 내가 무엇을 말하는지 알게됩니다).
  3. 다른 객체의 컨텍스트에서 객체의 메소드를 적용하고 객체 등에서 동적으로 메소드를 추가 및 교체하는 방법을 제공합니다 (강력한 언어로는 불가능한 것).

프로토 타입 OO의 단점은 다음과 같습니다.

  1. 개인 변수를 구현하는 쉬운 방법은 없습니다. 클로저를 사용하여 Crockford 의 마법사를 사용 하여 개인 변수를 구현할 수 있지만 Java 또는 C #과 같은 개인 변수를 사용하는 것만 큼 간단하지는 않습니다.
  2. 아직 JavaScript로 여러 상속 (그 가치에 따라)을 구현하는 방법을 모르겠습니다.

2
파이썬처럼 개인 변수에 대한 명명 규칙을 사용하십시오.
aehlke

1
js에서 private vars를 수행하는 방법은 클로저를 사용하는 것이며 선택한 상속 유형과 독립적입니다.
Benja

6
Crockford는 상당히 간단한 스크립팅 언어가 내부적으로 대단한 매혹으로 변형되어 JavaScript를 손상시키기 위해 많은 노력을 기울였습니다. JS에는 진정한 비공개 키워드 범위 나 진정한 다중 상속이 없습니다. 위조하려고하지 마십시오.
Hal50000
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.