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는 최근 일부 브라우저에서 제공되었으므로 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 () 함수 ( 201 페이지-JSON 객체, 의사 코드 페이지 205) 는 객체에서 사용할 수있는 경우 toJSON () 함수를 사용합니다.
Prototype.js (또는 사용중인 다른 라이브러리)가 Array.prototype.toJSON () 함수를 정의하기 때문에 배열은 먼저 Array.prototype.toJSON ()을 사용하여 문자열로 변환 된 다음 JSON.stringify ()로 인용 된 문자열로 변환됩니다. 배열 주위에 잘못된 추가 따옴표가 있습니다.
따라서 솔루션은 간단하고 간단합니다 (이것은 Raphael Schweikert의 답변을 단순화 한 버전입니다).
delete Array.prototype.toJSON
이것은 물론 배열에 대한 toJSON () 함수 속성에 의존하는 라이브러리에 대한 부작용을 생성합니다. 하지만 ECMAScript 5와의 비 호환성을 고려하면 사소한 불편 함을 발견했습니다.
ECMAScript 5에 정의 된 JSON 개체는 최신 브라우저에서 효율적으로 구현되므로 가장 좋은 솔루션은 표준을 준수하고 기존 라이브러리를 수정하는 것입니다.
다른 프로토 타입 종속성에 영향을주지 않는 가능한 솔루션은 다음과 같습니다.
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와의 Array toJSON 비 호환성을 처리하고 다른 Prototype 라이브러리가 의존 할 수 있으므로 toJSON 기능을 유지합니다.
좀 더 정확하게 수정하세요.
코드의 문제 핵심 부분은 JSON.org의 JSON 라이브러리 (및 ECMAScript 5의 JSON 객체의 다른 구현)에 있습니다.
if (값 && 값 유형 === '객체'&& typeof value.toJSON === '함수') { 값 = value.toJSON (key); }
문제는 Prototype 라이브러리가 위의 코드에서 JSON 개체가 호출하는 toJSON 메서드를 포함하도록 Array를 확장한다는 것입니다. JSON 객체가 배열 값에 도달하면 Prototype에 정의 된 배열에서 toJSON을 호출하고 해당 메서드는 배열의 문자열 버전을 반환합니다. 따라서 배열 대괄호를 따옴표로 묶습니다.
Array 객체에서 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 ()를 유지하므로 이전 브라우저와 더 잘 호환됩니다.
나는 Prototype에 능숙하지 않지만 문서 에서 이것을 보았다 .
Object.toJSON({"a":[1,2]})
I'm not sure if this would have the same problem the current encoding has, though.
There's also a longer tutorial about using JSON with Prototype.
This is the code I used for the same issue:
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)
}
You check if Prototype exists, then you check the version. If old version use Object.toJSON (if is defined) in all other cases fallback to JSON.stringify()
Here's how I'm dealing with it.
var methodCallString = Object.toJSON? Object.toJSON(options.jsonMethodCall) : JSON.stringify(options.jsonMethodCall);
My tolerant solution checks whether Array.prototype.toJSON is harmful for JSON stringify and keeps it when possible to let the surrounding code work as expected:
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
}
}
As people have pointed out, this is due to Prototype.js - specifically versions prior to 1.7. I had a similar situation but had to have code that operated whether Prototype.js was there or not; this means I can't just delete the Array.prototype.toJSON as I'm not sure what relies on it. For that situation this is the best solution I came up with:
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
}
}
Hopefully it will help someone.
If you don't want to kill everything, and have a code that would be okay on most browsers, you could do it this way :
(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));
This seems complex, but this is complex only to handle most use cases. The main idea is overriding JSON.stringify
to remove toJSON
from the object passed as an argument, then call the old JSON.stringify
, and finally restore it.
참고URL : https://stackoverflow.com/questions/710586/json-stringify-array-bizarreness-with-prototype-js
'programing tip' 카테고리의 다른 글
"스택 오버플로"는 어떻게 발생하며 어떻게 방지합니까? (0) | 2020.09.25 |
---|---|
Swift에서 HTTP 요청 + 기본 인증을 만드는 방법 (0) | 2020.09.24 |
C #에서 null이 아닌 경우 메서드 호출 (0) | 2020.09.24 |
Option [T] 클래스의 요점은 무엇입니까? (0) | 2020.09.24 |
Javascript를 사용하여 특정 날짜의 에포크 얻기 (0) | 2020.09.24 |