Serializing and Deserializing Instances of Types in JavaScript

The code below builds a complex object that contains sub-objects as properties, serializes the object with all its children to JSON, deserializes that string to get back the original object, re-serializes that deserialized object, and then prints the two different serialized strings to demonstrate that they are identical.

This implementation improves significantly upon that in a previous post, in that it actually converts the deserialized objects as actual instances of their respective types, rather than just as generic “objects”.


<html>
<body>
<script type='text/javascript'>

// main

function main()
{
	var serializer = new Serializer
	([
		TestClass1,
		TestClass2,
	]);

	var testInstanceToSerialize = new TestClass1
	(
		"One", // name
		1, // value
		// children
		[
			new TestClass2
			(
				"TwoThroughFive",
				[2, 3, 4, 5]
			)
		]
	);

	var testInstanceSerialized = serializer.serialize
	(
		testInstanceToSerialize
	);

	var testInstanceDeserialized = serializer.deserialize
	(
		testInstanceSerialized
	);
	
	var testInstanceReserialized = serializer.serialize
	(
		testInstanceDeserialized
	);

	var newline = "<br />";

	document.write
	(
		"testInstanceSerialized is: " 
		+ testInstanceSerialized 
		+ newline
	);

	document.write
	(
		"testInstanceReserialized is: " 
		+ testInstanceReserialized 
		+ newline
	);
}

// classes

function Serializer(knownTypes)
{
	this.knownTypes = knownTypes;

	for (var i = 0; i < this.knownTypes.length; i++)
	{
		var knownType = this.knownTypes[i];
		this.knownTypes[knownType.name] = knownType;
	}
}
{
	Serializer.prototype.deleteClassNameRecursively = function(objectToDeleteClassNameOn)
	{
		var className = objectToDeleteClassNameOn.constructor.name;
		if (this.knownTypes[className] != null)
		{
			delete objectToDeleteClassNameOn.className;

			for (var childPropertyName in objectToDeleteClassNameOn)
			{
				var childProperty = objectToDeleteClassNameOn[childPropertyName];
				this.deleteClassNameRecursively(childProperty);
			}
		}
		else if (className == "Array")
		{
			for (var i = 0; i < objectToDeleteClassNameOn.length; i++)
			{
				var element = objectToDeleteClassNameOn[i];
				this.deleteClassNameRecursively(element);
			}
		}
	}

	Serializer.prototype.deserialize = function(stringToDeserialize)
	{
		var objectDeserialized = JSON.parse(stringToDeserialize);

		this.setPrototypeRecursively(objectDeserialized);

		this.deleteClassNameRecursively(objectDeserialized);

		return objectDeserialized;
	}

	Serializer.prototype.serialize = function(objectToSerialize)
	{
		this.setClassNameRecursively(objectToSerialize);

		var returnValue = JSON.stringify(objectToSerialize);

		this.deleteClassNameRecursively(objectToSerialize);

		return returnValue;
	}

	Serializer.prototype.setClassNameRecursively = function(objectToSetClassNameOn)
	{
		var className = objectToSetClassNameOn.constructor.name;
		
		if (this.knownTypes[className] != null)
		{
			for (var childPropertyName in objectToSetClassNameOn)
			{
				var childProperty = objectToSetClassNameOn[childPropertyName];
				this.setClassNameRecursively(childProperty);
			}

			objectToSetClassNameOn.className = className;
		}
		else if (className == "Array")
		{
			for (var i = 0; i < objectToSetClassNameOn.length; i++)
			{
				var element = objectToSetClassNameOn[i];
				this.setClassNameRecursively(element);
			}
		}
	}

	Serializer.prototype.setPrototypeRecursively = function(objectToSetPrototypeOn)
	{
		var typeOfObjectToSetPrototypeOn = this.knownTypes[objectToSetPrototypeOn.className];

		if (typeOfObjectToSetPrototypeOn != null)
		{
			objectToSetPrototypeOn.__proto__ = typeOfObjectToSetPrototypeOn.prototype;
	
			for (var childPropertyName in objectToSetPrototypeOn)
			{
				var childProperty = objectToSetPrototypeOn[childPropertyName];
				if (childProperty.constructor.name == "Array")
				{
					for (var i = 0; i < childProperty.length; i++)
					{
						var element = childProperty[i];
						this.setPrototypeRecursively(element);
					}
				}
			}
		}
	}
}

function TestClass1(name, value, children)
{
	this.name = name;
	this.value = value;
	this.children = children;
}

function TestClass2(name, arrayOfValues)
{
	this.name = name;
	this.arrayOfValues = arrayOfValues;
}

// run

main();

</script>
</body>
</html>

This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s