Сериализация Javascript типизированных объектов - PullRequest
8 голосов
/ 28 декабря 2011

Мне неясно, как сериализация / десериализация должна работать на типизированных объектах в JavaScript.Например, у меня есть объект «MapLayer», который содержит различные члены и массивы.Я написал (но еще не протестировал) следующий код, чтобы попытаться его сериализовать:

MapLayer.prototype.serialize = function() {
   var result = "{tileset:tilesets." + tilesets.getTilesetName(this.tileset) + ",columns:" + this.columns + ",rows:" + this.rows + 
   ",offsetX:" + this.offsetX + ",offsetY:" + this.offsetY + ",currentX:" + this.currentX + ",currentY:" + this.currentY + 
   ",scrollRateX:" + this.scrollRateX + ",scrollRateY:" + this.scrollRateY + ",virtualColumns:" + this.virtualColumns + ",virtualRows:" + this.virtualRows +
   ",tiles:\"" + this.encodeTileData2() + "\"";
   for(key in this)
   {
      if(this[key] instanceof Sprite)
         result += "," + key + ":" + this[key].serialize();
   }
   return result;
}

Мой вопрос заключается в том, как полученный объект должен десериализоваться как объект MapLayer, а не как универсальный объект.,И как все экземпляры Sprite должны быть десериализованы как спрайты?Должен ли я использовать «новый MapLayer ()» вместо «{}»?Или я просто должен включить свойства прототипа и конструктора объекта в сериализацию?Что-то еще я пропускаю?Я делаю это глупо?Есть 2 причины, по которым я не использую общий код сериализации / десериализации:

  1. Я хочу сериализовать данные тайла в оптимизированном формате, а не хранить строковое представление base-10 для каждой тайла,и все они должны быть разделены запятыми.
  2. Я не хочу сериализовать набор плиток как объект, который создается как новый объект во время десериализации, а скорее как ссылку на существующий объект.Возможно ли это с использованием кода, подобного предложенному выше?

Редактировать: Извините, что у меня нет правильной терминологии;JavaScript - один из моих менее опытных языков.Что я имею в виду, когда говорю «Типизированный объект» - это объект с конструктором.В этом примере мой конструктор:

function MapLayer(map, tileset, columns, rows, virtualColumns, virtualRows, offsetX, offsetY, scrollRateX, scrollRateY, priority, tileData) {
   this.map = map;
   this.tileset = tileset;
   this.columns = columns;
   this.rows = rows;
   this.offsetX = offsetX;
   this.offsetY = offsetY;
   this.currentX = offsetX;
   this.currentY = offsetY;
   this.scrollRateX = scrollRateX;
   this.scrollRateY = scrollRateY;
   if(tileData.length < columns * rows * 2)
      this.tiles = DecodeData1(tileData);
   else
      this.tiles = DecodeData2(tileData);
   this.virtualColumns = virtualColumns ? virtualColumns : columns;
   this.virtualRows = virtualRows ? virtualRows : rows;
}

Редактировать 2: Взяв код из ответа Шиме Видаса, я добавил связанный объект под названием «Устройство»:

function Device( description, memory ) {
    this.description = description;
    this.memory = memory;
}

function Person( name, sex, age, devices ) {
    this.name = name;
    this.sex = sex; 
    this.age = age;
    this.devices = devices;
}

Person.deserialize = function ( input ) {
    var obj = JSON.parse( input );
    return new Person( obj.name, obj.sex, obj.age, obj.devices );
};

var device = new Device( 'Blackberry', 64);
var device2 = new Device( 'Playstation 3', 600000);
var person = new Person( 'John', 'male', 25, [device, device2] );

var string = JSON.stringify(person);
console.log( string );

var person2 = Person.deserialize( string );
console.log( person2 );
console.log( person2 instanceof Person );

Теперь вопрос состоит в том, как лучше всего включить такие зависимые объекты, потому что еще раз «тип» (прототип?) Объекта теряется JSON.Вместо запуска конструктора, почему бы нам просто не изменить функции сериализации и десериализации, чтобы гарантировать, что объект должен быть сконструирован только один раз, а не создан и скопирован?

Person.prototype.serialize = function () {
    var obj = this; 
    return '({ ' + Object.getOwnPropertyNames( this ).map( function ( key ) {
        var value = obj[key];
        if ( typeof value === 'string' ) { value = '"' + value + '"'; }
        return key + ': ' + value;
    }).join( ', ' ) + ',"__proto__":Person.prototype})'; 
};

Person.deserialize = function ( input ) {
    return eval( input );
};

Редактировать 3: Другая проблема, с которой я столкнулся, заключается в том, что JSON не работает в IE9.Я использую этот тестовый файл:

<html>
<head>
<title>Script test</title>
<script language="javascript">
console.log(JSON);
</script>
</head>
</html>

И вывод консоли:

SCRIPT5009: 'JSON' is undefined 
test.html, line 5 character 1

Редактировать 4: Чтобы исправить проблему JSON, я должен включить правильнуюТег DOCTYPE в начале.

Ответы [ 2 ]

8 голосов
/ 28 декабря 2011

Для начала, вот простой пример пользовательской сериализации / десериализации:

function Person( name, sex, age ) {
    this.name = name;
    this.sex = sex;
    this.age = age;
}

Person.prototype.serialize = function () {
    var obj = this;
    return '{ ' + Object.getOwnPropertyNames( this ).map( function ( key ) {
        var value = obj[key];
        if ( typeof value === 'string' ) { value = '"' + value + '"'; }
        return '"' + key + '": ' + value;
    }).join( ', ' ) + ' }';
};

Person.deserialize = function ( input ) {
    var obj = JSON.parse( input );
    return new Person( obj.name, obj.sex, obj.age );
};

Использование:

Сначала мы создаем новый экземпляр объекта:

var person = new Person( 'John', 'male', 25 );

Теперь мы сериализуем этот объект в строку, используя метод Person.prototype.serialize:

var string = person.serialize();

Это даст использование этой строки:

{ "name": "John", "sex": "male", "age": 25 }

Наконец, мы десериализовываем эту строку, используя статический метод Person.deserialize:

var person2 = Person.deserialize( string );

Теперь person2 является экземпляром Person и содержит те же значения свойств, что и исходный person экземпляр.

Демонстрационная версия: http://jsfiddle.net/VMqQN/


Теперь, хотя статический метод Person.deserialize необходим в любом случае (он использует JSON.parse для внутренних целей и вызывает конструктор Person для инициализации нового экземпляра), метод Person.prototype.serialize, с другой стороны, требуется только в том случае, если встроенного JSON.stringify статического метода недостаточно.

В моем примере выше var string = JSON.stringify( person ) тоже выполнит свою работу, поэтому специальный механизм сериализации не нужен. Смотрите здесь: http://jsfiddle.net/VMqQN/1/ Однако ваш случай более сложный, поэтому вам нужно определить пользовательскую функцию сериализации.

1 голос
/ 10 марта 2012

Если вы посмотрите на проект ST-JS (http://st -js.org ), он позволяет создать ваш граф объектов в Java на стороне сервера, сериализовать его в JSON и десериализовать его на стороне клиента (Javascript) типизированным способом, т.е. объекты будут создаваться с использованием их конструктора, и вы можете вызывать методы для созданных объектов.

Чтобы использовать ST-JS, вы должны написать свой клиентский код на Java, который преобразуется почти один в один в Javascript.

Глава AJAX / JSON на домашней странице сайта объясняет, как анализировать строку JSON при сохранении информации о типе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...