How to do a non-destructive overwrite of a function in javascript

I really don’t like the “non-destructive” expression but I couldn’t come up with a better one.

What?

You want to create a function but you will overwrite the old one. You just want to add some code before or after it.

Example, you create a javascript applet that can be added to web sites you do not own and you want to call a function in the body.onclick() event. Maybe the site already has something in the body.onclick() event and you don’t want to overwrite it because the other developer will be mad at you. You’re stuck!

How?

First of all, don’t panic. Take a deep breath and relax.

Now, you’re ready.

  1. var oldBodyOnClick = body.onclick;
  2. body.onclick = function() {
  3.         // Add your code here!
  4.         alert("Before the old event");
  5.  
  6.         if (oldBodyOnClick != null) {
  7.                 oldBodyOnClick();
  8.         }
  9.  
  10.         // or here!
  11.         alert("After the old event");
  12. }

Could you repeat slower please?

Ok.

First, I assign the body.onclick() event to a new variable.

  1. var oldBodyOnClick = body.onclick;

Second, I create a new function that will be called on the body.onclick() event.

  1. body.onclick = function() {

Third, I add code before the old event

  1. alert("Before the old event");

Fourth, I call the old event if it is not null

  1. if (oldBodyOnClick != null) {
  2. oldBodyOnClick();
  3. }

Third, I add code after the old event

  1. alert("After the old event");

That’s it!

Commentaires

  1. BK May 3 2007 at 10:02:09

    Here come the recuer again! :P Here Comes: THE CLOSURE!

    function FnBuilder(){
    var Old=document.getElementById(”myb”).onclick
    function New(){Old();alert(5678);}
    return New
    }
    document.getElementById(’myb’).onclick=FnBuilder();
    FnBuilder=null;

  2. Boyan May 4 2007 at 08:38:29

    Nice. Don’t most js libraries take care of this automatically already? Oh, and by the way (nitpick coming), the past tense of “stick” is “stuck” and not “stucked”

  3. Dan (maintainer of Javascript Kata) May 4 2007 at 09:14:11

    @Boyan
    I guess that a lot of librairies can take care of this… but sometimes you don’t have any librairie for a small web site or a bookmarklet…

    Thanks for the correction…

  4. si May 4 2007 at 16:34:04

    While I don’t like that method of event adding (I think a nice cross-browser addEvent function is far safer / nicer), it’s quite a pretty way of doing it - one good consequence is that you can specify whether yours happens before or after all of the existing methods.

    Another similar “trick” which I like is overriding the alert() function to get rid of potentially missed debug code, like so:

    _alert = alert;
    alert = null;

  5. Scott Becker May 7 2007 at 15:07:30

    Since you’re not really overwriting the function, but adding before and after callbacks, ActsAsAspect is an elegant way of doing this - http://beppu.lbox.org/articles/2006/09/06/actsasaspect

    Basically, you can take a function or object or class with some existing methods:

    MyObj.go = function() { alert(’go’); }

    and call actsAsAspect() on it like so:

    actsAsAspect(MyObj);

    then it gets some some extra methods - before, after, & around, which let you add listeners to that function like this:

    MyObj.before(’go’, function() { alert(’do this before go() gets called!’) })

    It’s short and sweet, I love that little script.

  6. James Craig May 19 2007 at 15:31:24

    Even without a library, try DOM Level 2 assignment and you won’t overwrite any of these DOM 1 assignments or other DOM 2 events.

  7. BK May 22 2007 at 09:11:39

    What do you mean by DOM Level 2?
    Are you talking about the register event stuff?

  8. Stephan Wehner June 2 2008 at 03:05:44

    Couldn’t get this to work with “console.debug” (which comes with Firebug, for Firefox) — I got “too many recursions” with

    var origcd = console.debug
    console.debug = function(s) {
    origcd(’console-debug: ‘ + s)
    }
    :
    :
    :
    console.debug(’test’)

    console.debug writes to a console, that can be viewed with Firebug.

    Stephan

Post a comment

Comments are moderated and innapropriate ones won't be approved. Please respect this public space.