Support for sessionStorage
and localStorage
is quite broad, so it should not cause problems in most of the browsers / devices on which you use them. The other part that your code depends on is the JSON parsing API which also has broad support. Here is the details of the versions that you can find in caniuse for Storage and JSON
Storage and JSON
Android 2.1 +
IOS 3.2 +
Chrome 4 +
Firefox 3.5 +
There is an alternative when you want to increase the support for these APIs that is to create a polyfill in memory but keep in mind that this is not a 100% equivalent replacement since
The data stored in localStorage does not have an expiration date
and
The information stored in sessionStorage is deleted at the end of the session of the page. The session of the page lasts while the browser is open, and remains above the reloads and reopenings of the page
Creating an in-memory storage will allow you to use the API but as soon as you update the page all that information will be erased. You can use cookies to get around this obstacle but remember that cookies have security considerations and the storage size is much lower (~ 5Mb total localStorage
=>
~ 4 kb per cookie, 20 cookies per domain).
Here is the pollyfill for localStorage
. This is a variant of the MDN officer to support events and the clear
method (in addition to not use obsolete methods like escape
and unescape
).
if (!window.localStorage) {
Object.defineProperty(window, 'localStorage', new (function () {
var aKeys = [], oStorage = {};
var dispatchStorageEvent = function (key, newValue) {
var oldValue = (key == null) ? null : oStorage.getItem(key);
var url = location.href.substr(location.origin.length);
var storageEvent = document.createEvent('StorageEvent');
storageEvent.initStorageEvent('storage', false, false, key, oldValue, newValue, url, null);
window.dispatchEvent(storageEvent);
};
Object.defineProperty(oStorage, 'getItem', {
value: function (sKey) {
return sKey ? this[sKey] : null;
},
writable: false,
configurable: false,
enumerable: false
});
Object.defineProperty(oStorage, 'key', {
value: function (nKeyId) {
return aKeys[nKeyId];
},
writable: false,
configurable: false,
enumerable: false
});
Object.defineProperty(oStorage, 'setItem', {
value: function (sKey, sValue) {
if (!sKey) {
return;
}
document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + '; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/';
dispatchStorageEvent(sKey, sValue);
},
writable: false,
configurable: false,
enumerable: false
});
Object.defineProperty(oStorage, 'length', {
get: function () {
return aKeys.length;
},
configurable: false,
enumerable: false
});
Object.defineProperty(oStorage, 'removeItem', {
value: function (sKey) {
if (!sKey) {
return;
}
document.cookie = encodeURIComponent(sKey) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
dispatchStorageEvent(sKey, null);
},
writable: false,
configurable: false,
enumerable: false
});
Object.defineProperty(oStorage, 'clear', {
value: function () {
document.cookie.split(/\s*;\s*/).forEach(function (c) {
document.cookie = c.replace(/^ +/, '').replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/');
});
dispatchStorageEvent(null, null);
},
writable: false,
configurable: false,
enumerable: false
});
this.get = function () {
var iThisIndx;
for (var sKey in oStorage) {
iThisIndx = aKeys.indexOf(sKey);
if (iThisIndx === -1) {
oStorage.setItem(sKey, oStorage[sKey]);
}
else {
aKeys.splice(iThisIndx, 1);
}
delete oStorage[sKey];
}
for (aKeys; aKeys.length > 0; aKeys.splice(0, 1)) {
oStorage.removeItem(aKeys[0]);
}
for (var aCouple, iKey, nIdx = 0, aCouples = document.cookie.split(/\s*;\s*/); nIdx < aCouples.length; nIdx++) {
aCouple = aCouples[nIdx].split(/\s*=\s*/);
if (aCouple.length > 1) {
oStorage[iKey = decodeURIComponent(aCouple[0])] = decodeURIComponent(aCouple[1]);
aKeys.push(iKey);
}
}
return oStorage;
};
this.configurable = false;
this.enumerable = true;
})());
}
Note: Using the clear
method will remove all cookies from the document including those that were not created with setItem
Here is a polyfill for JSON
if (!window.JSON) {
window.JSON = {
parse: function(sJSON) { return eval('(' + sJSON + ')'); },
stringify: (function () {
var toString = Object.prototype.toString;
var isArray = Array.isArray || function (a) { return toString.call(a) === '[object Array]'; };
var escMap = {'"': '\"', '\': '\\', '\b': '\b', '\f': '\f', '\n': '\n', '\r': '\r', '\t': '\t'};
var escFunc = function (m) { return escMap[m] || '\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); };
var escRE = /[\"\u0000-\u001F\u2028\u2029]/g;
return function stringify(value) {
if (value == null) {
return 'null';
} else if (typeof value === 'number') {
return isFinite(value) ? value.toString() : 'null';
} else if (typeof value === 'boolean') {
return value.toString();
} else if (typeof value === 'object') {
if (typeof value.toJSON === 'function') {
return stringify(value.toJSON());
} else if (isArray(value)) {
var res = '[';
for (var i = 0; i < value.length; i++)
res += (i ? ', ' : '') + stringify(value[i]);
return res + ']';
} else if (toString.call(value) === '[object Object]') {
var tmp = [];
for (var k in value) {
if (value.hasOwnProperty(k))
tmp.push(stringify(k) + ': ' + stringify(value[k]));
}
return '{' + tmp.join(', ') + '}';
}
}
return '"' + value.toString().replace(escRE, escFunc) + '"';
};
})()
};
}