Nadpisywanie funkcji JavaScript podczas odwoływania się do oryginału

Mam funkcję a(), którą chcę nadpisać, ale chcę również, aby oryginalna a() była wykonywana w kolejności zależnej od kontekstu. Na przykład, czasami, gdy generuję stronę, będę chciał nadpisać Tak:

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

I czasami tak:

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

Jak mam to zdobyć original_a() z przejazdu a()? Czy to w ogóle możliwe?

Proszę nie sugerować alternatywy dla nadmiernej jazdy w ten sposób, wiem o wielu. Pytam o ten sposób konkretnie.

Author: John Slegers, 2008-11-17

11 answers

Mógłbyś zrobić coś takiego:

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

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

Deklaracja original_a wewnątrz funkcji anonimowej zapobiega zaśmiecaniu globalnej przestrzeni nazw, ale jest dostępna w funkcjach wewnętrznych.

Jak wspomniał Nerdmaster w komentarzach, pamiętaj, aby dołączyć () na końcu. Chcesz wywołać funkcję zewnętrzną i zapisać wynik (jedną z dwóch funkcji wewnętrznych) w a, a nie przechowywać samą funkcję zewnętrzną w a.

 173
Author: Matthew Crumley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-21 22:33:50

Wzór Proxy może Ci pomóc:

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

Powyższy kod zawija w funkcję ukrywającą zmienną "proxied". Zapisuje metodę setArray jQuery w zamknięciu i nadpisuje ją. Następnie proxy rejestruje wszystkie wywołania metody i przekazuje wywołanie do oryginału. Użycie apply (this, arguments) gwarantuje, że wywołujący nie będzie w stanie zauważyć różnicy między oryginalną i proxyowaną metodą.

 75
Author: PhilHoy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-17 22:57:53

Dzięki chłopaki the proxy pattern naprawdę pomógł.....Właściwie to chciałem nazwać globalną funkcję foo.. Na niektórych stronach muszę zrobić kilka kontroli. Więc zrobiłem następujące rzeczy.

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

Thnx to naprawdę mi pomogło

 26
Author: Naresh S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-17 22:58:23

Możesz nadpisać funkcję używając konstrukcji takiej jak:

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

Na przykład:

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

Edit: Poprawiono literówkę.

 8
Author: Hai Phan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-04 12:02:40

Przekazywanie arbitralnych argumentów:

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
Author: Edric Garran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-31 17:24:27

Powyższe przykłady nie stosują poprawnie this lub przekazują arguments do nadpisania funkcji. Podkreślenie _.wrap() zawija istniejące funkcje, stosuje this i przekazuje arguments poprawnie. Zobacz: http://underscorejs.org/#wrap

 1
Author: nevf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-06 15:44:27

Odpowiedź, którą zapewnia @Matthew Crumley, polega na wykorzystaniu bezpośrednio wywołanych wyrażeń funkcji, aby zamknąć starszą funkcję " a " w kontekście wykonywania zwracanej funkcji. Myślę, że to była najlepsza odpowiedź, ale osobiście wolałbym przekazać funkcję "a" jako argument do życia. Myślę, że to jest bardziej zrozumiałe.

   var a = (function(original_a) {
        if (condition) {
            return function() {
                new_code();
                original_a();
            }
        } else {
            return function() {
                original_a();
                other_new_code();
            }
        }
    })(a);
 1
Author: Rodrigo Hernandez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-17 12:49:40

Miałem jakiś kod napisany przez kogoś innego i chciałem dodać linię do funkcji, której nie mogłem znaleźć w kodzie. Więc jako obejście chciałem to obejść.

Jednak żadne z rozwiązań nie zadziałało.

Oto co zadziałało w moim przypadku:

if (typeof originalFunction === "undefined") {
    originalFunction = targetFunction;
    targetFunction = function(x, y) {
        //Your code
        originalFunction(a, b);
        //Your Code
    };  
}
 0
Author: Sagar Sodah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-17 22:54:28

Stworzyłem mały helper dla podobnego scenariusza, ponieważ często musiałem nadpisywać funkcje z kilku bibliotek. Ten Pomocnik akceptuje "przestrzeń nazw" (kontener funkcji), nazwę funkcji i funkcję nadrzędną. Zastąpi oryginalną funkcję w wymienionej przestrzeni nazw nową.

Nowa funkcja przyjmuje oryginalną funkcję jako pierwszy argument, a oryginalne argumenty funkcji jako resztę. Zachowa kontekst za każdym razem. Informatyka obsługuje również funkcje void i non-void.

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

Użycie na przykład z Bootstrap:

overrideFunction($.fn.popover.Constructor.prototype, 'leave', function(baseFn, obj) {
    // ... do stuff before base call
    baseFn(obj);
    // ... do stuff after base call
});
Nie stworzyłem jednak żadnych testów wydajnościowych. Może to ewentualnie dodać niechciane koszty, które mogą lub nie mogą być wielką sprawą, w zależności od scenariuszy.
 0
Author: Zoltán Tamási,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-17 22:57:35

Moim zdaniem najlepsze odpowiedzi nie są czytelne/utrzymywalne, a pozostałe odpowiedzi nie wiążą odpowiednio kontekstu. Oto czytelne rozwiązanie wykorzystujące składnię ES6 do rozwiązania obu tych problemów.

const orginial = someObject.foo;
someObject.foo = function() {
  if (condition) orginial.bind(this)(...arguments);
};
 0
Author: James L.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-12 01:41:10

Więc moja odpowiedź okazała się rozwiązaniem, które pozwala mi użyć zmiennej _this wskazującej na oryginalny obiekt. I utworzyć nową instancję "kwadrat" jednak nienawidziłem sposób "kwadrat" generowane jego rozmiar. Pomyślałem, że powinno być zgodne z moimi konkretnymi potrzebami. Jednak w tym celu potrzebowałem, aby kwadrat miał zaktualizowaną funkcję "GetSize" z wewnętrznymi funkcjami tej funkcji wywołującymi inne funkcje już istniejące w kwadracie, takie jak ta.wysokość, to.GetVolume (). Ale w tym celu Musiałem to zrobić bez żadnych szalonych hacków. Oto moje rozwiązanie.

Jakaś inna funkcja inicjalizująca lub pomocnicza obiekt.

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

Funkcja w innym obiekcie.

updateToolbarButtons = function(viewer) {
  var _viewer = viewer;
  return function(width, height){ 
blah blah black sheep I can refer to this.anything();
}
};
 0
Author: SteckDEV,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-30 06:17:05