Most JavaScript developers are keenly aware of what they add to the global object and do their best to namespace their work or sequester it in closures. Namespacing and closures reduce the likelihood that necessary functions and variables will be accidentally overwritten, causing errors to be thrown and interfaces to break. Unfortunately, the localStorage API (available in most modern browsers) doesnt inherently support creating isolated caches for each script because the cache is site-specific and consists simply of key-value pairs. Internet Explorers userData behavior (which is available all the way back to IE5) does support sequestering the cache to a degree because you need to provide a name for it, but the API doesnt make a whole lot of sense and isnt at all equivalent to localStorage.

Using the native APIs, its quite easy to accidentally overwrite an existing key in the cache. Beyond that, a simple call to localStorage.clear() will wipe out not only your own data, but anything else stored in the local cache. Its not good.

While working on eCSStenders implementation of client-side caching, I came to realize the problems with the current state of things and sought to address them by implementing faux namespacing via prefixed keys. Ive since copied that code out of eCSStender and created a small library named Squirrel.js that not only evens out the differences between localStorage and userData, but also makes it easier to manage your client-side data store in a manner unlikely to cause issues with other scripts also using client-side caching.

Here is a quick rundown of how Squirrel.js works:

// create a Squirrel instance
var $S = new Squirrel( scale-song );
// write a value to the cache
$S.write( doe, ray );
// read it back
$S.read( doe ); // ray
// write a value to a sub-cache
$S.write( song, doe, a dear, a female dear );
// read back the original value
$S.read( doe ); // ray
// read back the sub-cached value
$S.read( song, doe ); // a dear, a female dear
// removing a single property from the sub-cache
$S.remove( song, doe );
// try to read the sub-cached value
$S.read( song, doe ); // null
// read the root value
$S.read( doe ); // ray
// add some more content to the sub-cache
$S.write( song, doe, a dear, a female dear );
$S.write( song, ray, a drop of golden sun );
// clear the whole sub-cache
$S.clear( song );
// check that its been cleared
$S.read( song, doe ); // null
$S.read( song, ray ); // null
// check that the root values still instact
$S.read( doe ); // ray
// remove a property form the main cache
$S.remove( doe );
// check its value
$S.read( doe ); // null
// write a bit more data in the root and in a sub-cache
$S.write( doe, ray );
$S.write( song, doe, a dear, a female dear );
$S.write( song, ray, a drop of golden sun );
// clear the whole cache
$S.clear();
// check its all gone
$S.read( song, doe ); // null
$S.read( song, ray ); // null
$S.read( doe ); // null