Hook document.CreateElement

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 X feed as well.