1

我正在使用 Chrome 的原生 JSON.stringify 序列化相当复杂的数据结构(稍后将切换到一些序列化库以获得跨浏览器支持)。大多数数据可以看作是静态的,但有些是动态的。

在构建数据时,我希望能够做类似的事情

var dynamicString=new String();
{a:"foo", b:dynamicString}

然后稍后设置 dynamicString 的原始字符串值。我想这样做而不是更改该对象的属性“b”,因为这样可以更轻松地构造这些数据。即类似的东西:

我已经发现不能更改字符串对象的原始值。我还发现 valueOf-function 可以设置为自定义函数,并且通过在该函数中返回所需的值,如果执行以下操作基本上可以实现:

var dynamicString=new String("bar");
a.valueOf=function(){return ("foo")};
alert (a+"bar");//foobar

问题是序列化显然不使用 valueOf 函数。在这种情况下,对动态字符串对象进行序列化会将“bar”放入 JSON.stringify 返回的字符串中,而不是所需的“foo”。

获得我所追求的一种方法是在序列化之前递归循环遍历数据结构的所有对象,并用它们返回的原始值替换动态数据对象。但如果可能的话,我想避免这种情况。

有什么建议么?

编辑:我当然也可以在数据中放置一个对象,我也可以参考。然后我可以“动态地”设置该对象的数据,这将反映在结果字符串中。但这增加了结构的另一个层次。我只想要一个字符串,而不是具有字符串属性的对象。

4

2 回答 2

1

使用第二个参数JSON.stringifyreplacer

您也可以使用该toJSON属性,它的行为类似于toString.

于 2013-05-17T15:03:02.937 回答
1

我还发现 valueOf-function 可以设置为自定义函数,并且通过在该函数中返回所需的值,如果执行以下操作,基本上可以实现:

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 函数。在这种情况下,对动态字符串对象进行序列化会将“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方法(但它们会产生原始字符串,而不是动态字符串)。

于 2013-05-17T15:08:54.957 回答