Jan Turoň
Jan Turoň

Reputation: 32912

Behavior of 'return' and 'new' in constructors

I wonder what's the difference between these two calls:

var a = Array(1,2,3);
var b = new Array(1,2,3);

I tried to mimic the behavior this way:

function test() {
  return {x:42};
}

var a = test();
var b = new test();
console.log(a,b); // the same

How is that possible that b is the same like a? If new is used, the return value should be ignored:

function test() {
  return 1;
}

var a = test();
var b = new test();
console.log(a,b); // 1 test{}

Upvotes: 2

Views: 71

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074168

When you call a function using new, a new object is created and passed into the function as this. If the function doesn't return anything (or returns a primitive), that new object that was passed in is the result of the new expression. But, if the function returns an object, that new object that was created is thrown away and the object returned by the function is the result of the new expression instead. This is covered in turgid prose in Section 11.2.2 of the spec. It's mostly useful for immutable objects where the constructor maintains some kind of cache and reuses instances if the arguments are identical (or of course, singletons).

So in your example, since your test function returns an object, calling it via new just creates and throws away the object created by the new operator, and the result is the object you're returning from test instead.

I probably shouldn't say that the object from new is necessarily "thrown away" if you return a different object. The constructor might do something with the object from new that keeps it from being thrown away. For instance, you could write a constructor like this:

function WeirdConstructor() {
    return {
        theNewObject: this
    };
}

...which takes the object created by new and makes it a property of the object it returns. To call this a special scenario is to put it mildly. :-)

The fact that Array(1, 2, 3) and new Array(1, 2, 3) both return a new array is actually just a special feature of the Array constructor, covered by Section 15.4.1. The spec carefully lays out what each of the standard constructors does if you don't call them via new. The behavior varies. Many of them do type coercion, a couple like Array just act like you used new even though you didn't, and Date does a really weird thing (gives you a string version of the current date, basically String(new Date())).


Specifically regarding Array: I wouldn't use either Array(1, 2, 3) or new Array(1, 2, 3). I'd use [1, 2, 3]. It's not ambiguous (does new Array(3) create a blank array with length = 3 or an array with one entry, 3, in it? what about new Array("3")?), and it's possible (though unlikely) someone could shadow the symbol Array, but they can't shadow the literal form. But I don't think that was the point of your question. :-)

Upvotes: 11

Related Questions