Javascript: строковый объект (включая членов функции типа) - PullRequest
21 голосов
/ 10 сентября 2010

Я ищу решение для сериализации (и десериализации) объектов Javascript в строку в разных браузерах, включая элементы объекта, которые оказались функциями.Типичный объект будет выглядеть следующим образом:

{
   color: 'red',
   doSomething: function (arg) {
        alert('Do someting called with ' + arg);
   }
}

doSomething () будет содержать только локальные переменные (не нужно также сериализовать вызывающий контекст!).

JSON.stringify () будет игнорироватьсячлен doSomething, потому что это функция.Я знал, что метод toSource () будет делать то, что я хочу, но это зависит от FF.

Ответы [ 5 ]

8 голосов
/ 02 декабря 2014

Вы можете использовать JSON.stringify с replacer, например:

JSON.stringify({
   color: 'red',
   doSomething: function (arg) {
        alert('Do someting called with ' + arg);
   }
}, function(key, val) {
        return (typeof val === 'function') ? '' + val : val;
});
7 голосов
/ 10 сентября 2010

Быстрый и грязный способ будет выглядеть следующим образом:

Object.prototype.toJSON = function() {
  var sobj = {}, i;
  for (i in this) 
    if (this.hasOwnProperty(i))
      sobj[i] = typeof this[i] == 'function' ?
        this[i].toString() : this[i];

 return sobj;

};

Очевидно, что это повлияет на сериализацию каждого объекта в вашем коде и может привести к путанице при использовании нефильтрованных циклов for in.«Правильным» способом было бы написать рекурсивную функцию, которая добавила бы функцию toJSON на всех дочерних элементах любого данного объекта, имея дело с циклическими ссылками и тому подобным.Однако, принимая во внимание однопотоковый Javascript (без Web Workers), этот метод должен работать и не вызывать каких-либо непреднамеренных побочных эффектов.

Аналогичная функция должна быть добавлена ​​в прототип массива для переопределения объекта путем возврата массива, а не объекта,Другой вариант - прикрепить один и позволить ему выборочно возвращать массив или объект в зависимости от собственной природы объектов, но, вероятно, он будет медленнее.

function JSONstringifyWithFuncs(obj) {
  Object.prototype.toJSON = function() {
    var sobj = {}, i;
    for (i in this) 
      if (this.hasOwnProperty(i))
        sobj[i] = typeof this[i] == 'function' ?
          this[i].toString() : this[i];

    return sobj;
  };
  Array.prototype.toJSON = function() {
      var sarr = [], i;
      for (i = 0 ; i < this.length; i++) 
          sarr.push(typeof this[i] == 'function' ? this[i].toString() : this[i]);

      return sarr;
  };

  var str = JSON.stringify(obj);

  delete Object.prototype.toJSON;
  delete Array.prototype.toJSON;

  return str;
}

http://jsbin.com/yerumateno/2/edit

1 голос
/ 01 августа 2013

Плагин JSONfn - это именно то, что вы ищете.

http://www.eslinstructor.net/jsonfn/

- Вадим

1 голос
/ 17 сентября 2010

Это невозможно без помощи самого объекта. Например, как бы вы сериализовали результат этого выражения?

(function () {
  var x; 
  return {
      get: function () { return x; },
      set: function (y) { return x = y; }
    };
})();

Если вы просто берете текст функции, то при десериализации, x будет ссылаться на глобальную переменную, а не на закрывающую. Кроме того, если ваша функция закрывается из-за состояния браузера (например, ссылка на div), вам нужно подумать о том, что вы хотите, чтобы это означало.

Конечно, вы можете написать свои собственные методы, специфичные для отдельных объектов, которые кодируют, какую семантику вы хотите, чтобы ссылки на другие объекты имели.

1 голос
/ 10 сентября 2010

Примерно так ...

(function(o) {
    var s = "";
    for (var x in o) {
        s += x + ": " + o[x] + "\n";
    }
    return s;
})(obj)

Примечание: это выражение.Он возвращает строковое представление объекта, который передается в качестве аргумента (в моем примере я передаю переменную с именем obj).

Вы также можете переопределить метод toString прототипа объекта:

Object.prototype.toString = function() {
    // define what string you want to return when toString is called on objects
}
...