122

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.

alex
  • 479,566
  • 201
  • 878
  • 984
Claudiu
  • 224,032
  • 165
  • 485
  • 680

23 Answers23

98

As of ECMAScript 6, this is possible with new.target

new.target will be set as true if the function is called with new (or with Reflect.construct, which acts like new), otherwise it's undefined.

function Foo() {
  if (new.target) {
    console.log('called with new');
  } else {
    console.log('not called with new');
  }
}

new Foo(); // "called with new"
Foo(); // "not called with new"
Foo.call({}); // "not called with new"
vsync
  • 118,978
  • 58
  • 307
  • 400
Daniel Weiner
  • 1,874
  • 12
  • 19
95

NOTE: This is now possible in ES2015 and later. See Daniel Weiner's answer.

I don't think what you want is possible [prior to ES2015]. There simply isn't enough information available within the function to make a reliable inference.

Looking at the ECMAScript 3rd edition spec, the steps taken when new x() is called are essentially:

  • Create a new object
  • Assign its internal [[Prototype]] property to the prototype property of x
  • Call x as normal, passing it the new object as this
  • If the call to x returned an object, return it, otherwise return the new object

Nothing useful about how the function was called is made available to the executing code, so the only thing it's possible to test inside x is the this value, which is what all the answers here are doing. As you've observed, a new instance of* x when calling x as a constructor is indistinguishable from a pre-existing instance of x passed as this when calling x as a function, unless you assign a property to every new object created by x as it is constructed:

function x(y) {
    var isConstructor = false;
    if (this instanceof x // <- You could use arguments.callee instead of x here,
                          // except in in EcmaScript 5 strict mode.
            && !this.__previouslyConstructedByX) {
        isConstructor = true;
        this.__previouslyConstructedByX = true;
    }
    alert(isConstructor);
}

Obviously this is not ideal, since you now have an extra useless property on every object constructed by x that could be overwritten, but I think it's the best you can do.

(*) "instance of" is an inaccurate term but is close enough, and more concise than "object that has been created by calling x as a constructor"

Community
  • 1
  • 1
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • why are you using this.__previouslyConstructedByX instead of var previouslyConstructedByX ? – bgw Dec 13 '09 at 14:12
  • 1
    @PiPeep: Only as a naming convention intended to suggest that the property isn't to be used for any other purpose. Some people use a convention that properties not intended as part of the public API for an object start with an underscore, while there are some non-standard properties of JavaScript objects in some browsers that start with double underscores and I was taking my cue from those ideas. I didn't think about it in great detail and could be persuaded that the two underscores is a bad idea. – Tim Down Dec 13 '09 at 22:03
  • I think this is the right answer. in the general case, you just can't do it. – Claudiu Dec 13 '09 at 23:54
  • 3
    I just stopped by and was pretty surprised to see that this answer only had one upvote. It is a great answer. Come on, people, don't be so stingy. (Needless to say, plus 1). – Charlie Flowers Jan 20 '10 at 02:58
  • 10
    I've come up with this technique independently, and I'm using `Object.defineProperty('__previouslyConstructedByX', { value : true, writeable : false, enumerable : false})` This makes the extra property much less likely to be found accidentally, and guarantees it will never change. I'm working in node.js so I can be sure the implementation will support it, but in the browser you'd have to feature test to use this. – Nathan MacInnes Jul 20 '12 at 12:14
  • 1
    Note that arguments.callee is deprecated in ES5 strict mode. – Deqing Sep 11 '13 at 02:50
  • @Deqing: Yes. I'll add a note. Thanks. – Tim Down Sep 11 '13 at 08:42
  • In case you're using require.js, it won't let you call a module as a function, and will output the error to the console – Hal50000 Dec 10 '15 at 20:58
  • NOTE: this is now possible as of ES6. See [Daniel Weiner's](http://stackoverflow.com/a/31060154/4077294) answer. – James Ko Jan 01 '16 at 16:45
  • @JamesKo: Good point. I've added a note to my answer. Thanks. – Tim Down Jan 04 '16 at 13:27
  • What does `a new instance of x when calling x as a constructor is indistinguishable from a pre-existing instance of x passed as this when calling x as a function` mean? – Melab Nov 18 '18 at 20:43
  • Sorry. What's the point of `this.__previouslyConstructedByX`? Thank you! – tonix Sep 07 '20 at 21:02
  • With private members landing soonish, this answer works even better now! – Connor Clark Jul 18 '21 at 19:45
57

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

TheHippo
  • 61,720
  • 15
  • 75
  • 100
Greg
  • 316,276
  • 54
  • 369
  • 333
  • 1
    ah, nice. is this.constructor undefined in the 'else'? – Claudiu Dec 15 '08 at 09:06
  • No it's default object constructor because the context of 'this' in that case is the function x itself, as you can see in my redundant answer below which I wouldn't have posted if SO had indicated this was already answered *sigh* – annakata Dec 15 '08 at 09:14
  • @annakata: no worries, your answer is still valuabe. upvote from me in any case. – Claudiu Dec 15 '08 at 09:31
  • 36
    NOTE: The return value is not discarded; if the return value is an Object, then that object is returned instead of the 'this'. – Claudiu Dec 22 '08 at 19:38
  • 2
    this also doesn't work if something like "x.prototype = new Array()", and the x.prototype.constructor field isn't re-assigned. – Claudiu Feb 09 '09 at 01:34
  • 4
    This doesn't work. Behold: { var Z = new x(); Z.lolol = x; Z.lolol();}. It thinks the 2nd invocation is it being called as a constructor. – Claudiu Dec 09 '09 at 20:19
  • 14
    This fails if `window.constructor == x`. Use `instanceof` or `Object.getPrototypeOf`. – Eli Grey Dec 09 '09 at 20:41
  • You probably need to test first if this is not undefined, in strict mode it will throw Error – jcubic Jul 07 '18 at 11:27
  • @Claudiu What do mean by "discarded"? Why does it matter? – Melab Nov 18 '18 at 20:56
20

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.

some
  • 48,070
  • 14
  • 77
  • 93
  • 2
    This doesn't work. Behold: { var Z = new x(); Z.lolol = x; Z.lolol();}. It thinks the 2nd invocation is it being called as a constructor. – Claudiu Dec 09 '09 at 20:14
  • 2
    This doesn't seem to be allowed by `"use strict";`. – Matt Fenwick May 04 '12 at 19:56
  • 3
    @MattFenwick Correct, since `arguments.callee` is forbidden in strict mode. If you replace that with the name of the constructor it should work. – some Sep 03 '12 at 06:42
  • But anonymous functions ("function expressions") can specify bound names: `0, function x() {}`, then `x` will be in its execution context –  May 24 '17 at 13:25
  • The problem Claudiu pointed out was that if the object is constructed, it's`__CCC` will be set to 1, and if the constructor is then _assigned as a method_, then the `this` value will be that object with the function _now being a method_. This also breaks, because all functions declared at global scope in the browser are methods on the `window` object, so if `__CCC` or `this.__CCC` is set in the global scope, or any scope where the function was declared, it will break as well. –  Oct 02 '17 at 18:54
  • 1
    @DaMaxContent Please note that this answer was given in 2008, almost 10 years ago. I tried to give the questioner an answer that would solve the problem the questioner asked. At the time, 10 years ago, this was what was available. There are of course corner cases where it don't work, like the one that Claudiu proposed. I am very sorry that this answer dosen't work for you almost 10 years after it was written. – some Oct 03 '17 at 01:08
  • People will still come across it, much like I did. It is important to keep it as accurate as possible for those viewers. Hence, my commentary –  Oct 03 '17 at 07:06
  • Another better approach (in ES5) is to use a non-leaky WeakMap polyfill that generates random property names. This is more bullet-proof approach than a hard coded property name because people will have to guess the property name or iterate and delete all properties which would obviously be trying to break everything on purpose and therefore pointless. – trusktr Apr 04 '18 at 02:12
  • "use strict"; function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } } function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Polygon = function Polygon(height, width) { _classCallCheck(this, Polygon); this.name = 'Polygon'; this.height = height; this.width = width; }; // the `_classCallCheck` is from Babel/Babylon/6to5 – user1742529 Feb 20 '20 at 04:51
8

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
  }
}
annakata
  • 74,572
  • 17
  • 113
  • 180
  • typeof (this) will always be 'object' in your examples – Greg Dec 15 '08 at 09:21
  • bah, getting ahead of myself should just be testing 'this' directly - edited – annakata Dec 15 '08 at 09:42
  • 1
    note that this.constructor for a non-new call is DOMWindow in Chrome, and undefined in IE , so you can't rely on it. – Claudiu Dec 15 '08 at 09:44
  • but in either of those cases the salient fact is that this.constructor is *still not* a.baz which is what matters – annakata Dec 15 '08 at 10:29
  • yep, definitely - just wanted to point out that "and the system Object constructor otherwise" is not necessarily correct – Claudiu Dec 15 '08 at 12:17
  • Your first one is the only method that worked for me out of all the solutions posted here (including your other ones). – mpen Aug 16 '13 at 05:59
5

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");
            }
        });
Peter Aron Zentai
  • 11,482
  • 5
  • 41
  • 71
  • Of course, this will only work in browsers that have .bind implemented natively, i.e. browsers that support ecmascript 5, but it looks like you've got the only solution here that addresses the problem without adding extra properties to the object. – kybernetikos Feb 25 '13 at 19:41
  • I wanted to add some code to show how your solution solves the specific problem, but apparently it's more appropriate in a comment (sorry that comments don't show code nicely): ```var x = function x(arg) { /* note: strict mode deprecates arguments.callee, but you can use the function name here. */ if (this instanceof x == false) { /* called as a function */ return 30; } }.bind({}); var Z = new x(); console.log(Z); Z.lolol = x; console.log(Z.lolol());``` – kybernetikos Feb 26 '13 at 08:23
  • Of course, a variation on this solution is to keep a reference to the object that the constructor is bound to, and then do an === check against that instead of the instanceof. – kybernetikos Feb 26 '13 at 08:28
  • Whether all this is worth it is debatable, but as far as the question goes this seems to be the best answer as it doesn't require the extra property. +1 – Stijn de Witt Sep 03 '15 at 20:21
4

actually the solution is very possible and simple... don't understand why so many words been written for such a tiny thing

UPDATE: thanks to TwilightSun the solution is now completed, even for the test Claudiu suggested! thank you guys!!!

function Something()
{
    this.constructed;

    if (Something.prototype.isPrototypeOf(this) && !this.constructed)
    {
        console.log("called as a c'tor"); this.constructed = true;
    }
    else
    {
        console.log("called as a function");
    }
}

Something(); //"called as a function"
new Something(); //"called as a c'tor"

demonstrated here: https://jsfiddle.net/9cqtppuf/

ymz
  • 6,602
  • 1
  • 20
  • 39
  • Fails for `x = new Something(); x.func = Something; x.func();`. For the second call it prints called as a c'tor doesn't it? – Claudiu Apr 19 '15 at 16:05
  • 1
    I like this solution. Just add a property on `this` to flag that the constructor is already called if you really care. – TwilightSun Jul 29 '15 at 11:49
  • `isPrototypeOf` is only available in ECMAScript 5 and later. At the time the question was asked, ECMAScript 5 didn't exist; when my answer was written, ECMAScript 5 had been published a week previously and no mainstream browser implemented it. Also, this doesn't seem to be significantly different from my answer; you still have to add an otherwise useless property to your object. – Tim Down Sep 21 '15 at 10:52
3

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
Frunsi
  • 7,099
  • 5
  • 36
  • 42
  • 2
    That's exactly the same as my suggested solution, except using the weaker check on the `constructor` property rather than using `instanceof` – Tim Down Dec 14 '09 at 15:56
3

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.

acelent
  • 7,965
  • 21
  • 39
2

In my testing for http://packagesinjavascript.wordpress.com/ I found the test if (this == window) to be working cross-browser in all cases, so that's the one I ended up using.

-Stijn

2

From John Resig:

function makecls() {

   return function(args) {

        if( this instanceof arguments.callee) {
            if ( typeof this.init == "function")
                this.init.apply(this, args.callee ? args : arguments)
        }else{
            return new arguments.callee(args);
        }
    };
}

var User = makecls();

User.prototype.init = function(first, last){

    this.name = first + last;
};

var user = User("John", "Resig");

user.name
mykhal
  • 19,175
  • 11
  • 72
  • 80
haijin
  • 938
  • 2
  • 11
  • 17
2

Until I saw this thread I never considered that the constructor might be a property of an instance, but I think the following code covers that rare scenario.

// Store instances in a variable to compare against the current this
// Based on Tim Down's solution where instances are tracked
var Klass = (function () {
    // Store references to each instance in a "class"-level closure
    var instances = [];

    // The actual constructor function
    return function () {
        if (this instanceof Klass && instances.indexOf(this) === -1) {
            instances.push(this);
            console.log("constructor");
        } else {
            console.log("not constructor");
        }
    };
}());

var instance = new Klass();  // "constructor"
instance.klass = Klass;
instance.klass();            // "not constructor"

For most cases I'll probably just check instanceof.

  • Oh yeah. IE6 will need an implementation of indexOf added to Array.prototype. –  Sep 16 '10 at 02:08
  • ah nice. I like this answer best so far, since you can't tamper with it as much as if you tack on a property to the object – Claudiu Sep 16 '10 at 13:54
  • ES6 could solve memory leak with `WeakMap` or `WeakSet`. –  May 24 '17 at 14:10
2

If you're going hackish, then instanceof is the minimum solution after new.target as by other answers. But using the instanceof solution it would fail with this example:

let inst = new x;
x.call(inst);

Combining with @TimDown solution, you can use ES6's WeakSet if you want compatibility with older ECMAScript versions to prevent putting properties inside instances. Well, WeakSet will be used in order to allow unused objects be garbage collected. new.target won't be compatible in the same source code, as it is a ES6's syntax feature. ECMAScript specifies identifiers cannot be one of the reserved words, and new is not an object, anyways.

(function factory()
{
    'use strict';
    var log = console.log;

    function x()
    {
        log(isConstructing(this) ?
            'Constructing' :
            'Not constructing'
        );
    }

    var isConstructing, tracks;
    var hasOwnProperty = {}.hasOwnProperty;

    if (typeof WeakMap === 'function')
    {
        tracks = new WeakSet;
        isConstructing = function(inst)
        {
            if (inst instanceof x)
            {
                return tracks.has(inst) ?
                    false : !!tracks.add(inst);
            }
            return false;
        }
    } else {
        isConstructing = function(inst)
        {
            return inst._constructed ?
                false : inst._constructed = true;
        };
    }
    var z = new x; // Constructing
    x.call(z)      // Not constructing
})();

ECMAScript 3's instanceof operator of is specified as:

11.8.6 The instanceof operator
--- The production RelationalExpression: RelationalExpression instanceof ShiftExpression is evaluated as follows:
--- 1. Evaluate RelationalExpression.
--- 2. Call GetValue(Result(1)).
--- 3. Evaluate ShiftExpression.
--- 4. Call GetValue(Result(3)).
--- 5. If Result(4) is not an object, throw a TypeError exception.
--- 6. If Result(4) does not have a [[HasInstance]] method, throw a TypeError exception.
--- 7. Call the [[HasInstance]] method of Result(4) with parameter Result(2).
--- 8. Return Result(7).
15.3.5.3 [[HasInstance]] (V)
--- Assume F is a Function object.
--- When the [[HasInstance]] method of F is called with value V, the following steps are taken:
--- 1. If V is not an object, return false.
--- 2. Call the [[Get]] method of F with property name "prototype".
--- 3. Let O be Result(2).
--- 4. If O is not an object, throw a TypeError exception.
--- 5. Let V be the value of the [[Prototype]] property of V.
--- 6. If V is **null**, return false.
--- 7. If O and V refer to the same object or if they refer to objects joined to each other (13.1.2), return true.
--- 8. Go to step 5.

And that means it'll be recursing the left hand side value after going to its prototype until it is not an object or until it is equal to the prototype of the right hand side object with the specified [[HasInstance]] method. What means it'll check if left hand side is an instance of the right hand side, consuming all internal prototypes of the left hand side though.

function x() {
    if (this instanceof x) {
        /* Probably invoked as constructor */
    } else return 30;
}
1

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
fedeghe
  • 1,243
  • 13
  • 22
1

Although this thread is ancient, I'm surprised that nobody has mentioned that under strict mode ('use strict') a function's default this value is undefined, instead of set to global/window as before, so to check if new is not used simply test for falsey value of !this - EG:

function ctor() { 'use strict';
  if (typeof this === 'undefined') 
    console.log('Function called under strict mode (this == undefined)');
  else if (this == (window || global))
    console.log('Function called normally (this == window)');
  else if (this instanceof ctor)
    console.log('Function called with new (this == instance)');
  return this; 
}

If you test that function as-is, you will get undefined as this value, due to the 'use strict' directive at the start of the function. Of course, if already has strict mode on then it won't change if you remove the 'use strict' directive, but otherwise if you remove it the this value will be set to window or global. If you use new to call the function then the this value will match the instanceof check (although if you checked the other things, then instance is last option so this check is not needed, and to be avoided if you want to inherit instances anyway)

function ctor() { 'use strict';
  if (!this) return ctor.apply(Object.create(ctor.prototype), arguments);
  console.log([this].concat([].slice.call(arguments)));
  return this;
}

This will log the this value and any arguments you pass to the function to console, and return the this value. If the this value is falsey then it creates a new instance using Object.create(ctor.prototype) and uses Function.apply() to re-call the constructor with the same params but with correct instance as this. If the this value is anything other than falsey then it is assumed to be a valid instance and returned.

BoB
  • 71
  • 4
1

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; 
         };
    };
})();
Tom Ebel
  • 11
  • 2
0

If you don't want to put a __previouslyConstructedByX property in the object - because it pollutes the object's public interface and could easily be overwritten - just don't return an instance of x:

function x() {

    if(this instanceof x) {
        console.log("You invoked the new keyword!");
        return that;
    }
    else {
        console.log("No new keyword");
        return undefined;
    }

}

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

Now the x function never returns an object of type x, so (I think) this instanceof x only evaluates to true when the function is invoked with the new keyword.

The downside is this effectively screws up the behaviour of instanceof - but depending on how much you use it (I don't tend to) that may not be a problem.


If you're goal is for both cases to return 30, you could return an instance of Number instead of an instance of x:

function x() {

    if(this instanceof x) {
        console.log("You invoked the new keyword!");
        var that = {};
        return new Number(30);
    }
    else {
        console.log("No new");
        return 30;
    }

}

console.log(x());
var Z = new x();
console.log(Z);
Z.lolol = x;
console.log(Z.lolol());
console.log(new Z.lolol());
Richard JP Le Guen
  • 28,364
  • 7
  • 89
  • 119
0

I had this same problem when I tried to implement a function that returns a string instead of an object.

It seems to be enough to check for the existence of "this" in the beginning of your function:

function RGB(red, green, blue) {
    if (this) {
        throw new Error("RGB can't be instantiated");
    }

    var result = "#";
    result += toHex(red);
    result += toHex(green);
    result += toHex(blue);

    function toHex(dec) {
        var result = dec.toString(16);

        if (result.length < 2) {
            result = "0" + result;
        }

        return result;
    }

    return result;
}

Anyway, in the end I just decided to turn my RGB() pseudoclass into an rgb() function, so I just won't try to instantiate it, thus needing no safety check at all. But that would depend on what you're trying to do.

Diogo Schneider
  • 339
  • 2
  • 9
0

Tim Down I think is correct. I think that once you get to the point where you think you need to be able to distinguish between the two calling modes, then you should not use the "this" keyword. this is unreliable, and it could be the global object, or it could be some completely different object. the fact is, that having a function with these different modes of activation, some of which work as you intended, others do something totally wild, is undesirable. I think maybe you're trying to figure this out because of that.

There is an idiomatic way to create a constructor function that behaves the same no matter how it's called. whether it's like Thing(), new Thing(), or foo.Thing(). It goes like this:

function Thing () {
   var that = Object.create(Thing.prototype);
   that.foo="bar";
   that.bar="baz";
   return that;
}

where Object.create is a new ecmascript 5 standard method which can be implemented in regular javascript like this:

if(!Object.create) {
    Object.create = function(Function){
        // WebReflection Revision
       return function(Object){
           Function.prototype = Object;
           return new Function;
    }}(function(){});
}

Object.create will take an object as a parameter, and return a new object with that passed in object as its prototype.

If however, you really are trying to make a function behave differently depending on how it's called, then you are a bad person and you shouldn't write javascript code.

Breton
  • 15,401
  • 3
  • 59
  • 76
  • 1
    That's an unfortunate choice of parameter names in the `Object.create` implementation: `Function` and `Object` both being native JavaScript objects makes it more confusing to read. – Tim Down Dec 11 '09 at 09:33
  • You're right, but I'll note that I didn't write it. It's simply the best implementation of that particular function I'm able to find. The final ES5 version actually takes some additional parameters, that this won't handle. I await the canonical backwards compatible implementations for ES5 functions. Alas I'm not quite clever enough to write them myself. – Breton Dec 11 '09 at 10:33
0
function createConstructor(func) {
    return func.bind(Object.create(null));
}

var myClass = createConstructor(function myClass() {
    if (this instanceof myClass) {
        console.log('You used the "new" keyword');
    } else {
        console.log('You did NOT use the "new" keyword');
        return;
    }
    // constructor logic here
    // ...
});
Joshua Wise
  • 613
  • 4
  • 15
0

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);
Sumer
  • 2,687
  • 24
  • 24
  • While this doesn't actually answer the OP's question and doesn't handle the specific case where someone does a `Car.call(c1)` and using `instanceof` breaks inheritance, I'd argue that Javascript's inheritance model is broken-by-design and should therefore be prevented in most applications. Also, anyone doing `Car.call(c1)` is intentionally going out of their way to break things, so trying to try to detect that is kind of pointless. Therefore, using `instanceof` and routing "failed to call new" to a new call as above is probably the simplest (and possibly most correct) solution. – CubicleSoft Jun 05 '20 at 16:28
0

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()
Andronicus
  • 25,419
  • 17
  • 47
  • 88
-1

Use this instanceof arguments.callee (optionally replacing arguments.callee with the function it's in, which improves performance) to check if something is called as a constructor. Do not use this.constructor as that can be easily changed.

Eli Grey
  • 35,104
  • 14
  • 75
  • 93
  • Claudiu, I did, but none of them mentioned using `this isntanceof contructorName`. – Eli Grey Dec 09 '09 at 21:32
  • @Eli Grey: Really? I realize that it's almost two years ago since you wrote your comment, but could you please tell me what I used in [my answer](http://stackoverflow.com/questions/367768/how-to-detect-if-a-function-is-called-as-constructor/386903#386903) that was posted a few days short of one year before yours? – some Oct 29 '11 at 02:49
  • I don't know why I would have said that. I must've been on a second page or something. – Eli Grey Oct 29 '11 at 22:20