Stringify не решает всех проблем
Кажется, что ответы здесь не охватывают все типы, которые возможны в JavaScript, поэтому вот несколько коротких примеров того, как правильно с ними обращаться:
//Objects and Arrays:
var obj = {key: "value"};
localStorage.object = JSON.stringify(obj); //Will ignore private members
obj = JSON.parse(localStorage.object);
//Boolean:
var bool = false;
localStorage.bool = bool;
bool = (localStorage.bool === "true");
//Numbers:
var num = 42;
localStorage.num = num;
num = +localStorage.num; //short for "num = parseFloat(localStorage.num);"
//Dates:
var date = Date.now();
localStorage.date = date;
date = new Date(parseInt(localStorage.date));
//Regular expressions:
var regex = /^No\.[\d]*$/i; //usage example: "No.42".match(regex);
localStorage.regex = regex;
var components = localStorage.regex.match("^/(.*)/([a-z]*)$");
regex = new RegExp(components[1], components[2]);
//Functions (not recommended):
function func(){}
localStorage.func = func;
eval( localStorage.func ); //recreates the function with the name "func"
Я не рекомендую хранить функции, потому что eval()
это зло, может привести к проблемам, связанным с безопасностью, оптимизацией и отладкой.
Как правило, eval()
никогда не следует использовать в коде JavaScript.
Личные участники
Проблема с использованием JSON.stringify()
для хранения объектов заключается в том, что эта функция не может сериализовать закрытые члены.
Эту проблему можно решить, переписав метод .toString()
(который вызывается неявно при хранении данных в веб-хранилище):
//Object with private and public members:
function MyClass(privateContent, publicContent){
var privateMember = privateContent || "defaultPrivateValue";
this.publicMember = publicContent || "defaultPublicValue";
this.toString = function(){
return '{"private": "' + privateMember + '", "public": "' + this.publicMember + '"}';
};
}
MyClass.fromString = function(serialisedString){
var properties = JSON.parse(serialisedString || "{}");
return new MyClass( properties.private, properties.public );
};
//Storing:
var obj = new MyClass("invisible", "visible");
localStorage.object = obj;
//Loading:
obj = MyClass.fromString(localStorage.object);
Циркулярные ссылки
Другая проблема, с которой stringify
не может справиться, это циклические ссылки:
var obj = {};
obj["circular"] = obj;
localStorage.object = JSON.stringify(obj); //Fails
В этом примере JSON.stringify()
выдаст TypeError
"Преобразование круговой структуры в JSON" .
Если должно поддерживаться сохранение циклических ссылок, можно использовать второй параметр JSON.stringify()
:
var obj = {id: 1, sub: {}};
obj.sub["circular"] = obj;
localStorage.object = JSON.stringify( obj, function( key, value) {
if( key == 'circular') {
return "$ref"+value.id+"$";
} else {
return value;
}
});
Однако поиск эффективного решения для хранения циклических ссылок во многом зависит от задач, которые необходимо решить, и восстановление таких данных также не тривиально.
Уже есть вопрос о том, как SO решает эту проблему: Stringify (преобразовать в JSON) объект JavaScript с циклической ссылкой