2010-09-10 3 views
18

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

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

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

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

+1

Я просто оставить комментарий, потому что я не предлагает полное решение. Одна вещь, которая может помочь, состоит в том, что вы можете выполнить функцию Function с вызовом 'toString()'. http://jsfiddle.net/HFMaz/ Не уверен в поддержке кросс-браузера. – user113716

+1

это задают регулярно, но я не могу найти что-либо релевантное: \ почему вам нужно сериализовать функцию в любом случае? возможно, есть лучший способ организовать ваш код? – lincolnk

+0

Это для проекта WYSIWYG. Каждый объект Javascript (с помощью методов) определяет поведение компонентов страницы. Содержимое страницы (включая поведение JS) должно быть сохранено на стороне сервера, следовательно, сериализовано. –

ответ

5

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

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; 

}; 

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

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

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

Отлично, кроме массивов больше не сериализуются как массивы. – Adaptabi

+3

Как бы выглядела функция разбора? Все функции находятся в строках так, чтобы синтаксический анализ нам нужно было преобразовать их обратно в функции. – Justin

0

Что-то вроде этого ...

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

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

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

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

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

5

Вы можете использовать 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; 
}); 
+2

Я закончил с помощью 'JSON.stringify (myObject, function (key, val) {return (typeof val === 'function')? '[Function]': val;}, 4);' и он выводит действительно приятно , –

 Смежные вопросы

  • Нет связанных вопросов^_^