JSON stringify ES6 class property with getter/setter

后端 未结 5 1786
一向
一向 2020-11-30 13:40

I have a JavaScript ES6 class that has a property set with set and accessed with get functions. It is also a constructor parameter so the class can

相关标签:
5条回答
  • 2020-11-30 14:04

    As mentioned by @Amadan you can write your own toJSON method.

    Further more, in order to avoid re-updating your method every time you add a property to your class you can use a more generic toJSON implementation.

    class MyClass {
    
      get prop1() {
        return 'hello';
      }
      
      get prop2() {
        return 'world';
      }
    
      toJSON() {
    
        // start with an empty object (see other alternatives below) 
        const jsonObj = {};
    
        // add all properties
        const proto = Object.getPrototypeOf(this);
        for (const key of Object.getOwnPropertyNames(proto)) {      
          const desc = Object.getOwnPropertyDescriptor(proto, key);
          const hasGetter = desc && typeof desc.get === 'function';
          if (hasGetter) {
            jsonObj[key] = desc.get();
          }
        }
    
        return jsonObj;
      }
    }
    
    const instance = new MyClass();
    const json = JSON.stringify(instance);
    console.log(json); // outputs: {"prop1":"hello","prop2":"world"}

    If you want to emit all properties and all fields you can replace const jsonObj = {}; with

    const jsonObj = Object.assign({}, this);
    

    Alternatively, if you want to emit all properties and some specific fields you can replace it with

    const jsonObj = {
        myField: myOtherField
    };
    
    0 讨论(0)
  • 2020-11-30 14:05

    I made some adjustments to the script of Alon Bar. Below is a version of the script that works perfectly for me.

    toJSON() {
            const jsonObj = Object.assign({}, this);
            const proto = Object.getPrototypeOf(this);
            for (const key of Object.getOwnPropertyNames(proto)) {
                const desc = Object.getOwnPropertyDescriptor(proto, key);
                const hasGetter = desc && typeof desc.get === 'function';
                if (hasGetter) {
                    jsonObj[key] = this[key];
                }
            }
            return jsonObj;
        }
    
    0 讨论(0)
  • 2020-11-30 14:13

    You can use toJSON method to customise the way your class serialises to JSON:

    class MyClass {
      constructor(property) {
        this.property = property
      }
    
      set property(prop) {
      // Some validation etc.
      this._property = prop
      }
    
      get property() {
        return this._property
      }
    
      toJSON() {
        return {
          property: this.property
        }
      }
    }
    
    0 讨论(0)
  • 2020-11-30 14:15

    Use private fields for internal use.

    class PrivateClassFieldTest {
        #property;
        constructor(value) {
            this.property = value;
        }
        get property() {
            return this.#property;
        }
        set property(value) {
            this.#property = value;
        }
    }
    

    class Test {
    	constructor(value) {
    		this.property = value;
    	}
    	get property() {
    		return this._property;
    	}
    	set property(value) {
    		this._property = value;
    	}
    }
    
    class PublicClassFieldTest {
    	_property;
    	constructor(value) {
    		this.property = value;
    	}
    	get property() {
    		return this.property;
    	}
    	set property(value) {
    		this._property = value;
    	}
    }
    
    class PrivateClassFieldTest {
    	#property;
    	constructor(value) {
    		this.property = value;
    	}
    	get property() {
    		return this.#property;
    	}
    	set property(value) {
    		this.#property = value;
    	}
    }
    
    console.log(JSON.stringify(new Test("test")));
    console.log(JSON.stringify(new PublicClassFieldTest("test")));
    console.log(JSON.stringify(new PrivateClassFieldTest("test")));

    0 讨论(0)
  • 2020-11-30 14:16

    If you want to avoid calling toJson, there is another solution using enumerable and writable:

    class MyClass {
    
      constructor(property) {
    
        Object.defineProperties(this, {
            _property: {writable: true, enumerable: false},
            property: {
                get: function () { return this._property; },
                set: function (property) { this._property = property; },
                enumerable: true
            }
        });
    
        this.property = property;
      }
    
    }
    
    0 讨论(0)
提交回复
热议问题