2008-11-17 2 views
147

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

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

, а иногда, как это:

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

Как я понимаю, что original_a() изнутри выше- верховая езда a()? Возможно ли это?

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

ответ

172

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

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.

+0

Спасибо! Это очень полезно. – Kev 2008-11-17 20:06:21

+1

ничего себе. ultra cool – naveen 2011-03-04 03:54:14

+21

Для любых идиотов там, как и я, обратите внимание на «()» в конце - без этого он возвращает внешнюю функцию, а не внутренние функции :) – Nerdmaster 2012-07-24 18:27:30

75

Proxy pattern может помочь вам:

(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 (это, аргументы) гарантирует, что вызывающий абонент не сможет заметить разницу между исходным и прокси-методом.

26

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

8

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

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

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

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

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

0

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

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

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

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

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

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

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

0

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

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

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

var a = (function(original_a) { 
     if (condition) { 
      return function() { 
       new_code(); 
       original_a(); 
      } 
     } else { 
      return function() { 
       original_a(); 
       other_new_code(); 
      } 
     } 
    })(a); 
Смежные вопросы