web-dev-qa-db-fra.com

Ajout de code à une fonction javascript par programme

J'essaie de personnaliser une bibliothèque JS existante sans modifier le code JS d'origine. Ce code est chargé dans quelques fichiers JS externes auxquels j'ai accès, et ce que j'aimerais faire, c'est modifier l'une des fonctions contenues dans le fichier d'origine sans copier-coller le tout dans le deuxième fichier JS .
Ainsi, par exemple, le JS hors limites pourrait avoir une fonction comme celle-ci:

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

J'aimerais pouvoir en quelque sorte ajouter ou ajouter du code JS à cette fonction. La raison en est principalement que dans le JS intouchable d'origine, la fonction est assez énorme et que si ce JS est mis à jour, la fonction avec laquelle je l'écrase sera périmée.

Je ne suis pas tout à fait sûr que ce soit possible, mais je me suis dit que je vérifierais.

104
Munzilla

Si someFunction est globalement disponible, vous pouvez alors mettre la fonction en cache, créer la vôtre et la faire appeler par la vôtre.

Donc, si c'est l'original ...

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

Tu ferais ça ...

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;
    };
})();

Voici le violon


Notez que j'utilise .apply pour appeler la fonction en cache. Cela me permet de conserver la valeur attendue de this et de transmettre tous les arguments qui ont été transmis comme arguments individuels, quel que soit le nombre.

203
user1106925

d'abord stocker la fonction réelle dans une variable ..

var oldFunction = someFunction;

puis définissez le vôtre:

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

Vous pouvez créer une fonction qui appelle votre code, puis appelle la fonction.

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

Je ne sais pas si vous pouvez mettre à jour la fonction, mais selon la manière dont elle est référencée, vous pouvez créer une nouvelle fonction à sa place:

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

Également. Si vous voulez changer le contexte local, vous devez recréer la fonction. Par exemple:

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

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

À présent

z() // => log: undefined

Ensuite

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);

Et

z() // => log: 1

Mais ce n'est que l'exemple le plus simple. Il faudra encore beaucoup de travail pour gérer les arguments, les commentaires et la valeur renvoyée. De plus, les pièges restent nombreux.
toString | tranche | indexOf | lastIndexOf | nouvelle fonction

5
Ivan Black

Le modèle de proxy (tel qu'utilisé par l'utilisateur1106925) peut être placé dans une fonction. Celui que j'ai écrit ci-dessous fonctionne sur des fonctions qui ne sont pas dans la portée globale, et même sur des prototypes. Vous l'utiliseriez comme ceci:

extender(
  objectContainingFunction,
  nameOfFunctionToExtend,
  parameterlessFunctionOfCodeToPrepend,
  parameterlessFunctionOfCodeToAppend
)

Dans l'extrait ci-dessous, vous pouvez me voir en utilisant la fonction pour étendre test.prototype.doIt ().

// 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