Pouvez-vous dire que c'est un bon exemple de fermeture de Javascript. Où les endroits où nous devons envisager d'éviter les fermetures?

Problème et raison

L'un de mes coéquipiers s'est retrouvé dans une fonction de mise en œuvre désagréable accrochant en javascript. C'est le code actuel

function ActualMethod(){ this.doSomething = function() { this.testMethod(); }; this.testMethod = function(){ alert("testMethod"); }; } function ClosureTest(){ var objActual= new ActualMethod(); var closeHandler = objActual.doSomething; closeHandler(); closeHandler.apply(objActual,arguments); //the fix i have added this.ActualTest = function() { alert("ActualTest"); }; } 

Dans le code ci-dessus, var closeHandler est créé dans le contexte de ClosureTest (), mais il détient le gestionnaire de ActualMethod.doSomething. Chaque fois que l'appelant CloseHandler () s'est retrouvé dans l'erreur "objet ne supporte pas cette méthode".

C'est parce que la fonction doSomething () appelle une autre méthode à l'intérieur appelée this.testMethod () ;. Ici, cela se réfère au contexte de l'appelant non callee.so, je supposons que closeHandler est lié à l'environnement (ClosureTest) réellement créé. Même s'il retient le gestionnaire à l'autre contexte, il expose les propriétés de son propre contexte.

Solution

Pour éviter cela je suggère d'utiliser appliquer pour spécifier le conext dans lequel il doit être exécuté.

CloseHandler.apply (objActual, arguments);

Des questions

Est-ce un scénario parfait pour les fermetures … ??

Quels sont les endroits interstants que vous avez rencontrés des fermetures en javascript …?

METTRE À JOUR

Oui, c'est simple, je peux appeler la méthode directement. Mais le problème est que, dans un scénario particulier, je dois intercepter l'appel à la méthode actuelle et exécuter un code avant cela, finalement exécuter la méthode réelle.

Disons pour un exemple, j'utilise la bibliothèque de grille aspx de tiers, et tous les événements mouseclick sont piégés par leurs contrôles. En particulier, par clic de souris, j'ai besoin d'intercepter l'appel à leur méthode ilbrary et d'accrocher mon mthod pour l'exécuter à la place et de rediriger l'appel vers la méthode de la bibliothèque réelle

J'espère que cela t'aides

Mise à jour: parce que vous avez probablement laissé de côté certains détails dans votre code, il est difficile de l'adapter en quelque chose de réalisable sans avoir manqué le code réel. Je pense que je comprends votre problème sous-jacent comme vous le décrivez. J'espère que cela vous aidera.

Supposons l'exemple simple suivant:

 // Constructor function. function Example() { // Method: this.method = function() { alert("original method"); } } // You would use it like this: var obj = new Example(); obj.method(); // Calls original method. 

Pour intercepter un tel appel de méthode, vous pouvez le faire:

 function wrap(obj) { var originalMethod = obj.method; obj.method = function() { alert("intercepted call"); originalMethod.apply(this, arguments); } return obj; } var obj = wrap(new Example()); obj.method(); // Calls wrapped method. 

Malheureusement, parce que method() est définie dans la fonction constructeur, pas sur un prototype, vous devez avoir une instance d'objet pour envelopper l'objet.


Réponse à la question originale: la fonction doSomething() est utilisée comme méthode sur les objets créés avec ActualMethod() . Vous devez l'utiliser comme méthode, ne pas le détacher et l'utiliser comme fonction dans un contexte différent. Pourquoi n'appelais-tu pas directement la méthode?

 function ClosureTest(){ var objActual = new ActualMethod(); // Call method directly, avoid messy apply() calls. objActual.doSomething(); this.ActualTest = function() { alert("ActualTest"); }; } 

Si vous attribuez une méthode (une fonction sur un objet) à une variable locale en Javascript et que vous l'appelez, le contexte sera différent (la valeur de this modification). Si vous ne voulez pas que cela se produise, ne le faites pas.

Lorsque je souhaite accrocher une fonction, j'utilise la méthode de fonction suivante qui est aussi une belle démonstration de clôture:

 Function.prototype.wrap = function (wrapper) { var __method = this; return function() { var __obj = this; var args = [ __method.bind(__obj) ]; for(var i=0; i<arguments.length; i++) args.push(arguments[i]); return wrapper.apply(__obj, args); } }; 

Ensuite, faites quelque chose comme:

 ActualMethod = ActualMethod.wrap(function (proceed, option) { // ... handle option proceed(); // calls the wrapped function }); 

Procéder est lié à son objet initial, de sorte que vous pouvez l'appeler en toute sécurité.