Chapter 10. JSON: SON of JavaScript

image with no caption

JavaScript, objects, and notation, oh my!

If you ever need to represent objects in your JavaScript, then you’re going to love JSON, JavaScript Standard Object Notation. With JSON, you can represent complex objects and mappings with text and a few curly braces. Even better, you can send and receive JSON from other languages, like PHP, C#, Python, and Ruby. But how does JSON stack up as a data format? Turn the page and see...

image with no caption

Joe: I think we might have different definitions of flawless, man. Two DOM trees to work with, and dealing with whitespace in the server’s response?

Jim: That’s a good point, Frank. Did you even check for whitespace nodes?

Frank: No, but that’s easy enough to add in—

Joe: And your code will get even more convoluted.

Frank: Hey, at least my code works. And that CSV stuff was a total bust.

Jim: It worked great! At least... well, it worked pretty well until we had data where the structure changed depending on the item.

Joe: So you’ve got broken CSV, or convoluted XML. What a choice! Good thing there’s another option.

Jim: What? What did you find?

Frank: This better not be another innerHTML fiasco...

Joe: I found JSON!

Jim and Frank: JSON? What the heck is that?

Joe: JSON is JavaScript Standard Object Notation. It’s a way to represent a JavaScript object in plain text. So the server can send us JSON—which is just text, no XML or DOM issues to deal with—and our JavaScript can work with that response as an object.

Jim: What’s the big deal about that?

Frank: Hmm. Well, if Joe’s really onto something—

Joe: I am!

Frank: —then you wouldn’t need all this DOM stuff, or even split() and other text manipulation code. You could just say, for example, var description = itemDetails.description. That would be pretty cool.

Joe: Look, here’s how it works...

With CSV, comma-separated values, the CSV data was pure text. The server sent over the text, and our JavaScript had to use string manipulation routines like, split(), to turn the string into individual pieces of data.

image with no caption

With XML, the server sent text over, too, but that text was self-describing. So we could get a DOM representation of the text using the request object’s responseXML property. But then we had to use all those DOM methods to work with the object, instead of actual property names like description or urls.

image with no caption

But suppose we had a way to get text from the server, and then treat that text as a JavaScript object. Instead of using string manipulation or DOM methods, we’d just use code like item.description or itemDetails.urls. In other words, we’d have a format that was represented as text for easy network transmission, but an object when we needed to work with the data.

image with no caption

When you get JSON data from a server or some other source, you’re getting text... but that text can easily be turned into a JavaScript object. Then, all you need to do is access that object’s fields using dot notation. Dot notation just means you put the object name, and then a dot, and then a field name, like this:

var weakness = superman.weakness;

For instance, suppose you had an object like the one shown in the solution above. How do you think you’d access the value of the description field?

________________________________________________________

If you’re looking at your answer, and thinking it’s too simple, then you’ve probably got things just right. Working with JavaScript objects is about as easy as it gets.

image with no caption

When a server sends its response as JSON data, that data comes across the network as text. So you can get that data using the responseText property of your request object:

var jsonData = request.responseText;

JavaScript is pretty good at turning text into objects, functions, and lots of other things. You can give JavaScript some text, and it’s smart enough to figure out what that text represents.

For example, remember how we’ve been assigning event handlers?

image with no caption

JavaScript takes this textual function, and creates an actual function in memory. So when an image is clicked, the function code sitting in memory is executed. That all happens behind the scenes, though, and isn’t something you need to worry about.

But what about when you have text, and you need to TELL JavaScript to turn it into something more than text?

image with no caption

The eval() function tells JavaScript to actually evaluate text. So if you passed the text describing a statement to eval(), JavaScript would actually run that statement, and give you the result:

image with no caption
image with no caption

It looks like the object JavaScript creates from a JSON response is perfect for Rob’s rock inventory page. There’s just one thing to watch out for. You need to make sure that the overall JSON response string is seen as a single object. So when you call eval(), wrap the whole response in parentheses, like this:

image with no caption
image with no caption
image with no caption

Frank: You’re right! His JSON code doesn’t really help much in that case. His code depends on knowing the names of the object’s properties.

Jim: Exactly. And there’s no way it works with dynamic item descriptions, where the property names change.

Frank: Hmmm. You know, I was able to solve that problem with XML. I wonder if Joe—

Jim: No way, man. You’ve always read the name of properties from your element’s tag names. His code has the property names as part of the code... they’re not even parameters to search methods like getElementsByTagName().

Frank: You’re right. I’ll bet this will hang him up pretty good.

image with no caption

In compiled languages, you define your objects in a source file, like a .java or .cpp file. Then, you compile those files into bytecode. So once your program’s running, you’re stuck with the definitions that are compiled into bytecode. In other words, a Car object can’t suddenly have a new manufacturer property without recompilation. That lets everyone who’s using the Car object know what to expect.

JavaScript, however, isn’t compiled; it’s interpreted. Things can change at any time. Not only that, but the objects the server sends are created at runtime, using eval(). So whatever’s sent to our JavaScript, that’s what we get in the itemDetails object.

image with no caption

JavaScript will tell you what properties an object has. You just have to ask it, using the for/in syntax. Suppose you’ve got an object called itemDetails, and you want to know what properties itemDetails has. You’d use this code to get those properties:

for (var property in hero) {
  alert("Found a property named: " + property);
}

Pretty simple, right? So the variable property would have values like id, description, price, and urls.

But we don’t want just the property names; we also want the values for each property. That’s okay, though, because JavaScript lets you access an object’s properties as if the object were an array. But instead of supplying an array index, like itemDetails[0], you supply a property name, like itemDetails["price"].

In other words, the value returned for itemDetails["price"] for an object is the value of the property named price in that object.

image with no caption
image with no caption

JavaScript does NOT give you a built-in way to see if a value is an array.

Dealing with dynamic data is tricky business. For instance, when you write in your code itemDetails.urls, you know that the value for that property will be an array. But what about itemDetails[propertyName]? Is the value for that property an array or a single value, like a string?

Unfortunately, JavaScript doesn’t give you a simple way to check and see if a value is an array. You can use the typeof operator, but even for arrays, typeof returns “object,” and not “array” like you might expect.

To help you out, here’s a little Ready Bake Code that will tell you if a value is an array or not. Add this function to the end of thumbnails.js, and then see if you can finish up your exercise from the last page.

image with no caption

Good property names aren’t usually good label names, too.

Take a close look at the property names for an item’s description:

image with no caption

We’ve been printing out the property name and then the value for that property. But those property names look more like code than “human speak.”

Not only that, but the ID of each item is showing, too. That could wind up being a real security bug down the line.

What would YOU do to fix these problems?

image with no caption

Joe: Well, yeah, that’s kind of the point.

Frank: Do you really think that’s a good idea? Just running code that someone else gave you?

Joe: I’m not running it, I’m evaluating it. Haven’t you been paying attention?

Jim: Someone’s getting cranky that their JSON solution isn’t so easy...

Frank: Whether JSON’s easy or not, you can’t just evaluate that code blindly. What if it’s malicious code, like a script that hacks the user’s browser or something? Or it redirects their browser to a porn site?

Joe: Are you kidding me? It’s Rob’s server, for crying out loud!

Frank: What if it’s not correct JSON? What if there’s an error? Evaluating code with an error in it is going to generate errors for the users?

Jim: Sounds pretty dismal, Joe...

Joe: You’re both just annoyed that I was gonna win that guitar.

Frank: Hey, safety first, man. I’m telling you, you can’t go around using eval() on code that you don’t have any control over.

Joe: Great. Now what am I gonna do?

Calling eval() initiates a simple process: take a bit of text, and evaluate that text. What we need is an additional step. Suppose we could take a bit of text, and make sure it’s actually JSON-formatted data. Then, we could reasonably assume it’s safe to evaluate that data, and turn it into a JavaScript object.

That extra step—parsing the data and making sure the data is JSON—protects us from two important potential problems:

Fortunately for Joe (and us!), the JSON website at http://www.json.org provides a JSON parser that does all of these things, and more. You can download a script from json.org called json2.js, and then use this command to parse JSON-formatted data:

image with no caption

Run it!

Change your code to use JSON.parse().

The examples for Chapter 10 already include json2.js in the scripts/ directory. Add a reference to this new script in inventory.html, and update your version of thumbnails.js to use JSON.parse() instead of eval().

Put the reference to json2.js before the reference to thumbnails.js since the thumbnails script uses the json2 script.

There’s still lots to do. Can YOU help Joe out?

  • How could you avoid showing the ID of an item when a user clicks on that item?

  • What about those labels? Can you figure out a way to show better, more- readable labels?

  • What about those URLs? Can you figure out a way to format URLs as links (using <a> elements) so they’re clickable?

  • And besides all that, how do YOU think Rob’s inventory page could be improved?

  • Don’t forget to use a JSON parser, instead of eval()!

Can you make Rob’s inventory page even cooler using JSON? Build your best version of Rob’s page, and submit your URL in the Head First Labs “Head First Ajax” forum. We’ll be giving away cool prizes for the best entries in the coming months.

image with no caption
image with no caption

Joe: I know about lots of things I don’t like. Brussel sprouts, Melrose Place, velcro shoes... just because I know about something, doesn’t mean I like it!

Frank: I just don’t see what you really gain by using JSON. Maybe it’s a little easier for you to use, but it’s a pretty big pain when you get to dynamic data.

Jim: I don’t know, Frank... I got really confused dealing with 2 DOMs at once.

Frank: But XML is self-describing! We didn’t have any of those property-names-as-labels issues with XML.

Joe: I still think JSON lets me think in JavaScript, not some other language.