webentwicklung-frage-antwort-db.com.de

Überschreiben einer JavaScript-Funktion, während auf das Original verwiesen wird

Ich habe eine Funktion, a(), die ich überschreiben möchte, aber auch die ursprüngliche a() muss in einer Reihenfolge ausgeführt werden, die vom Kontext abhängt. Zum Beispiel möchte ich manchmal, wenn ich eine Seite generiere, Folgendes überschreiben:

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

und manchmal so:

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

Wie bekomme ich das original_a() aus dem übergeordneten a() heraus? Ist es überhaupt möglich?

Bitte schlagen Sie auf diese Weise keine Alternativen zum Überfahren vor, ich kenne viele. Ich frage speziell nach diesem Weg.

155
Kev

Sie könnten so etwas tun:

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

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

Durch das Deklarieren von original_a In einer anonymen Funktion wird verhindert, dass der globale Namespace überladen wird. Diese Funktion ist jedoch in den inneren Funktionen verfügbar.

Achten Sie darauf, wie Nerdmaster in den Kommentaren erwähnte, das () Am Ende einzufügen. Sie möchten die äußere Funktion aufrufen und das Ergebnis (eine der beiden inneren Funktionen) in a speichern, nicht die äußere Funktion selbst in a.

177
Matthew Crumley

Das Proxy-Muster könnte Ihnen helfen:

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

Das Obige umhüllt seinen Code mit einer Funktion, um die "Proxy" -Variable auszublenden. Es speichert die setArray-Methode von jQuery in einem Closure und überschreibt sie. Der Proxy protokolliert dann alle Aufrufe der Methode und delegiert den Aufruf an das Original. Durch die Verwendung von apply (this, arguments) wird sichergestellt, dass der Aufrufer den Unterschied zwischen der ursprünglichen und der Proxy-Methode nicht bemerken kann.

82
PhilHoy

Vielen Dank Jungs, das Proxy-Muster hat wirklich geholfen ..... Eigentlich wollte ich eine globale Funktion foo aufrufen .. Auf bestimmten Seiten muss ich einige Prüfungen durchführen. Also habe ich folgendes gemacht.

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

Das hat mir wirklich geholfen

27
Naresh S

Sie können eine Funktion mit einem Konstrukt wie dem folgenden überschreiben:

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

Beispielsweise:

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

Bearbeiten: Ein Tippfehler wurde behoben.

9
Hai Phan

Übergabe beliebiger Argumente:

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

Die Antwort von @Matthew Crumley besteht darin, die sofort aufgerufenen Funktionsausdrücke zu verwenden, um die ältere 'a'-Funktion im Ausführungskontext der zurückgegebenen Funktion zu schließen. Ich denke, dies war die beste Antwort, aber ich persönlich würde es vorziehen, die Funktion 'a' als Argument an IIFE zu übergeben. Ich finde es verständlicher.

   var a = (function(original_a) {
        if (condition) {
            return function() {
                new_code();
                original_a();
            }
        } else {
            return function() {
                original_a();
                other_new_code();
            }
        }
    })(a);
1

Die obigen Beispiele wenden this nicht korrekt an oder übergeben arguments nicht korrekt an die Funktionsüberschreibung. Der Unterstrich _.wrap () bricht vorhandene Funktionen um, wendet this an und übergibt arguments korrekt. Siehe: http://underscorejs.org/#wrap

1
nevf

Ich habe einen kleinen Helfer für ein ähnliches Szenario erstellt, da ich häufig Funktionen aus mehreren Bibliotheken überschreiben musste. Dieser Helfer akzeptiert einen "Namespace" (den Funktionscontainer), den Funktionsnamen und die überschreibende Funktion. Die ursprüngliche Funktion im angegebenen Namespace wird durch die neue ersetzt.

Die neue Funktion akzeptiert die ursprüngliche Funktion als erstes Argument und die ursprünglichen Funktionsargumente als Rest. Es wird immer den Kontext bewahren. Es unterstützt auch leere und nicht leere Funktionen.

function overrideFunction(namespace, baseFuncName, func) {
    var originalFn = namespace[baseFuncName];
    namespace[baseFuncName] = function () {
        return func.apply(this, [originalFn.bind(this)].concat(Array.prototype.slice.call(arguments, 0)));
    };
}

Verwendung zum Beispiel mit Bootstrap:

overrideFunction($.fn.popover.Constructor.prototype, 'leave', function(baseFn, obj) {
    // ... do stuff before base call
    baseFn(obj);
    // ... do stuff after base call
});

Ich habe jedoch keine Leistungstests erstellt. Dies kann möglicherweise zu unerwünschtem Overhead führen, der je nach Szenario eine große Rolle spielen kann oder auch nicht.

0
Zoltán Tamási

Ich hatte einen Code von jemand anderem geschrieben und wollte eine Zeile zu einer Funktion hinzufügen, die ich im Code nicht finden konnte. Als Workaround wollte ich das überschreiben.

Keine der Lösungen funktionierte jedoch für mich.

In meinem Fall hat Folgendes funktioniert:

if (typeof originalFunction === "undefined") {
    originalFunction = targetFunction;
    targetFunction = function(x, y) {
        //Your code
        originalFunction(a, b);
        //Your Code
    };  
}
0
Sagar Sodah

Meiner Meinung nach sind die Top-Antworten nicht lesbar/pflegbar und die anderen Antworten binden den Kontext nicht richtig. Hier ist eine lesbare Lösung mit ES6-Syntax, um beide Probleme zu lösen.

const orginial = someObject.foo;
someObject.foo = function() {
  if (condition) orginial.bind(this)(...arguments);
};
0
James L.

Meine Antwort war also eine Lösung, mit der ich die Variable _this verwenden kann, die auf das ursprüngliche Objekt zeigt. Ich erstelle eine neue Instanz eines "Quadrats", aber ich hasste es, wie das "Quadrat" seine Größe erzeugte. Ich dachte, es sollte meinen spezifischen Bedürfnissen entsprechen. Zu diesem Zweck musste das Quadrat eine aktualisierte "GetSize" -Funktion mit den Interna dieser Funktion haben, die andere bereits im Quadrat vorhandene Funktionen aufruft, z. B. this.height, this.GetVolume (). Aber dazu musste ich ohne verrückte Hacks auskommen. Also hier ist meine Lösung.

Eine andere Objektinitialisierungs- oder Hilfsfunktion.

this.viewer = new Autodesk.Viewing.Private.GuiViewer3D(
  this.viewerContainer)
var viewer = this.viewer;
viewer.updateToolbarButtons =  this.updateToolbarButtons(viewer);

Funktion im anderen Objekt.

updateToolbarButtons = function(viewer) {
  var _viewer = viewer;
  return function(width, height){ 
blah blah black sheep I can refer to this.anything();
}
};
0
SteckDEV