Обтекание функции в Javascript/jQuery

Если у меня есть произвольная функция myFunc, то я собираюсь сделать это, заменив эту функцию заверенным вызовом, который запускает код до и после его выполнения, например.

// note: psuedo-javascript

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

myFunc = wrap(myFunc, beforeExecute, afterExecute);

Однако у меня нет реализации требуемой функции wrap. Есть ли что-то, что уже существует в jQuery, как это (я хорошо просмотрел документы, но ничего не вижу)? Или кто-нибудь знает о хорошей реализации этого, потому что я подозреваю, что есть куча крайних случаев, которые я пропущу, если я попытаюсь написать это сам?

(BTW - причина этого заключается в том, чтобы сделать некоторые автоматические функции функций, потому что мы делаем много работы на закрытых устройствах, где Javascript-профилировщики и т.д. недоступны. Если есть лучший способ, чем это, тогда я буду благодарен за ответы по этим линиям тоже.)

Ответ 1

Heres a wrap функция, которая будет вызывать функции before и after с теми же самыми аргументами и, если она есть, то же значение для 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);

Ответ 2

Принятая реализация не предоставляет возможность условно вызывать завернутую (оригинальную) функцию.

Вот лучший способ обернуть и развернуть метод:

  /*
    Replaces sMethodName method of oContext with a function which calls the wrapper 
    with it 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;
    }
};

Ответ 3

Вы можете сделать что-то вроде:

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

Важная часть при переносе этого способа передаёт ваши аргументы из новой функции обратно в исходную функцию.

Ответ 4

Это пример, который я использовал бы

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

Ответ 5

Возможно, я ошибаюсь, но я думаю, что вы можете напрямую создать функцию анонима и назначить ее myFunc:

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

Таким образом вы можете управлять аргументами каждой функции.