我正在寻找一种解决方案来跨浏览器将 Javascript 对象序列化(和反序列化)为字符串,包括恰好是函数的对象成员。一个典型的对象看起来像这样:
{
color: 'red',
doSomething: function (arg) {
alert('Do someting called with ' + arg);
}
}
doSomething() 将仅包含局部变量(无需序列化调用上下文!)。
JSON.stringify() 将忽略 'doSomething' 成员,因为它是一个函数。我知道 toSource() 方法会执行我想要的操作,但它是 FF 特定的。
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;
});
一个快速而肮脏的方法是这样的:
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
循环使 niave 代码出错。 “正确”的方法是编写一个递归函数,在任何给定对象的所有后代成员上添加 toJSON
函数,处理循环引用等。但是,假设单线程 Javascript(没有 Web Workers),此方法应该有效并且不会产生任何意外的副作用。
必须将类似的函数添加到 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;
}
类似这样的事情...
(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
}
如果没有物体本身的帮助,这是不可能的。例如,您将如何序列化该表达式的结果?
(函数(){ 变量x; 返回 { 获取:函数(){返回x; }, 设置:函数(y){返回x=y; } }; })();
如果您只获取函数的文本,那么当您反序列化时,
x
将引用全局变量,而不是闭包中的变量。另外,如果您的函数在浏览器状态下关闭(例如对 div 的引用),您必须考虑您想要它的含义。
当然,您可以编写自己的特定于单个对象的方法,这些方法对您希望对其他对象的引用具有的语义进行编码。
通过 JSON.stringify() 中的 replacer-argument 完美字符串化对象中的函数。 坏处是它在返回值两边加上了撇号。当值是函数时,撇号不可能知道从哪里删除;就像 {"doSomething": "function(arg){...}"}。相反,返回一个 PLACEHOLDER,稍后由该值替换。
var myObj = {
color: 'red',
doSomething: function (arg) {
alert('Do someting called with ' + arg);
}
}
var placeholder = '____PLACEHOLDER____';
var fns = [];
var json = JSON.stringify(myObj, function(key, value) {
if (typeof value === 'function') {
fns.push(value);
return placeholder;
}
return value;
}, 2);
json = json.replace(new RegExp('"' + placeholder + '"', 'g'), function(_) {
return fns.shift();
});
console.log(json)