javascript - איך להמיר מופע של מחלקת TypeScript עם getter/setter ל-JSON כדי לאחסן במסד הנתונים MySQL
יש לי את מחלקת TypeScript הבאה שמכילה getter/setter:
export class KitSection {
uid: string;
order: number;
set layout(layout: KitLayout) {
this._layout = new KitLayout(layout);
}
get layout() {
return this._layout;
}
private _layout: KitLayout;
constructor(init?: Partial<KitSection>) {
Object.assign(this, init);
}
}
// I can create an instance like so:
const section = new KitSection(data);
אני צריך POST את המופע הזה לשרת שלי כאובייקט JSON כדי לאחסן בעמודה של מסד נתונים MySQL מסוג: JSON, אז חשבתי שאני יכול לעשות את הפעולה הבאה:
const jsonSection = JSON.parse(JSON.stringify(section))
זה יוצר אובייקט JSON, אבל כשאני בודק בקונסול, אני רואה את משתנה ה-getter/setter הפרטי שלי במקום המשתנה הציבורי באובייקט:
console.log(jsonSection);
///IN CONSOLE///
uid: "a"
order: 0
_layout: {_rows: Array(2), columns: 12}
אני לא רוצה לאחסן את המשתנה הפרטי _layout בבסיס הנתונים שלי, אני צריך לאחסן את המקבילה הציבורית המוגדרת ב-getter/setter: layout.
לאחר מכן, בדקתי את התשובה שניתנה כאן: https://stackoverflow.com/a/44237286/6480913 שבה מציעים להוסיף את המתודה הבאה כדי להמיר ל-JSON:
public toJSON(): string {
let obj = Object.assign(this);
let keys = Object.keys(this.constructor.prototype);
obj.toJSON = undefined;
return JSON.stringify(obj, keys);
}
עם זאת, זה מחזיר אובייקט ריק. לאחר בדיקה, כאשר אני console.log() את this.constructor.prototype, אני רואה את כל התכונות של האובייקט, אבל כל אובייקט נראה כאילו הוא אפור, אז כאשר אנחנו משתמשים ב-Object.keys(), אני מקבל מערך ריק. למה התכונות של הקונסטרקטור האלה מופיעות מוגדרות באפור?
תשובה #1
JSON.stringify יעקוב רק אחרי תכונות בר ניתנות לאיבוד שמוגדרות בעצמו. כאן, מכיוון ש-layout היא תכונה על אובייקט ה-prototype, ולא על המופע עצמו, כשמנסים להמיר את המופע למחרוזת JSON, ה-getter לא מופעל. (אבל מכיוון שה-_layout היא תכונה בר ניתנת לאיבוד שמוגדרת בעצמו, היא נכללת בתוצאה)
באופן דומה, האובייקט המומר למחרוזת הבא ריק:
const obj = Object.create({
get prop() {
return 'val';
}
});
console.log(JSON.stringify(obj));אתה יכול לתקן את זה על ידי הצבת המתודה getter ישירות על האובייקט, ועל ידי הפיכת _layout ללא ניתן לרישום. בדרך זו, כאשר המחרוזת נוצרת, המתודה getter תופעל, אך _layout לא ייכלל:
export class KitSection {
uid: string;
order: number;
private _layout: KitLayout;
constructor(init?: Partial<KitSection>) {
Object.defineProperty(
this,
'layout',
{
enumerable: true,
get() {
return this._layout;
},
set(newVal) {
this._layout = new KitLayout(newVal);
}
}
);
Object.defineProperty(
this,
'_layout',
{
enumerable: false,
value: undefined,
}
);
Object.assign(this, init);
}
}
const section = new KitSection(data);
זה יראה קצת ברור יותר אם תשתמש בתחביר של שדה מחלקה פרטי במקום:
export class KitSection {
#layout: KitLayout | undefined;
constructor(init?: Partial<KitSection>) {
Object.defineProperty(
this,
'layout',
{
enumerable: true,
get() {
return this.#layout;
},
set: (newVal) => {
this.#layout = new KitLayout(newVal);
}
}
);
Object.assign(this, init);
}
}
אתה יכול גם לקרוא למתווך באופן ידני.
אם ה-KitLayout ניתן בעצם לסיריאליזציה, כדי להפוך את האובייקט המוסרי חזרה לאינסטנס של KitSection, KitLayout או אחד מהשיטות העזר שלו צריכים להיות מסוגלים להפוך KitLayout מוסרי לאינסטנס. אפשר להעביר אותו דרך הבונה שוב (פשוט לקרוא ל-new KitSection שמועבר ל-KitLayout), או להפריד את ה-layout מהאובייקט המוסר וליצור שיטה נפרדת ב-KitSection שקוראת לשיטת העזר של KitLayout ומציבה את המאפיין הפרטי, אולי משהו כמו:
integrateLayout(layoutInfo) {
this.#layout = KitLayout.makeKitLayoutFromLayoutInfo(layoutInfo)
}
כאשר layoutInfo הוא האובייקט הפשוט.
