자바 스크립트 프로토 타입 상속?
-
23-08-2019 - |
문제
나는 그것을 더 잘 이해하기 위해 JS에서 상속을하고 있으며, 나를 혼란스럽게하는 것을 발견했습니다.
새 키워드로 '생성자 함수'를 호출 할 때 해당 기능의 프로토 타입을 참조하여 새 객체를 얻습니다.
또한 프로토 타입 상속을 만들려면 생성자 함수의 프로토 타입을 '슈퍼 클래스'가 될 객체의 인스턴스로 바꿔야한다는 것을 알고 있습니다.
그래서 나는이 개념들을 시도하기 위해이 어리석은 예를 들었습니다.
function Animal(){}
function Dog(){}
Animal.prototype.run = function(){alert("running...")};
Dog.prototype = new Animal();
Dog.prototype.bark = function(){alert("arf!")};
var fido = new Dog();
fido.bark() //ok
fido.run() //ok
console.log(Dog.prototype) // its an 'Object'
console.log(fido.prototype) // UNDEFINED
console.log(fido.constructor.prototype == Dog.prototype) //this is true
function KillerDog(){};
KillerDog.prototype.deathBite = function(){alert("AAARFFF! *bite*")}
fido.prototype = new KillerDog();
console.log(fido.prototype) // no longer UNDEFINED
fido.deathBite(); // but this doesn't work!
(이것은 Firebug의 콘솔에서 이루어졌습니다)
1) 모든 새 개체에 Creator 함수의 프로토 타입에 대한 참조가 포함되어 있으면 Fido.Prototype가 정의되지 않습니까?
2) 상속 체인 [obj] -> [생성자] -> [OBJ] -> [프로토 타입] 대신 [프로토 타입]?
3) 객체 (FIDO)의 '프로토 타입'속성이 확인 된 적이 있습니까? 그렇다면 ... 왜 'DeathBite'가 정의되지 않은가 (마지막 부분에서)?
해결책
1) 모든 새 개체에 Creator 함수의 프로토 타입에 대한 참조가 포함되어 있으면 Fido.Prototype가 정의되지 않습니까?
모든 새로운 객체는 시공 시점에 생성자에 존재하는 프로토 타입에 대한 참조를 보유합니다. 그러나이 참조를 저장하는 데 사용되는 속성 이름은 prototype
생성자 기능 자체에있는 것처럼. 일부 JavaScript 구현은 일부 속성 이름을 통해이 '숨겨진'속성에 액세스 할 수 있습니다. __proto__
다른 사람들이하지 않는 곳 (예 : 마이크로 소프트).
2) 상속 체인 [obj] -> [생성자] -> [OBJ] -> [프로토 타입] 대신 [프로토 타입]?
아니요. 이것을 살펴보십시오 :-
function Base() {}
Base.prototype.doThis = function() { alert("First"); }
function Base2() {}
Base2.prototype.doThis = function() { alert("Second"); }
function Derived() {}
Derived.prototype = new Base()
var x = new Derived()
Derived.prototype = new Base2()
x.doThis();
이것은 "첫 번째"가 아닌 경고합니다. 상속 체인이 생성자를 통해 진행되면 "두 번째"가 표시됩니다. 객체가 구성되면 Functions 프로토 타입 속성에 보관 된 현재 참조는 프로토 타입에 대한 객체 숨겨진 참조로 전송됩니다.
3) 객체 (FIDO)의 '프로토 타입'속성이 확인 된 적이 있습니까? 그렇다면 ... 왜 'DeathBite'가 정의되지 않은가 (마지막 부분에서)?
객체에 할당 (함수 제외) prototype
앞에서 언급 한 바와 같이, 객체는 그러한 속성 이름을 통해 프로토 타입에 대한 참조를 유지하지 않는 특별한 의미가 없습니다.
다른 팁
일단 인스턴스화되면 객체의 프로토 타입을 변경할 수 없습니다. new
.
위의 예에서는 선과 같은 선입니다
fido.prototype = new KillerDog();
단순히 이름이 지정된 새 속성을 만듭니다 prototype
대상에 fido
, 그리고 새로운 세트 KillerDog
물체. 그것은 다르지 않습니다
fido.foo = new KillerDog();
코드가 서있는 것처럼 ...
// Doesn't work because objects can't be changed via their constructors
fido.deathBite();
// Does work, because objects can be changed dynamically,
// and Javascript won't complain when you use prototype
//as an object attribute name
fido.prototype.deathBite();
스페셜 prototype
동작은 생성자가있는 JavaScript의 생성자에게만 적용됩니다. function
함께 호출 될 s new
.
질문에 대한 숫자로 답변 :
- 객체의 프로토 타입 속성은 호출되지 않습니다
prototype
. 표준 사용[[prototype]]
그것을 지정합니다. Firefox는이 속성을 __proto__라는 이름으로 공개합니다. - 상속 체인은입니다
[obj]
⇒[prototype object]
. 원래 가정 ([obj]
⇒[constructor]
⇒[prototype]
) 잘못되었고 수정하여 쉽게 반증 할 수 있습니다.constructor
및/또는constructor.prototype
, 그리고 어떤 방법을 호출 할 수 있는지 확인합니다.[obj]
- 이러한 수정이 아무것도 바꾸지 않는다는 것을 알게 될 것입니다. prototype
객체의 속성은 점검되지 않고 사용되지 않습니다. 원하는대로 설정할 수 있습니다. JavaScript는 객체 구성 중에 만 기능 객체에서 사용합니다.
#3을 입증하려면 여기에 코드가 있습니다. 도조:
dojo.delegate = dojo._delegate = (function(){
// boodman/crockford delegation w/ cornford optimization
function TMP(){}
return function(obj, props){
TMP.prototype = obj;
var tmp = new TMP();
if(props){
dojo._mixin(tmp, props);
}
return tmp; // Object
}
})();
보시다시피 사실을 활용합니다. prototype
동일한 함수를 재사용하여 한 곳에서만 사용됩니다. TMP
프로토 타입이 다른 모든 위임 된 객체에 대해. 사실로 prototype
기능을 호출하기 전에 직접 할당됩니다 new
, 생성 된 객체에 영향을 미치지 않으면 변경됩니다.
내 대답에서 생성 된 객체를 찾을 수 있습니다. [프로토 타입]]과 JavaScript의 프로토 타입 간의 관계.
나는 그것이 이미 대답을 받았다는 것을 알고 있지만 상속을하는 더 좋은 방법이 있습니다. 상속을 목적으로 만 생성자를 호출하는 것이 바람직하지 않습니다. 바람직하지 않은 효과 중 하나는입니다.
function Base() {this.a = "A"}
function Child() {this.b = "B"};
Child.prototype = new Base();
이제 당신은 의도하지 않은 어린이의 프로토 타입에 "a"를 추가했습니다.
올바른 방법은 다음과 같습니다 (나는 이것을 발명하지 않았다, Ext-JS 및 기타 Libs는 이것을 사용한다).
// This is used to avoid calling a base class's constructor just to setup inheritance.
function SurrogateCtor() {}
/**
* Sets a contructor to inherit from another constructor
*/
function extend(BaseCtor, DerivedCtor) {
// Copy the prototype to the surrogate constructor
SurrogateCtor.prototype = BaseCtor.prototype;
// this sets up the inheritance chain
DerivedCtor.prototype = new SurrogateCtor();
// Fix the constructor property, otherwise it would point to the BaseCtor
DerivedCtor.prototype.constructor = DerivedCtor;
// Might as well add a property to the constructor to
// allow for simpler calling of base class's method
DerivedCtor.superclass = BaseCtor;
}
function Base() {
this.a = "A";
}
Base.prototype.getA = function() {return this.a}
function Derived() {
Derived.superclass.call(this); // No need to reference the base class by name
this.b = "B";
}
extend(Base, Derived);
// Have to set methods on the prototype after the call to extend
// otherwise the prototype is overridden;
Derived.prototype.getB = function(){return this.b};
var obj = new Derived();
더 쉬운 방법은 세 번째 매개 변수를 추가하여 파생 클래스의 메소드를 지정하여 확장을 호출 할 필요가없고 프로토 타입에 메소드를 추가 할 필요가 없습니다.
extend(BaseCtor, DerivedCtor, {
getB: function() {return this.b}
});
그런 다음 구문 설탕을 위해 할 수있는 다른 많은 것들이 있습니다.
그것에 대해 블로그 : http://js-bits.blogspot.com/2010/08/javaScript-enheritance-right.html
ECMAScript 5 (즉, JavaScript 언어의 최신 버전)에서 인스턴스의 내부 [[프로토 타입]] 속성에 액세스 할 수 있다는 점에 주목할 가치가 있습니다. Object.getPrototypeOf
:
Object.getPrototypeOf(fido) === Dog.prototype