Estoy tratando de hacer que mi clase se comporte como un objeto "normal", ya que cuando se llama en object.entries , devuelve una matriz de pares de valores clave. Después de buscar un poco, he podido hacer que mi clase sea iterable. Pero no puedo encontrar por dónde empezar en términos de implementar object.entries .
Aquí es donde he llegado,
'use strict' class Person { #name constructor(name) { this.#name = name } get name () { return this.#name } *iterator () { var props = Object.getOwnPropertyNames(Object.getPrototypeOf(this)) for (const prop of props) { if (typeof this[prop] !== 'function') { const o = {} o[prop] = this[prop] yield o } } } [Symbol.iterator] () { return this.iterator() } } const person = new Person ('bill') //works - produces { name: 'bill' } for (const prop of person){ console.log (prop) } // doesn't work. Prints an empty array console.log (Object.entries(person))El problema es que sus instancias no tienen propiedades públicas "propias" (no heredadas), que es lo que Object.entries incluye en su matriz.
Estoy tratando de hacer que mi clase se comporte como un objeto "normal", en el sentido de que cuando se llama en object.entries, devuelve una matriz de pares de valores clave.
Ese es el comportamiento predeterminado, ya sea que cree el objeto a través de un constructor de clase o de alguna otra manera.
Después de buscar un poco, he podido hacer que mi clase sea iterable.
Object.entries no tiene nada que ver con si un objeto es iterable.
No creo que pueda hacer que Object.entries devuelva [[name, "value"]] sin hacer que el name sea una propiedad de datos "propia". Pero puede convertirlo en una propiedad de datos propios de solo lectura a través Object.defineProperty :
class Person { #name; constructor(name) { this.#name = name; Object.defineProperty(this, "name", { value: name, writable: false, enumerable: true, configurable: true }); } } const bill = new Person("Bill"); console.log(`bill.name:`, bill.name); console.log(`Object.entries(bill):`, Object.entries(bill)); Mantuve #name allí, pero probablemente no haya razón para ello, así que:
class Person { constructor(name) { Object.defineProperty(this, "name", { value: name, writable: false, enumerable: true, configurable: true }); } } const bill = new Person("Bill"); console.log(`bill.name:`, bill.name); console.log(`Object.entries(bill):`, Object.entries(bill)); Si desea poder establecer el name internamente, simplemente dése un método privado que repita defineProperty :
class Person { constructor(name) { this.#setName(name); } #setName(name) { Object.defineProperty(this, "name", { value: name, writable: false, enumerable: true, configurable: true }); } } const bill = new Person("Bill"); console.log(`bill.name:`, bill.name); console.log(`Object.entries(bill):`, Object.entries(bill)); Desafortunadamente, debido a que la propiedad es configurable, su código no es el único código que puede usar defineProperty para cambiarlo. (Esto es más bien como la propiedad de name en las funciones, que es de solo lectura de forma predeterminada, pero se puede cambiar a través defineProperty ). Por lo tanto, no es exactamente lo mismo que tener #name y get name , simplemente está cerca y brinda soporte para Object.entries .
En realidad, no tiene que implementar el iterador. La razón por la que Object.entries no funcionaría es que, debido al # la propiedad se trata como privada y, por lo tanto, no se devuelve. Si elimina el name # , Object.entries como en el ejemplo a continuación.
class Person { name constructor(name) { this.name = name } } const person = new Person ('bill') // doesn't work. Prints an empty array console.log(Object.entries(person))