The JSON.stringify API

Kent C. Dodds
InstructorKent C. Dodds

Share this video with your friends

Send Tweet
Published 6 years ago
Updated 3 years ago

JSON (JavaScript Object Notation) is a standard method to serialize JavaScript objects and is commonly used to transfer data from the server to the browser. The browser has a JSON API that allows you to serialize a JavaScript object or array into a JSON string. This API allows you to customize the serialization very specifically as well.

In this lesson we're going to be using the inspect library to assert certain things about the JSON.stringify API that we'll be exploring. So let's go ahead and we'll pull up our JavaScript in our console. In here we have this console.log that tests have passed, so if we run it right now, all of our tests are passing but that's because all of our assertions are commented out.

With JSON.stringify, generally what you find that you use this for is to serialize an object or an array of objects to a string that can be sent across the wire to a server, or persisted in local storage. So this is just the very basic API. We're going to use the JSON global object we'll call stringify, and we'll pass our input. That's going to get our test passing. So that's the basic API, that's what you'll use most of the time when using JSON.stringify, is just stringify this thing.

Something that's kind of interesting about that, is that you can actually pass primitive values and JSON has a way to represent those primitive values. But if it's a complex value like an object, for example, or a date, it's going to convert it to a JSON representation of that object. So we'll just stick our input in there and we'll move right along to spaces. This is really handy for sending stuff across the wire, it's lightweight, there's as few characters as possible to serialize this data.

But sometimes it's useful to represent these objects in a more readable fashion. So here in this example, we have an input that has a couple nested objects here, and we want to output it where it has some spacing to make it a little bit more reasonable. So we're looking an ES6 template literal here, so that we have these multiline strings and we get two spaces for every nested object here. To accomplish this, we're going to actually use the third parameter toJSON.stringify.

Let's go ahead and enable that test, we get that failing, and we'll skip the second parameter and we'll talk about that in a moment, and we'll pass 2 because we have 2 spaces as the third argument, and that will get our test passing. So let's explore this API a little bit. We can also pass 4, and that will give us 4 spaces. Let's go ahead and console.log the result, you see that a little bit more clearly.

So we get four spaces, we have two spaces, we have even three spaces, or one space, but you can also add the temp character to space these things. One other interesting thing is you can put any arbitrary string in here. So we could say Hello, and now it's spaced by hello. This can go up to 10 characters, and so Hello World Is actually 11 characters, so we're going to have the spacing be Hello Worl and it will repeat it twice for these nested objects.

Now let's move on to the replacer function. So remember that second argument that we talked about, that we specify as null. This is actually used for the replacer to instruct stringify how to serialize your objects. In this example if we run the test we're going to see that we're failing, and if you notice the expected output, so our result has a time stamp whereas what we want it to be is no time stamp at all, just the year, month, and day.

So we need to instruct stringify that no for these dates, we don't want you to do the default behavior for a date object, we actually want you to serialize this a little bit differently. So we instruct it with the replacer function. We'll place that function right here, and this will take a key and a value, and the hidden third argument would be the context, so this. We're going to actually be using the context because the value that we receive here is the serialized value.

So for example if we go ahead and we'll simply return the value here, and then we'll console.log the key and value, we're going to see that we get the initial key of an empty string, that represents the entire object to be serialized, and then for the title we get the string "Gone with the Wind," then for the published date, we're actually getting the serialized date object. We don't want to have that, we actually want to determine or not if this is actually a date object, and then serialize it ourselves.

So we're going to say if this at key is an instance of a date, then we'll return the value.susbstring 0 to 10, so it's the first 10 characters of the value, the serialized value. That will get our test passing. That's the replacer as a function. This API is a little bit overloaded, and you can actually provide an array of strings for that. That's what our next case is here.

So here we can see that we have this array of objects, and there's a lot more information in this array of objects than there are in our expected output which only has the ID and title, whereas this has the ID, title, rating, and genres. We can see that in the object here. So to accomplish this, for our replacer, it's actually quite simple. We simply add an array, we give it the properties that we want to have pulled out of those objects, and that will get our test passing.

So you can provide both a function as a replacer, as well as an array of strings as the replacer to specify the exact keys that you want to have serialized in your JavaScript object. Now we have something a little bit interesting with ES6. If you're familiar with symbols in ECMAScript 6, this test is to illustrate that those things are not actually serialized. So if we go ahead and uncomment out our test we're going to get that error.

So we're going to say var, var symbol = a symbol at var, and then again this is ECMAScript 6 so you need to be running this in a browser that supports that, Chrome does. We'll say input at var symbol = var, and that will get our test passing. So the interesting thing here though is we can still console.log input at var symbol and we're still going to get our value. So we still have access to this, it's just not serializable in Stringify, and that's what we're going for in this test. Symbols will not be stringified.

Another way to avoid having something be stringified is to prevent it from being enumerable. So in this example, we have the answer and the question, and all we want is the answer. So we want the question to not be serialized in our example. We're going to say var input = object.create and we'll pass null for the prototype, and then we'll pass our configuration object to indicate how this object should be created.

So the answer we'll specify as enumerable as true, and the value as 42. Then for the question, we'll say enumerable is false, and the value is, "Who knows?" Let's go ahead and delete our original input, that will get our test passing. Something kind of interesting about this API is actually an enumerable being false as the default, so we can remove that, and we still get our test passing. That's another way that you can prevent something from being serialized when you call JSON.stringify on it.

Finally, you can really fine-tune how an object is serialized by adding a toJSON method to it. So in this example, we have this input and here we are expecting this to be serialized to be name as an object where the property is awesome name, and it's the awesome name is Smith. That's the entire object, so we're totally missing the first, last, and middle names here. Then the user name is as you would expect.

We can add a toJSON function here, and that receives the key, and then we simply return an object that we want to have serialized. So in our case, it's going to be awesome name, and the context of the toJSON is on the object on which it is called, so we can say the awesome this.first, this.middle, and this.last. Then we run that, and our test passed, and we no longer need this key, but just to be complete about this, we can console.log the key and we'll see that it is name.

So it's the key of the containing object, but we don't need it here. That is the JSON.stringify API.