序列化和反序列化JS对象

时间:2014-05-04 18:22:20

标签: javascript string serialization deserialization

我最近在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解决方案中)?

我已经尝试过将函数存储为字符串并再次进行评估,但是无法保存对象的状态。

2 个答案:

答案 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;}"]]