Переопределение функции JavaScript при ссылке на оригинал
-
08-07-2019 - |
Вопрос
У меня есть функция, a()
, который я хочу переопределить, но при этом иметь оригинал a()
выполняться в порядке, зависящем от контекста.Например, иногда, когда я создаю страницу, мне нужно переопределить вот так:
function a() {
new_code();
original_a();
}
а иногда и так:
function a() {
original_a();
other_new_code();
}
Как мне это получить original_a()
изнутри превосходящего a()
?Возможно ли это вообще?
Пожалуйста, не предлагайте альтернативы такому переопределению, я знаю многих.Я спрашиваю конкретно об этом способе.
Решение
Вы могли бы сделать что-то вроде этого:
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, упомянутый в комментариях, обязательно добавьте ()
в конце. Вы хотите вызвать внешнюю функцию и сохранить result (одну из двух внутренних функций) в a
, а не сохранять саму внешнюю функцию в a
. р>
Другие советы
Шаблон прокси может помочь вам:
(function() {
// log all calls to setArray
var proxied = jQuery.fn.setArray;
jQuery.fn.setArray = function() {
console.log( this, arguments );
return proxied.apply( this, arguments );
};
})();
Приведенный выше код оборачивает свой код в функцию, чтобы скрыть переменную «прокси». Это сохраняет setArray-метод jQuery в замыкании и перезаписывает его. Затем прокси регистрирует все вызовы метода и делегирует вызов оригиналу. Использование apply (this, arguments) гарантирует, что вызывающая сторона не сможет заметить разницу между оригинальным и проксируемым методом.
Спасибо, ребята, шаблон прокси действительно помог ..... На самом деле я хотел вызвать глобальную функцию 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);
}
};
Спасибо, это действительно помогло мне
Вы можете переопределить функцию, используя такую конструкцию:
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(); }
});
Редактировать:Исправлена опечатка.
Передача произвольных аргументов.
a = override(a, function(original_a) {
if (condition) { new_code(); original_a.apply(this, arguments) ; }
else { original_a.apply(this, arguments); other_new_code(); }
});
Приведенные выше примеры неправильно применяют this
и не передают arguments
правильно для переопределения функции. Подчеркивание _.wrap () оборачивает существующие функции, применяет this
и правильно передает arguments
. Смотрите: http://underscorejs.org/#wrap
Ответ, который предоставляет @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);
У меня был какой-то код, написанный кем-то другим, и я хотел добавить строку в функцию, которую я не смог найти в коде. Так что в качестве обходного пути я хотел переопределить его.
Ни одно из решений не помогло мне.
Вот что сработало в моем случае:
if (typeof originalFunction === "undefined") {
originalFunction = targetFunction;
targetFunction = function(x, y) {
//Your code
originalFunction(a, b);
//Your Code
};
}
Я создал небольшого помощника для аналогичного сценария, потому что мне часто приходилось переопределять функции из нескольких библиотек. Этот помощник принимает «пространство имен» (контейнер функции), имя функции и переопределяющая функция. Он заменит исходную функцию в указанном пространстве имен новой. Р>
Новая функция принимает исходную функцию в качестве первого аргумента, а исходные функции - в качестве остальных. Это сохранит контекст каждый раз. Он также поддерживает функции 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
});
Я не создавал никаких тестов производительности. Это может добавить некоторые нежелательные накладные расходы, которые могут или не могут иметь большое значение, в зависимости от сценариев.
По моему мнению, верхние ответы не читабельны / не поддерживаются, а другие ответы неправильно связывают контекст. Вот удобочитаемое решение с использованием синтаксиса ES6 для решения обеих этих проблем.
const orginial = someObject.foo;
someObject.foo = function() {
if (condition) orginial.bind(this)(...arguments);
};
Итак, мой ответ оказался решением, которое позволяет мне использовать переменную _this, указывающую на исходный объект. Я создаю новый экземпляр " Квадрата " однако я ненавидел способ "Квадрат" генерируется его размер. Я думал, что это должно следовать моим конкретным потребностям. Однако для того, чтобы сделать это, мне нужно, чтобы в квадрате был обновленный " GetSize " Функция с внутренностями этой функции вызывает другие функции, уже существующие в квадрате, такие как this.height, this.GetVolume (). Но для этого мне нужно было делать это без каких-либо сумасшедших взломов. Так вот мое решение.
Некоторые другие инициализаторы объектов или вспомогательные функции.
this.viewer = new Autodesk.Viewing.Private.GuiViewer3D(
this.viewerContainer)
var viewer = this.viewer;
viewer.updateToolbarButtons = this.updateToolbarButtons(viewer);
Функция в другом объекте.
updateToolbarButtons = function(viewer) {
var _viewer = viewer;
return function(width, height){
blah blah black sheep I can refer to this.anything();
}
};