For a project I will talk later on, I need to hook the function document.createElement. The code I wanted to write was:

var original = document.createElement;
document.createElement = function (tag) {
  // Do something
  return original(tag);
};

Problem

However, there's a silly Javascript exception triggered if you try to take a reference of the function

var createElement = document.createElement;
createElement('div');
// TypeError: Illegal Invocation

Naive Solution

Since it looks like we cannot use anything else but document.createElement to execute the function, I decided to restore the original document.createElement within the hook function. It is verbose but works.

var original = document.createElement;
var hook = function (tag) {
  document.createElement = original;
  // Do something
  var el = document.createElement(tag);
  document.createElement = hook;
  return el;
};
document.createElement = hook;

Why?

But then, I asked myself, how did they implement a function that could only be called with document.createElement form. Then I remembered that this calling convention sets this to be document. So they must be doing a check like this:

document.createElement = function () {
  if (this !== document) {
    throw new TypeError('Illegal Invocation');
  }
  // ...
}

Solution

Now that we know that they check for this === document, we can use .call to force it :)

var original = document.createElement;
document.createElement = function (tag) {
  // Do something
  return original.call(document, tag);
};
If you liked this article, you might be interested in my Twitter feed as well.
 
  • Pingback: Vjeux » Intercept and alter <script> include

  • Ghasem Kiani

    Why not use Function.prototype.bind as this:

    var original = document.createElement.bind(document);
    document.createElement = function (tag) {
    // Do something
    return original(tag);
    };

    This works fine in Firefox and Chrome.

  • http://blog.vjeux.com/ Vjeux

    It works :) But in the end, that's only another way to set this to document.

 

Random Posts

  • January 8, 2011 -- Javascript – Comma Trick (0)
    Reading An Open Letter to JavaScript Leaders Regarding Semicolons where Isaac Z. Schlueter explains his unorthodox coding style a line of code struck me. if (!cb_ && typeof conf === "function") cb_ = conf , conf = {} He was able to execute more than one statement in a if without the need of { }. I...
  • October 14, 2011 -- Mathematical Morphology Presentation (0)
    Last year, I've done a one-hour presentation of Mathematical Morphology in front of other students. Here are the slides: ...
  • August 13, 2009 -- Dangerous Bracket Notation for Strings (0)
    The bracket notation for string is incomplete in Javascript and does not work in IE7. This is really painful to migrate to the .charAt(pos) equivalent, this is why i recommend you not to use it. // Bracket Notation "Hello World!"[6] // > "W" // Real Implementation "Hello World!".charAt(6)...
  • August 4, 2009 -- Project – MMO-Champion Optimization (0)
    [caption id="attachment_485" align="alignright" width="300" caption="MMO-Champion"][/caption] MMO-Champion is the biggest news website of World of Warcraft. The main page is viewed millions times a month and was done with old school tables. As a result, it was really slow to load but worse, all t...
  • September 11, 2011 -- World of Warcraft HTML Tooltip Diff (0)
    MMO-Champion is a World of Warcraft news website. When a new patch is released, we want to show what has changed in the game (Post Example). An english summary of each spell change is hand written, but we want to show the exact tooltip changes. jsHTMLDiff is available on Github. .sigri...