1

This is a follow-up question to Javascript Serialization of Typed Objects. That solution works OK for objects whose type is known, but now I have an object of a type that is unknown by the code that will be performing the de-serialization. There's a base class "Sprite" that has a number of properties that need to be serialized. Any number of derived classes (such as "Player" and "Platform" etc) may derive from class Sprite and add their own properties. I also have a "MapLayer" object that contains a collection of Sprite-derived objects. How do I de-serialize the layer and all of its sprites such that each sprite will be of the correct derived type when de-serialization is complete. Do I need to use eval("new " + derivedTypeName + parameterList)? Is there a better way?

More details: The Sprite base class is hard-coded, but all the derived classes are generated code. I can make the code generator generate deserialize functions for every derived class, but how do I call them appropriately from the generic base class deserialization function? There's only one MapLayer class, and somehow it has to potentially call the deserialize function on all the classes derived from Sprite.

Community
  • 1
  • 1
BlueMonkMN
  • 25,079
  • 9
  • 80
  • 146
  • Consider boiling this down to its essence. You reference another question but you go on to describe a scenario which doesn't match that question (e.g. you're asking about `new`, which isn't used in deserialization) – Ken Browning Dec 30 '11 at 18:54
  • @KenBrowning "new" is used in the suggested answer to that question. – BlueMonkMN Dec 31 '11 at 02:08

1 Answers1

2

In order to call the derived object's constructor function, you'll first need to know which constructor you want to call. You don't give details about how you're currently encoding that type information in your serialized payload, so let's say you've got something like the following:

var MyDerivedType = function () {...};
MyDerivedType.prototype.__derivedTypeName = 'MyDerivedType';
MyDerivedType.deserialize = function ( input ) {
    var obj = JSON.parse( input );
    return new MyDerivedType( obj );
};

If you're not assigning your derived types to the global scope then you'll need to be able to address them at the time of deserialization. Here's an example of storing them on the Sprite constructor itself:

Sprite.derivedTypes = Sprite.derivedTypes || {};
Sprite.derivedTypes['MyDerivedType'] = MyDerivedType;

Then you can avoid using eval and call the appropriate deserializer like this:

Sprite.deserialize = function(input) {

    // json parse the data string to pull out our derived type
    var o = JSON.parse(input);

    // delegate to the derived type's deserialize method
    return Sprite.derivedTypes[o.__derivedTypeName].deserialize(input);
};

There is nothing built-in to JavaScript/browser js environments which provides deserialization to "classes" in the sense that you're familiar with in .net.

Ken Browning
  • 28,693
  • 6
  • 56
  • 68
  • Is that the only/best way to refer to all the members of the global namespace by name: window[]? – BlueMonkMN Dec 31 '11 at 02:13
  • You can create a new variable which holds a reference to the global namespace. But it would be even more preferable to avoid "polluting" the global namespace and store references to your constructor function in some other variable. – Ken Browning Dec 31 '11 at 05:34
  • On reviewing my code, I found that my object is not in fact in the global namespace. However I'm still troubled that there seems to be no generic way for an unknown object to deserialize itself if, for example, it exists in an unpredictable namespace. In .NET you can simply use binary serialization or reflection to retrieve the fully qualified name of a type in order to reconstitute an object of the same type regardless of the namespace. If a JavaScript object in an arbitrary "namespace" decides to inherit from a serializable class, is there really no possibility for generic deserialization? – BlueMonkMN Dec 31 '11 at 08:42
  • JavaScript objects don't exist in namespaces. Variables exist in some scope. If you want to address your constructors (what I believe your original question was asking) then a reference to them needs to be addressable from whatever scope your code is executing in. Are you familiar with JSON.stringify/parse? http://www.json.org/js.html – Ken Browning Dec 31 '11 at 09:37
  • Yes, that is the problem. JavaScript doesn't have namespaces, so they are simulated with scopes. And there's no way to serialize a scope, so there's no way to deserialize an object whose scope is unknown. Does that sum it up? Yes, I'm familiar with JSON.stringify/parse, but they don't work for me because I have circular references. However, I just realized there are features of which I was unaware: toJSON and extra parameters on stringify may help me. – BlueMonkMN Dec 31 '11 at 09:48
  • 1
    Alright, here's my last attempt. If you're looking for something like .net deserialization it doesn't exist. You've already been building your own serialization mechanism. If you need it to account for derived types, then you have to program that in. – Ken Browning Jan 01 '12 at 01:16
  • Thanks. Once again (as in my previous question), I think I just needed some validation that I wasn't missing something (and the pointer toward what *is* available). With some additional research I have gained a somewhat better understanding of prototypes and the distinction between the external and internal prototype, which I think will also help. Prototype-based OO takes some getting used to coming from another paradigm. – BlueMonkMN Jan 01 '12 at 03:25