2009-02-12 6 views
10

J'ai:propriétés prototype et objet constructeur

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

} 

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

} 

maintenant quand je fais:

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

alert(obj.constructor) 

Je:

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

mais la fonction constructeur a été Obj2 .. . pourquoi ça? Obj1 est devenu le prototype Obj2 ...

que quelqu'un peut me expliquer, en détail, la chaîne prototype et la propriété constructeur

Merci

Répondre

25

constructor est une propriété régulière de l'objet prototype (avec DontEnum drapeau défini pour ne pas apparaître dans for..in boucles). Si vous remplacez l'objet prototype, la propriété constructor sera également remplacée - voir this explanation pour plus de détails.

Vous pouvez contourner le problème en définissant manuellement Obj2.prototype.constructor = Obj2, mais de cette façon, le drapeau DontEnum ne sera pas défini. En raison de ces problèmes, il n'est pas une bonne idée de s'appuyer sur constructor pour la vérification de type: utilisez instanceof ou isPrototypeOf() à la place.


Andrey Fedorov a soulevé la question de savoir pourquoi new n'attribue pas la propriété constructor à l'objet par exemple au lieu. Je suppose que la raison de ceci est le long des lignes suivantes:

Tous les objets créés à partir de la même fonction de constructeur partagent la propriété constructeur, et les propriétés partagées résident dans le prototype.

Le vrai problème est que JavaScript n'a pas de prise en charge intégrée des hiérarchies d'héritage. Il y a plusieurs façons de contourner la question (le vôtre est l'un d'entre eux), un autre plus « dans l'esprit » de JavaScript serait la suivante:

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() {}; 

Cela rend trivial l'héritage multiple aussi bien.

9

Extrayez le Tom Trenka's OOP woth ECMAscript, la page "Héritage". Tout le du prototype est hérité, y compris la propriété constructor. Ainsi, nous devons unbreak nous-mêmes:

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

Eh bien, la propriété constructeur est une propriété comme une autre, sur le prototype (propriété) de Obj1. Si vous understand how prototypes work, cela pourrait aider:

>>> 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! Donc obj n'a pas de constructeur, JS va chercher la chaîne [[Prototype]], depuis Obj1.prototype.constructor

Je ne sais pas pourquoi la propriété constructeur n'est pas simplement définie sur un objet quand vous utilisez `new ' Il pourrait y avoir une raison ou un simple oubli. De toute façon, j'ai tendance à l'éviter.

+1

'constructor' est une propriété qui est partagée entre toutes les instances des objets créés à partir du même constructeur, par conséquent, c'est la bonne chose à mettre dans le prototype; c'est juste que JS n'a pas de support intégré pour les hiérarchies d'héritage (profondes) - j'ajouterai une explication à ma réponse ... – Christoph

3

Version courte: 'constructor' ne fait pas ce que vous pensez, et n'est pas compatible avec tous les navigateurs. Ne l'utilisez jamais.

Version longue: Convention for prototype inheritance in JavaScript

En général: vous obtenez confus en raison de (a) et basé sur un prototype non-concordance d'impédance entre base de classe OO, et (b) l'étrangeté de l'interprétation assez pauvre particulière JavaScript de OO basé sur un prototype.

Vous serez probablement plus heureux si vous trouvez une implémentation de classes dans les prototypes que vous aimez et que vous en tenez compte. De nombreuses bibliothèques en ont un. Voici un arbitraire que j'utilise:

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(); 

Et voici un exemple de la façon dont on peut l'utiliser:

// 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); 
Questions connexes