With jQuery you can use .on()/.off()/.trigger() methods on any jQuery object, giving you powerful access to the event system. I'm trying to do something similar in vanilla JavaScript but I keep running into "TypeError: Illegal Invocation". I'm aware this error generally refers to losing a this reference when the method expects one. Using .apply or .call seems to usually do the trick, but I'm still running into problems.

Specifically, I'm trying to create an event enabled "class", which I can then extend other classes from, giving me a way to listen for and trigger events on non-DOM objects. (Yes, I know JS doesn't have real classes. I'm using CoffeeScript and thats the syntactic sugar used there.) Here is the "class" function which creates a new object with the same properties and values as the object passed to the constructor, and provides three methods that .apply() methods from EventTarget.prototype. Any guidance on how to get this working would be immensely appreciated!

EventEnabled = (function() {
  function EventEnabled(obj) {
    var key, val;
    for (key in obj) {
      val = obj[key];
      this[key] = val;
    }
  }

  EventEnabled.prototype.addEventListener = function() {
    return EventTarget.prototype.addEventListener.apply(this, arguments);
  };

  EventEnabled.prototype.removeEventListener = function() {
    return EventTarget.prototype.removeEventListener.apply(this, arguments);
  };

  EventEnabled.prototype.dispatchEvent = function() {
    return EventTarget.prototype.dispatchEvent.apply(this, arguments);
  };

  return EventEnabled;

})();

When I try to call any of those three methods on an instance of EventEnabled, I get a:

"TypeError: Illegal Invocation".

Thanks for any insight into this!


Solution 1:

EventTarget is only an interface which is implemented on native DOM objects, not a constructor that is available to javascript. While it might be available in the global scope, you cannot use it for instantiating instances of it.

Also, you can apply its methods only on objects that have natively implemented that interface (like DOM elements), not on an arbitrary instance of your EventEnabled constructor. You will either need to create an internal node, or you will need to implement your own event dispatching system (if you don't want to use any of the many available libraries).