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 aFunction
objectF
is
called, the following steps are taken:
- Create a new native ECMAScript object.
- Set the
[[Class]]
property ofResult(1)
to"Object"
.- Get the value of the prototype property of
F
.- If
Result(3)
is an object, set the[[Prototype]]
property ofResult(1)
toResult(3)
.- If
Result(3)
is not an object, set the[[Prototype]]
property ofResult(1)
to the originalObject
prototype object as
described in 15.2.3.1.- Invoke the
[[Call]]
property ofF
, providingResult(1)
as thethis
value and
providing the argument list passed into[[Construct]]
as the
argument values.- If
Type(Result(6))
is
Object
then returnResult(6)
.- 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:
- Let ref be the result of evaluating NewExpression.
- Let constructor be GetValue(ref).
- If Type(constructor) is not Object, throw a TypeError exception.
- If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.
- 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:
- Let obj be a newly created native ECMAScript object.
- Set all the internal methods of obj as specified in 8.12.
- Set the [[Class]] internal property of obj to "Object".
- Set the [[Extensible]] internal property of obj to true.
- Let proto be the value of calling the [[Get]] internal property of F with argument "prototype".
- If Type(proto) is Object, set the [[Prototype]] internal property of obj to proto.
- 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.- 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.
- If Type(result) is Object then return result.
- Return obj.
Changing the return value of a constructor
A class constructor returns the value of
this
when it gets called by thenew
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:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
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.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.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.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
Determining Image File Size + Dimensions via JavaScript
Why Are Callbacks from Promise '.Then' Methods an Anti-Pattern
What Is the Meaning of "$" Sign in JavaScript
What Is the Meaning of the 'G' Flag in Regular Expressions
What Is Minimum Millisecond Value of Settimeout
What Is Typescript and Why Would I Use It in Place of JavaScript
Object.Watch() for All Browsers
Js Client-Side Exif Orientation: Rotate and Mirror Jpeg Images
React Native - Image Require Module Using Dynamic Names
How to Find Events Bound on an Element with Jquery
Mongoose and Multiple Database in Single Node.Js Project
JavaScript Document.Getelementsbyclassname Compatibility with Ie
Preserving a Reference to "This" in JavaScript Prototype Functions
How to Convert an Array of Objects to Object with Key Value Pairs