What values can a constructor return to avoid returning this?
Solution 1
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))
isObject
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.
Solution 2
Concrete examples http://jsbin.com/zivivucahi/1/edit?html,js,console,output
/*
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('%')));
Solution 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).
Solution 4
Trying to put a few points in simpler words.
In javascript, when you use a new
keyword on a function and if,
- 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'
- 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
- 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'
Solution 5
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.
Thomas Eding
Updated on January 15, 2020Comments
-
Thomas Eding over 4 years
What are the exact circumstances for which a
return
statement in Javascript can return a value other thanthis
when a constructor is invoked using thenew
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. Otherwisesomething
is returned. Is this correct?In other words, what values can
something
take to cause(new Foo () instanceof Foo) === false
? -
Thomas Eding over 14 yearsI'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
. -
Camilo Martin over 11 yearsBy the way: this happens because
new Number(5)
(or even justNumber(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
. -
B T almost 11 yearsAdditional note: typeof(null) is "object", however returning null does not trigger step 7 to happen
-
Jo So over 10 years@BT: Testing on my node.js installation, it seems like "
Type(x)
isObject
" in the spec as cited above means "x instanceof Object
istrue
", not "typeof(x) === 'object'
istrue
". For example,null instanceof Object
evaluates to false (and indeed you can't returnnull
from a constructor), andnew String("asdf") instanceof Object
evaluates to true (and indeed you can return a String from the constructor...) -
Camilo Martin almost 10 yearsTwo 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)}
-
bcherny over 9 years@JoSo I think Type refers to an object's internal
[[Class]]
property. The best proxy for that value that we have from within JavaScript isObject.prototype.toString.call(x)
-
Guffa over 9 yearsWhy the downvote? If you don't explain what it is that you think is wrong, it can't improve the answer.
-
Bergi over 9 years@JoSo: No. It means that
x
is not a primitive value, but an object (including arrays, functions etc). It does have nothing to do withtypeof
orinstanceof
. -
MartianMartian over 5 yearsgreat example! lll
-
MartianMartian over 5 yearsjust add this: new Person({"stuff":"stuff"}) // {"stuff":"stuff"}
-
MartianMartian over 5 yearsbut why null doesn't get returned ?
-
Christian C. Salvadó over 5 years@Martian2049, because the internal type of a
null
value is the Null Type, internally, you may think that is "object" sincetypeof null == 'object'
, but that's not what the internal Type operation detects. It will return the object created in step 1 just because internally, thenull
value internal type is Null, not Object.