How to detect if a function is called as constructor?

Viewed 44523

Given a function:

function x(arg) { return 30; }

You can call it two ways:

result = x(4);
result = new x(4);

The first returns 30, the second returns an object.

How can you detect which way the function was called inside the function itself?

Whatever your solution is, it must work with the following invocation as well:

var Z = new x(); 
Z.lolol = x; 
Z.lolol();

All the solutions currently think the Z.lolol() is calling it as a constructor.

23 Answers

1) You can check this.constructor:

function x(y)
{
    if (this.constructor == x)
        alert('called with new');
    else
         alert('called as function');
}

2) Yes, the return value is just discarded when used in the new context

NOTE: This answer was written in 2008, when javascript was still in ES3 from 1999. A lot of new functionality has been added since then, so now better solutions exists. This answer is kept for historical reasons.

The benefit of the code below is that you don't need to specify the name of the function twice and it works for anonymous functions too.

function x() {
    if ( (this instanceof arguments.callee) ) {
      alert("called as constructor");
    } else {
      alert("called as function");
    }
}

Update As claudiu have pointed out in a comment below, the above code doesn't work if you assign the constructor to the same object it has created. I have never written code that does that and have newer seen anyone else do that eighter.

Claudius example:

var Z = new x();
Z.lolol = x;
Z.lolol();

By adding a property to the object, it's possible to detect if the object has been initialized.

function x() {
    if ( (this instanceof arguments.callee && !this.hasOwnProperty("__ClaudiusCornerCase")) ) {
        this.__ClaudiusCornerCase=1;
        alert("called as constructor");
    } else {
        alert("called as function");
    }
}

Even the code above will break if you delete the added property. You can however overwrite it with any value you like, including undefined, and it still works. But if you delete it, it will break.

There is at this time no native support in ecmascript for detecting if a function was called as a constructor. This is the closest thing I have come up with so far, and it should work unless you delete the property.

Two ways, essentially the same under the hood. You can test what the scope of this is or you can test what this.constructor is.

If you called a method as a constructor this will be a new instance of the class, if you call the method as a method this will be the methods' context object. Similarly the constructor of an object will be the method itself if called as new, and the system Object constructor otherwise. That's clear as mud, but this should help:

var a = {};

a.foo = function () 
{
  if(this==a) //'a' because the context of foo is the parent 'a'
  {
    //method call
  }
  else
  {
    //constructor call
  }
}

var bar = function () 
{
  if(this==window) //and 'window' is the default context here
  {
    //method call
  }
  else
  {
    //constructor call
  }
}

a.baz = function ()
{
  if(this.constructor==a.baz); //or whatever chain you need to reference this method
  {
    //constructor call
  }
  else
  {
    //method call
  }
}

Checking for the instance type of the [this] within the constructor is the way to go. The problem is that without any further ado this approach is error prone. There is a solution however.

Lets say that we are dealing with function ClassA(). The rudimentary approach is:

    function ClassA() {
        if (this instanceof arguments.callee) {
            console.log("called as a constructor");
        } else {
            console.log("called as a function");
        }
    }

There are several means that the above mentioned solution will not work as expected. Consider just these two:

    var instance = new ClassA;
    instance.classAFunction = ClassA;
    instance.classAFunction(); // <-- this will appear as constructor call

    ClassA.apply(instance); //<-- this too

To overcome these, some suggest that either a) place some information in a field on the instance, like "ConstructorFinished" and check back on it or b) keep a track of your constructed objects in a list. I am uncomfortable with both, as altering every instance of ClassA is way too invasive and expensive for a type related feature to work. Collecting all objects in a list could provide garbage collection and resource issues if ClassA will have many instances.

The way to go is to be able to control the execution of your ClassA function. The simple approach is:

    function createConstructor(typeFunction) {
        return typeFunction.bind({});
    }

    var ClassA = createConstructor(
        function ClassA() {
            if (this instanceof arguments.callee) {
                console.log("called as a function");
                return;
            }
            console.log("called as a constructor");
        });

    var instance = new ClassA();

This will effectively prevent all attempts to trick with the [this] value. A bound function will always keep its original [this] context unless you call it with the new operator.

The advanced version gives back the ability to apply the constructor on arbitrary objects. Some uses could be using the constructor as a typeconverter or providing an callable chain of base class constructors in inheritance scenarios.

    function createConstructor(typeFunction) {
        var result = typeFunction.bind({});
        result.apply = function (ths, args) {
            try {
                typeFunction.inApplyMode = true;
                typeFunction.apply(ths, args);
            } finally {
                delete typeFunction.inApplyMode;
            }
        };
        return result;
    }

    var ClassA = createConstructor(
        function ClassA() {
            if (this instanceof arguments.callee && !arguments.callee.inApplyMode) {
                console.log("called as a constructor");
            } else {
                console.log("called as a function");
            }
        });

Extending Gregs solution, this one works perfectly with the test cases you provided:

function x(y) {
    if( this.constructor == arguments.callee && !this._constructed ) {
        this._constructed = true;
        alert('called with new');
    } else {
        alert('called as function');
    }
}

EDIT: adding some test cases

x(4);             // OK, function
var X = new x(4); // OK, new

var Z = new x();  // OK, new
Z.lolol = x; 
Z.lolol();        // OK, function

var Y = x;
Y();              // OK, function
var y = new Y();  // OK, new
y.lolol = Y;
y.lolol();        // OK, function

There is no reliable way to distinguish how a function is called in JavaScript code.1

However, a function call will have this assigned to the global object, while a constructor will have this assigned to a new object. This new object cannot ever be the global object, because even if an implementation allows you to set the global object, you still haven't had the chance to do it.

You can get the global object by having a function called as a function (heh) returning this.

My intuition is that in the specification of ECMAScript 1.3, constructors that have a defined behavior for when called as a function are supposed to distinguish how they were called using this comparison:

function MyClass () {
    if ( this === (function () { return this; })() ) {
        // called as a function
    }
    else {
        // called as a constructor
    }
}

Anyway, anyone can just use a function's or constructor's call or apply and set this to anything. But this way, you can avoid "initializing" the global object:

function MyClass () {
    if ( this === (function () { return this; })() ) {
        // Maybe the caller forgot the "new" keyword
        return new MyClass();
    }
    else {
        // initialize
    }
}

1. The host (aka implementation) may be able to tell the difference, if it implements the equivalent to the internal properties [[Call]] and [[Construct]]. The former is invoked for function or method expressions, while the latter is invoked for new expressions.

maybe I`m wrong but (at the cost of a parasite) the following code seems like a solution:

function x(arg) {
    //console.debug('_' in this ? 'function' : 'constructor'); //WRONG!!!
    //
    // RIGHT(as accepted)
    console.debug((this instanceof x && !('_' in this)) ? 'function' : 'constructor');
    this._ = 1;
    return 30;
}
var result1 = x(4),     // function
    result2 = new x(4), // constructor
    Z = new x();        // constructor
Z.lolol = x; 
Z.lolol();              // function

I believe the solution is to turn your Constructor function into a wrapper of the real Constructor function and its prototype Constructor if required. This method will work in ES5 from 2009 and also work in strict mode. In the code window below I have an example using the module pattern, to hold the real constructor and its prototype's constructor, in a closure, which is accessible through scope within the constructor(wrapper). This works because no property is added to the "this" keyword within the Constructor(wrapper) and the Constructor(wrapper).prototype is not set, so is Object by default; thus the array returned from Object.getpropertyNames will have a length equal to 0, if the new keyword has been used with the Constructor(wrapper). If true then return new Vector.

var Vector = (function() {
        
     var Vector__proto__ = function Vector() {
         // Vector methods go here
     }
            
     var vector__proto__ = new Vector__proto__();;
        
     var Vector = function(size) {
         // vector properties and values go here
         this.x = 0;
         this.y = 0;
         this.x = 0;
         this.maxLen = size === undefined? -1 : size;
                
     };
     Vector.prototype = vector__proto__;
        
     return function(size){
                
         if ( Object.getOwnPropertyNames(this).length === 0 ) {
             // the new keyword WAS USED with the wrapper constructor
             return new Vector(size); 
         } else { 
             // the new keyword was NOT USED with the wrapper constructor
             return; 
         };
    };
})();

On the top of the question, below code will auto-fix the issue in case function is called without new.

function Car() {

    if (!(this instanceof Car)) return new Car();

    this.a = 1;
    console.log("Called as Constructor");

}
let c1 = new Car();
console.log(c1);

This can achieved without using ES6 new.target. You can run your code in strict mode and in this case value of this will be undefined if called without new otherwise it will be empty object. Example::

"use strict"
function Name(){
    console.log(this)
if(this){
    alert("called by new")
}
else
    alert("did not called using new")
}
new Name()
Related