2008-11-17 38 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);