164 votes

Remplacer une fonction JavaScript tout en faisant référence à l'original

J'ai une fonction, a() que je veux remplacer, mais aussi l'original. a() être exécutées dans un ordre dépendant du contexte. Par exemple, parfois, lorsque je génère une page, je veux passer outre comme ceci :

function a() {
    new_code();
    original_a();
}

et parfois comme ça :

function a() {
    original_a();
    other_new_code();
}

Comment puis-je obtenir ce original_a() dans le cadre de l'obligation a() ? Est-ce même possible ?

Je vous prie de ne pas suggérer d'alternatives à cette méthode de contournement, j'en connais beaucoup. Ma question porte sur cette méthode en particulier.

180voto

Matthew Crumley Points 47284

Vous pourriez faire quelque chose comme ça :

var a = (function() {
    var original_a = a;

    if (condition) {
        return function() {
            new_code();
            original_a();
        }
    } else {
        return function() {
            original_a();
            other_new_code();
        }
    }
})();

Déclarer original_a à l'intérieur d'une fonction anonyme l'empêche d'encombrer l'espace de nom global, mais il est disponible dans les fonctions internes.

Comme Nerdmaster l'a mentionné dans les commentaires, assurez-vous d'inclure l'adresse de l'entreprise. () à la fin. Vous voulez appeler la fonction externe et stocker le résultat de l'opération. résultat (l'une des deux fonctions internes) dans a ne pas stocker la fonction externe elle-même dans a .

27 votes

Pour les idiots comme moi, faites bien attention au "()" à la fin - sans cela, la fonction externe est retournée, pas les fonctions internes :)

1 votes

@Nerdmaster Merci de le signaler. J'ai ajouté une note dans l'espoir d'aider les gens à le remarquer.

5 votes

Wow, j'ai essayé de faire ça sans espace de nom et j'ai eu un débordement de pile, lol.

89voto

PhilHoy Points 548

El Modèle de proxy pourrait vous aider :

(function() {
    // log all calls to setArray
    var proxied = jQuery.fn.setArray;
    jQuery.fn.setArray = function() {
        console.log( this, arguments );
        return proxied.apply( this, arguments );
    };
})();

L'exemple ci-dessus englobe son code dans une fonction pour masquer la variable "proxied". Il enregistre la méthode setArray de jQuery dans une fermeture et l'écrase. Le proxy enregistre alors tous les appels à la méthode et délègue l'appel à l'original. L'utilisation de apply(this, arguments) garantit que l'appelant ne sera pas en mesure de remarquer la différence entre la méthode originale et la méthode mandatée.

10 votes

En effet, l'utilisation de "appliquer" et "arguments" rend cette réponse beaucoup plus robuste que les autres réponses.

0 votes

Notez que ce modèle ne requiert pas jQuery. Il utilise simplement l'une des fonctions de jQuery à titre d'exemple.

28voto

Naresh S Points 355

Merci les gars, le modèle de proxy m'a vraiment aidé.....En fait, je voulais appeler une fonction globale foo... Dans certaines pages, j'ai besoin de faire quelques vérifications. J'ai donc fait ce qui suit.

//Saving the original func
var org_foo = window.foo;

//Assigning proxy fucnc
window.foo = function(args){
    //Performing checks
    if(checkCondition(args)){
        //Calling original funcs
        org_foo(args);
    }
};

Merci, cela m'a vraiment aidé.

3 votes

En suivant le schéma de procuration Il sera important dans certains cas d'implémenter ce détail qui n'est pas présent dans le code de cette réponse : Au lieu de org_foo(args) appel org_foo.call(this, args) . Cela maintient this comme cela aurait été le cas lorsque window.foo est appelé normalement (non proxié). Voir cette réponse

11voto

Hai Phan Points 71

Vous pouvez remplacer une fonction en utilisant une construction comme :

function override(f, g) {
    return function() {
        return g(f);
    };
}

Par exemple :

 a = override(a, function(original_a) {
      if (condition) { new_code(); original_a(); }
      else { original_a(); other_new_code(); }
 });

Edit : Correction d'une faute de frappe.

0 votes

+1 C'est tellement plus lisible que les autres exemples de modèles de procuration !

1 votes

...mais si je ne me trompe pas, cela est limité aux fonctions à zéro argument, ou du moins à un nombre prédéterminé d'arguments. Existe-t-il un moyen de le généraliser à un nombre arbitraire d'arguments sans perdre la lisibilité ?

0 votes

@MuMind : oui, mais en utilisant correctement le modèle de proxy - cf. ma réponse .

4voto

Edric Garran Points 31

Passage d'arguments arbitraires :

a = override(a, function(original_a) {
    if (condition) { new_code(); original_a.apply(this, arguments) ; }
    else { original_a.apply(this, arguments); other_new_code(); }
});

1 votes

Les arguments font référence à original_a cependant ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X