2009-01-08 10 views
2

J'ai une fonction javascript (classe) qui prend une référence de fonction en tant que paramètre.Extend Javascript Fonction passée en paramètre

function MyClass (callBack) { 
    if (typeof callBack !== 'function') 
    throw "You didn't pass me a function!" 
} 

Pour des raisons que je ne vais pas aller ici, je dois ajouter quelque chose à la fonction en l'enfermant dans une fonction anonyme, mais la seule façon que je suis en mesure de comprendre comment le faire est en ajoutant une fonction publique à MyClass qui prend la fonction callBack en paramètre et renvoie la version modifiée. Est-il possible de faire cela fonctionner lors du passage de la fonction callBack en tant que paramètre à la classe? Tenter de modifier la fonction de cette manière quand on la passe en paramètre ne semble affecter que son instance dans la classe, mais cela ne semble pas être une hypothèse valide puisque les fonctions sont des objets en javascript, et sont donc passées par référence.

Mise à jour: comme souligné crescentfresh (et j'ai échoué à expliquer bien), je veux modifier la fonction callBack sur place. Je préfère ne pas appeler une seconde fonction s'il est possible de faire tout cela lorsque la classe est instanciée.

Répondre

5

objets de fonction ne fournissent pas des méthodes pour les modifier. Par conséquent, ce que vous voulez faire est impossible de la façon dont vous voulez le faire. C'est la même chose que Jon Skeet aime à signaler à propos de Java: Les objets ne sont pas vraiment passés par référence, mais à la place un pointeur sur eux est passé par valeur. Cela signifie que changer la valeur d'une variable d'argument en une nouvelle n'affectera pas du tout l'original.

Il n'y a que deux façons de faire ce que vous voulez dans les langages call-by-value comme Java et JavaScript: Le premier serait d'utiliser les méthodes de l'objet (function) pour le modifier. Comme je l'ai déjà dit, les objets de fonction n'en ont pas. L'autre est de passer l'objet dont l'objet fonction est une propriété en tant que second argument et de définir la propriété appropriée sur une nouvelle fonction qui enveloppe l'ancienne.

Exemple:

var foo = {}; 
foo.func = function() {}; 

function wrapFunc(obj) { 
    var oldFunc = obj.func; 
    obj.func = function() { 
     // do some stuff 
     oldFunc.call(obj, _some_argument__); 
    }; 
} 

wrapFunc(foo); 

Cela fonctionne pour des fonctions globales ainsi: ils sont des propriétés de l'objet window.

+0

Merci pour l'explication détaillée. Je ne comprenais pas exactement comment les objets de fonction ont été passés. – dmercer

0

Je suppose que vous enregistrez ce rappel quelque part ... Quelle raison cela ne fonctionnera pas?

function MyClass (callBack) { 
    var myCallBack; 

    if (typeof callBack !== 'function') 
    throw "You didn't pass me a function!" 

    var oldCallBack = callBack; 
    callBack = function() { 
    oldCallBack(); // call the original functionality 
    /* new code goes here */ 
    } 
    myCallBack = callback; 
} 
+0

depuis callBack est passé par référence, il ne faut pas attribuer la fonction anonyme à elle changer dans la espace de noms global (d'où est-il passé)? L'assigner à myCallBack va créer une nouvelle référence dans la classe, mais le nouveau code ne sera jamais exécuté, ce qui me fait penser que je me suis trompé quelque part – dmercer

+0

dmercer, vous voulez modifier callBack * en place *? Donc, après l'avoir transmis à votre classe, l'appelant peut l'appeler mais doit-il exécuter du code supplémentaire? –

+0

Oui, exactement. Normalement, je ne ferais pas quelque chose comme ça, mais je suis quelque peu contraint par le module particulier avec lequel je travaille. – dmercer

0

Vous voulez faire quelque chose comme:

function MyClass() { 
    this.modifyCallBack = function (callBack) { 
     var oldCallBack = callBack; 
     callBack = function() { 
      oldCallBack(); // call the original functionality 
      alert("new functionality"); 
     } 
     return callBack; 
    } 
} 

/* elsewhere on the page, after the class is instantiated and the callback function defined */ 
var myCallBackFunction = function() {alert("original");}; 
var MyClassInstance = new MyClass(); 
myCallBackFunction = MyClassInstance.modifyCallBack(myCallBackFunction); 
myCallBackFunction(); 
1

Comme Javascript utilise une portée lexicale sur les variables qui suit est possible:

var modifiableCallback=function() { alert('A'); }; 


function ModifyCallbackClass(callback) 
{ 
    modifiableCallback=function() { callback(); alert('B'); }; 
} 


function body_onload() 
{ 

    var myClass=new ModifyCallbackClass(modifiableCallback); 

    modifiableCallback(); 

} 

Cela fait ce que vous voulez, mais la fonction « modifiableCallback » doit être appelé avec le même nom à l'intérieur ModifyCallbackClass, sinon la fermeture sera ne pas être appliqué. Cela peut donc limiter un peu l'utilité de cette approche.

En utilisant eval (les performances peuvent souffrir un peu), il est également possible de rendre cette approche plus souple:

var modfiableCallback1=function() { alert('A'); }; 

var modfiableCallback2=function() { alert('B'); }; 

var modfiableCallback3=function() { alert('C'); }; 

function ModifyCallbackClass(callbackName) 
{ 
    var temp=eval(callbackName); 
    var temp2=eval(callbackName); 

    temp= function() { temp2(); alert('Modified'); }; 

    eval(callbackName + " = temp;"); 
} 


function body_onload() 
{ 

    var myClass=new ModifyCallbackClass("modfiableCallback1"); 

    modfiableCallback1(); 

    myClass=new ModifyCallbackClass("modfiableCallback2"); 

    modfiableCallback2(); 

    myClass=new ModifyCallbackClass("modfiableCallback3"); 

    modfiableCallback3(); 

} 
Questions connexes