TL;DR You can't have both a data property and an accessor property with the same name on the same object, and if you have a data property on an object, any property with the same name on its prototype won't be used (unless you do so explicitly). The name
class field definition creates an own data property on the object being constructed.
In the first case (as I think you know), this.name
inside the name
setter calls the name
setter again, recursing until you run out of stack. (And the same for the getter, if you used it.)
So what's different when you have that name
field definition there?
The way class fields are defined, that name
definition creates an own property on the instance being created, as though you had this code at the beginning of the constructor (just after a super
call if this were a subclass):
constructor(name) {
// Definition of `name` field:
Object.defineProperty(this, "name", {
value: undefined,
writable: true,
configurable: true,
enumerable: true,
});
// Remainder of constructor code:
this.name = name;
}
Since it's an own
property, this.name
resolves to that data property, not to the accessor property on the prototype that the get name
and set name
accessor definitions create. So those accessors on p
's prototype are never used.
You can see that if you look at the definition of the property in your second example:
class client {
name = null;
constructor(name){
this.name = name;
}
get name()
{
return this.name ;
}
set name(val)
{
this.name = val ;
}
}
let p = new client();
console.log(p) ;
console.log(Object.getOwnPropertyDescriptor(p, "name"));
If you want to have the accessor property, you could use a private field, which is quite new but supported in modern environments:
class Client {
#name = null;
constructor(name) {
this.#name = name;
}
get name() {
return this.#name;
}
set name(val) {
this.#name = val;
}
}
let p = new Client("Joe");
console.log(p.name);
console.log(Object.getOwnPropertyDescriptor(p, "name")); // undefined
console.log(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(p), "name")); // accessor
.as-console-wrapper {
max-height: 100% !important;
}