Ответ 1
Взгляните на плагин jQuery AOP. В общем, google "аспектно-ориентированное программирование на JavaScript".
EDIT: ОК, я считаю, что следующие решения действительны:
Используйте плагин jQuery AOP. Он в основном обертывает старую функцию вместе с крючком в функцию сэндвич и переназначает ее на старое имя функции. Это вызывает вложенность функций с каждым новым добавленным крюком.
Если jQuery не подходит для вас, просто разграбируйте исходный код, в плагине не было каких-либо зависимостей jQuery, а источник прост и очень мал.
Имейте объект, описывающий все крючки и их цели, и один, чтобы сохранить начальную немодифицированную функцию. При добавлении нового крючка обертка будет переделана вокруг исходной функции, вместо повторной обертывания предыдущей функции обертки.
Вы избегаете вложенных функций и получаете вместо этого два объекта. Потенциально это также может означать облегчение обработки перехвата, если вы добавляете/удаляете крючки часто и не в порядке.
Я пойду первым, так как это уже сделано, и у меня нет производительности, чтобы беспокоиться. И поскольку исходные функции не затронуты, даже если я переключу методы привязки, мне нужно будет только повторить добавление крюка, что может быть просто простой операцией поиска и замены.
Привет,
Возможно ли создать механизм, в котором функция A может иметь набор крючков (функции, которые будут выполняться до/после функции A)?
В идеале функция A не будет знать о функциональности подключения, так что мне не нужно изменять исходный код функции A, чтобы вызвать крючки. Что-то вроде:
A = function(){
alert("I'm a naive function");
};
B = function(){
alert("I'm having a piggyback ride on function A!"+
"And the fool doesn't even know it!");
};
addHook(B, A)//add hook B to function A
A()
//getting alerts "I'm a naive function"/"I'm having a
//piggyback ride on function A! And the fool doesn't even know it!"
Я пытался что-то взломать пару часов, но пока не повезло.
Взгляните на плагин jQuery AOP. В общем, google "аспектно-ориентированное программирование на JavaScript".
Возможно, не очень красиво, но, похоже, работает...
<script>
function A(x) { alert(x); return x; }
function B() { alert(123); }
function addHook(functionB, functionA, parent)
{
if (typeof parent == 'undefined')
parent = window;
for (var i in parent)
{
if (parent[i] === functionA)
{
parent[i] = function()
{
functionB();
return functionA.apply(this, arguments)
}
break;
}
}
}
addHook(B, A);
A(2);
</script>
Очень простой ответ:
function someFunction() { alert("Bar!") }
var placeholder=someFunction;
someFunction=function() {
alert("Foo?");
placeholder();
}
Этот ответ не является окончательным, а скорее демонстрирует другую технику, чем предлагаемые до сих пор. Это усиливает тот факт, что функция в Javascript является первоклассным объектом и, как таковая, a) вы можете передать ее как значение другой функции и b) вы можете добавить к ней свойства. Объедините эти черты с функциями встроенных методов "вызова" (или "примените" ), и у вас есть начало для решения.
var function_itself = function() {
alert('in function itself');
}
function_itself.PRE_PROCESS = function() {
alert('in pre_process');
}
function_itself.POST_PROCESS = function() {
alert('in post_process');
}
var function_processor = function(func) {
if (func.PRE_PROCESS) {
func.PRE_PROCESS.call();
}
func.call();
if (func.POST_PROCESS) {
func.POST_PROCESS.call();
}
}
Следующая функция даст вам до и после крючков, которые могут быть уложены в стек. Поэтому, если у вас есть несколько потенциальных функций, которые должны выполняться до данной функции или после данной функции, это будет рабочим решением. Это решение не требует jQuery и использует собственные методы массива (без прокладки). Он также должен быть чувствительным к контексту, поэтому, если вы вызываете исходную функцию с контекстом, если она должна запускаться каждый до и после функции аналогично.
// usage:
/*
function test(x) {
alert(x);
}
var htest = hookable(test);
htest.addHook("before", function (x) {
alert("Before " + x);
})
htest.addHook("after", function (x) {
alert("After " + x);
})
htest("test") // => Before test ... test ... After test
*/
function hookable(fn) {
var ifn = fn,
hooks = {
before : [],
after : []
};
function hookableFunction() {
var args = [].slice.call(arguments, 0),
i = 0,
fn;
for (i = 0; !!hooks.before[i]; i += 1) {
fn = hooks.before[i];
fn.apply(this, args);
}
ifn.apply(this, arguments);
for (i = 0; !!hooks.after[i]; i++) {
fn = hooks.after[i];
fn.apply(this, args);
}
}
hookableFunction.addHook = function (type, fn) {
if (hooks[type] instanceof Array) {
hooks[type].push(fn);
} else {
throw (function () {
var e = new Error("Invalid hook type");
e.expected = Object.keys(hooks);
e.got = type;
return e;
}());
}
};
return hookableFunction;
}
Здесь то, что я сделал, может быть полезно в других приложениях, таких как:
//Setup a hooking object
a={
hook:function(name,f){
aion.hooks[name]=f;
}
}a.hooks={
//default hooks (also sets the object)
};
//Add a hook
a.hook('test',function(){
alert('test');
});
//Apply each Hook (can be done with for)
$.each(a.hooks,function(index,f){
f();
});
Я не знаю, будет ли это полезно. Вам нужно изменить исходную функцию, но только один раз, и вам не нужно продолжать редактировать ее для стрельб.