2

I often come across the following constructor prologue in many node.js/javascript sources.

function MyClass () {
    // prologue
    if (!(this instanceof MyClass)) {
        return new MyClass();
    }
    // do actual constructor logic
}

Could you please explain what is this for? Thanks.

Alex Yursha
  • 3,208
  • 3
  • 26
  • 25

2 Answers2

2

instanceof checks an object to see if it was likely to have been constructed via the given constructor function. That prologue is there to handle the case where someone calls the MyClass constructor function without using new. It means you can use MyClass the way it's meant to be used:

var c = new MyClass();

...or without new:

var c = MyClass();

In the latter case, within the call to MyClass, this won't be instanceof MyClass (it'll either be undefined [in strict mode] or the global object [in loose mode]), and so the author knows that the caller didn't use new, and just has the function do the new for them by doing return new MyClass(); instead of its normal construction work.

Some people like to do that so the new is optional, others think it's a bad idea to make the new optional like that. In the bad old days before strict mode, the alternative was to detect the caller's failure to use new and throw an exception:

// Old pre-strict code
if (!(this instanceof MyClass)) {
    throw "MyClass is a constructor, use new";
}

If you don't do that, and you're using loose mode, and you assign properties to this, you'll be assigning properties to the global object (which are global variables), which is a Bad Idea(tm).

But now we have strict mode, and this is one of the many reasons to use it:

"use strict"; // At the top of the file or `script` block

function MyClass() {
    // No need for the check anymore
    this.someProperty = someValue;
}

That code is entirely safe from the issue of accidentally creating global variables, because the this.someProperty = someValue; line will throw if someone calls MyClass without new (because this will be undefined). (And it doesn't matter whether the caller uses strict mode; it's sufficient that we use strict mode in the code defining the MyClass constructor.)

Some will still prefer to make new optional, of course, in which case they still need the prologue.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

To avoid direct calling a contructor to register some variables to global, this is a famous flaw of JavaScript.

function Foo() {
    // don't do prologue
    this.foo = 'foo';
}

Foo(); // direct call a constructor

console.log(window.foo) // foo, global is polluted.
hjl
  • 2,794
  • 3
  • 18
  • 26