92

What are the exact circumstances for which a return statement in Javascript can return a value other than this when a constructor is invoked using the new keyword?

Example:

function Foo () {
  return something;
}

var foo = new Foo ();

If I'm not mistaken, if something is a non-function primitive, this will be returned. Otherwise something is returned. Is this correct?

In other words, what values can something take to cause (new Foo () instanceof Foo) === false?

ruffin
  • 16,507
  • 9
  • 88
  • 138
Thomas Eding
  • 35,312
  • 13
  • 75
  • 106
  • related: [What is returned from a constructor?](http://stackoverflow.com/q/3350215/1048572) – Bergi Jul 19 '14 at 16:54

6 Answers6

163

The exact condition is described on the [[Construct]] internal property, which is used by the new operator:

From the ECMA-262 3rd. Edition Specification:

13.2.2 [[Construct]]

When the [[Construct]] property for a Function object F is called, the following steps are taken:

  1. Create a new native ECMAScript object.
  2. Set the [[Class]] property of Result(1) to "Object".
  3. Get the value of the prototype property of F.
  4. If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).
  5. If Result(3) is not an object, set the [[Prototype]] property of Result(1) to the original Object prototype object as described in 15.2.3.1.
  6. Invoke the [[Call]] property of F, providing Result(1) as the this value and providing the argument list passed into [[Construct]] as the argument values.
  7. If Type(Result(6)) is Object then return Result(6).
  8. Return Result(1).

Look at steps 7 and 8, the new object will be returned only if the type of Result(6) (the value returned from the F constructor function) is not an Object.

ruffin
  • 16,507
  • 9
  • 88
  • 138
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • 16
    Additional note: typeof(null) is "object", however returning null does *not* trigger step 7 to happen – B T Jul 25 '13 at 06:51
  • 8
    @BT: Testing on my node.js installation, it seems like "`Type(x)` is `Object`" in the spec as cited above means "`x instanceof Object` is `true`", *not* "`typeof(x) === 'object'` is `true`". For example, `null instanceof Object` evaluates to false (and indeed you can't return `null` from a constructor), and `new String("asdf") instanceof Object` evaluates to true (and indeed you can return a String from the constructor...) – Jo So Jan 24 '14 at 16:29
  • @JoSo I think Type refers to an object's internal `[[Class]]` property. The best proxy for that value that we have from within JavaScript is `Object.prototype.toString.call(x)` – bcherny Nov 05 '14 at 06:04
  • 3
    @JoSo: No. It means that `x` is not a primitive value, but an object (including arrays, functions etc). It does have nothing to do with `typeof` or `instanceof`. – Bergi Mar 17 '15 at 11:43
  • 1
    but why null doesn't get returned ? – MartianMartian Jan 03 '19 at 12:50
  • 2
    @Martian2049, because the internal type of a `null` value is the [Null Type](https://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-language-types-null-type), internally, you may think that is "object" since `typeof null == 'object'`, but that's not what the internal Type operation detects. It will return the object created in step 1 just because internally, the `null` value _internal type_ is Null, not Object. – Christian C. Salvadó Jan 03 '19 at 16:33
4

Concrete examples

/*
ECMA 262 v 5
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
"4.3.2
primitive value
member of one of the types Undefined, Null, Boolean, Number, Symbol, or String as defined in clause 6"
*/

var Person = function(x){
  return x;
};


console.log(Person.constructor);
console.log(Person.prototype.constructor);
console.log(typeof(Person));
console.log(typeof(Person.prototype));

function log(x){
  console.log(x instanceof Person);
  console.log(typeof x);
  console.log(typeof x.prototype);
}

log(new Person(undefined));
log(new Person(null));
log(new Person(true));
log(new Person(2));
log(new Person(""));

//returns a function not an object
log(new Person(function(){}));


//implementation?
//log(new Person(Symbol('%')));
EzioMercer
  • 1,502
  • 2
  • 7
  • 23
philn5d
  • 636
  • 7
  • 12
3

I couldn't find any documentation on the matter, but I think you're correct. For example, you can return new Number(5) from a constructor, but not the literal 5 (which is ignored and this is returned instead).

mkrause
  • 1,370
  • 1
  • 10
  • 11
  • 1
    By the way: this happens because `new Number(5)` (or even just `Number(5)`, as it is intended to work just the same if called as a function) creates a number *object*, for example this means that while `'' == false`, `!!new String('') == true`. – Camilo Martin Sep 30 '12 at 02:53
  • 1
    Two years later and ready to reply to correct my own comment, this works: `function One(){return new Number(1)}` but this doesn't: `function One(){return Number(1)}` – Camilo Martin Sep 19 '14 at 02:00
1

As a side note, the return value or this is just part of the equation.

For example, consider this:

function Two() { return new Number(2); }
var two = new Two;
two + 2; // 4
two.valueOf = function() { return 3; }
two + 2; // 5
two.valueOf = function() { return '2'; }
two + 2; // '22'

As you can see, .valueOf() is internally used and can be exploited for fun and profit. You can even create side effects, for example:

function AutoIncrementingNumber(start) {
    var n = new Number, val = start || 0;
    n.valueOf = function() { return val++; };
    return n;
}
var auto = new AutoIncrementingNumber(42);
auto + 1; // 43
auto + 1; // 44
auto + 1; // 45

I can imagine this must have some sort of practical application. And it doesn't have to be explicitly a Number either, if you add .valueOf to any object it can behave as a number:

({valueOf: function() { return Math.random(); }}) + 1; // 1.6451723610516638

You can exploit this to make an object that always returns a new GUID, for instance.

Camilo Martin
  • 37,236
  • 20
  • 111
  • 154
1

Trying to put a few points in simpler words.

In javascript, when you use a new keyword on a function and if,

  1. function does not return anything, it will return an intended object

function User() {
  this.name = 'Virat'
}

var user = new User();
console.log(user.name); //=> 'Virat'
  1. function returns any truthy complex object [object, array, function etc], that complex object takes priority and user variable will hold the returned complex object

function User() {
  this.name = 'Virat';
  return function(){};
}

var user = new User();
console.log(user.name); //=> undefined
console.log(user); //=> function
  1. function returns any literal, constructor takes priority and it will return an intended object

function User() {
  this.name = 'Virat';
  return 10;
}

var user = new User();
console.log(user.name); //=> 'Virat'
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Ravindra Thorat
  • 1,822
  • 1
  • 17
  • 24
-1

When you are using the new keyword, an object is created. Then the function is called to initialise the object.

There is nothing that the function can do to prevent the object being created, as that is done before the function is called.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • 2
    I'm not taking about that. I know you can do what I claim (I've tried it), but I don't know the definitive cases for which it occurs. In my example, it IS possible to end up with `(foo instanceof Foo) === false`. – Thomas Eding Dec 30 '09 at 02:19
  • Why the downvote? If you don't explain what it is that you think is wrong, it can't improve the answer. – Guffa Jan 02 '15 at 11:32