Как сериализовать объект и привести его обратно к тому же классу, что и исходный объект - PullRequest
1 голос
/ 10 февраля 2020

Я новичок в JavaScript, так что терпите меня, если я спрашиваю не "как вы это делаете в JavaScript". Советы по другим подходам приветствуются.

У меня есть класс с именем State, и мне нужно сериализовать объекты этого класса, используя JSON.stringify(). Следующий шаг - десериализация их обратно в объекты. Однако в моем классе используются сеттеры и геттеры.

Проблема, с которой я сталкиваюсь, заключается в том, что после десериализации этих объектов сеттеры и геттеры, похоже, исчезли. Я просто не могу понять, как правильно превратить сериализованные объекты обратно в объекты этого класса, чтобы они вели себя точно так же, как объекты, созданные с использованием new напрямую.

На другом языке я бы приводил эти объекты в State объекты. Я не могу найти механизм JavaScript, который, кажется, работает таким образом.

Код выглядит следующим образом:

class State {
  constructor(href) {
    this.url = href;
  }

  set url(href) {
    this._url      = new URL(href);
    this.demoParam = this._url.searchParams.get("demoParam");
  }

  get url() {
    return this._url;
  }

  set demoParam(value) {
    let param = parseInt(value, 10);
    if(isNaN(param)) {
      param = 2;
    }
    console.log("Setting 'demoParam' to value " + param);
    this._demoParam = param;
  }

  get demoParam() {
    return this._demoParam;
  }

  toJSON() {
    let stateObject  = {};
    const prototypes = Object.getPrototypeOf(this);
    for(const key of Object.getOwnPropertyNames(prototypes)) {
      const descriptor = Object.getOwnPropertyDescriptor(prototypes, key);
      if(descriptor && typeof descriptor.get === 'function') {
        stateObject[key] = this[key];
      }
    }
    return stateObject;
  }
}

let originalState = new State(window.location.href);

let newState1 = JSON.parse(JSON.stringify(originalState));
newState1.demoParam = 12;

let newState2 = Object.create(State.prototype, Object.getOwnPropertyDescriptors(JSON.parse(JSON.stringify(originalState))));
newState2.demoParam = 13;

let newState3 = Object.assign(new State(window.location.href), JSON.parse(JSON.stringify(originalState)));
newState3.demoParam = 14;

let newState4 = Object.setPrototypeOf(JSON.parse(JSON.stringify(originalState)), State.prototype);
newState4.demoParam = 15;

Я ожидаю, что каждый раз, когда я устанавливаю свойство demoParam объекта newStateX объект Я бы увидел сообщение журнала консоли. Однако. Я вижу это только дважды, т.е. для каждого new State(window.location.href) заявления.

Я использовал ответ на этот вопрос. Однако он не работает должным образом.

Ответы [ 2 ]

0 голосов
/ 10 февраля 2020

Вы можете использовать Object.assign, чтобы скопировать данные простого объекта в «пустой» новый экземпляр класса в соответствии с этим кодом:

function cast(o) {
   if (!o._cls) return o;
   var _cls = eval(o._cls);
   return Object.assign(new _cls(), o);
}

В JavaScript лично мне нравится избегать использования классы для моих объектов данных. TypeScript предлагает несколько лучших возможностей для решения этой проблемы, одна из них - Typed JSON:

https://github.com/JohnWeisz/TypedJSON

0 голосов
/ 10 февраля 2020

когда вы сериализуете объект, вы запускаете метод toString или toJSON экземпляра вашего класса и в итоге получаете просто "тупое" JSON представление ваших перечисляемых атрибутов.

если Если вы хотите воссоздать экземпляр, который ведет себя так же, как и до сериализации, вам нужно будет установить дополнительную пару ключ / значение в вашей функции на JSON, например ___internalType: 'state', а затем позже использовать, например. оператор switch для воссоздания заданного вами c класса с new MyClass(serializedData) и передачи вашего сериализованного экземпляра. Внутри конструктора вашего класса вы устанавливаете все необходимые атрибуты и вуаля, у вас снова есть «старый» экземпляр

/ edit: чтобы выяснить причину, по которой ваши журналы консоли не отображаются, потому что вы не воссоздаете экземпляр вашего класса, а просто создаете новый простой объект.

...