json.stringify不处理对象方法

时间:2013-08-06 19:40:44

标签: javascript json local-storage

我正在尝试开发一个适用于大多数现代浏览器(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方法,我将非常感激。

3 个答案:

答案 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