Javascript stringify()数组与Prototype.js的奇异性

Javascript stringify()数组与Prototype.js的奇异性,javascript,json,prototypejs,Javascript,Json,Prototypejs,我试图找出我的json序列化出了什么问题,将我的应用程序的当前版本与旧版本进行了比较,并发现json.stringify()的工作方式(使用json.org中的json库)存在一些令人惊讶的差异 在我的应用程序的旧版本中: JSON.stringify({"a":[1,2]}) JSON.stringify({"a":[1,2]}) 给我这个 "{\"a\":[1,2]}" "{\"a\":\"[1, 2]\"}" 在新版本中 给我这个 "{\"a\":[1,2]}" "{\"a\

我试图找出我的json序列化出了什么问题,将我的应用程序的当前版本与旧版本进行了比较,并发现json.stringify()的工作方式(使用json.org中的json库)存在一些令人惊讶的差异

在我的应用程序的旧版本中:

 JSON.stringify({"a":[1,2]})
 JSON.stringify({"a":[1,2]})
给我这个

"{\"a\":[1,2]}"
"{\"a\":\"[1, 2]\"}"
在新版本中

给我这个

"{\"a\":[1,2]}"
"{\"a\":\"[1, 2]\"}"

你知道在新版本中,为了让同一个库在数组括号中加上引号,会发生什么变化吗?

下面是我的处理方法

var methodCallString =  Object.toJSON? Object.toJSON(options.jsonMethodCall) :  JSON.stringify(options.jsonMethodCall);

我是这样处理的

var methodCallString =  Object.toJSON? Object.toJSON(options.jsonMethodCall) :  JSON.stringify(options.jsonMethodCall);

我对原型不太熟悉,但我从它的:

不过,我不确定这是否会与当前编码存在相同的问题


在Prototype中使用JSON还有一个较长的问题。

我对Prototype不是很熟练,但我从中看到了这一点:

不过,我不确定这是否会与当前编码存在相同的问题


在Prototype中使用JSON还有一个较长的问题。

我认为更好的解决方案是在Prototype加载后立即包含此内容

JSON = JSON || {};

JSON.stringify = function(value) { return value.toJSON(); };

JSON.parse = JSON.parse || function(jsonsring) { return jsonsring.evalJSON(true); };

这使得prototype函数可以作为标准的JSON.stringify()和JSON.parse()使用,但如果可以的话,可以保留原生的JSON.parse(),因此这使得它与旧浏览器更兼容。

我认为更好的解决方案是在加载prototype之后包含它

JSON = JSON || {};

JSON.stringify = function(value) { return value.toJSON(); };

JSON.parse = JSON.parse || function(jsonsring) { return jsonsring.evalJSON(true); };

这使得原型函数可以作为标准的JSON.stringify()和JSON.parse()使用,但如果可以,则保留本机的JSON.parse(),因此这使它与旧浏览器更兼容。

编辑以使其更加准确:

代码的关键问题在于JSON.org中的JSON库(以及ECMAScript 5的JSON对象的其他实现):

问题是原型库扩展了数组以包含一个toJSON方法,JSON对象将在上面的代码中调用该方法。当JSON对象命中数组值时,它调用原型中定义的数组上的toJSON,该方法返回数组的字符串版本。因此,数组方括号中的引号是正确的


如果从数组对象中删除toJSON,JSON库应该可以正常工作。或者,只需使用JSON库。

编辑使其更加准确:

代码的关键问题在于JSON.org中的JSON库(以及ECMAScript 5的JSON对象的其他实现):

问题是原型库扩展了数组以包含一个toJSON方法,JSON对象将在上面的代码中调用该方法。当JSON对象命中数组值时,它调用原型中定义的数组上的toJSON,该方法返回数组的字符串版本。因此,数组方括号中的引号是正确的


如果从数组对象中删除toJSON,JSON库应该可以正常工作。或者,只需使用JSON库。

由于JSON.stringify最近已随一些浏览器提供,我建议使用它而不是Prototype的toJSON。然后检查window.JSON&&window.JSON.stringify,否则只包括JSON.org库(通过
document.createElement('script')
…)。要解决不兼容问题,请使用:

if(window.Prototype) {
    delete Object.prototype.toJSON;
    delete Array.prototype.toJSON;
    delete Hash.prototype.toJSON;
    delete String.prototype.toJSON;
}

由于JSON.stringify最近已经随一些浏览器发布,我建议使用它而不是Prototype的toJSON。然后检查window.JSON&&window.JSON.stringify,否则只包括JSON.org库(通过
document.createElement('script')
…)。要解决不兼容问题,请使用:

if(window.Prototype) {
    delete Object.prototype.toJSON;
    delete Array.prototype.toJSON;
    delete Hash.prototype.toJSON;
    delete String.prototype.toJSON;
}

中定义的函数JSON.stringify()在对象上可用时使用函数toJSON()

因为Prototype.js(或您正在使用的另一个库)定义了Array.Prototype.toJSON()函数,所以首先使用Array.Prototype.toJSON()将数组转换为字符串,然后使用JSON.stringify()引用字符串,因此数组周围的额外引号不正确

因此,解决方案简单明了(这是Raphael Schweikert答案的简化版本):

这当然会对依赖于数组的toJSON()函数属性的库产生副作用。但考虑到与ECMAScript 5的不兼容性,我觉得这是一个小小的不便


必须注意的是,ECMAScript 5中定义的JSON对象在现代浏览器中得到了有效实现,因此最好的解决方案是遵守标准并修改现有库。

中定义的函数JSON.stringify()在对象上可用时使用函数toJSON()

因为Prototype.js(或您正在使用的另一个库)定义了Array.Prototype.toJSON()函数,所以首先使用Array.Prototype.toJSON()将数组转换为字符串,然后使用JSON.stringify()引用字符串,因此数组周围的额外引号不正确

因此,解决方案简单明了(这是Raphael Schweikert答案的简化版本):

这当然会对依赖于数组的toJSON()函数属性的库产生副作用。但考虑到与ECMAScript 5的不兼容性,我觉得这是一个小小的不便


必须注意的是,ECMAScript 5中定义的JSON对象在现代浏览器中得到了有效的实现,因此最好的解决方案是遵守标准并修改现有库。

我的容错解决方案检查Array.prototype.toJSON是否对JSON字符串化有害,并在可能的情况下保留它,以便让周围的代码按预期工作:

var dummy = { data: [{hello: 'world'}] }, test = {};

if(Array.prototype.toJSON) {
    try {
        test = JSON.parse(JSON.stringify(dummy));
        if(!test || dummy.data !== test.data) {
            delete Array.prototype.toJSON;
        }
    } catch(e) {
        // there only hope
    }
}

我的容错解决方案检查Array.prototype.toJSON是否对JSON stringify有害,并在可能的情况下保留它,以使周围的代码按预期工作:

var dummy = { data: [{hello: 'world'}] }, test = {};

if(Array.prototype.toJSON) {
    try {
        test = JSON.parse(JSON.stringify(dummy));
        if(!test || dummy.data !== test.data) {
            delete Array.prototype.toJSON;
        }
    } catch(e) {
        // there only hope
    }
}

正如人们指出的,这是由于Prototype.js,特别是1.7之前的版本。我也遇到过类似的情况,但无论Prototype.js是否存在,我都必须有运行的代码;这意味着我不能仅仅删除数组。
function stringify(object){
      var Prototype = window.Prototype
      if (Prototype && Prototype.Version < '1.7' &&
          Array.prototype.toJSON && Object.toJSON){
              return Object.toJSON(object)
      }
      return JSON.stringify(object)
}