38

I would like to override a Javascript built-in function with a new version that calls the original (similarly to overriding a method on a class with a version that calls super in many languages). How can I do this?

For example...

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

    //super.alert(str) // How do I do this bit?
}
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
  • A similar, but slightly more complex case: http://stackoverflow.com/questions/296667/overriding-a-javascript-function-while-referencing-the-original –  May 03 '12 at 08:38
  • Shows overriding alert: http://stackoverflow.com/questions/1729501/javascript-overriding-alert –  May 03 '12 at 08:41
  • I removed the "OO" and "superclass" tags because they did not apply. But this question covers mocking "super" in JavaScript: http://stackoverflow.com/questions/6885404/javascript-override-methods –  May 03 '12 at 08:42

6 Answers6

64

Store a reference to the original function in a variable:

(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
    };
})();

The universal way is <original_func_reference>.apply(this, arguments) - To preserve context and pass all arguments. Usually, the return value of the original method should also be returned.

However, it's known that alert is a void function, takes only one argument, and does not use the this object. So, _alert(str) is sufficient in this case.

Note: IE <= 8 throws an error if you try to overwrite alert, so make sure that you're using window.alert = ... instead of alert = ....

Agostino
  • 2,723
  • 9
  • 48
  • 65
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • 3
    Just tested: All major browsers allow the modification of the global `window.alert`, except for IE <= 8. Prior IE 9, an error was thrown when attempting to overwrite `alert`. – Rob W May 03 '12 at 08:41
  • @Rob Thanks for the heads-up. Did you notice the IE problem with other built-in funcs? – Déjà vu Nov 04 '12 at 09:11
  • 1
    @ring0 Basically every built-in: `confirm`, `document`, ... If you want to intercept `window.alert` calls, you can wrap the code in a closure where a custom `window` (or `alert`) variable is declared and defined. This will always work if your application does not rely on implicit variable declaration. – Rob W Nov 04 '12 at 10:47
  • @RobW even though this post is pretty old, just tested alert override in IE 7.0.6002.18005 (Vista) and IE 8.0.6001.18702 (Win XP) and works in both. – Jeremy S. Jan 28 '14 at 15:21
  • @JeremyS. Oh, you're right. When I wrote that statement, I used `alert = ....`. This throws an error. But if you use `window.alert = ...`, then everything will work as intended. – Rob W Jan 28 '14 at 15:25
  • @RobW perfect, can you please remove the note for future readers – Jeremy S. Jan 28 '14 at 16:06
  • Thats such an Amaaaaaazing way :D – Bishoy Hanna Nov 27 '19 at 07:50
24

There is no "super". Anyway, create a closure to "keep" around the original function-object.

Note the "self invoking function" that returns a new function-object (that is assigned to the window.alert property). The new function-object returned creates a closure around the variable original which evaluates to the original value of window.alert that was passed in to the "self invoking function".

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

However, I believe some browsers may prevent alert and other built-ins from being modified...

Happy coding.

7

I'm assuming your question is how do you overwrite a built-in and still be able to call it. First off as a disclaimer, you should never overwrite built ins unless you have a good reason for doing it since it will make it impossible to debug/test.

This is how you would do it:

window._alert = window.alert;
window.alert = function(str) { 
     if(console) console.log(str);
     window._alert(str);
}
Art
  • 5,864
  • 3
  • 30
  • 32
2

How to do simple classical inheritance in Javascript:

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

How to override functions:

this.myFunction = this.myFunction.override(
                    function(){
                      this.superFunction(); // call the overridden function
                    }
                  );

The override function is created like this:

Function.prototype.override = function(func)
{
 var superFunction = this;
 return function() 
 {
  this.superFunction = superFunction;
  return func.apply(this,arguments);
 };
};

Works with multiple arguments.
Fails when trying to override undefined or nonfunctions.
Makes "superFunction" a "reserved" word :-)

Poul Krogh
  • 21
  • 1
1

JavaScript does not use a classical inheritance model. There is a nice article here which describes a way to write your classes so that a similar syntax can be used, but it's not natively supported.

David M
  • 71,481
  • 13
  • 158
  • 186
1

By using proxy object you can do this.

window.alert = new Proxy(window.alert , {
apply: function(target,that,args){
    console && console.log(args.join('\n'));
    target.apply(that,args)
}})
Keval-IW
  • 21
  • 3