1

Context

I've noticed that some functions can only be called with the new prefix. When called without it, the error Illegal Invocation is thrown. Below is two examples of how the console reacted when the Image was called in different ways.

-> new Image();
<- <img>
-> Image();
<- TypeError: DOM object constructor cannot be called as a function.

Even more interesting, under closer observation, these types of functions seem like functions, yet they aren't. Take Image for example, the typeof command reveals that Image is a function yet the constructor of Image implies that it is an Object.

This is very different than most construction functions like the one below.

function Foo(){
    this.identity = 'Bar';
}

The function Foo can be called two ways, new Foo() and Foo(). This is very different than the Image function.

The Question

This action with the Image function is very different than most construction functions. How is this possible? Is this why the new prefix must be used with Image? And more importantly can this type of function be recreated?

Hunter Larco
  • 785
  • 5
  • 17
  • possible duplicate of [What is the 'new' keyword in JavaScript?](http://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript) – mplungjan Apr 20 '13 at 22:15
  • It isn't I have scoured that question and it doesn't address mine. I am asking why some construction functions require the new prefix while others are indifferent. What makes the difference and how can i recreate it? – Hunter Larco Apr 20 '13 at 22:26
  • Simple, check if `this` is a `MyObj` with `function MyObj() { if(!(this instanceof MyObj)) throw new TypeError("MyObj must be called as a constructor") }` – apsillers Apr 20 '13 at 22:37
  • @apsillers: You can do it generically (in case the function name changes) with: `if (!(this instanceof arguments.callee)) throw new Error("Constructor called as a function");` See [here](http://stackoverflow.com/questions/383402/is-javascript-s-new-keyword-considered-harmful). – Cᴏʀʏ Apr 20 '13 at 22:40

2 Answers2

4

I think this is the logic you're looking for that reproduces the exception when the new keyword isn't used to create an instance of Foo:

function Foo() {
    if (!(this instanceof arguments.callee)) 
        throw new TypeError("DOM object constructor cannot be called as a function.");

    this.identity = 'Bar';
}

According to some comments in this post, instead of arguments.callee you'd have to use the function name Foo if you are in strict mode:

function Foo() {
    if (!(this instanceof Foo)) 
        throw new TypeError("DOM object constructor cannot be called as a function.");

    this.identity = 'Bar';
}

See a DEMO here that illustrates the situation.

Community
  • 1
  • 1
Cᴏʀʏ
  • 105,112
  • 20
  • 162
  • 194
2

The problem with Image is that it is a host object - which means it does not need to follow the strict semantics of native EcmaScript objects. For example, it can inherit from something that is not Function.prototype, implement the internal [[Construct]] method but not [[Call]] and similar things.

They are specified by the DOM (see Where are constructors such as, `new Image()` and `new Option()`, documented?), specifically here:

A constructor is provided for creating HTMLImageElement objects (in addition to the factory methods from DOM such as createElement()): Image(width, height). When invoked as a constructor, this must return a new HTMLImageElement object (a new img element). […]

Yet it implemented browser-specific: For example Opera creates images without new as well, not throwing the NOT SUPPORTED error.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375