set
でプロパティが設定され、get
関数でアクセスできるJavaScript ES6クラスがあります。これはコンストラクターパラメーターでもあるため、クラスは上記のプロパティでインスタンス化できます。
_class MyClass {
constructor(property) {
this.property = property
}
set property(prop) {
// Some validation etc.
this._property = prop
}
get property() {
return this._property
}
}
_
__property
_を使用して、property
に直接設定すると、無限ループが発生するget/setを使用するというJSの問題を回避します。
次に、MyClassのインスタンスを文字列化して、HTTPリクエストで送信する必要があります。文字列化されたJSONは次のようなオブジェクトです。
_{
//...
_property:
}
_
結果のJSON文字列がproperty
を保持して、送信先のサービスが正しく解析できるようにする必要があります。サービスから送信されたJSONからMyClassのインスタンスを作成する必要があるため、property
もコンストラクターに残す必要があります(__property
_ではなくproperty
でオブジェクトを送信しています)。
どうすればこれを回避できますか? MyClassインスタンスをインターセプトしてからHTTPリクエストに送信し、正規表現を使用して__property
_をproperty
に変更する必要がありますか?これは見苦しいようですが、現在のコードを保持できます。
あるいは、サービスからクライアントに送信されているJSONをインターセプトして、まったく異なるプロパティ名でMyClassをインスタンス化することもできます。ただし、これは、サービスのいずれかの側のクラスの異なる表現を意味します。
toJSON
method を使用して、クラスを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の呼び出しを避けたい場合は、列挙可能および書き込み可能を使用する別の解決策があります。
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
メソッドを作成できます。
さらに、クラスにプロパティを追加するたびにメソッドが更新されないようにするために、より一般的な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;
}
内部使用にはprivate fieldsを使用します。
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")));