wake-up-neo.com

Programmgesteuertes Hinzufügen von Code zu einer JavaScript-Funktion

Ich versuche, eine vorhandene JS-Bibliothek anzupassen, ohne den ursprünglichen JS-Code zu ändern. Dieser Code wird in ein paar externe JS-Dateien geladen, auf die ich Zugriff habe, und ich möchte, dass eine der Funktionen in der Originaldatei geändert wird, ohne dass das Ganze kopiert und in die zweite JS-Datei eingefügt wird. .
Zum Beispiel könnten die Off-Grenzen-JS eine Funktion wie folgt haben:

var someFunction = function(){
    alert("done");
}

Ich möchte gerne etwas JS-Code an diese Funktion anhängen oder anfügen. Der Grund ist in erster Linie, dass in der ursprünglichen unberührbaren JS die Funktion ziemlich groß ist und wenn diese JS jemals aktualisiert wird, ist die Funktion, mit der ich sie überschreibe, nicht mehr aktuell.

Ich bin nicht ganz sicher, ob das möglich ist, aber ich dachte mir, ich würde es überprüfen.

104
Munzilla

Wenn someFunction global verfügbar ist, können Sie die Funktion zwischenspeichern, Ihre eigene erstellen und Ihre Funktion aufrufen.

Wenn das also das Original ist ...

someFunction = function() {
    alert("done");
}

Sie würden das tun ...

someFunction = (function() {
    var cached_function = someFunction;

    return function() {
        // your code

        var result = cached_function.apply(this, arguments); // use .apply() to call it

        // more of your code

        return result;
    };
})();

Hier ist die Geige


Beachten Sie, dass ich .apply benutze, um die zwischengespeicherte Funktion aufzurufen. Dadurch kann ich den erwarteten Wert von this beibehalten und die weitergeleiteten Argumente als einzelne Argumente übergeben, unabhängig davon, wie viele vorhanden waren.

203
user1106925

speichern Sie zuerst die eigentliche Funktion in einer Variablen.

var oldFunction = someFunction;

dann definieren Sie Ihre eigenen:

someFunction = function(){
  // do something before
  oldFunction();
  // do something after
};
29
ggreiner

Sie können eine Funktion erstellen, die Ihren Code aufruft und dann die Funktion aufruft.

var old_someFunction = someFunction;
someFunction = function(){
    alert('Hello');
    old_someFunction();
    alert('Goodbye');
}
10
Rocket Hazmat

Ich weiß nicht, ob Sie die Funktion aktualisieren können, aber abhängig von der Art der Referenzierung können Sie stattdessen eine neue Funktion erstellen:

var the_old_function = someFunction;
someFunction = function () {
    /* ..My new code... */
    the_old_function();
    /* ..More of my new code.. */
}
6
Ned Batchelder

Ebenfalls. Wenn Sie den lokalen Kontext ändern möchten, müssen Sie die Funktion neu erstellen. Zum Beispiel:

var t = function() {
    var a = 1;
};

var z = function() {
    console.log(a);
};

Jetzt

z() // => log: undefined

Dann

var ts = t.toString(),
    zs = z.toString();

ts = ts.slice(ts.indexOf("{") + 1, ts.lastIndexOf("}"));
zs = zs.slice(zs.indexOf("{") + 1, zs.lastIndexOf("}"));

var z = new Function(ts + "\n" + zs);

Und

z() // => log: 1

Dies ist jedoch nur das einfachste Beispiel. Der Umgang mit Argumenten, Kommentaren und Rückgabewerten erfordert noch viel Arbeit. Darüber hinaus gibt es noch viele Fallstricke.
toString | Scheibe | indexOf | lastIndexOf | neue Funktion

5
Ivan Black

Das Proxy-Muster (wie von user1106925 verwendet) kann in eine Funktion eingefügt werden. Die folgende, die ich geschrieben habe, befasst sich mit Funktionen, die nicht im globalen Bereich liegen, und sogar auf Prototypen. Sie würden es so verwenden:

extender(
  objectContainingFunction,
  nameOfFunctionToExtend,
  parameterlessFunctionOfCodeToPrepend,
  parameterlessFunctionOfCodeToAppend
)

Im folgenden Snippet können Sie sehen, wie ich test.prototype.doIt () mit der Funktion erweitert.

// allows you to prepend or append code to an existing function
function extender (container, funcName, prepend, append) {

    (function() {

        let proxied = container[funcName];

        container[funcName] = function() {
            if (prepend) prepend.apply( this );
            let result = proxied.apply( this, arguments );
            if (append) append.apply( this );
            return result;
        };

    })();

}

// class we're going to want to test our extender on
class test {
    constructor() {
        this.x = 'instance val';
    }
    doIt (message) {
        console.log(`logged: ${message}`);
        return `returned: ${message}`;
    }
}

// extends test.prototype.doIt()
// (you could also just extend the instance below if desired)
extender(
    test.prototype, 
    'doIt', 
    function () { console.log(`prepended: ${this.x}`) },
    function () { console.log(`appended: ${this.x}`) }
);

// See if the prepended and appended code runs
let tval = new test().doIt('log this');
console.log(tval);

0
pwilcox