2010-08-24 1 views
16

J'ai une « classe » Javascript défini comme ceci:Puis-je "étendre" une "classe" définie par une fermeture en Javascript?

var Welcomer = function(name) { 
    var pName = name; 
    var pMessage = function() { 
    return "Hi, " + pName + "!"; 
    }; 

    return { 
    sayHi: function() { 
     alert(pMessage()); 
    } 
    }; 
}; 

new Welcomer('Sue').sayHi(); 

est-il un moyen de « sous-classe » Welcomer de telle sorte que je puisse redéfinir les méthodes publiques et d'avoir accès aux méthodes privées et les variables? Ce qui suit me donne accès aux méthodes publiques, mais pas aux privés:

var UnhappyWelcomer = function(name) { 
    var pSadMessage = function() { 
    // won't work, b/c I don't have access to pMessage 
    return pMessage() + " Miserable day, innit?"; 
    }; 

    return { 
    sayHi: function() { 
     alert(pSadMessage()); 
    } 
    }; 
}; 
UnhappyWelcomer.prototype = Welcomer(); // failed attempt at inheritance 

new UnhappyWelcomer().sayHi(); 
+1

Vous voudrez peut-être lire ce document [cet article] (http://mckoss.com/jscript/object.htm). –

+0

Marquer cet article. Thx –

Répondre

10

La réponse simple à votre question est No. Vous ne pouvez rien faire pour accéder à ces choses définies, à moins que votre fonction ne soit dans le même champ ou que vous rendiez les informations publiques (en les retournant ou en les réglant sur this). Si vous avez toutefois la possibilité d'éditer la fonction d'origine, vous pouvez réécrire les choses de telle sorte que ces fonctions puissent être «transmises» à une fonction d'extension, ce qui peut modifier la portée «protégée» de l'objet. Le code suivant devrait donner une bonne idée de ce que je propose.

var Welcomer = function(name) { 
    var _protected = { 
    name: name, 
    message: function() { 
     return "Hi, " + _protected.name + "!"; 
    } 
    }; 

    return { 
    extendWith: function(extender) { 
     extender.call(this, _protected); 
     return this; 
    }, 
    sayHi: function() { 
     alert(_protected.message()); 
    } 
    }; 
}; 

var UnhappyWelcomer = function(name) { 
    var self = Welcomer(name).extendWith(function(_protected) { 
    _protected.sadMessage = function() { 
     return _protected.message() + " Miserable day, innit?"; 
    }; 
    // extending the public while still having scope to _protected... 
    this.sayHi = function() { 
     alert(_protected.sadMessage()); 
    }; 
    }); 
    return self; 
}; 

UnhappyWelcomer('bob').sayHi(); 
+0

* avoir accès à la fonction d'origine, donc j'adorerais l'écrire de manière à rendre les choses "protégées" au lieu de "privées". Pouvez vous donner un exemple? –

+0

Je voudrais ajouter que c'est HUGELY gaspillage d'espace "scope" ... – gnarf

1

Si vous avez vraiment besoin d'héritage, il y a quelques bibliothèques là-bas qui vous aideront énormément. Une option est trait.js, qui peut effectivement devenir une partie standard de javascript à un moment donné. Si cela ne fait pas flotter votre bateau, les bibliothèques comme jQuery et le prototype ont des aides pour l'héritage.

Si vous voulez adopter une approche minimale/à partir de rien, je vous suggère fortement d'utiliser le modèle prototype pour tout. Vous verrez une augmentation importante des performances par rapport au modèle que vous avez dans vos exemples.

Pour répondre plus directement à votre question, non. Vous aurez un temps plus facile si vous concevez vos «classes» afin que les fonctions privées ne sont pas fiables.

+0

J'ai essayé 'return jQuery.extend ({}, Welcomer(), {sayHi: function() {alert (pSadMessage());});', mais 'extend' ne copie apparemment que les éléments définis dans le littéral d'objet (les méthodes publiques), pas la portée de la fermeture. –

+0

Oui, la façon dont vous avez conçu votre "classe" avec les var/fonctions privées définies dans le constructeur, ils ne seront pas visibles, c'est pourquoi je passerai certainement à une structure basée sur un prototype plus standard – jdc0589

9

Ce modèle « classe » est pas un modèle « de classe », il est connu comme un Module Pattern. Il renvoie un objet qui n'a aucun lien avec la fonction qui l'a créé, sinon la disponibilité de ses variables privées. L'objet retourné n'est PAS une instance de la fonction qui l'a créé. Lorsque vous appelez 'new Class()', vous créez une instance de cette fonction, mais elle renvoie également un autre objet. Toute autre opération est en fait sur l'objet retourné et non sur l'instance.

Pour utiliser l'héritage, vous devez vraiment utiliser l'héritage prototypique bien, je vous suggère de lire:

Autres lectures:

Désolé de vous laisser avec du matériel de lecture, mais il me semble que vous exploriez possibilités. Ces articles donneront un aperçu plus profond de la question. Une fois que vous en saurez plus sur le sujet, vous ignorerez probablement tous les membres privés et utiliserez le préfixe _ et en ferez un membre public comme tout le monde;) C'est simplement plus facile et les membres privés sont inutiles de toute façon.

Questions connexes