Javascript: stringify object (включая элементы функции типа)
Я ищу решение для сериализации (и unserialize) объектов Javascript для строки в браузерах, включая членов объекта, которые являются функциями. Типичный объект будет выглядеть следующим образом:
{
color: 'red',
doSomething: function (arg) {
alert('Do someting called with ' + arg);
}
}
doSomething() будет содержать только локальные переменные (не нужно также сериализовать вызывающий контекст!).
JSON.stringify() будет игнорировать элемент 'doSomething', потому что это функция. Я знал, что метод toSource() будет делать то, что я хочу, но он специфичен для FF.
Ответы
Ответ 1
Быстрый и грязный способ будет таким:
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 для переопределения объекта Object, возвращая массив, а не объект. Другим вариантом будет присоединение одного и пусть оно выборочно возвращает массив или объект в зависимости от собственной природы объектов, но, вероятно, будет медленнее.
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
Ответ 2
Вы можете использовать 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;
});
Ответ 3
Это невозможно без помощи самого объекта. Например, как бы вы сериализовали результат этого выражения?
(function () {
var x;
return {
get: function () { return x; },
set: function (y) { return x = y; }
};
})();
Если вы просто возьмете текст функции, то при десериализации x
будет ссылаться на глобальную переменную, а не на закрытие. Кроме того, если ваша функция закрывается над состоянием браузера (например, ссылкой на div), вам придется подумать о том, что вы хотите, чтобы это означало.
Вы можете, конечно, написать свои собственные методы, специфичные для отдельных объектов, которые кодируют, какую семантику вы хотите использовать для других объектов.
Ответ 4
Что-то вроде этого...
(function(o) {
var s = "";
for (var x in o) {
s += x + ": " + o[x] + "\n";
}
return s;
})(obj)
Примечание: это выражение. Он возвращает строковое представление объекта, переданного в качестве аргумента (в моем примере я передаю переменную с именем obj).
Вы также можете переопределить метод toString прототипа Object:
Object.prototype.toString = function() {
// define what string you want to return when toString is called on objects
}
Ответ 5
Плагин JSONfn - это именно то, что вы ищете.
http://www.eslinstructor.net/jsonfn/
- Вадим