Переопределение функции JavaScript при ссылке на оригинал

У меня есть функция a(), которую я хочу переопределить, но также иметь исходный a() в порядке, зависящем от контекста. Например, иногда, когда я создаю страницу, я хочу переопределить вот так:

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

а иногда так:

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

Как мне получить original_a() в пределах a()? Возможно ли это?

Пожалуйста, не предлагайте альтернативы переезду таким образом, я знаю многих. Я прошу об этом конкретно.

Ответ 1

Вы можете сделать что-то вроде этого:

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

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

Объявление original_a внутри анонимной функции не позволяет помешать глобальному пространству имен, но доступно во внутренних функциях.

Как упоминается в комментариях Nerdmaster, обязательно включите () в конец. Вы хотите вызвать внешнюю функцию и сохранить результат (одну из двух внутренних функций) в a, а не хранить внешнюю функцию в a.

Ответ 2

шаблон прокси может помочь вам:

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

Вышеприведенный код сворачивает свой код в функцию, чтобы скрыть "прокси" -переменная. Он сохраняет jQuery setArray-метод в закрытии и перезаписывает его. Затем прокси регистрирует все вызовы метода и делегирует вызов оригиналу. Использование apply (это, аргументы) гарантирует, что вызывающий не сможет заметить разницу между исходным и прокси-методом.

Ответ 3

Спасибо, ребята, прокси-шаблон действительно помог..... На самом деле я хотел назвать глобальную функцию foo.. На некоторых страницах мне нужно сделать некоторые проверки. Поэтому я сделал следующее.

//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 это действительно помогло мне

Ответ 4

Вы можете переопределить функцию, используя следующую конструкцию:

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

Например:

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

Ответ 5

Передача произвольных аргументов:

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

Ответ 6

Приведенные выше примеры не корректно применяют this или передают arguments правильно к переопределению функции. Подчеркивание _.wrap() обертывает существующие функции, применяет this и передает arguments правильно. См.: http://underscorejs.org/#wrap

Ответ 7

У меня был код, написанный кем-то другим, и мне хотелось добавить строку к функции, которую я не смог найти в коде. Поэтому в качестве обходного пути я хотел бы переопределить его.

Ни один из решений не работал у меня.

Вот что сработало в моем случае:

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

Ответ 8

Я создал небольшой помощник для аналогичного сценария, потому что мне часто приходилось переопределять функции из нескольких библиотек. Этот помощник принимает "пространство имен" (контейнер функций), имя функции и функцию переопределения. Он заменит исходную функцию в названном пространстве имен новым.

Новая функция принимает исходную функцию как первый аргумент, а исходные аргументы функций - как остальные. Он будет сохранять контекст каждый раз. Он также поддерживает функции void и 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)));
    };
}

Использование, например, с помощью Bootstrap:

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

Я не создавал никаких тестов производительности. Он может добавить некоторые нежелательные накладные расходы, которые могут или не могут быть большой сделкой, в зависимости от сценариев.

Ответ 9

По моему мнению, верхние ответы не читабельны/поддерживаемы, а другие ответы неправильно привязывают контекст. Здесь читаемое решение с использованием синтаксиса ES6 для решения обеих этих проблем.

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

Ответ 10

Ответ, который предоставляет @Matthew Crumley, использует сразу вызываемые функциональные выражения, чтобы закрыть более старую функцию "a" в контексте выполнения возвращаемой функции. Я думаю, что это был лучший ответ, но лично я предпочел бы передать функцию "а" в качестве аргумента для IIFE. Я думаю, что это более понятно.

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