Si declaramos una clase como esta:
class client{ constructor(name){ this.name = name } get name() { return this.name ; } set name(val) { this.name = val ; } }Instanciarlo dará un error (demasiada recursividad) y eso es normal porque el setter se llamará a sí mismo.
class client{ constructor(name){ this.name = name } get name() { return this.name ; } set name(val) { this.name = val ; } } let cl = new client();Pero cuando declaro 'nombre' como campo de clase, no recibo ese error, no entiendo por qué.
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) ;TL; DR No puede tener una propiedad de datos y una propiedad de acceso con el mismo nombre en el mismo objeto, y si tiene una propiedad de datos en un objeto, no se usará ninguna propiedad con el mismo nombre en su prototipo (a menos que lo haga explícitamente). La definición de campo de clase de name crea una propiedad de datos propia en el objeto que se está construyendo.
En el primer caso (como creo que sabes), this.name dentro del setter de name llama al setter de name nuevamente, recursivamente hasta que te quedas sin pila. (Y lo mismo para el getter, si lo usaste).
Entonces, ¿qué es diferente cuando tienes esa definición de campo de name allí?
La forma en que se definen los campos de clase, esa definición de name crea una propiedad propia en la instancia que se está creando, como si tuviera este código al comienzo del constructor (justo después de una super si se tratara de una subclase):
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; } Dado que es una propiedad own , this.name resuelve en esa propiedad de datos, no en la propiedad de acceso en el prototipo que crean las definiciones de acceso de get name y set name . Entonces, esos accesores en el prototipo de p nunca se usan.
Puede ver eso si observa la definición de la propiedad en su segundo ejemplo:
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"));Si desea tener la propiedad de acceso, puede usar un campo privado, que es bastante nuevo pero compatible con entornos modernos:
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; }