JSON.stringify不使用装饰器显示对象的getter

时间:2018-03-29 19:35:14

标签: angular typescript

我希望JSON.stringify也输出geters。我知道它没有显示,因为geters不是“可枚举的”。

我找到了一个解决方案,我正在使用Object.defineProperty来扩展具有可枚举属性的geter,如以下链接所示: Working example with Object.defineProperty in the constractor

我想使用装饰器做同样的事情,但它不起作用,如下面的链接所示: Not working example with Object.defineProperty in the decorator - How can i fix that?

请不要建议我实现toJSON()属性,我知道它可能会有所帮助,但我不想要那个解决方案,我希望它只与装饰器一起工作。

有人可以帮忙吗?

它也适用于 Angular ,因为我需要对formGroup.patchValue也适用于getter。

我用@acdcjunior建议更新了我的例子:this link,希望他能找到我在这里缺少的东西。

2 个答案:

答案 0 :(得分:1)

https://developer.amazon.com/docs/fire-tv/audio-video-synchronization.html#section1-2,仅序列化对象自己的可枚举属性。使用该装饰器,您可以将getter添加为原型对象的属性。

来自JSON.stringify()

  

24.3.2.3运行时语义:SerializeJSONObject(value)

     

带参数值的抽象操作SerializeJSONObject   序列化一个对象。它可以访问堆栈,缩进,间隙和   stringify方法的当前调用的PropertyList值。

     

(...)

     
      
    1.   
    2. 如果 PropertyList 未定义,则      
          
      • 设K PropertyList
      •   
    3.   
  •   
    1.   
    2. 否则,      
    3.   
  •   

相关点是6

如果你问, PropertyList EnumerableOwnNames有关,所以它不能成为逃生舱。

使用方法级别装饰器,虽然你说你不想要它,但我能想到的唯一方法是让装饰器添加toJSON(如果不存在)原型类。

这样的toJSON将(仅在第一次调用时)将类原型中的getter(作为可枚举属性)添加到正在调用toJSON的实例中。

当你装饰了多个吸气剂时,棘手的部分是,当处理第二个和装饰器时,区分你所拥有的toJSON是否由你创造(然后你可以"追加"当前装饰器的属性)或者它是否在最初的类中(在这种情况下你会忽略)。很棘手,但据我所知,可行。

演示

根据要求,你去吧。 serialization of arrays

class MyClass {
  constructor(public name) {}
  @enumerable(true)
    get location(): string {
    return 'Hello from Location!'
  }
  @enumerable(true)
    get age(): number {
    return 12345;
  }
    get sex(): string {
    return "f";
  }
}
class MyClassWithToJson {
  constructor(public name) {}
  @enumerable(true)
    get nickname(): string {
    return 'I shall still be non enumerable'
  }
  toJSON() { return 'Previously existing toJSON()!' }
}

function enumerable(value: boolean) {
  return function (target: any, propertyKey: string) {
      if (!value) {
        // didnt ask to enumerate, nothing to do because even enumerables at the prototype wont
        // appear in the JSON
        return;
      }
        if (target.toJSON && !target.__propsToMakeEnumerable) {
        return; // previously existing toJSON, nothing to do!
      }
      target.__propsToMakeEnumerable = (target.__propsToMakeEnumerable || []).concat([{propertyKey, value}])

      target.toJSON = function () {
        let self = this; // JSFiddle transpiler apparently is not transpiling arrow functions properly
        if (!this.__propsToMakeEnumerableAlreadyProcessed) { // so we just do this once
          console.log('processing non-enumerable props...'); // remove later, just for testing
          let propsToMakeEnumerable = self.__propsToMakeEnumerable;
          (propsToMakeEnumerable || []).forEach(({propertyKey, value}) => {
              let descriptor = Object.getOwnPropertyDescriptor(self.__proto__, propertyKey);
              descriptor.enumerable = true;
              Object.defineProperty(self, propertyKey, descriptor);
          });
          Object.defineProperty(this, '__propsToMakeEnumerableAlreadyProcessed', {value: true, enumerable: false});
        }
        return this;
      }
  };
}

let obj = new MyClass('Bob');
console.log(JSON.stringify( obj ));
console.log(JSON.stringify( obj )); // this second time it shouldn't print "processing..."
console.log(JSON.stringify( new MyClassWithToJson('MyClassWithToJson') ));

更新了JSFiddle demo here.

答案 1 :(得分:0)

嗯,我很确定你真的不能,AFAIK标准说JSON.stringify只会输出一个对象自己的可枚举属性。我认为最简单的解决方案是使用JSON.stringifypass in the keys you want to whitelist的第二个参数,这将使它使用您自己的键列表而不是我认为它们从{{1}获得的列表}:

Object.getOwnPropertyNames