Добавить код в конец существующей функции
Мне нужно вызвать функцию bar(), когда срабатывает функция foo(). У меня нет контроля над функцией foo или она изменится в будущем. У меня такая ситуация регулярно (и я ее ненавижу).
Я написал эту функцию, чтобы добавить мой код в конец функции foo:
function appendToFunction(fn,code){
if(typeof fn == 'function'){
var fnCode = fn.toString() ;
fnCode = fnCode.replace(/\}$/,code+"\n}") ;
window.eval(fnCode); // Global scope
return true ;
}
else{
return false ;
}
}
например:
appendToFunction(foo,"bar();");
Это поражает меня как ужасную идею, но она работает. Может ли кто-нибудь указать мне лучшее (безопасное) направление, пожалуйста.
EDIT: foo
- это не определенная функция, а множество функций, с которыми я сталкиваюсь. Они не изменяются динамически на странице. Но они могут время от времени меняться (например, требования к проверке формы).
Решение:
Я остановился на модифицированной версии Adam Answer. Это не идеально, но это лучше, чем у меня:
var oldFoo = foo ;
foo = function(){
var result = oldFoo.apply(this, arguments);
bar();
return result ;
}
NB. Следите за некоторыми встроенными функциями в IE6/7, которые не имеют метода .apply()
.
Ответы
Ответ 1
Вы можете просто переопределить foo
с помощью специальной функции, которая вызывает оригинал.
например.
var old_foo = foo;
foo = function() {
old_foo();
bar();
}
Вы также должны передать любые аргументы, которые foo
берет на себя через вашу заменяющую функцию.
Ответ 2
function extend(fn,code){
return function(){
fn.apply(fn,arguments)
code.apply(fn,argumnets)
}
}
и используйте его следующим образом:
function appendToFunction(fn,code){
if(typeof fn == 'function'){
var fnCode = fn.toString() ;
fnCode = fnCode.replace(/\}$/,code+"\n}") ;
window.eval(fnCode); // Global scope
return true ;
}
else{
return false ;
}
}
appendToFunction = extend(appendToFunction,function(){/*some code*/});
это даст вам тот же "this" в обеих функциях
Ответ 3
Вы можете сделать что-то вроде этого: ДЕМО.
function foo() {
console.log('foo');
}
function appendToFunction(fn, callback) {
window[fn] = (function(fn){
return function() {
fn();
callback();
}
}(window[fn]));
}
appendToFunction('foo', function(){console.log('appended!')});
foo();
Ответ 4
Хм, это касается и меня, вы упомянули, что
У меня такая ситуация регулярно (и я ее ненавижу).
Не возражаете, если я спрошу, в каком сценарии это происходит? Является ли он в корпоративном масштабе или в личном объеме проекта? У вас явно есть голова на плечах и знаете, что то, что вы делаете, необычно, поэтому мне интересно, есть ли альтернативное решение.
Я спрашиваю: этот подход потенциально может открыть проблему проблем. Что делать, если foo
не работает, например, или если foo
возвращает значение средней оценки? Простое добавление bar
к фактической функции не гарантирует ее выполнения. Предварительно ожидающая его, с другой стороны, означает, что она скорее всего будет выполнена, но, по-моему, это не очень хороший подход.
Рассматривали ли вы пересмотр функции foo
? Я знаю, что это может показаться глупым вопросом, но это может стоить того, если вы столкнетесь с подобными проблемами. Если вы хотите сохранить абстрагирование объектов, вы можете применить подход "обработчик событий", в результате чего foo
запускает событие на window
, которое, в свою очередь, запускает bar
, будет ли это работать в вашем случае.
В качестве альтернативы, если вы знаете, что такое foo
, и что он делает, вы можете подключить к нему прототип, если это объект, а затем соответствующим образом изменить код. Однако вы отметили, что эта функция открыта для изменения, что может сделать эту опцию излишней, но тем не менее это возможное решение.
Ответ 5
Вы можете добавить или добавить новый код к существующей функции, просто слияние, используя, например:
function mergeFunctions(function1, function2, instance1, instance2, numberOfArgumentsToPassToFunc1) {
return function() {
var _arguments = Array.prototype.slice.apply(arguments);
var _arguments1 = _arguments.slice(0, numberOfArgumentsToPassToFunc1);
var _arguments2 = _arguments.slice(numberOfArgumentsToPassToFunc1);
var that = this;
(function(function1, function2) {
if (typeof function1 == "function") {
if (typeof instance1 != "undefined") {
function1.apply(instance1, _arguments1);
}
else if (that == window) {
function1.apply(function1, _arguments1);
}
else {
var compare = mergeFunctions(function(){}, function(){});
if (that.toString() == compare.toString()) {
function1.apply(function1, _arguments1);
}
else {
function1.apply(that, _arguments1);
}
}
}
if (typeof function2 == "function") {
if (typeof instance2 != "undefined") {
function2.apply(instance2, _arguments2);
}
else if (that == window) {
function2.apply(function2, _arguments2);
}
else {
var compare = mergeFunctions(function(){}, function(){});
if (that.toString() == compare.toString()) {
function2.apply(function2, _arguments2);
}
else {
function2.apply(that, _arguments2);
}
}
}
})(function1, function2);
}
}
базовый пример:
// Original function:
var someFunction = function(){
console.log("original content");
};
// Prepend new code:
// --------------------------------------------------------
someFunction = mergeFunctions(function() {
console.log("--- prepended code");
}, someFunction);
// Testing:
someFunction();
// Outout:
// [Log] --- prepended code
// [Log] original content
// Append new code:
// --------------------------------------------------------
someFunction = mergeFunctions(someFunction, function() {
console.log("appended code");
});
// Testing:
someFunction();
// Output:
// [Log] --- prepended code
// [Log] original content
// [Log] appended code
Примечание, что функция слияния пытается применить ожидаемый 'this' к объединенным частям, иначе вы можете просто передать желаемый 'this' им, а также обработать относительные аргументы. < ш > более общий пример может быть следующим:
function firstPart(a, b) {
console.log("--- first part");
console.log("'this' here is:");
console.log(this.name);
console.log("a: "+a);
console.log("b: "+b);
}
function MyObject() {
this.x = "x property of MyObject";
}
MyObject.prototype.secondPart = function (y) {
console.log("");
console.log("--- second part");
console.log("'this' here is:");
console.log(this.name);
this.x = y;
console.log("x: "+this.x);
}
MyObject.prototype.merged = mergeFunctions(firstPart, MyObject.prototype.secondPart, firstPart, MyObject, 2);
// Testing
var test = new MyObject();
test.merged("a parameter", "b parameter", "x parameter overrides x property of MyObject");
// Console output:
// [Log] --- first part
// [Log] 'this' here is:
// [Log] firstPart
// [Log] a: a parameter
// [Log] b: b parameter
// [Log]
// [Log] --- second part
// [Log] 'this' here is:
// [Log] MyObject
// [Log] x: x parameter overrides x property of MyObject