我正在尝试开发一个适用于大多数现代浏览器(Chrome,Firefox,IE 9 +,Safari,Opera)的离线HTML5应用程序。由于Safari(尚未)支持IndexedDB,并且不推荐使用WebSQL,因此我决定使用localStorage存储用户生成的JavaScript对象,并使用JSON.stringify()
/ JSON.parse()
来放入或取出对象。但是,我发现JSON.stringify()
不处理方法。这是一个带有简单方法的示例对象:
var myObject = {};
myObject.foo = 'bar';
myObject.someFunction = function () {/*code in this function*/}
如果我将此对象字符串化(稍后将其放入localStorage),则所有将保留的内容为myObject.foo
,而不是myObject.someFunction()
。
//put object into localStorage
localStorage.setItem('myObject',JSON.stringify(myObject));
//pull it out of localStorage and set it to myObject
myObject = localStorage.getItem('myObject');
//undefined!
myObject.someFunction
我相信很多人可能已经知道这个限制/功能/无论你想叫它什么。我提出的解决方法是使用方法(myObject = new objectConstructor()
)创建一个对象,从localStorage中提取对象属性,并将它们分配给我创建的新对象。我觉得这是一个迂回的方法,但我是JavaScript世界的新手,所以这就是我解决它的方法。所以这是我的大问题:我希望将整个对象(属性+方法)包含在localStorage中。我该怎么做呢?如果您可以向我展示一个更好的算法,或者我不了解的其他JSON方法,我将非常感激。
答案 0 :(得分:35)
javascript中的函数不仅仅是代码。他们也有范围。代码可以进行字符串化,但范围不能。
JSON.stringify()
将编码JSON支持的值。具有可以是对象,数组,字符串,数字和布尔值的值的对象。其他任何内容都将被忽略或抛出错误。函数不是JSON中受支持的实体。 JSON仅处理纯数据,函数不是数据,而是具有更复杂语义的行为。
那说你可以改变JSON.stringify()
的工作方式。第二个参数是replacer
函数。因此,您可以通过强制执行功能的强制来强制执行所需的行为:
var obj = {
foo: function() {
return "I'm a function!";
}
};
var json = JSON.stringify(obj, function(key, value) {
if (typeof value === 'function') {
return value.toString();
} else {
return value;
}
});
console.log(json);
// {"foo":"function () { return \"I'm a function!\" }"}
但是当你读回来时,你必须评估函数字符串并将结果设置回对象,因为JSON 不支持函数。
JSON中的所有编码功能都可以变得非常多毛。你确定你要这么做吗?可能有更好的方法......
也许您可以保存原始数据,并将其传递给页面上加载的JS中的构造函数。 localStorage
只会保存数据,但加载到页面上的代码会提供操作该数据的方法。
// contrived example...
var MyClass = function(data) {
this.firstName = data.firstName;
this.lastName = data.lastName;
}
MyClass.prototype.getName() {
return this.firstName + ' ' + this.lastName;
}
localStorage.peopleData = [{
firstName: 'Bob',
lastName: 'McDudeFace'
}];
var peopleData = localStorage.peopleData;
var bob = new MyClass(peopleData[0]);
bob.getName() // 'Bob McDudeFace'
我们无需将getName()
方法保存到localStorage
。我们只需要将数据提供给将提供该方法的构造函数。
答案 1 :(得分:1)
如果要对对象进行字符串化,但它们具有函数,则可以将JSON.stringify()
与第二个参数replacer
一起使用。要防止对象的循环依赖,可以使用var cache = []
。
在我们的项目中,我们使用lodash。我们使用以下函数生成日志。可以用它将对象保存到localStorage
。
var stringifyObj = function(obj) {
var cache = []
return JSON.stringify(obj, function(key, value) {
if (
_.isString(value) ||
_.isNumber(value) ||
_.isBoolean(value)
) {
return value
} else if (_.isError(value)) {
return value.stack || ''
} else if (_.isPlainObject(value) || _.isArray(value)) {
if (cache.indexOf(value) !== -1) {
return
} else {
// cache each item
cache.push(value)
return value
}
}
})
}
// create a circular object
var circularObject = {}
circularObject.circularObject = circularObject
// stringify an object
$('body').text(
stringifyObj(
{
myBooblean: true,
myString: 'foo',
myNumber: 1,
myArray: [1, 2, 3],
myObject: {},
myCircularObject: circularObject,
myFunction: function () {}
}
)
)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
答案 2 :(得分:0)
不按要求修复函数,而是在本地存储变量的方法...
<html>
<head>
<title>Blank</title>
<script>
if(localStorage.g===undefined) localStorage.g={};
var g=JSON.parse(localStorage.g);
</script>
</head>
<body>
<input type=button onClick="localStorage.g=JSON.stringify(g, null, ' ')" value="Save">
<input type=button onClick="g=JSON.parse(localStorage.g)" value="Load">
</body>
</html>
保留对象g
中的所有变量。示例:
g.arr=[1,2,3];
Date
,您需要执行以下操作: g.date=new Date(g.date);
g