Search code examples
javascriptprototype

How instanceof works?


Given this code:

/**
 * Transform base class
 */
function Transform() {
    this.type = "2d";
}

Transform.prototype.toString = function() {
    return "Transform";
}

/**
 * Translation class.
 */
function Translation(x, y) {
    // Parent constructor
    Transform.call(this);

    // Public properties
    this.x = x;
    this.y = y;
}

// Inheritance
Translation.prototype = Object.create(Transform.prototype);

translation = new Translation(10, 15);

console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true

console.log(translation.__proto__); // Transform
console.log(translation.constructor); // Transform

Why translation.constructor is Transform and not Translation? Also, which property allows instanceof to know that translation is an instance of Translation (if it's not __proto__ nor constructor)?


Solution

  • Why translation.constructor is Transform and not Translation?

    Because you have missed a step while creating a subclass Translation. Every function gets a default prototype property and this has a constructor property equal to the function itself.

    function Translation() {
    }
    
    const translation = new Translation();
    
    console.log(Translation.prototype.constructor === Translation)
    console.log(translation.constructor === Translation)
    
    console.log(translation.__proto__ === Translation.prototype)
    console.log(Object.getPrototypeOf(translation) === Translation.prototype)

    So, why doesn't translation.constructor return Translation in your case? Because, to inherit from Transform, the default prototype is overwritten.

    Translation.prototype = Object.create(Transform.prototype);
    

    ^ When you did that, the default prototype object which had the constructor got overwritten with a new object. If you check the documentation for Classical inheritance, you have missed a step in creating this inheritance. You need to set the constructor property to the original function. This will help identify the constructor function that created an object

    Translation.prototype.constructor = Translation
    

    If you don't add this, a call to translation.constructor will be as follows:

    • It will look for a constructor property directly on the object. It doesn't exist.
    • Then it will look inside Translation.prototype. This object was overwritten by the Object.create(Transform.prototype) line and the object doesn't have any own properties.
    • Translation.prototype falls back to Transform.prototype. There is a constructor property here an it is the function Transform. This is why you get Transform

    And as to why instanceof works is explained in this answer from the duplicate.