Last night, I was reading the jQuery Cookbook (review to come soon) and I came across something that I had never seen before; or rather, they mentioned something that I had never seen before (the concept was not actually demonstrated in the book). They mentioned in a side note that Javascript's Function() constructor could be used to evaluate JSON (Javascript Object Notation) data. I very rarely ever use the Function() constructor, so I wanted to see if I could get this to work.
The Function() constructor takes an optional list of argument names and final content argument and builds a function object using the given content as the method body such that this:
function foo( bar ){ alert( bar ); };
... and this:
var foo = new Function( "bar", "alert( bar );" );
... are equivalent.
Because our JSON data is string-based in its serialized format as is the above method body, we can easily create a function using the serialized JSON data:
<!DOCTYPE HTML>
<html>
<head>
<title>Using Function() To Deserialize JSON Data</title>
<script type="text/javascript">
// Mimic the JSON string as it might come back from a
// remote AJAX call.
var jsonString = "{ 'myArray': ['a','b','c'] }";
// Use the Function constructor to create a function
// that will return the JSON object. Because the Function
// constructor takes a string value, we can easily
// integrate it directly into the method definition.
//
// NOTE: Immediately invoke the method such that it
// returns the evaluated JSON value.
var jsonValue = (new Function( "return( " + jsonString + " );" ))();
// Log the new de-serialized JSON value.
console.log( jsonValue );
</script>
</head>
<body>
<!--- No data. --->
</body>
</html>
As you can see, our dynamically generated method body simply returns the JSON data. When we run the above code, we get the following Firebug console output:
Cool - works just fine. I am not sure how this is being run internally to the Javascript engine, or if it's doing anything different than the eval() statement does. I just wanted to see if I could get it to work.
Reader Comments
That's pretty sweet. I'd like to see some speed tests done on this code Ben. Wonder if you could just create a "deserializeJSON() method once and reuse it rather than creating a new one each time.
@Andy,
As far as speed, I would assume that going the Function() route is going to be slower than just going straight to eval() simply because there's probably overhead in creating the resultant function.
I think jQuery, under the hood, will try to the native JSON object it is available, or default to eval() or something - so, the other obvious benefit to abstraction is that you can have a centralized point of branch-logic.
Doesn't appear to work that way. Must be something special in the constructor.
@Andy,
Hmmm, I don't know. I've never actually looked at their evaluation technique; but, I thought I had read something about it leveraging the internal JSON object in the new browsers.
I feel bad about posting links from ASP.NET, but anyway this performance test is quite interesting. It's about the performance between eval(), a new function and the native support of common browsers. http://bit.ly/92Fl5
@Roman,
No worries about .NET ;) It's still good results. Thanks for posting it.
This sounds a bit sketchy. Could a hacker not use this to return a malicious script as JSON data?
@Brian,
No more so than with the use of an eval() statement.
Something else to watch for as I learn AJAX then.
@Brian,
I might be very ignorant here, but I get very suspect of all the hoopla people have over the eval() / hacker stuff. It's one thing when people have an issue with AJAX-driven data; but, a lot of people get in a huff about the use of eval() to strictly internal usage.
I'm not really sure how big a problem it is. I read about it all the time.
I follow the "best practice" guidelines whenever I find them for whatever programming languages I'm using, but is that enough to protect my apps/websites? I hope so. It's not like I'm leaving out a "Welcome Hacker" mat on my virtual front porch. But those guys can be pretty persistent in finding vulnerabilities and exploiting them.
Aside: How about posting some of YOUR Best Practices for ColdFusion or JQuery or anything really?
@Brian,
MY best practices?? Hmm, that's an interesting question. I'll do some thinking and see if I can formalize some stuff.
Thanks for this article, very helpful.
@Danny,
Glad you found it useful.
the most brilliant idea i've ever seen. i tested with ASP.NET JavaScriptSerializer class and it worked. thank you.