【问题标题】:How to make JSON.stringify output getters of an object by using decorators?如何使用装饰器使对象的 JSON.stringify 输出 getter?
【发布时间】:2018-09-08 20:47:45
【问题描述】:

我需要JSON.stringify 方法来输出getter。我知道它没有这样做,因为吸气剂不是“可枚举的”。

我找到了一个解决方案,我正在使用Object.defineProperty 来增加具有可枚举属性的getter,如Playground 所示。

我想用装饰器做同样的事情,但它不能像shown here那样工作。

请不要建议实现 toJSON 方法,我知道它可能会有所帮助,但我想要一个仅限装饰器的解决方案。

它也与 Angular 相关,因为我需要它来使 formGroup.patchValue 为 getter 工作。

updated my example 和 @acdcjunior 建议 - 希望他们能在这里找到我所缺少的。

【问题讨论】:

    标签: angular typescript getter typescript-decorator


    【解决方案1】:

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

    constructor() {
        const obj = new MyClass();
        document.write(JSON.stringify(obj, Object.keys(obj.constructor.prototype)))
    }
    

    【讨论】:

      【解决方案2】:

      JSON.stringify(),只序列化对象自己的可枚举属性。使用该装饰器,您可以将 getter 添加为原型对象的属性。

      来自ES6 Spec

      24.3.2.3 运行时语义:SerializeJSONObject(值)

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

      (...)

        1. 如果 PropertyList 不是未定义的,则
          • 设 K 为 PropertyList
        1. 否则,

      相关点是6

      如果你问,PropertyListserialization of arrays 相关,所以它不可能是逃生舱。


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

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

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

      演示

      根据要求,您就可以了。 JSFiddle demo here.

      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') ));
      

      更新TypeScript playground link here

      【讨论】:

      • 你能根据我在链接上分享的代码分享一个例子吗?
      • 好了。看看吧!
      • 你试过了吗?有任何判决吗?
      • 刚刚用你的解决方案更新了我的问题,但它不起作用,你能看看更新问题最后几行的链接吗?
      • 你去。检查更新的答案。我在底部粘贴了一个链接。
      猜你喜欢
      • 1970-01-01
      • 2021-08-16
      • 2018-12-14
      • 1970-01-01
      • 2021-07-19
      • 2021-03-28
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      相关资源
      最近更新 更多