Serialize and deserialize objects in JavaScript
This post will discuss how to serialize and deserialize objects in JavaScript.
Serializing and deserializing objects in JavaScript is a common task that involves converting an object into a string format that can be stored or transmitted, and then convert the string back to the original object. There are several ways to do this, depending on the complexity and structure of the object, as well as the desired format of the output. Here are some of the most popular functions:
1. Using JSON functions
One of the most common and standard formats for serialization and deserialization is JSON (JavaScript Object Notation), which is a lightweight and human-readable data format that can represent objects, arrays, strings, numbers, booleans, and null values. To serialize an object to JSON, we can use the built-in JSON.stringify() function, which takes an object as a parameter and returns a JSON string. For instance:
|
1 2 3 4 5 6 7 8 9 10 |
let person = { name: "Jack", age: 25, hobbies: ["reading", "cooking", "football"] }; let json = JSON.stringify(person); // {'name':'Jack','age':25,'hobbies':['reading','cooking','football']} console.log(json); |
To deserialize a JSON string to an object, we can use the built-in JSON.parse() function, which takes a JSON string as a parameter and returns an object. For instance:
|
1 2 3 4 5 6 |
let json = '{"name":"Jack","age":25,"hobbies":["reading","cooking","football"]}'; let person = JSON.parse(json); // {name: 'Jack', age: 25, hobbies: ['reading', 'cooking', 'football']} console.log(person); |
However, JSON has some limitations and cannot represent all types of JavaScript values, such as functions, dates, symbols, circular references, or custom types. For instance:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
let person = { name: "Jack", age: 25, sayHello: function() { console.log("Hello, I'm " + this.name); } }; // JSON.stringify will ignore the function property let json = JSON.stringify(person); console.log(json); // {"name":"Jack","age":25} // JSON.parse will create a plain object without the sayHello function // {name: "Jack", age: 25} let obj = JSON.parse(json); // this will throw an error try { obj.sayHello(); } catch (e) { // TypeError: obj.sayHello is not a function console.log(`${e.name}: ${e.message}`); } |
If we need to serialize and deserialize such values, we may need to use custom functions that can handle them. For instance:
1. To serialize and deserialize functions, we can use the Function.prototype.toString() function to convert a function to a string, and the Function() constructor to create a function from a string. For instance:
|
1 2 3 4 5 6 7 8 9 |
function greet(name) { console.log("Hello, " + name); } let fnString = greet.toString(); console.log(fnString); // function greet(name) { console.log("Hello, " + name); } let fn = Function("return (" + fnString + ")")(); fn("Anne"); // Hello, Anne |
2. To serialize and deserialize dates, we can use the Date.prototype.toISOString() function to convert a date to a string in ISO format, and the Date() constructor to create a date from a string. For instance:
|
1 2 3 4 5 6 7 8 9 |
let date = new Date(); // serialize date let dateString = date.toISOString(); console.log(dateString); // e.g. 2020-10-01T08:47:17.333Z // deserialize date let _date = new Date("2020-10-01T08:47:17.333Z"); console.log(_date); |
To overcome these JSON limitations, we can use the second argument of JSON.stringify() and the second argument of JSON.parse() to customize the serialization and deserialization process. These arguments are functions that can modify the values before or after the conversion. For instance:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// an object with a date and a function let person = { name: "Jack", age: 25, birthday: new Date(1991, 0, 1), sayHello: function() { console.log("Hello, I'm " + this.name); } }; // serialize the object to a JSON string with custom logic let json = JSON.stringify(person, function(key, value) { // if the value is a function, return its source code as a string if (typeof value === "function") { return value.toString(); } // if the value is a date, return its ISO string if (value instanceof Date) { return value.toISOString(); } // otherwise, return the value as it is return value; }); // {"name":"Jack","age":25,"birthday":"1990-12-31T18:30:00.000Z", // "sayHello":"function() { console.log(\"Hello, I'm \" + this.name); }"} console.log(json); // deserialize the JSON string to an object with custom logic let obj = JSON.parse(json, function(key, value) { // if the value is a string that starts with "function", return it as a function if (typeof value === "string" && value.startsWith("function")) { return Function("return (" + value + ")")(); } // if the value is a string that matches the date format, return it as a date if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) { return new Date(value); } // otherwise, return the value as it is return value; }); // this will print "Hello, I'm Jack" obj.sayHello(); // {name: 'Jack', age: 25, birthday: 1990-12-31T18:30:00.000Z, sayHello: [Function (anonymous)]} console.log(obj); |
2. Using jsan or flatted library
To serialize and deserialize objects with circular references, we can use a library such as jsan or flattted, which can handle circular dependencies by using placeholders and references. These libraries offer various functions and options for converting objects to and from strings. We can install these libraries using npm or include them in our HTML file using a script tag. Here’s an example using the jsan library:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// import jsan from npm const jsan = require("jsan"); // an object with a date and a function const person = { name: "Jack", age: 25, birthday: new Date(1991, 0, 1) }; person.self = person; // add a circular reference // serialize the object to a string using jsan let str = jsan.stringify(person); // {"name":"Jack","age":25,"birthday":"1990-12-31T18:30:00.000Z","self":{"$jsan":"$"}} console.log(str); // deserialize the jsan string to an object let obj = jsan.parse(str); // <ref *1> { name: 'Jack', age: 25, birthday: '1990-12-31T18:30:00.000Z', self: [Circular *1] } console.log(obj); |
Alternatively, we can use the flatted library in the same way to handle circular references and other complex cases. It provides the flatted.stringify() function to serialize an object to a flatted string, and flatted.parse() function to deserialize a flatted string to an object, which will restore the original structure and values of the object. Here’s an example:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// import flatted from npm const Flatted = require("flatted"); // an object with a date and a function const person = { name: "Jack", age: 25, birthday: new Date(1991, 0, 1) }; person.self = person; // add a circular reference // serialize the object to a string using flatted let str = Flatted.stringify(person); // [{"name":"1","age":25,"birthday":"2","self":"0"},"Jack","1990-12-31T18:30:00.000Z"] console.log(str); // deserialize the flatted string to an object let obj = Flatted.parse(str); // <ref *1> { name: 'Jack', age: 25, birthday: '1990-12-31T18:30:00.000Z', self: [Circular *1] } console.log(obj); |
That’s all about serializing and deserializing objects in JavaScript.
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)