시제품 유전의 이점은 고전적인 것에 비해 무엇입니까?
그래서 나는 마침내 시간을 끌지 않고 자바스크립트를 "적절하게" 배우기로 했다.언어 설계에서 가장 중요한 요소 중 하나는 상속의 구현입니다.Ruby에서 경험을 쌓은 저는 폐쇄와 동적 타이핑을 보고 매우 기뻤습니다만, 상속을 위해 다른 인스턴스를 사용하는 오브젝트 인스턴스가 어떤 이점을 가져다 줄지 전혀 알 수 없습니다.
이 답변이 3년 늦은 것은 알지만, 현재의 답변은 고전적인 상속보다 프로토타입 상속이 얼마나 좋은지에 대한 충분한 정보를 제공하지 못한다고 생각합니다.
먼저 JavaScript 프로그래머가 프로토타입 상속을 방어하기 위해 하는 가장 일반적인 인수를 살펴보겠습니다(현재 답변 풀에서 다음 인수를 취합니다).
- 간단해요.
- 힘이 세요.
- 더 작고 덜 중복된 코드를 만들 수 있습니다.
- 역동적이기 때문에 역동적인 언어에 적합합니다.
이제 이 주장들은 모두 타당하지만, 아무도 이유를 설명하려고 하지 않았다.그것은 마치 아이에게 수학 공부가 중요하다고 말하는 것과 같다.물론 그렇겠지만, 아이는 확실히 신경 쓰지 않는다; 그리고 수학이 중요하다고 해서 아이를 수학처럼 만들 수는 없다.
시제품 상속의 문제는 JavaScript의 관점에서 설명된다는 것이라고 생각합니다.나는 자바스크립트를 좋아하지만, 자바스크립트의 프로토타입 상속이 잘못되었다.전통적인 유전과 달리 원형 유전에는 두 가지 패턴이 있습니다.
- 원형 유전의 원형 패턴입니다.
- 프로토타입 상속의 생성자 패턴입니다.
안타깝게도 JavaScript는 프로토타입 상속의 컨스트럭터 패턴을 사용합니다.JavaScript가 작성되었을 때 Brendan Eich(JS의 작성자)는 자바(클래식 상속을 받은 것)처럼 보이기를 원했기 때문입니다.
Visual Basic과 같은 보완언어는 당시 마이크로소프트 언어 패밀리의 C++와 같았기 때문에 우리는 자바에 동생으로 이 프로그램을 추진하고 있었습니다.
이는 JavaScript에서 컨스트럭터를 사용할 때 다른 컨스트럭터로부터 상속받는 컨스트럭터를 떠올리기 때문에 좋지 않습니다.이는 잘못되었다.원형 상속에서 개체는 다른 개체로부터 상속됩니다.건설업자는 절대 관여하지 않는다.이것이 대부분의 사람들을 혼란스럽게 하는 것이다.
자바와 같이 고전적인 유산을 물려받은 언어에서 온 사람들은 컨스트럭터가 클래스처럼 보이지만 클래스처럼 행동하지 않기 때문에 더욱 혼란스러워한다.Douglas Crockford가 말했듯이:
이 간접은 클래식하게 훈련된 프로그래머들에게 언어를 더 친숙하게 보이도록 의도되었지만 자바 프로그래머들이 자바스크립트에 대해 가지고 있는 매우 낮은 평가에서 알 수 있듯이 그렇게 하지 못했다.JavaScript의 컨스트럭터 패턴은 고전적인 군중들에게 어필하지 않았다.또한 JavaScript의 진정한 프로토타입 성격을 가렸다.그 결과, 언어를 효과적으로 사용하는 방법을 아는 프로그래머는 거의 없다.
바로 그겁니다.믿을 만한 소식통으로부터 직접.
진정한 시제품 상속
원형 유산은 모두 물건에 관한 것입니다.개체는 다른 개체에서 속성을 상속합니다.그게 다예요.프로토타입 상속을 사용하여 객체를 만드는 방법에는 두 가지가 있습니다.
- 새 개체를 만듭니다.
- 기존 개체를 복제하고 확장합니다.
주의: JavaScript는 개체를 복제하는 두 가지 방법, 즉 위임과 연결을 제공합니다.따라서 위임을 통한 상속을 배타적으로 지칭하는 "clone"이라는 단어와 연결을 통한 상속을 배타적으로 지칭하는 "copy"라는 단어를 사용합니다.
얘기는 그만해.몇 가지 예를 들어보자.반지름의 원이 있다고 칩시다.5
:
var circle = {
radius: 5
};
반지름에서 원의 면적과 둘레를 계산할 수 있습니다.
circle.area = function () {
var radius = this.radius;
return Math.PI * radius * radius;
};
circle.circumference = function () {
return 2 * Math.PI * this.radius;
};
이제 반지름의 다른 원을 만들고 싶다.10
이를 위한 한 가지 방법은 다음과 같습니다.
var circle2 = {
radius: 10,
area: circle.area,
circumference: circle.circumference
};
그러나 JavaScript는 더 나은 방법인 위임을 제공합니다.이 함수는 이를 위해 사용됩니다.
var circle2 = Object.create(circle);
circle2.radius = 10;
그게 다예요.방금 JavaScript에서 프로토타입 상속을 했습니다.간단하지 않나요?오브젝트를 가져와서 복제하고 필요한 것을 바꾸면 새로운 오브젝트를 얻을 수 있습니다.
"어떻게 간단하지?"라고 물으실 수도 있습니다.새 원을 만들 때마다 복제해야 합니다.circle
수동으로 반지름을 할당합니다.해결책은 무거운 물건을 들어주는 기능을 사용하는 것입니다.
function createCircle(radius) {
var newCircle = Object.create(circle);
newCircle.radius = radius;
return newCircle;
}
var circle2 = createCircle(10);
실제로 다음과 같이 이 모든 것을 단일 개체 리터럴로 결합할 수 있습니다.
var circle = {
radius: 5,
create: function (radius) {
var circle = Object.create(this);
circle.radius = radius;
return circle;
},
area: function () {
var radius = this.radius;
return Math.PI * radius * radius;
},
circumference: function () {
return 2 * Math.PI * this.radius;
}
};
var circle2 = circle.create(10);
JavaScript의 프로토타입 상속
위의 프로그램에서 알아차린 경우create
함수가 클론을 작성하다circle
에 의해 새로운 것이 할당됩니다.radius
다시 돌려줄 수 있습니다.JavaScript에서 컨스트럭터가 수행하는 작업은 다음과 같습니다.
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.area = function () {
var radius = this.radius;
return Math.PI * radius * radius;
};
Circle.prototype.circumference = function () {
return 2 * Math.PI * this.radius;
};
var circle = new Circle(5);
var circle2 = new Circle(10);
JavaScript의 컨스트럭터 패턴은 반전된 원형 패턴입니다.개체를 만드는 대신 생성자를 만듭니다.그new
키워드를 지정하면,this
컨스트럭터 내의 포인터prototype
생성자의 것입니다.
헷갈리게 들리나요?JavaScript의 컨스트럭터 패턴이 불필요하게 복잡해지기 때문입니다.이것은 대부분의 프로그래머들이 이해하기 어려운 것이다.
다른 개체로부터 상속받는 개체를 생각하는 대신 다른 생성자로부터 상속받는 구성자를 떠올리면 완전히 혼란스러워진다.
JavaScript에서 컨스트럭터 패턴을 피해야 하는 이유는 그 밖에도 많이 있습니다.제 블로그 게시물: 건설자 vs 프로토타입에서 이에 대해 읽어보실 수 있습니다.
그렇다면 고전적인 유전보다 프로토타입 유전의 이점은 무엇일까요?가장 흔한 논쟁을 다시 한 번 살펴보고 그 이유를 설명해보겠습니다.
1. 시제품 상속이 간단함
CMS는 다음과 같이 답변합니다.
내 생각에 프로토타입 상속의 가장 큰 장점은 단순함이다.
우리가 방금 한 일을 생각해 봅시다.개체를 만들었습니다.circle
반경이 1미터였다.5
그리고 클론을 복제하고 클론에게 반경을 부여했습니다.10
.
따라서 시제품 상속을 위해 필요한 것은 두 가지뿐입니다.
- 새 객체(예: 객체 리터럴)를 만드는 방법입니다.
- 기존 개체를 확장하는 방법(예:
Object.create
).
대조적으로 고전적인 유전은 훨씬 더 복잡하다.고전적 상속에는 다음이 있습니다.
- 반.
- 물건.
- 인터페이스
- Abstractive 클래스.
- 파이널 클래스
- 가상 베이스 클래스
- 컨스트럭터
- 파괴자들.
무슨 말인지 아시겠죠?요점은 프로토타입 상속이 이해하기 쉽고 구현하기 쉬우며 추론하기 쉽다는 것입니다.
Steve Yegge가 그의 클래식 블로그 투고 "N00b의 초상"에서 말한 것처럼:
메타데이터는 다른 것에 대한 모든 종류의 설명 또는 모델입니다.코드의 코멘트는, 계산의 자연스러운 설명에 지나지 않습니다.메타데이터 메타데이터를 만드는 것은 엄밀하게 필요하지 않기 때문입니다.혈통서류가 있는 개를 기르고 있는데 서류를 잃어버렸다면, 난 여전히 완벽하게 유효한 개를 기르고 있는 거야.
같은 의미에서 클래스는 메타 데이터일 뿐입니다.상속을 위해 클래스가 꼭 필요한 것은 아닙니다.그러나 일부 사용자(보통 n00bs)는 수업이 함께 일하기 더 편하다고 생각합니다.그것은 그들에게 잘못된 안정감을 준다.
정적 유형은 메타데이터에 불과하다는 것도 알고 있습니다.프로그래머와 컴파일러의 두 가지 독자를 대상으로 한 전문적인 코멘트입니다.정적 유형은 아마도 두 독자 그룹이 프로그램의 의도를 이해하는 데 도움을 주기 위해 계산에 대한 이야기를 합니다.그러나 정적 유형은 결국 스타일화된 댓글에 불과하기 때문에 런타임에 폐기될 수 있습니다.그것은 마치 혈통서류 같은 것이다.그것은 어떤 불안정한 성격의 타입을 그들의 개에 대해 더 행복하게 만들지도 모르지만, 개는 확실히 개의치 않는다.
앞서 말했듯이, 수업은 사람들에게 잘못된 안정감을 준다.예를 들어, 너무 많은 것을 얻을 수 있습니다.NullPointerException
코드를 완전히 읽을 수 있는 경우에도 Java로 표시됩니다.고전적인 유전은 보통 프로그래밍에 방해가 되지만, 어쩌면 자바일 수도 있습니다.Python은 놀라운 고전적인 상속 시스템을 가지고 있다.
2. 강력한 프로토타입 상속
고전적인 배경을 가진 대부분의 프로그래머들은 고전적인 유전은 다음과 같은 특징이 있기 때문에 원형 유전보다 더 강력하다고 주장합니다.
- 개인 변수
- 다중 상속
이 주장은 거짓이다.JavaScript가 폐쇄를 통해 개인 변수를 지원한다는 것은 이미 알고 있지만, 다중 상속은 어떻습니까?JavaScript의 개체에는 프로토타입이 하나만 있습니다.
사실 프로토타입 상속은 여러 프로토타입에서 상속을 지원합니다.원형 상속은 단순히 하나의 개체가 다른 개체로부터 상속되는 것을 의미합니다.프로토타입 상속을 구현하는 방법은 실제로 두 가지가 있습니다.
- 위임 또는 차등 상속
- 복제 또는 연결 상속
예. JavaScript에서는 오브젝트를 다른 오브젝트에 위임할 수 있습니다.그러나 임의의 수의 개체 속성을 복사할 수 있습니다.예를 들어 이것만 하면 됩니다.
물론 많은 프로그래머들은 이것이 진정한 상속이라고 생각하지 않습니다. 왜냐하면, 그리고 그렇지 않다고 말하기 때문입니다.그러나 이 문제는 연결을 통해 프로토타입에서 상속된 모든 개체에 프로토타입의 어레이를 저장하면 쉽게 해결할 수 있습니다.
function copyOf(object, prototype) {
var prototypes = object.prototypes;
var prototypeOf = Object.isPrototypeOf;
return prototypes.indexOf(prototype) >= 0 ||
prototypes.some(prototypeOf, prototype);
}
따라서 원형 유전은 고전적인 유전만큼이나 강력합니다.프로토타입 상속에서는 복사할 속성과 여러 프로토타입에서 제외할 속성을 손으로 선택할 수 있기 때문에 기존 상속 방식보다 훨씬 강력합니다.
기존 상속에서는 상속할 속성을 선택하는 것이 불가능하거나 최소한 매우 어렵습니다.이들은 다이아몬드 문제를 해결하기 위해 가상 베이스 클래스 및 인터페이스를 사용합니다.
그러나 JavaScript에서는 다이아몬드 문제에 대해 들어본 적이 없을 것입니다. 왜냐하면 어떤 속성을 상속받고 어떤 프로토타입으로부터 상속받고 싶은지 정확하게 제어할 수 있기 때문입니다.
3. 시제품 상속의 중복성 감소
고전적인 상속이 반드시 더 많은 중복 코드를 초래하는 것은 아니기 때문에 이 점은 설명하기가 조금 더 어렵습니다.실제로 상속은 고전적이든 프로토타입적이든 코드의 중복성을 줄이기 위해 사용됩니다.
하나의 주장은 고전적인 상속을 가진 대부분의 프로그래밍 언어가 정적으로 입력되어 사용자가 명시적으로 유형을 선언해야 한다는 것입니다(암묵적인 정적인 입력이 있는 Haskell과는 다릅니다).따라서 이것은 보다 상세한 코드로 이어진다.
Java는 이 동작으로 악명이 높습니다.Bob Nystrom이 Pratt Parsers에 관한 블로그 투고에서 다음과 같은 일화를 언급했던 것을 나는 분명히 기억한다.
자바의 "제발 서명해 주세요" 수준의 관료주의를 좋아해야 합니다.
다시 말씀드리지만, 그건 자바가 너무 형편없기 때문이라고 생각합니다.
하나의 유효한 주장은 고전적인 상속을 가진 모든 언어가 다중 상속을 지원하는 것은 아니라는 것입니다.다시 자바가 떠오른다.네, Java에는 인터페이스가 있지만 그것만으로는 충분하지 않습니다.때로는 여러 번 상속을 받아야 할 때도 있어요.
프로토타입 상속은 다중 상속을 허용하므로, 다중 상속이 필요한 코드는 고전적 상속이 있지만 다중 상속이 없는 언어로 작성되는 것보다 프로토타입 상속을 사용하여 작성되면 중복성이 줄어듭니다.
4. 시제품 상속이 역동적
프로토타입 상속의 가장 중요한 장점 중 하나는 프로토타입이 생성된 후 새로운 속성을 프로토타입에 추가할 수 있다는 것입니다.그러면 해당 프로토타입에 위임된 모든 객체가 자동으로 사용할 수 있는 새로운 메서드를 프로토타입에 추가할 수 있습니다.
클래스가 생성되면 런타임에 수정할 수 없으므로 기존 상속에서는 이 작업을 수행할 수 없습니다.이것은 아마도 고전적인 유전보다 프로토타입 유전의 가장 큰 장점일 것입니다. 그리고 그것은 맨 위에 있었어야 했습니다.하지만 나는 마지막을 위해 최선을 다하는 것을 좋아한다.
결론
원형 유전이 중요합니다.JavaScript 프로그래머에게 프로토타입 상속의 생성자 패턴을 버리고 프로토타입 상속의 프로토타입 패턴을 선택해야 하는 이유를 교육하는 것이 중요합니다.
JavaScript를 올바르게 가르쳐야 합니다.그것은 새로운 프로그래머에게 컨스트럭터 패턴이 아닌 프로토타입 패턴을 사용하여 코드를 작성하는 방법을 보여주는 것을 의미합니다.
프로토타입 패턴을 사용하여 프로토타입 상속을 설명하는 것이 더 쉬울 뿐만 아니라 더 나은 프로그래머가 될 것입니다.
만약 이 답변이 마음에 든다면, "시제품 상속이 중요한 이유"에 대한 제 블로그 게시물도 읽어보셔야 합니다.날 믿어, 실망하지 않을 거야.
제가 실제로 그 질문에 인라인으로 대답할 수 있게 해 주세요.
원형 상속에는 다음과 같은 장점이 있습니다.
- 상속은 환경만큼이나 동적이기 때문에 동적 언어에 더 적합합니다.(여기서 JavaScript에 대한 적용 가능성은 명확해야 합니다.)이를 통해 대량의 인프라 코드 없이 클래스를 커스터마이즈하는 등의 작업을 신속하게 수행할 수 있습니다.
- 기존의 클래스/객체 이분법 체계보다 프로토타이핑 객체 체계를 구현하는 것이 더 쉽습니다.
- 이것에 의해, 「메타클래스」(마음에 드는 메타클래스…미안합니다!)나 「특징값」등의 복잡한 날카로운 오브젝트 모델의 가장자리가 불필요하게 됩니다.
단, 다음과 같은 단점이 있습니다.
- 프로토타입 언어를 체크하는 것은 불가능하지 않지만 매우 어려운 일입니다.프로토타입 언어의 "유형 검사"는 대부분 런타임 "덕 타이핑" 스타일의 검사입니다.이것은 모든 환경에 적합한 것은 아닙니다.
- 마찬가지로 정적(또는 동적) 분석을 통해 메서드 디스패치를 최적화하는 것도 어렵습니다.매우 쉽게 비효율적일 수 있습니다.
- 마찬가지로 프로토타이핑 언어에서 객체 생성은 더 일반적인 클래스/객체 이분법 체계에서보다 훨씬 느릴 수 있습니다(일반적으로 더 느릴 수 있습니다.
나는 당신이 위의 행간을 읽고 전통적인 클래스/오브젝트 방식의 장단점을 생각해 낼 수 있다고 생각한다.물론 각 분야에 더 있기 때문에 나머지는 다른 분들의 답변에 맡기겠습니다.
IMO의 가장 큰 장점은 단순함입니다.
언어의 원형은 고전적인 훈련을 받은 사람들을 혼란스럽게 할 수 있지만, 사실 이것은 매우 단순하고 강력한 개념으로, 차등적인 유전이라는 것이 밝혀졌습니다.
분류할 필요가 없습니다.코드는 작고 중복성이 적고 오브젝트는 다른 일반적인 오브젝트로부터 상속됩니다.
프로토타입으로 생각하면 수업이 필요없다는 걸 금방 알 수 있을 거예요.
시제품 상속은 가까운 미래에 훨씬 더 인기를 끌 것입니다. ECMAScript 5th Edition 사양에서는 다른 개체 인스턴스를 매우 간단한 방법으로 상속하는 새로운 개체 인스턴스를 생성할 수 있는 방법을 도입했습니다.
var obj = Object.create(baseInstance);
이 표준의 새로운 버전은 모든 브라우저 벤더에 의해 구현되고 있으며, 보다 순수한 프로토타입 상속을 볼 수 있을 것으로 생각합니다.
그 두 가지 방법 중 선택할 수 있는 것은 정말 많지 않다.기본적으로 파악해야 할 것은 JavaScript 엔진에 읽을 객체의 속성이 주어지면 먼저 인스턴스를 체크하고 해당 속성이 누락된 경우 프로토타입 체인을 체크하는 것입니다.다음은 프로토타입과 클래식 간의 차이를 보여주는 예입니다.
시제품
var single = { status: "Single" },
princeWilliam = Object.create(single),
cliffRichard = Object.create(single);
console.log(Object.keys(princeWilliam).length); // 0
console.log(Object.keys(cliffRichard).length); // 0
// Marriage event occurs
princeWilliam.status = "Married";
console.log(Object.keys(princeWilliam).length); // 1 (New instance property)
console.log(Object.keys(cliffRichard).length); // 0 (Still refers to prototype)
인스턴스(instance) 메서드를 사용하는 고전적 방법(각 인스턴스가 고유한 속성을 저장하므로 비효율적)
function Single() {
this.status = "Single";
}
var princeWilliam = new Single(),
cliffRichard = new Single();
console.log(Object.keys(princeWilliam).length); // 1
console.log(Object.keys(cliffRichard).length); // 1
효율적인 클래식
function Single() {
}
Single.prototype.status = "Single";
var princeWilliam = new Single(),
cliffRichard = new Single();
princeWilliam.status = "Married";
console.log(Object.keys(princeWilliam).length); // 1
console.log(Object.keys(cliffRichard).length); // 0
console.log(cliffRichard.status); // "Single"
보시다시피 고전적인 스타일로 선언된 "클래스"의 프로토타입을 조작할 수 있기 때문에 프로토타입을 사용하는 것은 실제로 이점이 없습니다.그것은 고전적인 방법의 하위 집합이다.
웹 개발: 시제품 상속 vs.고전적 상속
http://chamnapchhorn.blogspot.com/2009/05/prototypal-inheritance-vs-classical.html
기존 대 프로토타입 상속 - 스택 오버플로
언급URL : https://stackoverflow.com/questions/2800964/benefits-of-prototypal-inheritance-over-classical
'programing' 카테고리의 다른 글
Python 문자열에 단어가 있는지 확인합니다. (0) | 2022.11.07 |
---|---|
PHP 스크립트에 대한 동시 요청 (0) | 2022.11.07 |
PDO 데이터베이스 쿼리를 디버깅하는 방법 (0) | 2022.11.07 |
2.4 ebean 업데이트 최적 잠금 재생 (0) | 2022.10.30 |
삽입된 ID를 TypeORM & NestJS raw 쿼리: wait connection.manager와 함께 반환합니다.쿼리('삽입처') (0) | 2022.10.30 |