senäh

17senäh und so…

Code Snippet Thumb

HTML/CSS/JS
17. Mai 2012
Kommentare: 0

JS-Code-Snippet: Mit Function-Wrappern die Logik einer Funktion erweitern

Kategorien: HTML/CSS/JS | 17. Mai 2012 | Kommentare: 0

Ich hatte letztens das Problem, dass ich mit einer Funktion arbeiten musste, deren Aufruf ich nicht beeinflussen konnte. Leider hat die Funktion nicht genau das gemacht, was ich benötigte. Ich konnte diese Funktion aber auch nicht einfach überschreiben, da sie eine innere Logik besaß, die ich benötigte und die nicht so einfach reproduzierbar war. Eine sehr knifflige Lage!

Ich musste also einen Weg finden, wie ich diese Funktion um bestimmte Logiken erweitern konnte ohne(!) sie selbst oder die Art und Weise des Funktionsaufrufes zu verändern. Ganz ehrlich: Wenn ihr in dieser Situation steckt, macht ihr irgendetwas falsch. Wahrscheinlich ist eure Applikation-Architektur oder API nicht gut genug durchdacht. Blöd nur, dass dieses Problem bei mir bei einem Framework auftauchte, welches ich nicht selbst entwickelt hatte und dort war mein Anwendungsfall einfach nicht vorgesehen. Ich konnte auch das Framework nicht einfach so ändern…

Function-Wrapper to the rescue!

Was tun? Man nimmt sich die bestehende Funktion, nennt sie um, erweitert sie um vorhergehende/nachfolgende Logik und speichert das Ganze in einer neuen Funktion mit dem Namen der alten Funktion. Puuh. Das funktioniert prächtig, ist aber nicht unbedingt übersichtlich und debugging-freundlich. Ihr solltet diese Technik also mit Bedacht anwenden!

Angenommen ihr habt folgende Funktion:

var coolObject = {
    coolFunction: function(name) {
        console.log("Look at me, " + name + " is so cool.");
    }
}

coolObject.coolFunction("Pipo");
// "Look at me, Pipo is so cool."

Die Funktion nimmt in diesem Fall einen Parameter (es könnten auch beliebig viele sein oder gar keins!!!) und führt irgendeine Logik aus. Der Funktionsaufruf erfolgt mit coolObject.coolFunction("Pipo");. Nun möchte ich mit dem gleichen Funktionsaufruf noch mehr Logik ausführen. Diese Logik definiere ich in zwei Funktionen:

var prevExample = function(name) {
    console.log("Yeah, this is an example for " + name);
};

var pastExample = function(name) {
    console.log("I'm the last example for " + name);
};

Beide erhalten die gleichen Parameter wie die originale Funktion. Jetzt kommt der Function-Wrapper:

var functionWrapper = function(obj, originalFuncStr, prevFunc, pastFunc) {
    var originalFunc = obj[originalFuncStr];
    obj['_' + originalFuncStr] = originalFunc;
    obj[originalFuncStr] = (function(obj, originalFuncStr, prevFunc, pastFunc){
        return function() {
            if(prevFunc) prevFunc.apply(obj, arguments);
            obj['_' + originalFuncStr].apply(obj, arguments);
            if(pastFunc) pastFunc.apply(obj, arguments);
        }
    })(obj, originalFuncStr, prevFunc, pastFunc);
};

Und siehe da: Schicke ich alle Funktionen durch den Function-Wrapper, so erhalte ich mit dem gleichen Funktionsaufruf noch mehr Logik 😉

functionWrapper(coolObject, "coolFunction", prevExample, pastExample);

coolObject.coolFunction("Pipo");
// Yeah, this is an example for Pipo
// Look at me, Pipo is so cool.
// I'm the last example for Pipo

Die Originalfunktion ist übrigens unter coolObject._coolFunction zu finden. Sie hat nur ein „_“ als Präfix bekommen. Ihr seit auch nicht gezwungen eine vorhergehende und eine nachfolgende Funktion zu verwenden. Eins von beiden genügt auch.

Ich hoffe, das konnte euch weiterhelfen 🙂

PS: Hier noch das Beispiel in JsFiddle!

Autor: Pipo

...kommt ursprünglich aus der Designerecke, ist aber im Laufe seines Studiums in die Webentwicklung gestolpert. Kann sich seit dem nicht so richtig entscheiden wo er hingehört und wagt deswegen vielleicht die Flucht nach vorne in ein komplett neues Gebiet. Vielleicht Management? Niemand weiß es. Auch er nicht.