1

Consider the following code:

const defclass = prototype => {
    const constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
};

const Person = defclass({
    constructor: function Person(firstname, lastname) {
        this.firstname = firstname;
        this.lastname  = lastname;
    },
    get fullname() {
        delete this.fullname; // doesn't delete on instances
        return this.fullname = this.firstname + " " + this.lastname;
    }
});

const john = new Person("John", "Doe");
const jane = new Person("Jane", "Doe");

console.log(john.fullname); // John Doe
console.log(jane.fullname); // Jane Doe

This works because the property assignment on this shadows the non-existent setter.


Now, consider the same code using ES6 classes:

class Person {
    constructor(firstname, lastname) {
        this.firstname = firstname;
        this.lastname  = lastname;
    }

    get fullname() {
        delete this.fullname; // doesn't delete on instances
        return this.fullname = this.firstname + " " + this.lastname;
    }
}

const john = new Person("John", "Doe");
const jane = new Person("Jane", "Doe");

console.log(john.fullname); // throws an error because there is no setter
console.log(jane.fullname);

The reason why it doesn't work is explained in the this answer. It's because we find the property in the prototype chain and it doesn't have a setter. So, why isn't the same error thrown when we use regular prototypes?

Note: You can delete the line with the delete keyword without affecting the behavior of the code.

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299

1 Answers1

2

I do get the same error with the first code:

const defclass = prototype => {
    const constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
};

const Person = defclass({
    constructor: function Person(firstname, lastname) {
        this.firstname = firstname;
        this.lastname  = lastname;
    },
    get fullname() {
        "use strict";
//      ^^^^^^^^^^^^
        return this.fullname = this.firstname + " " + this.lastname;
    }
});

const john = new Person("John", "Doe");
const jane = new Person("Jane", "Doe");

console.log(john.fullname); // John Doe
console.log(jane.fullname); // Jane Doe

It's just that class code is in strict mode by default.

In sloppy mode, the assignment doesn't work but is ignored and the right hand side value is returned from the getter. Accessing .fullname again would run the getter again.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375