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

StackOverflow https://stackoverflow.com/questions/296667

Вопрос

У меня есть функция, 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();
}
};
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top