Я пытаюсь выяснить, что пошло не так с моей сериализацией json, имею текущую версию моего приложения и старую, и нахожу некоторые удивительные различия в том, как работает JSON.stringify () (Использование библиотеки JSON с json.org ).
В старой версии моего приложения:
JSON.stringify({"a":[1,2]})
дает мне это;
"{\"a\":[1,2]}"
в новой версии,
JSON.stringify({"a":[1,2]})
дает мне это;
"{\"a\":\"[1, 2]\"}"
есть идеи, что можно было изменить, чтобы та же библиотека помещала кавычки вокруг скобок массива в новой версии?
javascript
json
prototypejs
морганкоды
источник
источник
Ответы:
Поскольку JSON.stringify в последнее время поставляется с некоторыми браузерами, я бы предложил использовать его вместо 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 (), определенная в ECMAScript 5 и выше (стр. 201 - объект JSON, псевдокод, стр. 205) , использует функцию toJSON (), если она доступна для объектов.
Поскольку Prototype.js (или другая используемая вами библиотека) определяет функцию Array.prototype.toJSON (), массивы сначала преобразуются в строки с помощью Array.prototype.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, поскольку от него могут зависеть другие библиотеки прототипов.
источник
if(typeof Prototype !== 'undefined' && parseFloat(Prototype.Version.substr(0,3)) < 1.7 && typeof Array.prototype.toJSON !== 'undefined')
. Это сработало.Отредактируйте, чтобы сделать немного точнее:
Проблемный ключевой бит кода находится в библиотеке JSON от JSON.org (и других реализациях объекта JSON ECMAScript 5):
if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); }
Проблема в том, что библиотека Prototype расширяет массив, чтобы включить метод toJSON, который объект JSON будет вызывать в приведенном выше коде. Когда объект JSON достигает значения массива, он вызывает JSON в массиве, который определен в Prototype, и этот метод возвращает строковую версию массива. Следовательно, кавычки вокруг скобок массива.
Если вы удалите toJSON из объекта Array, библиотека 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 (), если он доступен, поэтому это делает вещи более совместимыми со старыми браузерами.
источник
Я не так хорошо владею Prototype, но я видел это в его документации :
Object.toJSON({"a":[1,2]})
Я не уверен, что это будет иметь ту же проблему, что и текущая кодировка.
Также есть более подробное руководство по использованию JSON с Prototype.
источник
Это код, который я использовал для той же проблемы:
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);
источник
Мое терпимое решение проверяет, вреден ли 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 или нет; это означает, что я не могу просто удалить Array.prototype.toJSON, поскольку я не уверен, что от него зависит. В этой ситуации это лучшее решение, которое я придумал:
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
и, наконец, восстановить его.источник