programing

JSON.stringify() 어레이의 bizareness with 프로토타입.js

kakaobank 2023. 3. 18. 08:46
반응형

JSON.stringify() 어레이의 bizareness with 프로토타입.js

JSON의 시리얼화에 어떤 문제가 있는지 알아내려고 합니다.또한 JSON.stringify()의 동작 방식에서 놀라운 차이를 발견하려고 합니다(json.org의 JSON 라이브러리 사용).

내 앱의 이전 버전:

 JSON.stringify({"a":[1,2]})

이거 주세요.

"{\"a\":[1,2]}"

새로운 버전에서는

 JSON.stringify({"a":[1,2]})

이거 주세요.

"{\"a\":\"[1, 2]\"}"

새로운 버전에서는 같은 라이브러리가 어레이 브래킷에 따옴표를 붙이기 위해 무엇이 바뀌었을까요?

JSON.stringify는 J에 대한 명령어입니다.SON son son son son son son son son son son son son son son son son 。츠키다JSON & "" 및 "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 Object, 의사 코드 페이지 205)는 객체에서 사용 가능한 경우 함수를 ToJSON()으로 사용합니다.

Prototype.js(또는 사용하고 있는 다른 라이브러리)는 Array.protype을 정의하기 때문입니다.toJSON() 함수는 Array.protype을 사용하여 어레이를 문자열로 변환합니다.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;
};

그러면 Array toJ가 처리됩니다.SON은 JSON.stringify와 호환되지 않으며 J에 대해서도 호환됩니다.다른 프로토타입 라이브러리와 마찬가지로 SON 기능도 이에 의존할 수 있습니다.

조금 더 정확하게 편집:

코드의 문제 키비트는 JSON.org의 JSON 라이브러리에 있습니다(및 ECMAScript 5의 JSON 오브젝트의 기타 구현).

if (value && typeof value === 'object' &&
  typeof value.toJSON === 'function') {
  value = value.toJSON(key);
}

문제는 프로토타입 라이브러리가 어레이를 확장하여 toJ를 포함한다는 것입니다.SON 메서드. JSON 오브젝트가 위의 코드를 호출합니다.JSON 개체가 어레이 값에 도달하면 J를 호출합니다.프로토타입에 정의된 어레이의 SON. 이 메서드는 어레이의 문자열 버전을 반환합니다.따라서 어레이 브래킷 주위에 따옴표가 표시됩니다.

ToJ를 삭제한 경우어레이 오브젝트의 SON은 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()를 사용할 수 있는 경우에는 그대로 유지되므로 오래된 브라우저와의 호환성이 향상됩니다.

저는 프로토타입에 능숙하지는 않지만, 문서에는 다음과 같은 내용이 기재되어 있습니다.

Object.toJSON({"a":[1,2]})

다만, 이것이 현재의 인코딩과 같은 문제를 가지고 있는지는 잘 모르겠습니다.

JSON을 프로토타입과 함께 사용하는 방법에 대한 더 튜토리얼도 있습니다.

같은 문제에 사용한 코드는 다음과 같습니다.

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.to.JSON(정의되어 있는 경우)을 사용하는 경우 기타 모든 경우 JSON.stringify()로 폴백합니다.

이게 내가 대처하는 방법이야.

var methodCallString =  Object.toJSON? Object.toJSON(options.jsonMethodCall) :  JSON.stringify(options.jsonMethodCall);

내구성 솔루션은 Array.protype 여부를 확인합니다.toJSON은 JSON 문자열화에 유해하며 가능한 경우 주변 코드가 예상대로 작동하도록 유지합니다.

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
    }
}

사람들이 지적한 바와 같이, 이는 PROTEM.js, 특히 1.7 이전 버전 때문입니다.저도 비슷한 상황이었지만, PROTEM.js의 존재 여부에 관계없이 동작하는 코드가 필요합니다.이것은 Array.protype을 삭제할 수 없다는 것을 의미합니다.뭐가 달려있는지 잘모르겠어요.이러한 상황에서 제가 생각해낸 최고의 해결책입니다.

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.stringifytoJSON에서 옛 합니다.JSON.stringify마지막으로 복원한다.

언급URL : https://stackoverflow.com/questions/710586/json-stringify-array-bizarreness-with-prototype-js

반응형