使用Prototype.js JSON.stringify()数组奇怪

我试图找出什么是我的JSON序列化出了问题,具有我的应用程序的旧版本和当前版本JSON.stringify()工作方式(使用json.org JSON库)。

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

JSON.stringify({"a":[1,2]}) 

给我这个;

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

在新版本中,

  JSON.stringify({"a":[1,2]}) 

给我这个;

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

任何想法什么可以改变,使相同的库放在新版本的数组括号周围引号?

由于JSON.stringify最近一直在使用一些浏览器,我build议使用它而不是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; } 

在ECMAScript 5及更高版本中定义的函数JSON.stringify(),在对象上可用时使用函数toJSON()。

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

因此,解决scheme是简单直接的(这是Raphael Schweikert的答案的简化版本):

 delete Array.prototype.toJSON 

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

必须注意的是,在ECMAScript 5中定义的JSON对象在现代浏览器中被高效地实现,因此最好的解决scheme是符合标准并修改现有的库。

不会影响其他Prototype依赖关系的可能的解决scheme是:

 var _json_stringify = JSON.stringify; JSON.stringify = function(value) { var _array_tojson = Array.prototype.toJSON; delete Array.prototype.toJSON; var r=_json_stringify(value); Array.prototype.toJSON = _array_tojson; return r; }; 

这将照顾与JSON.stringify数组toJSON不兼容,并保留到JSONfunction,因为其他Prototype库可能依赖于它。

编辑更精确一点:

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

  if(value && typeof value ==='object'&&
                 typeof value.toJSON ==='function'){
             value = value.toJSON(key);
         } 

问题是Prototype库扩展了Array以包含一个toJSON方法,JSON对象将在上面的代码中调用。 当JSON对象命中数组值时,它将在Prototype中定义的数组上调用JSON,并且该方法返回数组的string版本。 因此,数组括号内的引号。

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

我认为一个更好的解决scheme就是在原型加载之后join

 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(),所以这使得事情与旧版浏览器更加兼容。

我不太熟悉Prototype,但是我在文档中看到了这个:

 Object.toJSON({"a":[1,2]}) 

我不知道这是否会有相同的问题目前的编码了,但。

还有一个关于在Prototype中使用JSON的更长的教程 。

这是我用于相同的问题的代码:

 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) } 

你检查原型是否存在,然后检查版本。 如果旧版本在所有其他情况下使用Object.toJSON(如果已定义)则回退到JSON.stringify()

我正在处理这个问题。

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

我宽容的解决scheme检查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之前的版本。 我也有类似的情况,但不pipePrototype.js是否存在,都必须有代码。 这意味着我不能只是删除Array.prototype.toJSON,因为我不知道什么依赖它。 对于这种情况,这是我提出的最好的解决scheme:

 function safeToJSON(item){ if ([1,2,3] === JSON.parse(JSON.stringify([1,2,3]))){ return JSON.stringify(item); //sane behavior } else { return item.toJSON(); // Prototype.js nonsense } } 

希望它会帮助别人。

如果你不想杀死所有的东西,并且在大多数浏览器上有一个可以使用的代码,你可以这样做:

 (function (undefined) { // This is just to limit _json_stringify to this scope and to redefine undefined in case it was if (true ||typeof (Prototype) !== 'undefined') { // First, ensure we can access the prototype of an object. // See http://stackoverflow.com/questions/7662147/how-to-access-object-prototype-in-javascript if(typeof (Object.getPrototypeOf) === 'undefined') { if(({}).__proto__ === Object.prototype && ([]).__proto__ === Array.prototype) { Object.getPrototypeOf = function getPrototypeOf (object) { return object.__proto__; }; } else { Object.getPrototypeOf = function getPrototypeOf (object) { // May break if the constructor has been changed or removed return object.constructor ? object.constructor.prototype : undefined; } } } var _json_stringify = JSON.stringify; // We save the actual JSON.stringify JSON.stringify = function stringify (obj) { var obj_prototype = Object.getPrototypeOf(obj), old_json = obj_prototype.toJSON, // We save the toJSON of the object res = null; if (old_json) { // If toJSON exists on the object obj_prototype.toJSON = undefined; } res = _json_stringify.apply(this, arguments); if (old_json) obj_prototype.toJSON = old_json; return res; }; } }.call(this)); 

这似乎很复杂,但这只是处理大多数使用情况的复杂过程。 主要思想是覆盖JSON.stringify从作为parameter passing的对象中删除toJSON ,然后调用旧的JSON.stringify ,最后恢复它。