формат JSON.преобразовать в строки() странностей массива с прототипом.js
Я пытаюсь выяснить, что пошло не так с моей сериализацией json, есть текущая версия моего приложения и старая, и я нахожу некоторые удивительные различия в том, как JSON.stringify () работает (используя библиотеку JSON из json.org).
в старой версии моего приложения:
JSON.stringify({"a":[1,2]})
дает мне это:
"{"a":[1,2]}"
в новой версии
JSON.stringify({"a":[1,2]})
дает мне это:
"{"a":"[1, 2]"}"
любая идея, что можно было бы изменить, чтобы сделать та же библиотека помещает кавычки вокруг скобок массива в новой версии?
11 ответов:
начиная с JSON.stringify в последнее время поставляется с некоторыми браузерами, я бы предложил использовать его вместо прототипа toJSON. Затем вы проверили бы окно.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 () определяется в ECMAScript 5 и выше (страница 201-объект JSON, псевдокодовая страница 205), использует функцию toJSON () при наличии на объектах.
Потому Что Прототип.JS (или другая библиотека, которую вы используете) определяет массив.прототип.функция toJSON (), массивы сначала преобразуются в строки с помощью массива.прототип.метод toJSON (), то строка, заключенная с помощью JSON.stringify (), следовательно, неправильные дополнительные кавычки вокруг матрицы.
delete Array.prototype.toJSONЭто создает, конечно, побочные эффекты для библиотек, которые полагаются на свойство функции toJSON () для массивов. Но я нахожу это незначительным неудобством, учитывая несовместимость с ECMAScript 5.
следует отметить, что объект JSON, определенный в ECMAScript 5, эффективно реализован в современных браузерах и поэтому лучшим решением является соответствие стандарту и изменение существующих библиотек.
возможным решением, которое не повлияет на другие зависимости прототипа, будет:
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; };Это заботится о несовместимости массива toJSON с JSON.stringify, а также сохраняет функциональность toJSON, поскольку от нее могут зависеть другие библиотеки прототипов.
изменить, чтобы сделать немного более точным:
проблемный ключевой бит кода находится в библиотеке JSON из JSON.org (и другие реализации объекта JSON ECMAScript 5):
if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); }проблема в том, что библиотека прототипов расширяет массив, чтобы включить метод toJSON, который объект JSON вызовет в коде выше. Когда объект JSON попадает в значение массива, он вызывает toJSON в массиве, который определен в Prototype, и этот метод возвращает строковую версию матрица. Следовательно, кавычки вокруг скобок массива.
Если вы удалите toJSON из объекта массива, библиотека JSON должна работать правильно. Или просто используйте библиотеку JSON.
Я думаю, что лучшим решением было бы включить это сразу после загрузки прототипа
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 () если он доступен, так что это делает вещи более совместимыми со старыми браузерами.
Это код, который я использовал для той же проблемы:
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) }вы проверяете, существует ли прототип, затем вы проверяете версию. Если старая версия использовать объект.toJSON (если определено) во всех остальных случаях является резервным вариантом для JSON.преобразовать в строки()
вот как я с этим справляюсь.
var methodCallString = Object.toJSON? Object.toJSON(options.jsonMethodCall) : JSON.stringify(options.jsonMethodCall);
мое толерантное решение проверяет, является ли массив.прототип.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 } }
как люди указали, это связано с прототипом.js-конкретно версии до 1.7. У меня была аналогичная ситуация, но должен был быть код, который работал ли прототип.js был там или нет; это означает, что я не могу просто удалить массив.прототип.тойсон, как я не уверен, что полагается на это. Для этой ситуации это лучшее решение, которое я придумал:
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удалитьtoJSONиз объекта, переданного в качестве аргумента, а затем вызвать старогоJSON.stringifyи, наконец, восстановить его.
Comments