문제

나는 그것을 더 잘 이해하기 위해 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.

질문에 대한 숫자로 답변 :

  1. 객체의 프로토 타입 속성은 호출되지 않습니다 prototype. 표준 사용 [[prototype]] 그것을 지정합니다. Firefox는이 속성을 __proto__라는 이름으로 공개합니다.
  2. 상속 체인은입니다 [obj][prototype object]. 원래 가정 ([obj][constructor][prototype]) 잘못되었고 수정하여 쉽게 반증 할 수 있습니다. constructor 및/또는 constructor.prototype, 그리고 어떤 방법을 호출 할 수 있는지 확인합니다. [obj] - 이러한 수정이 아무것도 바꾸지 않는다는 것을 알게 될 것입니다.
  3. 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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top