【问题标题】:Javascript: stringify object (including members of type function)Javascript:字符串化对象(包括类型函数的成员)
【发布时间】:2011-04-10 18:51:33
【问题描述】:

我正在寻找一种跨浏览器将 Javascript 对象序列化(和反序列化)为字符串的解决方案,包括恰好是函数的对象成员。一个典型的对象如下所示:

{
   color: 'red',
   doSomething: function (arg) {
        alert('Do someting called with ' + arg);
   }
}

doSomething() 将只包含局部变量(无需同时序列化调用上下文!)。

JSON.stringify() 将忽略 'doSomething' 成员,因为它是一个函数。我知道 toSource() 方法会做我想做的,但它是 FF 特定的。

【问题讨论】:

  • 我只是发表评论,因为我没有提供完整的解决方案。可能有帮助的一件事是,您可以通过调用 toString() 来对函数进行字符串化。 jsfiddle.net/HFMaz 不确定是否支持跨浏览器。
  • 这是经常被问到的,但我找不到任何相关的东西:\为什么你仍然需要序列化函数?也许有更好的方法来安排你的代码?
  • 这是所见即所得的项目。每个 Javascript 对象(带有方法)都定义了页面组件的行为。页面内容(包括 JS 行为)必须保存在服务器端,因此需要序列化。
  • 代码是如何创建的?看来您应该可以在流程的早期阶段访问所有这些的字符串表示形式。
  • 我希望这不会被广大公众使用......否则你必须确保我无法 XSS 那个东西。

标签: javascript json function serialization stringify


【解决方案1】:

您可以将JSON.stringifyreplacer 一起使用,例如:

JSON.stringify({
   color: 'red',
   doSomething: function (arg) {
        alert('Do someting called with ' + arg);
   }
}, function(key, val) {
        return (typeof val === 'function') ? '' + val : val;
});

【讨论】:

  • 我最终使用了JSON.stringify(myObject, function(key, val) { return (typeof val === 'function') ? '[function]' : val; }, 4);,它的输出非常好。
【解决方案2】:

一种快速而肮脏的方式是这样的:

Object.prototype.toJSON = function() {
  var sobj = {}, i;
  for (i in this) 
    if (this.hasOwnProperty(i))
      sobj[i] = typeof this[i] == 'function' ?
        this[i].toString() : this[i];

 return sobj;

};

显然,这会影响代码中每个对象的序列化,并且可能会使用未过滤的 for in 循环使 naive 代码绊倒。 “正确”的方法是编写一个递归函数,在任何给定对象的所有后代成员上添加 toJSON 函数,处理循环引用等。但是,假设单线程 Javascript(没有 Web Workers),这个方法应该可以工作并且不会产生任何意外的副作用。

必须将类似的函数添加到 Array 的原型中,以通过返回数组而不是对象来覆盖 Object 的。另一种选择是附加一个,让它根据对象自身的性质有选择地返回一个数组或一个对象,但它可能会更慢。

function JSONstringifyWithFuncs(obj) {
  Object.prototype.toJSON = function() {
    var sobj = {}, i;
    for (i in this) 
      if (this.hasOwnProperty(i))
        sobj[i] = typeof this[i] == 'function' ?
          this[i].toString() : this[i];

    return sobj;
  };
  Array.prototype.toJSON = function() {
      var sarr = [], i;
      for (i = 0 ; i < this.length; i++) 
          sarr.push(typeof this[i] == 'function' ? this[i].toString() : this[i]);

      return sarr;
  };

  var str = JSON.stringify(obj);

  delete Object.prototype.toJSON;
  delete Array.prototype.toJSON;

  return str;
}

http://jsbin.com/yerumateno/2/edit

【讨论】:

  • 很好,除了数组不再序列化为数组。
  • 解析函数会是什么样子?所有函数都在字符串中,所以在解析时我们需要将它们转换回函数。
【解决方案3】:

这样的……

(function(o) {
    var s = "";
    for (var x in o) {
        s += x + ": " + o[x] + "\n";
    }
    return s;
})(obj)

注意:这是一个表达式。它返回作为参数传入的对象的字符串表示形式(在我的示例中,我将传递名为 obj 的变量)。

你也可以重写 Object 原型的 toString 方法:

Object.prototype.toString = function() {
    // define what string you want to return when toString is called on objects
}

【讨论】:

    【解决方案4】:

    没有对象本身的帮助是不可能的。例如,你将如何序列化这个表达式的结果?

    (功能 () { 变量 x; 返回 { 获取:函数(){返回x; }, 设置:函数(y){返回x = y; } }; })();

    如果你只取函数的文本,那么当你反序列化时,x 将引用全局变量,而不是闭包中的一个。此外,如果您的函数在浏览器状态下关闭(例如对 div 的引用),您必须考虑您想要它的含义。

    当然,您可以编写自己的特定于单个对象的方法,这些方法对您希望引用其他对象具有的语义进行编码。

    【讨论】:

      【解决方案5】:

      JSONfn 插件正是您正在寻找的。​​p>

      http://www.eslinstructor.net/jsonfn/

      --瓦迪姆

      【讨论】:

      • 我已经用我的对象进行了测试,该对象具有功能但无法正常工作。
      猜你喜欢
      • 2021-07-03
      • 1970-01-01
      • 2011-10-20
      • 2011-11-08
      • 1970-01-01
      • 1970-01-01
      • 2015-07-04
      • 1970-01-01
      • 2013-08-25
      相关资源
      最近更新 更多