12 months ago

Found a great SO post on this topic:

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 originalObject` prototype object as described in
  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).

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
← JavaScript __proto___ and Function.prototype Django CSRF cookie not set →
comments powered by Disqus