формат JSON.преобразовать в строки() странностей массива с прототипом.js



Я пытаюсь выяснить, что пошло не так с моей сериализацией json, есть текущая версия моего приложения и старая, и я нахожу некоторые удивительные различия в том, как JSON.stringify () работает (используя библиотеку JSON из json.org).



в старой версии моего приложения:



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


дает мне это:



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


в новой версии



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


дает мне это:



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


любая идея, что можно было бы изменить, чтобы сделать та же библиотека помещает кавычки вокруг скобок массива в новой версии?

563   11  

11 ответов:

начиная с JSON.stringify в последнее время поставляется с некоторыми браузерами, я бы предложил использовать его вместо прототипа toJSON. Затем вы проверили бы окно.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 () при наличии на объектах.

Потому Что Прототип.JS (или другая библиотека, которую вы используете) определяет массив.прототип.функция toJSON (), массивы сначала преобразуются в строки с помощью массива.прототип.метод 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, поскольку от нее могут зависеть другие библиотеки прототипов.

изменить, чтобы сделать немного более точным:

проблемный ключевой бит кода находится в библиотеке JSON из JSON.org (и другие реализации объекта JSON ECMAScript 5):

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

проблема в том, что библиотека прототипов расширяет массив, чтобы включить метод toJSON, который объект JSON вызовет в коде выше. Когда объект JSON попадает в значение массива, он вызывает toJSON в массиве, который определен в Prototype, и этот метод возвращает строковую версию матрица. Следовательно, кавычки вокруг скобок массива.

Если вы удалите 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 () если он доступен, так что это делает вещи более совместимыми со старыми браузерами.

Я не так хорошо разбираюсь в прототипе, но я видел это в своем docs:

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

вы проверяете, существует ли прототип, затем вы проверяете версию. Если старая версия использовать объект.toJSON (если определено) во всех остальных случаях является резервным вариантом для JSON.преобразовать в строки()

вот как я с этим справляюсь.

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

мое толерантное решение проверяет, является ли массив.прототип.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
    }
}

как люди указали, это связано с прототипом.js-конкретно версии до 1.7. У меня была аналогичная ситуация, но должен был быть код, который работал ли прототип.js был там или нет; это означает, что я не могу просто удалить массив.прототип.тойсон, как я не уверен, что полагается на это. Для этой ситуации это лучшее решение, которое я придумал:

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 и, наконец, восстановить его.

Comments

    Ничего не найдено.