patternjavascriptMinor
Persistent Object using localStorage
Viewed 0 times
persistentobjectusinglocalstorage
Problem
The goal is to
The code is used as follows:
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
- make an object that persists upon page reloads,
- have an interface as close as possible to the
Objectclass.
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 && 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.Solution
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
Here's what I came up with.
The
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.
Now we can write code like this:
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 bothvar 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);Code Snippets
function localObject(key) {
var _this = JSON.parse(localStorage[key] || '{}');
Object.defineProperty(_this, 'save', {
get: function () {
return function () {
localStorage[key] = JSON.stringify(this);
};
}
});
return _this;
}var scores = new localObject('highscores'); // and
var scores = localObject('highscores');`.function local(key, value) {
if (value === undefined) {
return key in localStorage ? JSON.parse(localStorage[key]) : undefined;
} else {
localStorage[key] = JSON.stringify(value);
return value;
}
}var score = local('highscore');
// use score like a normal variable, because it is one. then, eventually:
local('highscore', score);Context
StackExchange Code Review Q#11747, answer score: 2
Revisions (0)
No revisions yet.