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.

 

Related Posts

  • August 19, 2011 Javascript – Stupid Idea: Hoisting at the end (0)
    JSLint imposes us to do manual hoisting of variables. What if we did it but at the end of the function? :P How you write function print_array (array) { var length = array.length; for (var i = 0; i < length; ++i) { var elem = array[i]; console.log(elem); […]
  • September 25, 2011 Javascript Object Difference (5)
    This article is about a difference algorithm. It extracts changes from one version of an object to another. It helps storing a smaller amount of information. Template In a project, I have a template object with all the default settings for a widget. var template = { […]
  • May 10, 2012 Generic Image Processing With Climb – 5th ELS (0)
    ELS Presentation | A Generic and Dynamic Approach to Image Processing | Chaining Operators & Component Trees | Property-based dispatch in functional languages Laurent Senta had the opportunity to go to the 5th European Lisp Symposium to present Climb, the project I've been […]
  • August 29, 2011 Javascript: Improve Cache Performance: Reduce Lookups (2)
    In my Binary Decision Diagram Library, the performance bottleneck was the uniqueness cache. By reducing the number of cache lookup, it is possible to greatly improve the performances. Common pattern In order to test if the key is already in the cache, the usual pattern is to use key […]
  • June 13, 2012 Project – Tagging Improvement using Face Detection (3)
    The first non-trivial feature I've done at Facebook is now released :) If you have ever tagged an album, you must know the pain it is to go over all the photos and tag everyone. In order to make this process easier, we can make use of image recognition algorithms to find faces. […]