2011-03-10 71 views
10

如果我有一个任意的函数myFunc,我打算做的是用一个在其执行前后运行代码的包装函数替换这个函数。用Javascript包装一个函数/ jQuery

// note: psuedo-javascript 

var beforeExecute = function() { ... } 
var afterExecute = function() { ... } 

myFunc = wrap(myFunc, beforeExecute, afterExecute); 

但是,我没有执行所需的wrap函数。这样的jQuery中是否存在任何已存在的东西(我已经通过文档了解了很多,但看不到任何东西)?或者,任何人都知道这一点很好的实现,因为我怀疑,如果我自己写这些,我会怀念一些边缘案例吗? (这是因为我们在封闭设备上做了很多工作,其中Javascript分析器等不可用,所以我需要做一些自动的函数检测工作,如果有更好的方法,那么我会很感激沿着这些线路的答案太)

回答

11

这里是一个wrap功能,将调用beforeafter功能完全相同的参数,如果提供,用于this相同的值:

var wrap = function (functionToWrap, before, after, thisObject) { 
    return function() { 
     var args = Array.prototype.slice.call(arguments), 
      result; 
     if (before) before.apply(thisObject || this, args); 
     result = functionToWrap.apply(thisObject || this, args); 
     if (after) after.apply(thisObject || this, args); 
     return result; 
    }; 
}; 

myFunc = wrap(myFunc, beforeExecute, afterExecute); 
+0

我打算选择这个作为正确答案,因为我认为这是问题的最完整解决方案,并用任意数量的参数处理函数。干杯!希望在jQuery中可能会有一个标准的库函数,但我总是可以将它添加到我们的扩展中。 – 2011-03-10 15:54:26

+0

我做了一个小小的编辑,所以如果在创建包装器时没有指定'thisObject',就使用'regular''this'对象。 – Martijn 2011-03-11 08:14:29

2

你可以这样做:

var wrap = function(func, pre, post) 
{ 
    return function() 
    { 
    var callee = arguments.callee; 
    var args = arguments; 

    pre();  
    func.apply(callee, args);  
    post(); 
    }; 
}; 

这将允许你这样做:

var someFunc = function(arg1, arg2) 
{ 
    console.log(arg1); 
    console.log(arg2); 
}; 

someFunc = wrap(
    someFunc, 
    function() { console.log("pre"); }, 
    function() { console.log("post"); }); 

someFunc("Hello", 27); 

其中给出我在Firebug的输出:

pre 
Hello 
27 
post 

的重要组成部分,包装这样的情况下,从新功能传递你的论点回到原来的功能。

+0

你为什么想要通过被叫为'this'? – Martijn 2011-03-11 08:15:12

2

这是我会用例子

<script type="text/javascript"> 
    var before = function(){alert("before")}; 
    var after = function(param){alert(param)}; 
    var wrap = function(func, wrap_before, wrap_after){ 
    wrap_before.call(); 
    func.call(); 
    wrap_after.call(); 
    }; 
    wrap(function(){alert("in the middle");},before,function(){after("after")}); 
</script> 
+0

它还显示了如何参数化您用包装运行的函数。如果你像这样调用函数,可以在包装自己之前执行参数乳清。 – m4risU 2011-03-10 11:23:04

+0

如果被包装的功能有参数,这似乎不起作用...? – 2011-03-10 11:40:36

+0

这就是为什么你应该在function(){...}调用中包装参数函数。否则,您将最终启动函数以获取其结果。 – m4risU 2011-03-10 11:41:34

-1

也许我错了,但我认为你可以直接创建一个化名功能,并将其分配给myFunc的:

 
myFunc = function(){ 
      BeforeFunction(); 
      myFunc(); 
      AfterFunction(); 
     } 

这样你可以控制每个函数的参数。

4

接受的实现不提供一个选项,以有条件地调用包装(原始)功能。

这里是一个更好的方式来包装和解开的方法:

/* 
    Replaces sMethodName method of oContext with a function which calls the wrapper 
    with it's list of parameters prepended by a reference to wrapped (original) function. 

    This provides convenience of allowing conditional calls of the 
    original function within the wrapper, 

    unlike a common implementation that supplies "before" and "after" 
    cross cutting concerns as two separate methods. 

    wrap() stores a reference to original (unwrapped) function for 
    subsequent unwrap() calls. 

    Example: 
    ========================================= 

    var o = { 
     test: function(sText) { return sText; } 
    } 

    wrap('test', o, function(fOriginal, sText) { 
     return 'before ' + fOriginal(sText) + ' after'; 
    }); 
    o.test('mytext') // returns: "before mytext after" 

    unwrap('test', o); 
    o.test('mytext') // returns: "mytext" 

    ========================================= 
*/ 
function wrap(sMethodName, oContext, fWrapper, oWrapperContext) { 
    var fOriginal = oContext[sMethodName]; 

    oContext[sMethodName] = function() { 
     var a = Array.prototype.slice.call(arguments); 
     a.unshift(fOriginal.bind(oContext)); 
     return fWrapper.apply(oWrapperContext || oContext, a); 
    }; 
    oContext[sMethodName].unwrapped = fOriginal; 
}; 

/* 
    Reverts method sMethodName of oContext to reference original function, 
    the way it was before wrap() call 
*/ 
function unwrap(sMethodName, oContext) { 
    if (typeof oContext[sMethodName] == 'function') { 
     oContext[sMethodName] = oContext[sMethodName].unwrapped; 
    } 
}; 
相关问题