Saya mencoba mencari tahu apa yang salah dengan serialisasi json saya, memiliki versi aplikasi saya saat ini dan versi lama dan saya menemukan beberapa perbedaan mengejutkan dalam cara kerja JSON.stringify () (Menggunakan perpustakaan JSON dari json.org ).
Di versi lama aplikasi saya:
JSON.stringify({"a":[1,2]})
berikan aku ini;
"{\"a\":[1,2]}"
di versi baru,
JSON.stringify({"a":[1,2]})
berikan aku ini;
"{\"a\":\"[1, 2]\"}"
tahu apa yang bisa berubah untuk membuat pustaka yang sama memberi tanda kutip di sekitar tanda kurung siku di versi baru?
javascript
json
prototypejs
kamar mayat
sumber
sumber
Jawaban:
Karena JSON.stringify telah dikirim dengan beberapa browser belakangan ini, saya akan menyarankan untuk menggunakannya daripada toJSON Prototipe. Anda kemudian akan memeriksa window.JSON && window.JSON.stringify dan hanya menyertakan pustaka json.org jika tidak (melalui
document.createElement('script')
…). Untuk mengatasi ketidakcocokan, gunakan:if(window.Prototype) { delete Object.prototype.toJSON; delete Array.prototype.toJSON; delete Hash.prototype.toJSON; delete String.prototype.toJSON; }
sumber
Fungsi JSON.stringify () yang didefinisikan dalam ECMAScript 5 dan di atasnya (Halaman 201 - Objek JSON, pseudo-code Halaman 205) , menggunakan fungsi toJSON () jika tersedia pada objek.
Karena Prototype.js (atau pustaka lain yang Anda gunakan) mendefinisikan fungsi Array.prototype.toJSON (), array pertama-tama diubah menjadi string menggunakan Array.prototype.toJSON () lalu string dikutip oleh JSON.stringify (), maka kutipan tambahan yang salah di sekitar array.
Oleh karena itu, solusinya langsung ke depan dan sepele (ini adalah versi sederhana dari jawaban Raphael Schweikert):
delete Array.prototype.toJSON
Hal ini tentu saja menghasilkan efek samping pada pustaka yang mengandalkan properti fungsi toJSON () untuk array. Tapi saya menemukan ini ketidaknyamanan kecil mengingat ketidakcocokan dengan ECMAScript 5.
Perlu dicatat bahwa Objek JSON yang ditentukan dalam ECMAScript 5 diimplementasikan secara efisien di browser modern dan oleh karena itu solusi terbaik adalah menyesuaikan dengan standar dan memodifikasi pustaka yang ada.
sumber
Solusi yang memungkinkan yang tidak akan memengaruhi dependensi Prototipe lainnya adalah:
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; };
Ini menangani ketidakcocokan Array toJSON dengan JSON.stringify dan juga mempertahankan fungsionalitas toJSON karena pustaka Prototipe lain mungkin bergantung padanya.
sumber
if(typeof Prototype !== 'undefined' && parseFloat(Prototype.Version.substr(0,3)) < 1.7 && typeof Array.prototype.toJSON !== 'undefined')
. Berhasil.Edit untuk membuatnya lebih akurat:
Bit kode kunci masalah ada di pustaka JSON dari JSON.org (dan implementasi lain dari objek JSON ECMAScript 5):
if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); }
Masalahnya adalah bahwa pustaka Prototipe memperluas Array untuk menyertakan metode toJSON, yang akan dipanggil oleh objek JSON dalam kode di atas. Saat objek JSON mencapai nilai array, ia memanggil toJSON pada array yang didefinisikan dalam Prototipe, dan metode itu mengembalikan versi string dari array. Karenanya, tanda kutip di sekitar tanda kurung siku.
Jika Anda menghapus toJSON dari objek Array, pustaka JSON akan berfungsi dengan baik. Atau, cukup gunakan perpustakaan JSON.
sumber
Saya pikir solusi yang lebih baik adalah memasukkan ini setelah prototipe dimuat
JSON = JSON || {}; JSON.stringify = function(value) { return value.toJSON(); }; JSON.parse = JSON.parse || function(jsonsring) { return jsonsring.evalJSON(true); };
Ini membuat fungsi prototipe tersedia sebagai JSON.stringify () standar dan JSON.parse (), tetapi tetap mempertahankan JSON.parse () asli jika tersedia, jadi ini membuat segalanya lebih kompatibel dengan browser lama.
sumber
Saya tidak begitu fasih dengan Prototipe, tapi saya melihat ini di dokumennya :
Object.toJSON({"a":[1,2]})
Saya tidak yakin apakah ini akan memiliki masalah yang sama dengan pengkodean saat ini.
Ada juga tutorial yang lebih panjang tentang menggunakan JSON dengan Prototipe.
sumber
Ini adalah kode yang saya gunakan untuk masalah yang sama:
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) }
Anda memeriksa apakah Prototipe ada, lalu Anda memeriksa versinya. Jika versi lama menggunakan Object.toJSON (jika ditentukan) dalam semua kasus lainnya, fallback ke JSON.stringify ()
sumber
Begini cara saya menghadapinya.
var methodCallString = Object.toJSON? Object.toJSON(options.jsonMethodCall) : JSON.stringify(options.jsonMethodCall);
sumber
Solusi toleran saya memeriksa apakah Array.prototype.toJSON berbahaya untuk stringify JSON dan menyimpannya bila memungkinkan untuk membiarkan kode di sekitarnya berfungsi seperti yang diharapkan:
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 } }
sumber
Seperti yang ditunjukkan orang, ini karena Prototype.js - khususnya versi sebelum 1.7. Saya memiliki situasi yang sama tetapi harus memiliki kode yang beroperasi apakah Prototype.js ada atau tidak; ini berarti saya tidak bisa begitu saja menghapus Array.prototype.toJSON karena saya tidak yakin apa yang bergantung padanya. Untuk situasi itu, ini adalah solusi terbaik yang saya buat:
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 } }
Semoga bisa membantu seseorang.
sumber
Jika Anda tidak ingin mematikan semuanya, dan memiliki kode yang baik-baik saja di sebagian besar browser, Anda dapat melakukannya dengan cara ini:
(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));
Ini tampaknya rumit, tetapi rumit hanya untuk menangani sebagian besar kasus penggunaan. Ide utamanya adalah menimpa
JSON.stringify
untuk menghapustoJSON
dari objek yang diteruskan sebagai argumen, kemudian memanggil yang lamaJSON.stringify
, dan akhirnya memulihkannya.sumber