42

If I return some value or object in constructor function, what will the var get?

function MyConstroctor()
{
    //what in case when return 5;
    //what in case when return someObject;
}

var n = new MyConstroctor();

what n will get in both cases?

Actually its a quiz question, what will be the answer?
What is returned from a custom object constructor?
a)The newly-instantiated object
b)undefined - constructors do not return values
c)Whatever is the return statement
d)Whatever is the return statement; the newly-instantiated object if no return statement

coure2011
  • 40,286
  • 83
  • 216
  • 349
  • 1
    related: [What values can a constructor return to avoid returning this?](http://stackoverflow.com/q/1978049/1048572) – Bergi Jul 19 '14 at 16:55
  • 4
    MyConstroctor is great. Never edit that. You've come a long way coure2011. – ADJenks Jun 23 '20 at 17:45

7 Answers7

97

Short Answer

The constructor returns the this object.

function Car() {
   this.num_wheels = 4;
}

// car = { num_wheels:4 };
var car = new Car();

Long Answer

By the Javascript spec, when a function is invoked with new, Javascript creates a new object, then sets the "constructor" property of that object to the function invoked, and finally assigns that object to the name this. You then have access to the this object from the body of the function.

Once the function body is executed, Javascript will return:

ANY object if the type of the returned value is object:

function Car(){
  this.num_wheels = 4;
  return { num_wheels:37 };
}

var car = new Car();
alert(car.num_wheels); // 37

The this object if the function has no return statement OR if the function returns a value of a type other than object:

function Car() {
  this.num_wheels = 4;
  return 'VROOM';
}

var car = new Car();
alert(car.num_wheels); // 4
alert(Car()); // No 'new', so the alert will show 'VROOM'
Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51
Kenan Banks
  • 207,056
  • 34
  • 155
  • 173
57

Basically if your constructor returns a primitive value, such as a string, number, boolean, null or undefined, (or you don't return anything which is equivalent to returning undefined), a newly created object that inherits from the constructor's prototype will be returned.

That's the object you have access with the this keyword inside the constructor when called with the new keyword.

For example:

function Test() {
  return 5; // returning a primitive
}

var obj = new Test();
obj == 5; // false
obj instanceof Test; // true, it inherits from Test.prototype
Test.prototype.isPrototypeOf(obj); // true

But if the returned value is an object reference, that will be the returned value, e.g.:

function Test2() {
  this.foo = ""; // the object referred by `this` will be lost...
  return {foo: 'bar'};
}

var obj = new Test2();
obj.foo; // "bar"

If you are interested on the internals of the new operator, you can check the algorithm of the [[Construct]] internal operation, is the one responsible of creating the new object that inherits from the constructor's prototype, and to decide what to return:

13.2.2 [[Construct]]

When the [[Construct]] internal method for a Function object F is called with a possibly empty list of arguments, the following steps are taken:

  1. Let obj be a newly created native ECMAScript object.
  2. Set all the internal methods of obj as specified in 8.12.
  3. Set the [[Class]] internal property of obj to "Object".
  4. Set the [[Extensible]] internal property of obj to true.
  5. Let proto be the value of calling the [[Get]] internal property of F with argument "prototype".
  6. If Type(proto) is Object, set the[[Prototype]]` internal property of obj to proto.
  7. If Type(proto) is not Object, set the [[Prototype]] internal property of obj to the standard built-in Object prototype object as described in 15.2.4.
  8. Let result be the result of calling the [[Call]] internal property of F, providing obj as the this value and providing the argument list passed into [[Construct]] as args.
  9. If Type(result) is Object then return result.
  10. Return obj.
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • @CMS so basically if you set some attributes on a `function object` via `this` and **return a primitive** or anything else from a `function object` except an `object` itself, 2 things happen: 1. when you create a new instance with it via the `new` keyword that primitive return value is meaningless but the attributes are set on the newly created object, however if you return an `object` the previously set attributes are **lost**. 2. when you call it as a normal function, those attributes are set on `window` and you get the primitive value that you've returned. Is this accurate? – Marius Mucenicu Jun 13 '19 at 14:12
  • @George, yes, it's accurate. Just note that for your point no. 2, if you are on strict mode, on a "normal function call" `this` will be `undefined`. This will produce a `TypeError` when trying to assign a property to it. – Christian C. Salvadó Jun 13 '19 at 16:48
  • 1
    @CMS the link appears to be broken. It either times out or redirects to a non programming page. I believe either one of these: [this](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-ordinarycreatefromconstructor) or [this](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-getprototypefromconstructor) describe what you described above. Would you please update the answer with the relevant link so that folks can go to the appropriate page. Thx! – Marius Mucenicu Jun 14 '19 at 05:33
  • 1
    @George, thanks for noticing!. On the last version of the spec would be [this section](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-ecmascript-function-objects-construct-argumentslist-newtarget) but the described algorithm in my answer was from ES5. – Christian C. Salvadó Jun 14 '19 at 12:29
  • @CMS surprisingly if I return a **function** it does return that **function**. So for instance if I write a closure and I return the reference to the inner function it does return that reference. From step **10** I would have expected it to return `object` just like when I return a primitive. Hmm.. Please take a look at [this example](https://pastebin.com/WC5hK6th) for what I'm trying to say. – Marius Mucenicu Jun 17 '19 at 10:08
  • @George, how are you running the code ? It seems to work as expected to me, check: https://runkit.com/cms/5d078aeb9ab09c001a631a40 – Christian C. Salvadó Jun 17 '19 at 12:46
  • We've got the same results but I would've expected the return to be an `object` not a `function`. I thought anything other than an `object` gets discarded and an `object` gets returned. If you return a `primitive` that is meaningless and you get an `object`, if you return a `function` however, you get that `function`. Interesting.. – Marius Mucenicu Jun 17 '19 at 13:01
  • @George, Ah! I see what you mean, functions are just objects with special characteristics, they are not primitive values. Primitive values are values of types: number, string, boolean, null, undefined and symbols... Functions are just special objects! – Christian C. Salvadó Jun 17 '19 at 13:48
  • @George, I know the `typeof` operator makes it sound like there is actually a 'function type' but that's not the case. The expression `typeof x == 'function'` just tells you `x` is *"callable"* as a function. (note that calling a function, and using the new operator are two different operations. For instance, arrow functions are callable, but you cannot use `new` with them.) – Christian C. Salvadó Jun 17 '19 at 15:42
  • @CMS thanks for all your inputs! made everything more clear. I wish I could understand the spec a bit more...usually one should go to the spec when official docs like w3schools or MDN are ambiguous, but that formal grammar of the spec is not so obvious :( – Marius Mucenicu Jun 18 '19 at 04:37
  • 1
    @George, you're welcome. Yes, the spec. language is quite technical and dry. I guess I got used to it, I started geeking out and reading it since the 3rd edition. Now it's considerably more complex than it was before. If you have any questions, feel free to contact me through twitter or drop me a mail: c@cms.gt Cheers! – Christian C. Salvadó Jun 18 '19 at 17:53
26

I found this great link:

JavaScript: Constructor Return Value

The second piece of magic eluded to above is the ability for a constructor to return a specific, possibly pre-existing object, rather than a reference to a new instance. This would allow you to manage the number of actual instances yourself if needed; possibly for reasons of limited resources or whatnot.

var g_deebee = new Deebee();
function Deebee() { return g_deebee; }
var db1 = new Deebee();
var db2 = new Deebee();
if (db1 != db2)
  throw Error("JS constructor returned wrong object!");
else console.log('Equal');
namgold
  • 1,009
  • 1
  • 11
  • 32
Haim Evgi
  • 123,187
  • 45
  • 217
  • 223
  • 1
    Here is the archive link: https://web.archive.org/web/20100216124827/http://www.gibdon.com/2008/08/javascript-constructor-return-value.html – Kamafeather Jul 19 '17 at 17:14
  • What about garbage collection? The article in the link above alludes to "managing it procedurally", but the article is now 10 years old. Is there any change to that in newer implementations of javascript classes? I don't think you can put this at the end of your constructor: `delete this;` Or can you? Otherwise you have to stash `this` somewhere global so that the function calling the constructor can delete it. Any further insights into this? I'm not trying to use this feature to manage instances. I'm using it, in certain cases, to return an instance of a different class. – Sideways S Sep 15 '18 at 16:01
2

It's as easy as it said in documentation (new operator) :

The object returned by the constructor function becomes the result of the whole new expression. If the constructor function doesn't explicitly return an object, the object created in step 1 is used instead. (Normally constructors don't return a value, but they can choose to do so if they want to override the normal object creation process.)

Philipp Munin
  • 5,610
  • 7
  • 37
  • 60
2

Trying to simplify the existing answers by providing discrete examples proving that:

Only constructors that return primitive or undefined implicitly create a new instance of themselves. Otherwise the exact object returned by the constructor is used as is.

Consider the following constructor that returns exactly what we pass to it. Check the usages:

//A constructor returning the passed value, or not returning at all.
function MyConstructor(obj){
    if(obj!==undefined){
        return obj;
    }
    //else do not call return
}

//no value passed (no value is returned from constructor)
console.log((new MyConstructor()) instanceof MyConstructor)
//true

//Primitive passed:
console.log((new MyConstructor(1)) instanceof MyConstructor)
//true
console.log((new MyConstructor(false)) instanceof MyConstructor)
//true
console.log((new MyConstructor("1")) instanceof MyConstructor)
//true
console.log((new MyConstructor(1.0)) instanceof MyConstructor)
//true

//Object passed
console.log((new MyConstructor(new Number(1))) instanceof MyConstructor)
//false
console.log((new MyConstructor({num:1})) instanceof MyConstructor)
//false
console.log((new MyConstructor([1])) instanceof MyConstructor)
//false
console.log((new MyConstructor(MyConstructor)) instanceof MyConstructor)
//false

//Same results if we use: MyConstructor.prototype.isPrototypeOf(new MyConstructor()) e.t.c..

The same rules as above apply also for class constructors. This means that, if the constructor does not return undefined or primitive, we can have the following, which might feel weird to people coming from java:

(new MyClass()) instanceof MyClass //false

Using the same constructor, check in practice how the instance is different when undefined or primitive is returned:

//As above
function MyConstructor(obj){
    if(obj!==undefined){
        return obj;
    }
    //else do not call return
}

//Same object passed (same instance to both variables)
let obj = {};
let a1 = new MyConstructor(obj)
let a2 = new MyConstructor(obj)

a1.x=1
a2.x=2

console.log(a1.x === a2.x, a1.x, a2.x)
//true 2 2

//undefined passed (different instance to each variable)
let b1 = new MyConstructor()
let b2 = new MyConstructor()

b1.x=1
b2.x=2
console.log(b1.x === b2.x, b1.x, b2.x)
//false 1 2

//Primitive passed (different instance to each variable)
let c1 = new MyConstructor(5)
let c2 = new MyConstructor(5)

c1.x=1
c2.x=2
console.log(c1.x === c2.x, c1.x, c2.x)
//false 1 2

Additional note: Sometimes a function could act as a constructor even if it is not called as a constructor:

function F(){
    //If not called as a constructor, call as a constructor and return the result
    if(!new.target){
        return new F();
    }
}

console.log(F() instanceof F)
//true
console.log(new F() instanceof F)
//true
Marinos An
  • 9,481
  • 6
  • 63
  • 96
1

You shouldn't return anything in a constructor. A constructor is used to initialize the object. In case you want to know what happens is that if you return 5 then n will simply be an empty object and if you return for example { a: 5 }, then n will have a property a=5.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 1
    see my comment http://www.gibdon.com/2008/08/javascript-constructor-return-value.html – Haim Evgi Jul 28 '10 at 05:53
  • 1
    If you return 5 you will get an empty object, and if you return an object then n will probably point to this object. – Darin Dimitrov Jul 28 '10 at 05:54
  • Nope, just tested on firefox, if i return 5 it gives me default object. and if i return some object it gives me that object. – coure2011 Jul 28 '10 at 06:00
  • 1
    There are actually many common OOP patterns in Javascript that do manually return an object in a constructor. Even Douglas Crockford is ok with it. – Kenan Banks Jul 28 '10 at 06:27
1

To answer your specific question:

function MyConstructor()
{
    return 5;
}
var n = new MyConstructor();

n is an object instance of MyConstructor.

function SomeObject(name) {
    this.name = name;
    this.shout = function() {
        alert("Hello " + this.name)
    }
} 

function MyConstructor()
{
    return new SomeObject("coure06");
}

var n = new MyConstructor();

 n.shout();

n is an instance of SomeObject (call n.shout() to prove it)

To make this all absolutely clear...

1) If you return a primitive type, like a number or a string, it will be ignored. 2) Otherwise, you will pass back the object

Functions and constructors are exactly the same in JavaScript, but how you call them changes their behaviour. A quick example of this is below...

function AddTwoNumbers(first, second) {
    return first + second;
}

var functionCall = AddTwoNumbers(5, 3);
alert(functionCall);// 8

var constructorCall = new AddTwoNumbers(5, 3);
alert(constructorCall);// object
Fenton
  • 241,084
  • 71
  • 387
  • 401