Search code examples
javascriptprototype

JS ES6 class syntax and prototype confusion


Okay, so according to my knowledge, we would write a class constructor like so

class User {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    //anything outside of constructor belong to this.prototype

    getName() {
        console.log(this.name);
    }
    getAge() {
        console.log(this.age);
    }
}

So instead, if I write something like this:

class User {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    getName() {
        console.log(this.name);
    }
}

User.prototype.getAge = function () {
    console.log(this.age);
};

It should technically be exactly the same, right? Or I am wrong? Because when I tried this which each one, I get 2 different result:

let user = new User('john', 23);

let properties = [];

for (let prop in user) {
    properties.push(prop);
}

console.log(properties); //The first code result : ["name", "age"]
                         //The second code result : ["name", "age", "getAge"]

So what is the difference between the two?


Solution

  • The difference between the two is that using User.prototype.getAge = ... will add the property with the property descriptor enumerable: true. This means it shows up in for...in loops.

    The for...in statement iterates over all enumerable properties of an object that are keyed by strings (ignoring ones keyed by Symbols), including inherited enumerable properties.

    class User {
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }
    
        getName() {
            console.log(this.name);
        }
    }
    
    User.prototype.getAge = function () {
        console.log(this.age);
    };
    
    let user = new User('john', 23);
    let properties = [];
    
    for (let prop in user) {
        properties.push(prop);
    }
    
    console.log(properties);
    
    console.log(Object.getOwnPropertyDescriptor(User.prototype, "getName"));
    console.log(Object.getOwnPropertyDescriptor(User.prototype, "getAge"));

    If you want to define the prototype the exact same way you'll have to use the same property descriptor. This can be achieved with Object.defineProperty():

    Object.defineProperty(User.prototype, "getAge", {
        value: function () {
            console.log(this.age);
        },
        writable: true,
        enumerable: false,
        configurable: true,
    });