Persistent Object using localStorage The goal is to


make an object that persists upon page reloads,
have an interface as close as possible to the Object class.




function PersistentObject(key,initial_value)
//use for(..in data.keys()) instead of for(..in data)
{
  var ret;
  if(localStorage[key]) ret=JSON.parse(localStorage[key]);
  if(!ret) ret = initial_value;
  if(!ret) ret = {};
  //JSON.stringify ignores put and keys functions
  ret.put=function() { localStorage[key]=JSON.stringify(this) };
  ret.keys=function()
  {
    var res = {};
    for(var prop in this) if(this[prop] !== this.put &amp;&amp; this[prop] !== this.keys)
      res[prop]=true;
    return res;
  };
  return ret;
}


The code is used as follows:

var myPersistentObject = new PersistentObject('myPersistentObject');
var myPersistentArray  = new PersistentObject('myPersistentArray',[]);


Unfortunately there is AFAIK no way to get the name of the variable and therefore the name of the variable needs to be passed as first argument.

Also unfortunate is that the function keys needs to be called in order to iterate over the object. I'm aware of the defineProperty function that allow to add a propoerty that is not enumerable but AFAIK cross browser compability is an issue with defineProperty.
It is impossible to know the variable name without passing it separately because the name is not part of the object itself, but only one (of potentially many) signs pointing to that object. Expecting the object to know that variable name is like expecting a building to know which road you drove in on. Besides, specifying the localStorage key separately is a good thing - it allows you to refer to the same key using different names in different parts of the program.

You can get around having your methods show up in for-in loops by using getters instead of properties or prototypes. If you're concerned about compatibility, you can fallback to __defineGetter__.

Here's what I came up with.

function localObject(key) {
    var _this = JSON.parse(localStorage[key] || '{}');
    Object.defineProperty(_this, 'save', {
        get: function () {
            return function () {
                localStorage[key] = JSON.stringify(this);
            };
        }
    });
    return _this;
}


The new is optional - you can write both

var scores = new localObject('highscores'); // and
var scores = localObject('highscores');`.


While the above solution works, it is somewhat inefficient and messy. This stems from the fact that you're trying to get javascript to work the way you want, when what you should be doing is trying to understand how javascript wants to work. Each language has a style, even a personality, and if you're flexible enough to go with it then your code will be shorter, faster, and cleaner. Here's how I would abstract away my JSONification.

function local(key, value) {
    if (value === undefined) {
        return key in localStorage ? JSON.parse(localStorage[key]) : undefined;
    } else {
        localStorage[key] = JSON.stringify(value);
        return value;
    }
}


Now we can write code like this:

var score = local('highscore');
// use score like a normal variable, because it is one. then, eventually:
local('highscore', score);