2011-03-10 50 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; 
    } 
}; 
相關問題