What Values Can a Constructor Return to Avoid Returning This

What values can a constructor return to avoid returning this?

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.

Why do constructors not return values?

What actually happens with the constructor is that the runtime uses type data generated by the compiler to determine how much space is needed to store an object instance in memory, be it on the stack or on the heap.

This space includes all members variables and the vtbl. After this space is allocated, the constructor is called as an internal part of the instantiation and initialization process to initialize the contents of the fields.

Then, when the constructor exits, the runtime returns the newly-created instance. So the reason the constructor doesn't return a value is because it's not called directly by your code, it's called by the memory allocation and object initialization code in the runtime.

Its return value (if it actually has one when compiled down to machine code) is opaque to the user - therefore, you can't specify it.

Is RETURN from constructor necessary when creating object with new

No, returning this is not necessary, but it is valid. If the returned value is an object, new will return that object instead of the newly created object.

See points 11.2.2 and 13.2.2 of ECMAScript 5:

The new operator calls the internal [[Construct]] method on the constructor (usually a function):

11.2.2 The new Operator

The production NewExpression : new NewExpression is evaluated as follows:

  1. Let ref be the result of evaluating NewExpression.
  2. Let constructor be GetValue(ref).
  3. If Type(constructor) is not Object, throw a TypeError exception.
  4. If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.
  5. Return the result of calling the [[Construct]] internal method on constructor, providing no arguments (that is, an empty list of arguments).

The [[Construct]] internal method of functions is described in point 13.2.2:

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.

Changing the return value of a constructor

A class constructor returns the value of this when it gets called by the new keyword.

See What is the 'new' keyword in JavaScript? and How does the new operator work in JavaScript? for details.

Can we change the return value to something else?

Yes, as long as it is an object, you can override the default by using return - as you did in your example code. See What values can a constructor return to avoid returning this? and What is returned from a constructor? for how that works exactly.

If yes, is it a bad practice?

Yes. Having new Car return a function and not a Car instance is weird and unexpected. People do not do this every day, and they shouldn't start doing it :-)

The only exception is the singleton pattern (which of course is problematic itself), where the constructor may return the singleton instance instead of a new one. (There are however other ways to write JS code for creating singletons, which avoid constructors altogether.)

How does constructor return if it doesn't have any return type?

Constructors don't return anything. A constructor simply initializes an instance.

A new instance creation expression

new SomeExample();

produces a reference to a new instance of the specified class

A new class instance is explicitly created when evaluation of a class
instance creation expression (§15.9) causes a class to be
instantiated.

and invokes the corresponding constructor to initialize the created instance

Just before a reference to the newly created object is returned as the
result, the indicated constructor is processed to initialize the new
object using the following procedure:

  1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.

  2. If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then
    evaluate the arguments and process that constructor invocation
    recursively using these same five steps. If that constructor
    invocation completes abruptly, then this procedure completes abruptly
    for the same reason; otherwise, continue with step 5.

  3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If
    this constructor is for a class other than Object, then this
    constructor will begin with an explicit or implicit invocation of a
    superclass constructor (using super). Evaluate the arguments and
    process that superclass constructor invocation recursively using these
    same five steps. If that constructor invocation completes abruptly,
    then this procedure completes abruptly for the same reason. Otherwise,
    continue with step 4.

  4. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable
    initializers to the corresponding instance variables, in the
    left-to-right order in which they appear textually in the source code
    for the class. If execution of any of these initializers results in an
    exception, then no further initializers are processed and this
    procedure completes abruptly with that same exception. Otherwise,
    continue with step 5.

  5. Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the
    same reason. Otherwise, this procedure completes normally.

What is returned from a constructor?

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');

Return from a javascript function when using NEW

From Mozilla JavaScript Reference:

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.)

In simpler words, this is how constructor calling works in JavaScript, i.e. if you return nothing or a primitive type (like plain string or numbers) or this, then they will be ignored and this will eventually be returned. However if you return an object or function from the constructor, that object will be returned with new.

I borrowed the following code from this blog post, which may be helpful here.

// Undefined return value.
function A() {
return;
}
// Reference to instance.

function B() {
return (this);
}
// String return value.

function C() {
return ("string");
}
// Number retun value.

function D() {
return (123);
}
// New object return value.

function E() {
return ({
foo: "bar"
});
}
// New array return value.

function F() {
return (["foo", "bar"]);
}
// New instantiation return value.

function G() {
return (new A());
}
// Native "object" return value -- this one would be the same
// for Number, Boolean, and String.

function H() {
return (new Number(123));
}
// -------------------------------------------------- //
// -------------------------------------------------- //
// See what reference we have as a result of instantiation.

console.log(new A());
console.log(new B());
console.log(new C());
console.log(new D());
console.log(new E());
console.log(new F());
console.log(new G());
console.log(new H());

this returns

A {}
B {}
C {}
D {}
Object { foo="bar"}
["foo", "bar"]
A {}
Number {}

Strange behaviour of Javascript `new` from `function`

When you use the new operator it creates an object.

The return value is as expected. If in the return it is an object will return that object otherwise if the return it is a function will return that function.

function A(){
this.b = 3;
return function(){return 4;};
}
function B(){
this.b = 3;
return { d:4};
}

console.log(typeof (new A())); //function
console.log(typeof (new B())); //object {d:4}

If any other value or non-existent in the return, this operator will take precedence returned as an object.

function C(){
this.b = 3;
return "78";
}
console.log(typeof (new C())); // object {b:3}


Related Topics



Leave a reply



Submit