JSON: JavaScript Object Notation
Introduction and Basic Syntax

JSON is an object notation that is natively recognized by JavaScript. This means that you can create JSON code directly within your script when creating an array or other complex object. JSON has a relatively easy syntax. It involves a combinations of [square brackets] around comma-separated array values, {curly braces} around objects that have properties, and "double quotes" or 'single quotes' around values. Some JSON validators expect double quotes (and then double quotes with in the value are escaped), and therefore this is good practice, however browsers tend to be flexible about handling variation in the use of single quotes around values, and even NO quotes around the actual variable names. Here is a sample of JSON code that contains an array of objects representing people. I will explain the structure in the paragraph that follows:

[ { "name": "Charles", "age": 25, "interests": [ "chess", "sci-fi", "horror" ] } , { "name": "Jane", "age": 22, "interests": [ "checkers", "history", "astrophysics" ] } ]
Using JSON in JavaScript

What this code gives us is two objects (presumed to be people). Each has a name, an age, and a set of interests. JSON is nice because, if coded neatly, it's fairly human-readable, while still being completely understandable by JavaScript. Watch what happens when we tweak our code a bit:

var people = [ { "name": "Charles", "age": 25, "interests": [ "chess", "sci-fi", "horror" ] } , { "name": "Jane", "age": 22, "interests": [ "checkers", "history", "astrophysics" ] } ]; var output = "There are two people:
"; for (var i in people) { output += people[i].name + " is " + people[i].age + " years old, and likes "; for (var j in people[i].interests) { if (j > 0) { output += ", "; if (j == people[i].interests.length-1) { output += "and "; } } output += people[i].interests[j]; } output += ".
"; } document.getElementById('output1').innerHTML = output;

Notice that we were able to declare that. However if we were to wrap that JSON in a string, we would get different results:

var people = '[ { "name": "Charles", "age": 25, "interests": [ "chess", "sci-fi", "horror" ] } , { "name": "Jane", "age": 22, "interests": [ "checkers", "history", "astrophysics" ] } ]'; var output; try { var output = "There are " + people.length + " people:
"; /* for (var i in people) { output += people[i].name + " is " + people[i].age + " years old, and likes "; for (var j in people[i].interests) { if (j > 0) { output += ", "; if (j == people[i].interests.length-1) { output += "and "; } } output += people[i].interests[j]; } output += ".
"; } */ } catch(er) { output = er; } document.getElementById('output2').innerHTML = output;

Uh oh. Let's not list all "89" people that it thinks it found. Instead, let's look at why it thinks that. The problem here is that the string is now simply a string representing object notation, and no longer an actual expression representing an object itself. So when our loop in the code above looks for the initial length of the expression that is evaluated by eval(), it finds the string, and then considers EVERY CHARACTER as it loops through. In each iteration through this very long loop, it fails to find the values we're asking for (it's looking in single characters, not objects that would have the properties we'd expect), and we see many nonsensical lines instead of the two we expect.

Converting JSON between Objects and Strings

For the reasons seen above, it's important to understand the difference between a STRING that contains JSON-like code, and JSON/object notation itself. This is especially important because we will be fetching JSON strings when making Ajax calls later, and we'll have to convert them from strings to complex objects or arrays. Fortunately there are some useful functions for this: JSON.stringify(object) and JSON.parse(string), which convert an object to a string and a string to an object, respectively. You can find these function calls near the top of one of the JavaScript files used by this page. The code below demonstrates their use:

/* http://www.sitepoint.com/javascript-json-serialization/#.T_HibfWWjbg */ function Person() { this.Name = ""; this.Interests = []; /* this.summarize = function() { return(this.Name + " likes: " + this.Interests.join(",")); }; */ } Person.prototype = { summarize: function() { return(this.Name + " likes: " + this.Interests.join(",")); } }; var person = new Person(); person.Name = "Jonathan"; person.Interests.push("Chess"); person.Interests.push("Sci-Fi"); person.Interests.push("Cats"); alert(person.Name+"'s properties:\n\n" + getObjectProperties(person)); /* Depending on browser, these JSON.whatever function may require custom building */ var data = JSON.stringify(person); var output3 = document.getElementById('output3'); output3.innerHTML = "

" + data + "

"; output3.innerHTML += "

" + person.summarize() + "

"; /* First let's try to make a clone using JSON.parse - It ignores the functions! */ alert("Let's try using JSON.parse to create a clone from our JSON string, and then explicitly rename the second person 'Bob'..."); var clone = JSON.parse(data); /* We should give him a different name: */ clone.Name = "Bob"; alert(clone.Name+"'s initial properties using 'JSON.parse':\n\n" + getObjectProperties(clone)); alert("Uh oh. It didn't include our summarize() function! Let's try the JSON.clone function instead."); /* JSON.clone works better, because it also factors in the prototype properties (the functions!) */ clone = JSON.clone(data, Person.prototype); /* Let's rename him again: */ clone.Name = "Bob"; alert(clone.Name+"'s properties using 'JSON.clone':\n\n" + getObjectProperties(clone)); alert("Terrific! Now it uses the functions! \ The slightly tweaked JSON.clone function also loops through the prototype \ that you pass along to see what functions it should include with the copy of \ your otherwise static object."); output3.innerHTML += "

" + clone.summarize() + "

";

Let's tear this sample apart a little. First of all, we have the specification of a class by declaring a function called Person. Note that instead of specifying the 'summarize()' function directly in the function, I modified it's "prototype" after the fact. There's a very specific reason for that, which I'll discuss below. In any case, each instance of a Person has a Name (a string) and a set of Interests (an array of strings). Each Person can also be summarized, in which case a string is returned giving a brief description of what we know about them.

function Person() { this.Name = ""; this.Interests = []; /* this.summarize = function() { return(this.Name + " likes: " + this.Interests.join(",")); }; */ } Person.prototype = { summarize: function() { return(this.Name + " likes: " + this.Interests.join(",")); } };

Once we have a function that describes our Person class, we can start making people. Let's make one, name him "Jonathan", and give him three interests:

var person = new Person(); person.Name = "Jonathan"; person.Interests.push("Chess"); person.Interests.push("Sci-Fi"); person.Interests.push("Cats");

If we summarize Jonathan, we'll get the string we expect from the summarize() function in the prototype for that object. Unfortunately, the JSON.parse() function that is built into some browsers (and provided as code in main.js mentioned above in case of browsers that don't natively support it) doesn't factor in the functions that an object might have. I've created a slightly improved JSON.clone(json,prototype) function that let's you not only pass in the JSON string, but also the prototype containing the functions that should be attached to the object once it's cloned, so you get a more complete copy. You can find that function with the other two (which are credited to their source) in the source code (see main.js). Using that function, creating a clone of an instance of an object is as easy as calling the function with the data to parse and the prototype to model it's functionality on:

var data = JSON.stringify(person); clone = JSON.clone(data, Person.prototype);

Recommended next: Ajax: Asychronous JavaScript and... uh... whatever.