JSON

CONSOLE

JSON is an acronym for JavaScript Object Notation, a serialization format that was developed in conjunction with ECMAScript 3. It is a standard format, as set by ECMA-404.

JSON Format

Essentially, it is a format for transmitting JavaScript objects. Consider the JavaScript object literal notation:

var whilma = {
  name: "Wilma Flintstone",
  relationship: "wife"
}
var pebbles = {
  name: "Pebbles Flintstone",
  age: 3,
  relationship: "daughter"
}
var fred = {
  name: "Fred Flintstone",
  job: "Quarry Worker",
  payRate: 8,
  dependents: [whilma, pebbles]
}

If we were to express the same object in JSON:

{
  "name": "Fred Flintstone",
  "job": "Quarry Worker",
  "payRate": 8,
  "dependents": [
    {
      "name": "Wilma Flintstone",
      "relationship": "wife"
    },
    {
      "name": "Pebbles Flintstone",
      "age": 3,
      "relationship": "daughter"
    }
  ]
}

As you probably notice, the two are very similar. Two differences probably stand out: First, references (like whilma and pebbles) are replaced with a JSON representation of their values. And second, all property names (the keys) are expressed as strings, not JavaScript symbols.

A discussion of the full syntax can be found in the MDN Documentation and also at json.org.

The JSON Object

The JavaScript language provides a JSON object with two very useful functions: JSON.stringify() and JSON.parse(). The first converts any JavaScript variable into a JSON string. Similarly, the second method parses a JSON string and returns what it represents.

The JSON object is available in browsers and in Node. Open the console and try converting objects and primitives to JSON strings with JSON.stringify() and back with JSON.parse().

Info

While JSON was developed in conjunction with JavaScript, it has become a popular exchange format for other languages as well. There are parsing libraries for most major programming languages that can convert JSON strings into native objects:

Some (like the Python one) are core language features. Others are open-source projects. There are many more available, just search the web!

JSON Nesting and Circular References

While JSON.parse() will handle almost anything you throw at it. Consider this object:

var guy = {
  name: "Guy",
  age: 25,
  hobbies: ["Reading", "Dancing", "Fly fishing"]
};

It converts just fine - you can see for yourself by pasting this code into the console. But what if we add reference to another object?

var guyMom = {
  name: "Guy's Mom",
  age: 52,
  hobbies: ["Knitting", "Needlework", "International Espionage"]
};
guy.mother = guyMom;

Try running JSON.stringify() on guy now:

JSON.stringify(guy);

Notice it works just fine, with Guy’s mother now serialized as a part of the guy object. But what if we add a reference from guyMother back to her son?

guyMom.son = guy;

And try JSON.stringify() on guy now…

JSON.stringify(guy);

We get a TypeError: Converting circular structure to JSON. The JSON.stringify algorithm cannot handle this sort of circular reference - it wants to serialize guy, and thus needs to serialize guyMom to represent guy.mother, but in doing so it needs to serialize guy again as guyMother.son references it. This is a potentially infinitely recursive process… so the algorithm stops and throws an exception as soon as it detects the existence of a circular reference.

Is there a way around this in practice? Yes - substitute direct references for keys, i.e.:

var people = {guy: guy, guyMom: guyMom}
guy.mother = "guyMom";
guyMom.son = "guy";
var peopleJSON = JSON.stringify(people);

Now when you deserialize people, you can rebuild the references:

var newPeople = JSON.parse(peopleJSON);
newPeople["guy"].mother = newPeople[newPeople["guy"].mother];
newPeople["guyMom"].son = newPeople[newPeople["guyMother"].son];

Given a standardized format, you can write a helper method to automate this kind of approach.

Info

The fact that JSON serializes references into objects makes it possible to create deep clones (copies of an object where the references are also clones) using JSON, i.e.:

function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj));
}

If we were to use this method on guy from the above example:

var guyClone = deepClone(guy);

And then alter some aspect of his mother:

var guyClone.mother.hobbies.push("Skydiving");

The original guy’s mother will be unchanged, i.e. it will not include Skydiving in her hobbies.