J'espère que je suis à la compréhension de ce droit.
Je crois que vous voulez un foncteur qui est à la fois une instance de l'avancement du prototype (oui, une classe, tout simplement pas un classique de la classe) ainsi que les appelle directement? Droit? Si oui, alors c'est parfaitement logique et est très flexible et puissant (surtout dans un très environnement asynchrone comme en JavaScript). Malheureusement, il n'y a aucun moyen de le faire avec élégance en JavaScript sans manipuler __proto__
. Vous pouvez le faire en donnant une fonction anonyme et copie de toutes les références à toutes les méthodes (ce qui semble être la direction de la rubrique) pour agir comme un proxy de la classe. Les inconvénients de cette...
- C'est très coûteux en termes de temps d'exécution.
-
(functorObj instanceof MyClass)
ne sera jamais true
.
- Les propriétés ne seront pas directement accessible (si ils ont été assignés par référence, ce serait une autre histoire, mais primitives qui sont affectés par valeur). Cela peut être résolu avec des accesseurs via
defineProperty
ou tout simplement nommé méthodes d'accès si nécessaire (il semble que c'est ce que vous cherchez, il suffit d'ajouter toutes les propriétés de l'foncteur avec defineProperty
via des getters/setters au lieu de simplement les fonctions si vous n'avez pas besoin de la croix-support moteur/arrière de compatibilité).
- Vous êtes confronté à des cas limites où la finale prototypes natifs (comme Objet.prototype ou d'un Tableau.prototype [si vous êtes à hériter de ce]) peut ne pas fonctionner comme prévu.
- Appelant
functorObj(someArg)
sera toujours faire de l' this
contexte, être l'objet, indépendamment de si elle est appelée functorObj.call(someOtherObj, someArg)
(ce n'est pas le cas pour les appels de méthode)
- Parce que le foncteur objet est créé au moment de la demande, il sera verrouillé dans le temps et en manipulant le prototype initial ne sera pas affecter l'allocation d'un foncteur des objets comme un objet normal serait affecté (modification de Maclasse.prototype n'affectera pas le foncteur des objets, et l'inverse est vrai aussi).
Si vous l'utilisez, doucement mais, rien de tout cela devrait être une grosse affaire.
Dans votre prototype de votre classe à définir quelque chose comme...
// This is you're emulated "overloaded" call() operator.
MyClass.prototype.execute = function() {
alert('I have been called like a function but have (semi-)proper access to this!');
};
MyClass.prototype.asFunctor = function(/* templateFunction */) {
if ((typeof arguments[0] !== 'function') && (typeof this.execute !== 'function'))
throw new TypeError('You really should define the calling operator for a functor shouldn\'t you?');
// This is both the resulting functor proxy object as well as the proxy call function
var res = function() {
var ret;
if (res.templateFunction !== null)
// the this context here could be res.asObject, or res, or whatever your goal is here
ret = res.templateFunction.call(this, arguments);
if (typeof res.asObject.execute === 'function')
ret = res.asObject.execute.apply(res.asObject, arguments);
return ret;
};
res.asObject = this;
res.templateFunction = (typeof arguments[0] === 'function') ? arguments[0] : null;
for (var k in this) {
if (typeof this[k] === 'function') {
res[k] = (function(reference) {
var m = function() {
return m.proxyReference.apply((this === res) ? res.asObject : this, arguments);
};
m.proxyReference = reference;
return m;
})(this.asObject[k]);
}
}
return res;
};
Résultant de l'utilisation ressemblerait à quelque chose comme...
var aobj = new MyClass();
var afunctor = aobj.asFunctor();
aobj.someMethodOfMine(); // << works
afunctor.someMethodOfMine(); // << works exactly like the previous call (including the this context).
afunctor('hello'); // << works by calling aobj.execute('hello');
(aobj instanceof MyClass) // << true
(afunctor instanceof MyClass) // << false
(afunctor.asObject === aobj) // << true
// to bind with a previous function...
var afunctor = (new MyClass()).asFunctor(function() { alert('I am the original call'); });
afunctor() // << first calls the original, then execute();
// To simply wrap a previous function, don't define execute() in the prototype.
Vous pourriez même chaîne se lier d'innombrables autres objets/fonctions/etc jusqu'à ce que les vaches sont venus à la maison. Juste refactoriser le proxy appeler un peu.
Espérons que cela aide. Oh, et bien sûr, vous pourriez changer l'usine de flux de sorte qu'un constructeur appelé sans le new
opérateur instancie un nouvel objet et renvoie le foncteur de l'objet. Toutefois vous préférez (vous pouvez certainement le faire par d'autres moyens).
Enfin, pour toute fonction devenir l'exécution de l'opérateur pour un foncteur en un peu plus élégant d'une manière, il suffit de faire le proxy fonction d'une méthode de Function.prototype
et passer à l'objet de retour si vous voulez faire quelque chose comme (vous pouvez swap templateFunction
avec this
et this
avec l'argument de cours)...
var functor = (function() { /* something */ }).asFunctor(aobj);