Javascript序列化的类型对象

时间:2011-12-28 14:35:16

标签: javascript json serialization

我不清楚序列化/反序列化应该如何处理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实例作为精灵进行反序列化。我应该使用“new MapLayer()”而不是“{}”吗?或者我只是想在序列化中包含对象的原型和构造函数属性?还有什么我想念的吗?我这样做是一种愚蠢的方式吗?我没有使用通用序列化/反序列化代码有两个原因:

  1. 我想以优化的格式序列化tile数据,而不是为每个tile存储一个base-10字符串表示,并用逗号分隔它们。
  2. 我不希望将tileset序列化为在反序列化期间构造为新对象的对象,而是将其作为对现有对象的引用。是否可以使用我上面提到的代码?
  3. 编辑:请原谅我缺乏适当的术语; JavaScript是我不那么专业的语言之一。当我说“Typed Object”是一个带有构造函数的对象时,我的意思是什么。在这个例子中,我的构造函数是:

    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:从ŠimeVidas的回答中获取代码后,我添加了一个名为“Device”的相关对象:

    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 );
    

    现在的问题是如何最好地合并这些依赖对象,因为对象的“类型”(原型?)再次被JS​​ON丢失。我们为什么不简单地更改serialize和反序列化函数来确保只需要像这样构造一次而不是创建和复制对象,而不是运行构造函数?

    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 个答案:

答案 0 :(得分:8)

首先,这是一个自定义序列化/反序列化的简单示例:

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 );

现在,person2Person的一个实例,包含与原始person实例相同的属性值。

现场演示: http://jsfiddle.net/VMqQN/


现在,虽然在任何情况下都需要Person.deserialize静态方法(它在内部使用JSON.parse,并调用Person构造函数来初始化新实例),{{1}另一方面,只有在内置Person.prototype.serialize静态方法不够的情况下才需要使用方法。

在上面的示例中,JSON.stringify也可以完成工作,因此不需要自定义序列化机制。请参阅此处:http://jsfiddle.net/VMqQN/1/但是,您的情况更复杂,因此您需要定义自定义序列化功能。

答案 1 :(得分:1)

如果你看一下ST-JS(http://st-js.org)项目,它允许在服务器端用Java创建你的对象图,用JSON序列化它,然后在客户端(Javascript)反序列化它。一种类型化的方式,即对象将使用它们的构造函数进行实例化,您可以在创建的对象上调用方法。

要使用ST-JS,您应该编写您的客户端代码是Java,在Javascript中几乎一对一转换。

网站主页上的AJAX / JSON章节向您解释如何在保留类型信息的同时解析JSON字符串。