在Javascript / jQuery中包装函数

时间:2011-03-10 11:09:13

标签: javascript jquery instrumentation

如果我有一个任意函数myFunc,那么我的目标是用一个在执行代码之前和之后运行代码的包装调用替换这个函数,例如

// note: psuedo-javascript

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

myFunc = wrap(myFunc, beforeExecute, afterExecute);

但是,我没有实现所需的wrap功能。这样的jQuery中是否存在任何东西(我通过文档很好看但却看不到任何东西)?或者有人知道这方面的一个很好的实现,因为我怀疑有一堆边缘情况,如果我自己编写它,我会想念它吗?

(顺便说一下 - 之所以这样做是为了做一些功能的自动检测,因为我们在Javascript剖析器等不可用的封闭设备上做了很多工作。如果有比这更好的方法那么我会很感激答案沿着这些方向。)

5 个答案:

答案 0 :(得分:11)

这是wrap函数,它将使用完全相同的参数调用beforeafter函数(如果提供),thisvar 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); 函数的值相同1}}:

{{1}}

答案 1 :(得分: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;
    }
};

答案 2 :(得分: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

以这种方式包装时的重要部分是将参数从新函数传递回原始函数。

答案 3 :(得分: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>

答案 4 :(得分:-1)

也许我错了,但我认为你可以直接创建一个匿名函数并将其分配给myFunc:

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

通过这种方式,您可以控制每个函数的参数。