Переопределение функции 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);