Búsqueda de sitios web

javascript - ¿Por qué desaparece mi propiedad después de Object.defineProperty en el decorador?


Tengo un decorador que convierte un número en cadena a un número en JavaScript.

Ejemplo: "87" -> 87.

El código es bastante simple:

function digit(target: any, key: string) {

  // property value
  var _val = this[key];

  // property getter
  var getter = () =>  _val;

  // property setter
  var setter = (newVal) => _val = parseInt(newVal)

  // Create new property with getter and setter
  Object.defineProperty(target, key, {
    get: getter,
    set: setter,
    enumerable: true,
    configurable: true,
  });
}

class User {

  @digit
  public id: number;
  public isActive: boolean;

  constructor(instanceData) {
    this.id = instanceData.id;
    this.isActive = instanceData.isActive;
  }
}

let user = new User({
  id: '712',
  isActive: '1'
})

console.log([user.id]) // [ 712 ] as expected
console.log(user) // Person { isActive: '1' }

¿Por qué no aparece el campo id en el segundo console.log y cómo puedo hacer que aparezca? Puedo acceder a él, pero está oculto en la consola.

¡Gracias!

Respuesta #1

Porque un decorador de propiedad para una propiedad de instancia se aplica al prototipo de la clase, no a ninguna instancia. Eso es lo mejor que puedes hacer porque ninguna instancia de User existe antes de que llames a new User(). Cuando simplemente usas console.log() para obtener salida de depuración, solo ves las propiedades propias de la instancia, no las que están en el prototipo.

Dado que todas las instancias comparten un prototipo, probablemente no quieras hacerlo de esta manera:

let user = new User({
  id: '712',
  isActive: '1'
}) 
let user2 = new User({
  id: '567',
  isActive: '1'
})
console.log(user.id) // 567!

Un prototipo, un valor de id para toda la clase. Todos los objetos User tienen el mismo id. Vaya.

Probablemente quieras al menos hacer algo con las instancias cuando estén disponibles:

function digit(target: any, key: string) {
  // Create new property with getter and setter
  Object.defineProperty(target, key, {
    get: function () { return this._val },
    set: function (newVal) { this._val = parseInt(newVal) },
    enumerable: true,
    configurable: true,
  });
}

Observe el uso de this dentro de los métodos get y set. Eso pone la propiedad _val en la instancia, por lo que obtendrás instancias distintas. Aún así, no verás id a través de console.log(), (y sÍ verás _val).

Hay demasiadas formas de configurar el objeto para que imprima lo que esperas con console.log() y se comporte de la manera que esperas (un id por instancia) como para enumerarlas aquí. Como una pista: podrías poner el accesor de propiedad en la instancia modificando el constructor de la clase en lugar de intentar usar un decorador. Y asegúrate de que el _val agregado no sea enumerable para que no aparezca. ¡Espero que eso ayude; buena suerte!