Found a great SO post on this topic:
When the [[Construct]]
property for a Function
object F
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 original
Object` prototype object as described in 15.2.3.1. - Invoke the
[[Call]]
property of F, providingResult(1)
as the this 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)
.
Let me translate that into code:
function Person() {}
var p1 = new Person();
//step 1
var newObj = {}
//step 2: I don't know what [[Class]] property is and I cannot find any reference so I will skip this step
//step 3:
var functionProto = Person.prototype;
if (typeof functionProto === 'object'){
//step 4:
newObj.__proto__ = functionProto;
} else {
//step 5:
newObj.__proto = Object.prototype;
}
//step 6:
Person.call(newObj, arguments);
if (typeof newPerson === 'object'){
//step 7:
return newPerson;
} else {
//step 8:
return newObj;
}
You can add an return
statement in the constructor to hijack what it returns:
function Person(){
return {};
}
var p1 = new Person(); // p1 is just a plain object not an instance of Person
If the returned object is not an object, then step 8 kicks in:
function Person(){
return 2;
}
var p1 = new Person(); // p1 is an instance object of Person instead of 2