Próbuję dowiedzieć się, co poszło nie tak z moją serializacją json, mam bieżącą wersję mojej aplikacji i starą i znajduję zaskakujące różnice w sposobie działania JSON.stringify () (Korzystanie z biblioteki JSON z json.org ).
W starej wersji mojej aplikacji:
JSON.stringify({"a":[1,2]})
daje mi to;
"{\"a\":[1,2]}"
w nowej wersji,
JSON.stringify({"a":[1,2]})
daje mi to;
"{\"a\":\"[1, 2]\"}"
masz jakiś pomysł, co mogło się zmienić, aby ta sama biblioteka umieszczała cudzysłowy wokół nawiasów tablicy w nowej wersji?
javascript
json
prototypejs
morgancodes
źródło
źródło
Odpowiedzi:
Ponieważ JSON.stringify jest ostatnio dostarczany z niektórymi przeglądarkami, sugerowałbym użycie go zamiast toJSON Prototype. Następnie należy sprawdzić window.JSON && window.JSON.stringify i dołączyć tylko bibliotekę json.org w innym przypadku (przez
document.createElement('script')
…). Aby rozwiązać niezgodności, użyj:if(window.Prototype) { delete Object.prototype.toJSON; delete Array.prototype.toJSON; delete Hash.prototype.toJSON; delete String.prototype.toJSON; }
źródło
Funkcja JSON.stringify () zdefiniowana w ECMAScript 5 i nowszych (Strona 201 - The JSON Object, pseudokod Strona 205) , używa funkcji toJSON (), gdy jest dostępna na obiektach.
Ponieważ Prototype.js (lub inna używana biblioteka) definiuje funkcję Array.prototype.toJSON (), tablice są najpierw konwertowane na ciągi za pomocą Array.prototype.toJSON (), a następnie ciąg cytowany przez JSON.stringify (), stąd niepoprawne dodatkowe cudzysłowy wokół tablic.
Rozwiązanie jest zatem proste i trywialne (jest to uproszczona wersja odpowiedzi Raphaela Schweikerta):
delete Array.prototype.toJSON
Daje to oczywiście efekty uboczne w bibliotekach, które polegają na właściwości funkcji toJSON () dla tablic. Ale uważam to za drobną niedogodność, biorąc pod uwagę niekompatybilność z ECMAScript 5.
Należy zaznaczyć, że obiekt JSON zdefiniowany w ECMAScript 5 jest sprawnie implementowany w nowoczesnych przeglądarkach, dlatego najlepszym rozwiązaniem jest dostosowanie się do standardu i modyfikacja istniejących bibliotek.
źródło
Możliwym rozwiązaniem, które nie wpłynie na inne zależności prototypu, byłoby:
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; };
Zajmuje się to niekompatybilnością Array toJSON z JSON.stringify, a także zachowuje funkcjonalność toJSON, ponieważ inne biblioteki Prototype mogą od niego zależeć.
źródło
if(typeof Prototype !== 'undefined' && parseFloat(Prototype.Version.substr(0,3)) < 1.7 && typeof Array.prototype.toJSON !== 'undefined')
. Zadziałało.Edytuj, aby uczynić trochę dokładniejszym:
Kod klucza problemu znajduje się w bibliotece JSON z JSON.org (i innych implementacjach obiektu JSON ECMAScript 5):
if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); }
Problem polega na tym, że biblioteka Prototype rozszerza Array o metodę toJSON, którą obiekt JSON wywoła w powyższym kodzie. Gdy obiekt JSON osiąga wartość tablicy, wywołuje toJSON na tablicy zdefiniowanej w Prototype, a ta metoda zwraca wersję ciągu tablicy. Stąd cudzysłowy wokół nawiasów tablicy.
Jeśli usuniesz toJSON z obiektu Array, biblioteka JSON powinna działać poprawnie. Lub po prostu użyj biblioteki JSON.
źródło
Myślę, że lepszym rozwiązaniem byłoby włączenie tego zaraz po załadowaniu prototypu
JSON = JSON || {}; JSON.stringify = function(value) { return value.toJSON(); }; JSON.parse = JSON.parse || function(jsonsring) { return jsonsring.evalJSON(true); };
To sprawia, że funkcja prototypu jest dostępna jako standardowe JSON.stringify () i JSON.parse (), ale zachowuje natywną JSON.parse (), jeśli jest dostępna, dzięki czemu jest bardziej kompatybilna ze starszymi przeglądarkami.
źródło
Nie jestem biegły w Prototype, ale widziałem to w jego dokumentacji :
Object.toJSON({"a":[1,2]})
Nie jestem jednak pewien, czy miałoby to ten sam problem, co obecne kodowanie.
Istnieje również dłuższy samouczek dotyczący używania JSON z Prototype.
źródło
Oto kod, którego użyłem do tego samego problemu:
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) }
Sprawdzasz, czy Prototyp istnieje, a następnie sprawdzasz wersję. Jeśli stara wersja, użyj Object.toJSON (jeśli jest zdefiniowana), we wszystkich innych przypadkach powrót do JSON.stringify ()
źródło
Oto jak sobie z tym radzę.
var methodCallString = Object.toJSON? Object.toJSON(options.jsonMethodCall) : JSON.stringify(options.jsonMethodCall);
źródło
Moje tolerancyjne rozwiązanie sprawdza, czy Array.prototype.toJSON jest szkodliwe dla stringify JSON i zachowuje je, gdy to możliwe, aby otaczający kod działał zgodnie z oczekiwaniami:
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 } }
źródło
Jak ludzie zauważyli, jest to spowodowane Prototype.js - konkretnie wersjami wcześniejszymi niż 1.7. Miałem podobną sytuację, ale musiałem mieć kod, który działał niezależnie od tego, czy Prototype.js był obecny, czy nie; oznacza to, że nie mogę po prostu usunąć Array.prototype.toJSON, ponieważ nie jestem pewien, na czym on polega. W tej sytuacji jest to najlepsze rozwiązanie, które wymyśliłem:
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 } }
Mam nadzieję, że to komuś pomoże.
źródło
Jeśli nie chcesz zabijać wszystkiego i masz kod, który byłby w porządku w większości przeglądarek, możesz to zrobić w ten sposób:
(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));
Wydaje się to skomplikowane, ale jest skomplikowane tylko w przypadku większości przypadków użycia. Główną ideą jest nadpisanie
JSON.stringify
usunięciatoJSON
z obiektu przekazanego jako argument, następnie wywołanie staregoJSON.stringify
i na koniec przywrócenie go.źródło