我使用chrome的原生JSON.stringify序列化相当复杂的数据结构(稍后将切换到某些序列化库以支持跨浏览器)。大多数数据可以看作是静态的,但有些是动态的。
在构建数据时,我希望能够执行类似
的操作var dynamicString=new String();
{a:"foo", b:dynamicString}
然后稍后设置dynamicString的原始字符串值。我想这样做而不是更改该对象的属性“b”,因为这样可以更容易地构建这些数据。 即类似的东西:
我已经发现无法更改String-object的原始值。我还发现valueOf函数可以设置为自定义函数,并且通过在该函数中返回所需的值,如果执行以下操作,基本上可以实现:
var dynamicString=new String("bar");
a.valueOf=function(){return ("foo")};
alert (a+"bar");//foobar
问题是序列化显然不使用valueOf函数。在这种情况下,序列化dynamicString-object会将“bar”放在JSON.stringify返回的字符串中,而不是所需的“foo”。
获得我所追求的东西的一种方法是在序列化之前递归循环数据结构的所有对象,并用它们返回的原始值替换dynamicData-objects。但是如果可能的话,我想避免这种情况。
有什么建议吗?
编辑:我当然也可以在数据中放置一个对象,我也有参考。然后我可以“动态”设置该对象的数据,这将反映在结果字符串中。但这增加了结构的另一个层次。我只想要一个字符串,而不是一个带有字符串属性的对象。
答案 0 :(得分:1)
将第二个参数用于JSON.stringify
:replacer
您还可以使用toJSON
属性,它的行为类似于toString
。
答案 1 :(得分:1)
我还发现valueOf函数可以设置为自定义函数,并且通过返回该函数中的所需值,如果执行以下操作,基本上可以实现:
var a = new String("bar"); a.valueOf = function(){return ("foo")}; console.log(a+"bar"); // "foobar"
然而,如果你覆盖valueOf
,使用String
对象(具有一些不同的内部值)没有任何意义。使用具有valueOf
函数的普通对象,或者甚至只使用动态更改的属性。根据您当前的方法,您将获得
console.log(a.concat("bar")); // "barbar"!
问题是序列化显然不使用valueOf函数。在这种情况下,序列化dynamicString-object会将“bar”放在JSON.stringify返回的字符串中,而不是所需的“foo”。
是。 JSON.stringify
会在对象上调用toJSON
方法,在您的情况下仍会返回内部值。如果你覆盖它,它将起作用:
a.toJSON = a.valueOf;
console.log(JSON.stringify(a)); // '"foo"'
如上所述,使用原生String
对象没有多大意义。相反,我们应该为它们创建一个额外的构造函数:
function DynamicString(value) {
if (!(this instanceof DynamicString))
return new DynamicString(value);
this.set(value);
}
var p = DynamicString.prototype = Object.create(String.prototype, {
constructor: {value: DynamicString, configurable: true}
});
p.set = function(value) {
this.__value__ = String(value);
};
p.valueOf = p.toString = p.toJSON = function() {
return this.__value__;
};
现在,使用它:
var a = new DynamicString("foo");
console.log(a+"bar"); // "foobar"
console.log(JSON.stringify({a:a, b:"bar"})); // '{"a":"foo","b":"bar"}'
你甚至得到了所有String.prototype
方法(但它们会产生原始字符串,而不是动态字符串)。