2008-11-17 56 views
147

我有一個功能,a(),我想覆蓋,但也有原始a()取決於上下文的順序執行。例如,有時當我生成一個網頁,我會想覆蓋這樣的:在引用原文的同時覆蓋JavaScript函數

function a() { 
    new_code(); 
    original_a(); 
} 

,有時是這樣的:

function a() { 
    original_a(); 
    other_new_code(); 
} 

如何獲取original_a()從內過度騎a()?它甚至有可能嗎?

請不要以這種方式建議替代方案,我知道很多。我特意問這種方式。

回答

172

你可以做這樣的事情:

var a = (function() { 
    var original_a = a; 

    if (condition) { 
     return function() { 
      new_code(); 
      original_a(); 
     } 
    } else { 
     return function() { 
      original_a(); 
      other_new_code(); 
     } 
    } 
})(); 

聲明original_a匿名函數內保持它塞滿全局命名空間,但它的內部功能可用。

和評論中提到的Nerdmaster一樣,一定要在末尾加上()。您要調用外部函數並將結果(兩個內部函數之一)存儲在a中,而不是將外部函數本身存儲在a中。

+0

謝謝!這非常有幫助。 – Kev 2008-11-17 20:06:21

+1

哇。超酷 – naveen 2011-03-04 03:54:14

+21

對於像我這樣的任何白癡 - 密切注意最後的「()」 - 沒有這個,它會返回外部函數,而不是內部函數:) – Nerdmaster 2012-07-24 18:27:30

75

Proxy pattern可能會幫助您:以上

(function() { 
    // log all calls to setArray 
    var proxied = jQuery.fn.setArray; 
    jQuery.fn.setArray = function() { 
     console.log(this, arguments); 
     return proxied.apply(this, arguments); 
    }; 
})(); 

包裹它的代碼在函數中隱藏 「代理」 -variable。它將jQuery的setArray方法保存在閉包中並覆蓋它。該代理然後記錄所有對該方法的調用並將該調用委託給原始。使用apply(this,arguments)可以保證調用者不會注意到原始和代理方法之間的區別。

26

感謝球員的代理模式真的幫助.....其實我想打電話給一個全局函數foo .. 在某些頁面我需要做一些檢查。所以我做了以下。

//Saving the original func 
var org_foo = window.foo; 

//Assigning proxy fucnc 
window.foo = function(args){ 
    //Performing checks 
    if(checkCondition(args)){ 
     //Calling original funcs 
     org_foo(args); 
    } 
}; 

日Thnx這真的幫了我

8

您可以使用結構像重載函數:

function override(f, g) { 
    return function() { 
     return g(f); 
    }: 
} 

例如:

a = override(a, function(original_a) { 
     if (condition) { new_code(); original_a(); } 
     else { original_a(); other_new_code(); } 
}); 
4

傳遞任意參數:

a = override(a, function(original_a) { 
    if (condition) { new_code(); original_a.apply(this, arguments) ; } 
    else { original_a.apply(this, arguments); other_new_code(); } 
}); 
1

以上示例沒有正確應用this或正確傳遞arguments到函數覆蓋。下劃線_.wrap()包裝現有功能,應用this並正確傳遞arguments。請參閱:http://underscorejs.org/#wrap

0

我有一些代碼由其他人編寫,並且希望將一行添加到我在代碼中找不到的函數中。所以作爲一個解決方法,我想覆蓋它。

沒有解決方案爲我工作。

這裏是我的情況下工作:

if (typeof originalFunction === "undefined") { 
    originalFunction = targetFunction; 
    targetFunction = function(x, y) { 
     //Your code 
     originalFunction(a, b); 
     //Your Code 
    }; 
} 
0

我已經創建了一個類似的場景一個小幫手,因爲我經常需要從幾個圖書館覆蓋功能。這個助手接受一個「命名空間」(函數容器),函數名和覆蓋函數。它將用新的名稱空間替換引用的名稱空間中的原始函數。

新函數接受原始函數作爲第一個參數,並將原始函數參數作爲其餘參數。它每次都會保留上下文。它也支持void和non-void函數。

function overrideFunction(namespace, baseFuncName, func) { 
    var originalFn = namespace[baseFuncName]; 
    namespace[baseFuncName] = function() { 
     return func.apply(this, [originalFn.bind(this)].concat(Array.prototype.slice.call(arguments, 0))); 
    }; 
} 

使用例如與引導:

overrideFunction($.fn.popover.Constructor.prototype, 'leave', function(baseFn, obj) { 
    // ... do stuff before base call 
    baseFn(obj); 
    // ... do stuff after base call 
}); 

我沒有,雖然產生任何性能測試。根據情況,它可能會添加一些不必要的開銷,這些開銷可以或不可以是一個大問題。

0

在我看來,最好的答案是不可讀/可維護的,其他答案沒有正確綁定上下文。以下是使用ES6語法解決這兩個問題的可讀解決方案。

const orginial = someObject.foo; 
someObject.foo = function() { 
    if (condition) orginial.bind(this)(...arguments); 
}; 
0

是@Matthew Crumley提供正在使用的立即調用函數表達式的答案,收舊的「A」功能到返回函數的執行上下文。我認爲這是最好的答案,但個人而言,我寧願將函數'a'作爲參數傳遞給IIFE。我認爲這更容易理解。

var a = (function(original_a) { 
     if (condition) { 
      return function() { 
       new_code(); 
       original_a(); 
      } 
     } else { 
      return function() { 
       original_a(); 
       other_new_code(); 
      } 
     } 
    })(a);