Javascript: appelant une méthode privée à partir d'une méthode prototype

Je suis sûr que cela doit être une question assez fréquente, mais après avoir parcouru les Internet pendant plusieurs heures, je n'ai pas trouvé de réponse. Voici la question:

Supposons que j'ai une interface appelée mammifère. Chaque mammifère doit pouvoir dormir et manger. (Dans le futur, je peux jeter des exceptions pour la classe Mammmère pour forcer les enfants à mettre en œuvre la fonction).

function Mammal() {}; Mammal.prototype.eat = function() {}; Mammal.prototype.sleep = function() {}; 

Maintenant, supposons que j'ai une classe de chien qui met en œuvre la classe de mammifères:

 function Dog() {}; Dog.prototype = new Mammal(); Dog.prototype.eat = function() { ... }; Dog.prototype.sleep = function() { ... }; 

La fonction de consommation du chien est très compliquée et j'aimerais utiliser une fonction d'aide. Je n'ai pas été en mesure de comprendre quelle est la meilleure façon de le faire. Voici les points à considérer:

  • La fonction helper ne doit jamais être appelée de l'extérieur de la classe de chien, donc, idéalement, elle devrait être privée.
  • La fonction manger n'a pas accès à des fonctions privées (les prototypes n'ont pas accès à des fonctions privées)
  • Je pourrais mettre la fonction helper dans une fonction privalaged mais:
    • Ce serait toujours une fonction publique – c'est-à-dire: tout le monde a le droit de l'appeler
    • Ce ne ferait pas partie du prototype afin que chaque chien ait besoin d'avoir sa propre fonction d'aide. S'il y avait beaucoup de chiens, cela semblait inefficace.
  • Je ne peux pas faire de la fonction manger une fonction privaligée car, pour que l'héritage des prototypes fonctionne, elle doit faire partie du prototype.

Question: Comment puis-je appeler une fonction privée à partir d'une fonction prototype? Ou plus généralement: lorsqu'un objet (objet enfant) hérite d'un autre objet (objet parent), comment les méthodes enfants doivent-elles utiliser des fonctions auxiliaires et est-il possible de les rendre privées?

Définissez votre "classe" de Dog dans une fermeture. Ensuite, vous pouvez avoir des fonctions privilégiées partagées. Il suffit de savoir que vous devrez faire attention à this lien correctement lorsque vous l'appelez.

 var Dog = (function() { function Dog() {}; // Common shared private function, available only to Dog. var privateHelper = function() { ... }; Dog.prototype = new Mammal(); Dog.prototype.eat = function() { privateHelper() // Or this if the helper needs to access the instance. // privateHelper.call(this); ... }; return Dog; })(); 

Une fonction sur un prototype est toujours juste une fonction . Donc, suit la même portée et les mêmes règles d'accès à la fermeture que n'importe quelle autre fonction. Donc, si vous définissez votre constructeur et prototype Dog entier et une île isolée de portée qui est la fonction d'auto-exécution, vous pouvez partager autant que vous le souhaitez sans exposer ou polluer la portée publique.

C'est exactement ce que les classes CoffeeScript compilent vers JS.

Ce n'est pas possible. Si vous avez besoin d'accéder à des variables / fonctions privées, vous devez utiliser des fonctions privilégiées (assistant).

Il est parfois possible d'utiliser des fonctions d'assistance dans un périmètre de fermeture local au lieu de fonctions d'assistant privé (dans la portée du constructeur), qui seraient accessibles à partir de fonctions de prototype. Voir les réponses d'Alex Wayne ou Raynos pour cela.

Tu as dit:

Je ne peux pas faire de la fonction manger une fonction privaligée car, pour que l'héritage des prototypes fonctionne, elle doit faire partie du prototype.

Pourquoi pas?

 MammalPrototype = { eat: function() {}, sleep: function() {} }; function Dog(color) { ... this.eat = function() { ... // using private functions MammalPrototype.eat.call(this, options) // ? }; }; Dog.prototype = Object.create(MammalPrototype); // inherit from an object 

new Mammal() est OK lorsque Mammal n'est vraiment qu'une fonction vide. Voir https://stackoverflow.com/a/5199135/1048572 pour savoir comment cela fonctionne. La cote proposée n'est évidemment pas ce qu'est une implantation native, mais c'est exactement ce dont nous avons besoin ici. Ne créez pas une instance pour y hériter!

 Dog.prototype.sleep = function() { ... }; function Dalmatian() { Dog.call(this, "black.white"); ... } Dalmatian.prototype = Object.create(Dog.prototype); // sic Dalmatian.prototype.xyz = function() {}; 

Appeler le super constructeur sur this moyen pour recevoir toutes les méthodes privilégiées et leurs fonctionnalités. Vous devrez le faire si vous utilisez des variables privées et / ou des fonctions dans des "classes" dont vous héritez, sinon tous les appels vers des fonctions privilégiées héritées affecteront uniquement la seule instance sur laquelle vous avez configuré votre prototype .

Lorsqu'un objet (objet enfant) hérite d'un autre objet (objet parent), comment les méthodes enfants doivent-elles utiliser des fonctions auxiliaires et est-il possible de les rendre privées?

Vous avez besoin de quelques couches d'abstraction pour atteindre ce que vous voulez: Live Example

Utilise klass

 var Mammal = klass(function (privates) { privates.local_helper = function () { console.log("local_helper invoked"); } return { constructor: function () { console.log("mammal constructed"); privates(this).caneat = true; }, eat: function () { privates.local_helper(); console.log("mammal eat"); }, sleep: function () { console.log("mammal sleep"); } }; }); var Dog = klass(Mammal, function (privates, $super) { return { constructor: function () { $super.constructor.call(this); console.log("dog constructed"); }, eat: function () { $super.eat.call(this); privates.local_helper(); console.log("dog eat"); console.log(privates(this).caneat); } }; }); var dog = new Dog(); dog.eat();