2009-02-12 17 views
10

mam:prototypowe i konstruktor właściwości obiektu

function Obj1(param) 
{ 
    this.test1 = param || 1; 

} 

function Obj2(param, par) 
{ 
    this.test2 = param; 

} 

teraz kiedy zrobić:

Obj2.prototype = new Obj1(44); 
var obj = new Obj2(55); 

alert(obj.constructor) 

mam:

function Obj1(param) { 
    this.test1 = param || 1; 
} 

ale funkcja konstruktor został obj2 .. . Dlaczego to? obj1 stał się prototypem obj2 ...

Czy ktoś może mi wyjaśnić, w szczegółach, łańcuch prototypu i obiekt konstruktor

Dzięki

Odpowiedz

25

constructor jest regularne własność obiektu prototypu (z DontEnum ustaw flagę, aby nie pojawiała się w pętlach for..in). Jeśli zamienisz obiekt prototypowy, właściwość constructor również zostanie wymieniona - więcej informacji znajdziesz w artykule this explanation.

Możesz obejść problem, ręcznie ustawiając Obj2.prototype.constructor = Obj2, ale w ten sposób flaga DontEnum nie zostanie ustawiona.

Z tego powodu nie jest dobrym pomysłem poleganie na sprawdzaniu typu: constructor: zamiast tego użyj instanceof lub isPrototypeOf().


Andriej Fiodorow postawił pytanie dlaczego new nie przypisać właściwość constructor do obiektu instancji zamiast. Sądzę, że powodem tego są następujące linie:

Wszystkie obiekty utworzone z tej samej funkcji konstruktora współdzielą własność konstruktora, a właściwości wspólne znajdują się w prototypie.

Prawdziwym problemem jest to, że JavaScript nie ma wbudowanej obsługi hierarchii dziedziczenia. Istnieje kilka sposobów na całym numerze (twój jest jednym z nich), inny więcej jeden „w duchu” JavaScriptu byłby następujący:

function addOwnProperties(obj /*, ...*/) { 
    for(var i = 1; i < arguments.length; ++i) { 
     var current = arguments[i]; 

     for(var prop in current) { 
      if(current.hasOwnProperty(prop)) 
       obj[prop] = current[prop]; 
     } 
    } 
} 

function Obj1(arg1) { 
    this.prop1 = arg1 || 1; 
} 

Obj1.prototype.method1 = function() {}; 

function Obj2(arg1, arg2) { 
    Obj1.call(this, arg1); 
    this.test2 = arg2 || 2; 
} 

addOwnProperties(Obj2.prototype, Obj1.prototype); 

Obj2.prototype.method2 = function() {}; 

To sprawia, wielokrotnego dziedziczenia trywialne, jak również.

9

Zapoznaj się z Tom Trenka's OOP woth ECMAscript, stroną "Dziedziczenie". Wszystko z prototypu jest dziedziczone, w tym właściwość constructor. Tak więc, musimy unbreak to sami:

Obj2.prototype = new Obj1(42); 
Obj2.prototype.constructor = Obj2; 
1

Dobrze, właściwość konstruktor jest właściwością jak każdy inny, na prototypie (mienia) obj1. Jeśli understand how prototypes work, to może pomóc:

>>> obj.hasOwnProperty("constructor") 
false 

// obj's [[Prototype]] is Obj2.prototype 
>>> Obj2.prototype.hasOwnProperty("constructor") 
false 

// Obj2.prototype's [[Prototype]] is Obj1.prototype 
>>> Obj1.prototype.hasOwnProperty("constructor") 
true 

// Oh? 
>>> Obj1.prototype.constructor 
Obj1() 

Aha! Tak więc nie ma konstruktora, JS idzie, aby uzyskać łańcuch [[Prototype]], aż do Obj1.prototype.constructor

Nie jestem pewien, dlaczego właściwość konstruktora nie jest ustawiona na obiekcie kiedy używasz `nowego '. Może być jakiś powód lub może to być tylko niedopatrzenie. Tak czy siak, staram się tego unikać.

+1

'constructor' jest nieruchomość, która jest dzielona pomiędzy wszystkich instancji obiektów utworzona z tego samego konstruktora, dlatego dobrze jest umieścić go w prototypie; Po prostu JS nie ma wbudowanej obsługi hierarchii dziedziczenia (głębokiego) - dodam wyjaśnienie do mojej odpowiedzi ... – Christoph

3

Krótka wersja: "konstruktor" nie robi tego, co myślisz i nie jest kompatybilny z wieloma przeglądarkami. Nigdy go nie używaj.

Długa wersja: Convention for prototype inheritance in JavaScript

Ogólnie: jesteś mylić uzyskiwanie powodu (a) niedopasowanie impedancji między klasa oparte i OO prototyp oparte, oraz (b) dziwność szczególności raczej złej interpretacji obsługa JavaScript dnia prototypowe OO.

Prawdopodobnie będziesz szczęśliwszy, jeśli znajdziesz jedną z implementacji klas-w-prototypach, którą lubisz i trzymasz się tego. Wiele bibliotek ma jedną. Oto arbitralny jeden używam:

Function.prototype.subclass= function() { 
    var c= new Function(
     'if (!(this instanceof arguments.callee)) throw(\'Constructor called without "new"\'); '+ 
     'if (arguments[0]!==Function.prototype.subclass.FLAG && this._init) this._init.apply(this, arguments); ' 
    ); 
    if (this!==Object) 
     c.prototype= new this(Function.prototype.subclass.FLAG); 
    return c; 
} 
Function.prototype.subclass.FLAG= new Object(); 

A oto przykład, jak można by go używać:

// make a new class 
var Employee= Object.subclass(); 

// add members to it 
Employee.prototype._LEGS= 2; 
Employee.prototype.getLegs= function() { 
    return this._LEGS; 
}; 

// optional initialiser, takes arguments from constructor 
Employee.prototype._init= function(name) { 
    this.name= name; 
}; 

// make a subclass 
Manager= Employee.subclass(); 

// extend subclass method 
Manager.prototype._init= function(name, importance) { 
    // call base class's method 
    Employee.prototype._init.call(this, name); 
    this.importance= importance; 
} 

// all managers are well-known to have three legs 
Manager.prototype._LEGS= 3; 

// create one 
var jake= new Manager('Jake the Peg', 100); 
Powiązane problemy