我最近在JavaScript中尝试了对象序列化。我已经在查看有关Javascript中预定义对象的序列化和反序列化的一些问题,但我正在寻找更通用的解决方案。这方面的一个例子是:
function anObject(){
var x = 1;
this.test = function(){return x;};
this.add = function(a){x+a;};
}
var x = new anObject();
x.add(2);
console.log(x.test());
>>> 3
var y = deserialize(serialize(x));
console.log(y.test());
>>> 3
有没有办法序列化这个对象并反序列化它,这样反序列化的对象仍然可以访问局部变量x而不使用该对象的原型(如在this解决方案中)?
我已经尝试过将函数存储为字符串并再次进行评估,但是无法保存对象的状态。
答案 0 :(得分:1)
如果没有代码内省和代码重写,我想要做的就是不可能,我认为这不是一个好主意。但是,这样的事情呢?
function AnObject() {
var x = 1;
this.x = function () { return x; };
this.addToX = function (num) { x += num; };
this.memento = function () {
return { x: x };
};
this.restoreState = function (memento) {
x = memento.x;
};
}
var o = new AnObject();
o.addToX(2);
o.x(); //3
var serializedState = JSON.stringify(o.memento()),
o = new AnObject();
o.restoreState(JSON.parse(serializedState));
o.x(); //3
然而,请注意,由于您失去了使用原型的好处,因此获得特权会员成本很高。出于这个原因,我不想强制实施真正的隐私,而是依赖于this._myPrivateVariable
之类的命名约定(除非你隐藏模块的成员)。
答案 1 :(得分:0)
感谢您的回复。虽然plalx的答案完全适用于特定的对象,但我希望有一些更通用的东西,它适用于你抛出的任何对象。
可以使用的另一种解决方案是这样的:
function construct(constructor, args, vars) {
function Obj() {
var variables = vars
return constructor.apply(this, args);
}
Obj.prototype = constructor.prototype;
return new Obj();
}
function addFunction(anObject, aFunction, variables) {
var objectSource = anObject.toString();
var functionSource = aFunction.toString();
objectSource = objectSource.substring(0,objectSource.length-1);
var functionName = functionSource.substring(9, functionSource.indexOf('('));
var functionArgs = functionSource.substring(functionSource.indexOf('('), functionSource.indexOf('{')+1);
var functionBody = functionSource.substring(functionSource.indexOf('{')+1, functionSource.length);
return objectSource + "this." + functionName + " = function" +
functionArgs + "var variables = " + variables + ";\n" + functionBody + "}";
}
function makeSerializable(anObject) {
var obj = JSON.stringify(anObject, function(key, val) {
return ((typeof val === "function") ? val+'' : val);
});
var variables = [];
while(obj.indexOf("var") > -1) {
var subString = obj.substring(obj.indexOf("var")+3, obj.length-1);
while (subString[0] == " ")
subString = subString.replace(" ", "");
var varEnd = Math.min(subString.indexOf(" "), subString.indexOf(";"));
var varName = subString.substring(0, varEnd);
variables.push(varName);
obj = obj.replace("var","");
}
var anObjectSource = addFunction(anObject,
function serialize(){
var vars = [];
console.log("hidden variables:" + variables);
variables.forEach(function(variable) {
console.log(variable + ": " + eval(variable));
vars += JSON.stringify([variable, eval(variable)]);
});
var serialized = [];
serialized.push(vars);
for (var func in this){
if (func != "serialize")
serialized.push([func, this[func].toString()]);
}
return JSON.stringify(serialized);
},
JSON.stringify(variables));
anObject = Function("return " + anObjectSource)();
var params = Array.prototype.slice.call(arguments);
params.shift();
return construct(anObject, params, variables);
}
这允许您序列化任何对象的所有元素,包括隐藏变量。然后,serialize()函数可以替换为隐藏变量的自定义字符串表示形式,可以在将字符串表示反序列化为对象时使用。
用法:
function anObject(){
var x = 1;
var y = [1,2];
var z = {"name": "test"};
this.test = function(){return x;};
this.add = function(a){x+a;};
}
var test = makeSerializable(anObject)
test.serialize()
>>>["[\"x\",1][\"y\",[1,2]][\"z\",{\"name\":\"test\"}]",["test","function (){return x;}"],["add","function (a){x+a;}"]]