JSON 将 ES6 class 属性 字符串化为 getter/setter
JSON stringify ES6 class property with getter/setter
我有一个 JavaScript ES6 class,它有一个 属性 设置 set
并使用 get
函数访问。它也是一个构造函数参数,因此 class 可以用 属性.
实例化
class MyClass {
constructor(property) {
this.property = property
}
set property(prop) {
// Some validation etc.
this._property = prop
}
get property() {
return this._property
}
}
我使用 _property
来避免使用 get/set 的 JS 问题,如果我直接设置为 property
.
会导致无限循环
现在我需要将 MyClass 的一个实例字符串化,以便通过 HTTP 请求发送它。字符串化的 JSON 是一个像这样的对象:
{
//...
_property:
}
我需要生成的 JSON 字符串来保留 property
以便我发送它的服务可以正确解析它。我还需要 property
保留在构造函数中,因为我需要从服务发送的 JSON 构造 MyClass 的实例(它正在发送带有 property
而不是 _property
的对象)。
我该如何解决这个问题?我是否应该在将 MyClass 实例发送到 HTTP 请求之前拦截它并使用正则表达式将 _property
变异为 property
?这看起来很难看,但我将能够保留我当前的代码。
或者,我可以拦截从服务发送到客户端的 JSON 并使用完全不同的 属性 名称实例化 MyClass。然而,这意味着 class 服务任一侧的不同表示。
您可以使用 toJSON
method 自定义 class 序列化为 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
}
}
}
如果你想避免调用toJson,还有一个使用enumerable和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;
}
}
如@Amadan 所述,您可以编写自己的 toJSON
方法。
此外,为了避免在每次向 class 添加 属性 时使用 re-updating 您的方法,您可以使用更通用的 toJSON
实现。
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"}
如果您想发出所有属性和所有字段,您可以将const jsonObj = {};
替换为
const jsonObj = Object.assign({}, this);
或者,如果您想发出所有属性和一些特定字段,您可以将其替换为
const jsonObj = {
myField: myOtherField
};
我对Alon Bar的剧本做了一些调整。下面是一个非常适合我的脚本版本。
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;
}
使用私有字段供内部使用。
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")));
我做了一个名为 esserializer 的 npm 模块来解决这样的问题:将 JavaScript class 的实例字符串化,以便它可以通过 HTTP 请求发送:
// Client side
const ESSerializer = require('esserializer');
const serializedText = ESSerializer.serialize(anInstanceOfMyClass);
// Send HTTP request, with serializedText as data
在服务端,再次使用esserializer将数据反序列化为anInstanceOfMyClass
的完美副本,并保留所有getter/setter字段(例如property
):
// Node.js service side
const deserializedObj = ESSerializer.deserialize(serializedText, [MyClass]);
// deserializedObj is a perfect copy of anInstanceOfMyClass
我有一个 JavaScript ES6 class,它有一个 属性 设置 set
并使用 get
函数访问。它也是一个构造函数参数,因此 class 可以用 属性.
class MyClass {
constructor(property) {
this.property = property
}
set property(prop) {
// Some validation etc.
this._property = prop
}
get property() {
return this._property
}
}
我使用 _property
来避免使用 get/set 的 JS 问题,如果我直接设置为 property
.
现在我需要将 MyClass 的一个实例字符串化,以便通过 HTTP 请求发送它。字符串化的 JSON 是一个像这样的对象:
{
//...
_property:
}
我需要生成的 JSON 字符串来保留 property
以便我发送它的服务可以正确解析它。我还需要 property
保留在构造函数中,因为我需要从服务发送的 JSON 构造 MyClass 的实例(它正在发送带有 property
而不是 _property
的对象)。
我该如何解决这个问题?我是否应该在将 MyClass 实例发送到 HTTP 请求之前拦截它并使用正则表达式将 _property
变异为 property
?这看起来很难看,但我将能够保留我当前的代码。
或者,我可以拦截从服务发送到客户端的 JSON 并使用完全不同的 属性 名称实例化 MyClass。然而,这意味着 class 服务任一侧的不同表示。
您可以使用 toJSON
method 自定义 class 序列化为 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
}
}
}
如果你想避免调用toJson,还有一个使用enumerable和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;
}
}
如@Amadan 所述,您可以编写自己的 toJSON
方法。
此外,为了避免在每次向 class 添加 属性 时使用 re-updating 您的方法,您可以使用更通用的 toJSON
实现。
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"}
如果您想发出所有属性和所有字段,您可以将const jsonObj = {};
替换为
const jsonObj = Object.assign({}, this);
或者,如果您想发出所有属性和一些特定字段,您可以将其替换为
const jsonObj = {
myField: myOtherField
};
我对Alon Bar的剧本做了一些调整。下面是一个非常适合我的脚本版本。
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;
}
使用私有字段供内部使用。
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")));
我做了一个名为 esserializer 的 npm 模块来解决这样的问题:将 JavaScript class 的实例字符串化,以便它可以通过 HTTP 请求发送:
// Client side
const ESSerializer = require('esserializer');
const serializedText = ESSerializer.serialize(anInstanceOfMyClass);
// Send HTTP request, with serializedText as data
在服务端,再次使用esserializer将数据反序列化为anInstanceOfMyClass
的完美副本,并保留所有getter/setter字段(例如property
):
// Node.js service side
const deserializedObj = ESSerializer.deserialize(serializedText, [MyClass]);
// deserializedObj is a perfect copy of anInstanceOfMyClass