【问题标题】:Javascript function hooksJavascript函数钩子
【发布时间】:2015-01-02 01:14:33
【问题描述】:

编辑:好的,我相信以下解决方案是有效的:

  1. 使用 jQuery AOP 插件。它基本上将旧函数与钩子一起包装成一个函数三明治,并将其重新分配给旧函数名。这会导致每个新添加的钩子都嵌套函数。
    如果jQuery不适合你,就盗用源码吧,插件里面好像没有任何jQuery依赖,而且源码很简单,很小。

  2. 拥有一个描述所有钩子及其目标的对象和一个用于存储初始未修改函数的对象。添加新钩子时,将围绕原始函数重做包装,而不是重新包装之前的包装函数。
    您转义嵌套函数,取而代之的是处理两个对象。如果您经常无序地添加/删除钩子,这也可能意味着更容易处理钩子。

我会选择第一个,因为它已经完成了,我不用担心性能问题。并且由于原有功能不受影响,即使我切换钩子方法,我只需要重新添加钩子,这可能只是一些简单的搜索和替换操作。


嗨,

是否有可能创建一种机制,其中函数 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!"

我已经尝试破解了几个小时,但到目前为止没有运气。

【问题讨论】:

  • 这是一个很好的问题,尽管我怀疑会有一个肯定的答案。您当然可以这样做,但需要某种解决方法。我正在为此添加书签。

标签: javascript aop hook


【解决方案1】:

可能不漂亮,但它似乎工作......

<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>

【讨论】:

  • 谢谢!我考虑过这个,它可以工作,但是您可以使用这种方法进行嵌套,因为每个新钩子都包含所有以前的钩子: hookC(hookB(hookA(functionA.apply(this,arguments)))) 我不确定是否这会以任何方式影响性能,但感觉不正确/不安全。是否使用了 parent 以便正确绑定来自 apply(this, arguments) 的 this?
【解决方案2】:

看看jQuery's AOP plugin。一般来说,谷歌“面向方面的javascript编程”。

【讨论】:

  • jQuery != Javascript。例如,如果您在 Facebook 平台以及其他“沙盒”环境中编程,这很重要。
  • @George:演示的技术仍然适用。到目前为止,Greg 是唯一一个在这里发布可用代码的人。
  • 感谢AOP的链接和提及,我不熟悉它。我能够并且确实使用 jQuery,所以这可能会奏效。现在正在尝试找出插件。
  • 您能否提供一个示例来说明如何实现?
【解决方案3】:

很简单的答案:

function someFunction() { alert("Bar!") }
var placeholder=someFunction;
someFunction=function() {
  alert("Foo?");
  placeholder();
}

【讨论】:

    【解决方案4】:

    这个答案不是确定的,而是说明了一种与迄今为止提供的不同的技术。这利用了 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();
        }        
    }
    

    【讨论】:

    • 这行得通,但是您必须使用 function_processor 在所有将要调用它的地方调用 function_itself,这在某种程度上违背了目的。代码可能会很快演变成一堆 function_processor 调用。
    【解决方案5】:

    以下函数将为您提供可以堆叠的前后挂钩。因此,如果您有许多潜在的函数需要在给定函数之前或给定函数之后运行,那么这将是一个可行的解决方案。此解决方案不需要 jQuery 并使用本机数组方法(不需要 shims)。它也应该是上下文敏感的,所以如果你使用上下文调用原始函数,是否应该同样运行每个函数之前和之后的函数。

    // 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;
    }
    

    【讨论】:

      【解决方案6】:

      这是我所做的,可能对其他应用程序有用:

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

      【讨论】:

        【解决方案7】:

        我不知道这是否有用。您确实需要修改原始函数,但只需要修改一次,并且您不需要继续编辑它来触发钩子

        https://github.com/rcorp/hooker

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-02-05
          • 1970-01-01
          • 1970-01-01
          • 2012-07-27
          • 2012-05-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多