为什么我的属性在装饰器中的Object.defineProperty之后消失了?

时间:2017-10-27 16:21:12

标签: javascript typescript defineproperty

我有一个装饰器,可以将一个字符串编号转换为javascript编号。

示例:"87" - > 87

代码非常简单:

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' }

为什么id字段没有出现在第二个console.log中,如何显示? 我可以访问它,但它隐藏在控制台中。

谢谢!

1 个答案:

答案 0 :(得分:0)

因为实例属性的property decorator应用于类的原型,而不是任何实例。这是您可以做的最好的事情,因为在致电User之前,不存在new User()的实例。当您只使用console.log()获取调试输出时,您只能看到实例的own属性,而不是原型上的属性。

由于所有实例共享原型,您可能不希望这样做:

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

一个原型,整个类的一个id值。所有User个对象都具有相同的id。糟糕。

您可能希望至少在实例可用时执行某些操作:

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,
  });
}

请注意在thisget方法中使用set。这会将_val属性放在实例上,因此您将获得不同的属性。您仍然无法通过id看到console.log(),(看到_val)。

有太多方法可以配置对象,以便打印出您对console.log()的期望,并按照您期望的方式运行(每个实例一个id),以便我在此枚举。作为一个提示:您可以通过修改类构造函数而不是尝试使用装饰器来将属性访问器放在实例上。并确保添加的_val不可枚举,因此不会显示。希望有所帮助;祝你好运!