Prototype JavaScript limité aux fonctions?

O.prototype = {…} ne fonctionne que si o est une fonction. Supposons que j'ai le code suivant

conf = { a: 2, b: 4 }; conf.prototype = { d: 16 } 

Conf.a et conf.b est OK et renvoie les valeurs appropriées. Mais conf.d ne retourne pas 16 plutôt, il va indéfini. Existe-t-il une solution qui suce que la généralisation basée sur un prototype peut également être appliquée sur ce type d'objets.

Vous confondez la propriété prototype qui peut être utilisée sur les Fonctions Constructeur et la propriété [[Prototype]] interne .

Tous les objets ont cette propriété [[Prototype]] interne, et seul le new opérateur lorsque vous l'appelez avec une fonction constructeur est autorisé à le configurer (via l'opération interne [[Construct]] ).

Si vous souhaitez avoir un héritage prototypique avec des instances d'objet (sans utiliser de constructeurs), la technique Object.create de Crockford est ce que vous voulez (cette méthode fait maintenant partie de la 5ème édition ECMAScript récemment approuvée):

 // Check if native implementation available if (typeof Object.create !== 'function') { Object.create = function (o) { function F() {} // empty constructor F.prototype = o; // set base object as prototype return new F(); // return empty object with right [[Prototype]] }; } var confProto = { d: 16 }; var conf = Object.create(confProto); conf.a = 2; conf.b = 4; 

Dans le code ci-dessus conf aura ses trois membres, mais seulement a et b y habiteront physiquement:

 conf.hasOwnProperty('a'); // true conf.hasOwnProperty('b'); // true conf.hasOwnProperty('d'); // false 

Parce que d existe sur conf [[Prototype]] ( confProto ).

Les accessors de propriété,. Et [] sont responsables de résoudre les propriétés recherchées si nécessaire dans la chaîne prototype (via la méthode interne [[Get]] ).

Il existe en fait deux types différents de "prototype" en JavaScript:

  1. L'un est le lien "caché" que chaque objet possède (utilisons [[Prototype]] pour représenter ce lien caché). Les littéralités d'objet par défaut ont leurs liens cachés pointant vers Object.prototype , les objets de fonction ont leur lien caché pointant sur Function.prototype , et les tableaux ont le leur pointant vers Array.prototype . Ces liens prototypes cachés ne sont pas liés aux propriétés avec le nom "prototype". Vous ne pouvez pas modifier ces liens cachés en ajoutant ou en modifiant o.prototype .
  2. Un autre est que tous les objets fonction ont automatiquement une propriété spéciale nommée « prototype ». Ceci est principalement pour l'utilisation du modèle d'invocation du constructeur.

[[Prototype]] est utilisé pour rechercher des propriétés (comme le parent dans la hiérarchie classique), chaque fois qu'une propriété ne peut être trouvée dans un objet, son [[Prototype]] est recherché à la place. Un scénario d'utilisation: disons que vous souhaitez ajouter une propriété à tous les objets, vous pouvez simplement l'ajouter à Object.prototype qui s'appliquerait automatiquement à tous les objets puisque tous les objets ont en quelque sorte Object.prototype comme racine de chaîne [[Prototype]] .

Revenons à la propriété " prototype " des objets fonctionnels. Ce n'est utile que lorsqu'il est utilisé avec un opérateur new . Prenez l'extrait de code suivant comme exemple:

 function F() {} // function declaration // F now has a property named "prototype" var f = new F(); // use "new" operator to create a new function object based on F 

Quelle new F() fait ci-dessus pour créer d'abord un nouvel objet de fonction, définissez [[Prototype]] (lien caché) de cet objet de fonction nouvellement créé pour être F.prototype , puis renvoyez le nouvel objet de fonction. C'est probablement ce que vous comprenez déjà, qui fonctionne pour les objets fonctionnels.

Rappelez-vous que j'ai dit que nous ne pouvons pas modifier [[Prototype]] objets? Eh bien, au moins pas directement. La fonction Object.create de Crockford fait exactement cela, en utilisant le fait que l'opérateur new pourrait aider à définir [[Prototype]] pour nous. Donc, en utilisant Object.create , vous pouvez délibérément indiquer où le lien caché de votre nouvel objet doit indiquer. (Certains ont l'impression d'indiquer qui est votre classe parent)

Dans votre exemple, conf est un objet littéral et conf.prototype n'est pas vraiment utile. Voici une autre version utilisant le style classique:

 function ConfBase() {} ConfBase.prototype.d = 16; var conf = new ConfBase(); conf.a = 2; conf.b = 4; document.writeln(conf.a); document.writeln(conf.b); document.writeln(conf.d); 

Par rapport à la réponse de @CMS, je préfère utiliser Object.create . Mais essentiellement, les 2 styles utilisent le même mécanisme sous-jacent, juste que Object.create aide à le ranger.