覆盖函数(例如“alert”)并调用原始函数?

38

我想用一个新版本来调用原版JavaScript内置函数(类似于在许多语言中使用super覆盖类中的方法)。我该如何做到这一点?

例如...

window.alert = function(str) {
    //do something additional
    if(console) console.log(str);

    //super.alert(str) // How do I do this bit?
}

一个类似但稍微复杂一些的情况:https://dev59.com/1XVC5IYBdhLWcg3wbghT - user166390
显示覆盖警告:https://dev59.com/X3I-5IYBdhLWcg3wsKh4 - user166390
我删除了“OO”和“超类”标签,因为它们不适用。但是这个问题涉及到在JavaScript中模拟“super”:https://dev59.com/Z2w15IYBdhLWcg3wA3CT - user166390
6个回答

66

将原始函数的引用存储到变量中:

(function() {
    var _alert = window.alert;                   // <-- Reference
    window.alert = function(str) {
        // do something additional
        if(console) console.log(str);
        //return _alert.apply(this, arguments);  // <-- The universal method
        _alert(str);                             // Suits for this case
    };
})();

通用的方式是 <original_func_reference>.apply(this, arguments) - 为了保留上下文并传递所有参数。通常应该返回原始方法的返回值。

但是,已知alert是一个无返回值函数,仅接受一个参数,并且不使用this对象。因此,在这种情况下,_alert(str)足够了。

注意:如果尝试覆盖alert,IE <= 8会抛出错误,因此请确保您使用window.alert = ...而不是alert = ...


3
测试结果显示:所有主流浏览器都允许修改全局 window.alert,除了 IE <= 8。在 IE 9 之前,尝试覆盖 alert 会引发错误。 - Rob W
@Rob 谢谢你提醒。你有没有注意到其他内置函数在IE上的问题? - Déjà vu
1
@ring0 基本上每个内置的:confirmdocument,... 如果你想拦截 window.alert 调用,你可以将代码包装在一个闭包中,在其中声明和定义一个自定义的 window(或 alert)变量。如果您的应用程序不依赖于隐式变量声明,则始终有效。 - Rob W
@RobW 尽管这篇文章很旧,但我刚刚在IE 7.0.6002.18005(Vista)和IE 8.0.6001.18702(Win XP)中测试了警报覆盖,并且两者都可以正常工作。 - Jeremy S.
@RobW 很好,您能否请删除未来读者的注释? - Jeremy S.
显示剩余2条评论

24

没有"super"。无论如何,创建一个闭包来“保留”原始函数对象。

注意“自执行函数”,它返回一个新的函数对象(分配给window.alert属性)。返回的新函数对象在变量original周围创建了一个闭包,该闭包评估为传递给“自执行函数”的window.alert的原始

window.alert = (function (original) {
  return function (str) {
    //do something additional
    if(console) {
      console.log(str)
    }
    original(str)
  }
})(window.alert)

然而,我相信一些浏览器可能会阻止修改alert和其他内置函数...

编程愉快。


这是闭包的一个非常优雅的用法。绝对是我见过的最小的闭包占用空间。 - rocketsarefast

7
我假设您的问题是如何覆盖内置函数并仍然能够调用它。首先作为免责声明,除非您有充分的理由,否则不应该覆盖内置函数,因为这将使调试/测试变得不可能。
以下是如何实现:
```html

我假设您的问题是如何覆盖内置函数并仍然能够调用它。首先作为免责声明,除非您有充分的理由,否则不应该覆盖内置函数,因为这将使调试/测试变得不可能。

以下是如何实现:

```
window._alert = window.alert;
window.alert = function(str) { 
     if(console) console.log(str);
     window._alert(str);
}

4
注意:这种方法不易于扩展。如果调用相同的代码两次,您将丢失原始方法。 - Rob W
3
如果只有在window._alert未定义时才设置它,那么就不会出现这种情况。 - Wesley

2

如何在Javascript中进行简单的经典继承:

SuperClass.call(this) // inherit from SuperClass (multiple inheritance yes)

如何覆盖函数:
this.myFunction = this.myFunction.override(
                    function(){
                      this.superFunction(); // call the overridden function
                    }
                  );

覆盖函数是这样创建的:
Function.prototype.override = function(func)
{
 var superFunction = this;
 return function() 
 {
  this.superFunction = superFunction;
  return func.apply(this,arguments);
 };
};

可以使用多个参数。
尝试覆盖未定义或非函数时会失败。
使"superFunction"成为一个"保留"单词 :-)


1

JavaScript不使用经典的继承模型。有一篇很好的文章在这里描述了一种编写类的方式,使得可以使用类似的语法,但它并没有本地支持。


1
通过使用代理对象,您可以实现这一点。
window.alert = new Proxy(window.alert , {
apply: function(target,that,args){
    console && console.log(args.join('\n'));
    target.apply(that,args)
}})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接