在自定义类上使用JSON.stringify

时间:2012-11-27 17:36:18

标签: javascript json node.js

我试图将对象存储在redis中,这是一个类的实例,因此具有函数,这是一个例子:

function myClass(){
    this._attr = "foo";
    this.getAttr = function(){
        return this._attr;
    }
}

有没有办法将这个对象与函数一起存储在redis中?我试过了JSON.stringify(),但只保留了属性。如何存储函数定义并能够执行以下操作:

var myObj = new myClass();
var stringObj = JSON.stringify(myObj);
// store in redis and retreive as stringObj again
var parsedObj = JSON.parse(stringObj);

console.log(myObj.getAttr()); //prints foo
console.log(parsedObj.getAttr()); // prints "Object has no method 'getAttr'"

如何在致电foo时获得parsedObj.getAttr()

提前谢谢!

修改

有建议修改MyClass.prototype并存储值,但是这样的事情(除了setter / getter之外的函数):

function myClass(){
    this._attr = "foo";
    this._accessCounts = 0;
    this.getAttr = function(){
        this._accessCounts++;
        return this._attr;
    }
    this.getCount = function(){
        return this._accessCounts;
    }
}

我试图说明一个函数,除了执行其他操作外,每当调用它时计算类似计数或平均值的函数。

5 个答案:

答案 0 :(得分:10)

首先,你没有定义一个类。

它只是一个对象,其属性的值是一个函数(在构造函数中定义的所有成员函数在创建新的实例时将复制,这就是为什么我说它不是一个班级。)

使用JSON.stringify时会被删除。

考虑到你使用的是使用V8的node.js,最好的方法是定义一个真正的类,并用__proto__发挥一点魔力。无论你在类中使用了多少属性(只要每个属性都使用原始数据类型),哪个属性都可以正常工作。

以下是一个例子:

function MyClass(){
  this._attr = "foo";
}
MyClass.prototype = {
  getAttr: function(){
    return this._attr;
  }
};
var myClass = new MyClass();
var json = JSON.stringify(myClass);

var newMyClass = JSON.parse(json);
newMyClass.__proto__ = MyClass.prototype;

console.log(newMyClass instanceof MyClass, newMyClass.getAttr());

将输出:

true "foo"

答案 1 :(得分:5)

不,JSON不存储函数(这也是非常低效的)。相反,使用序列化方法和反序列化构造函数。例如:

function MyClass(){
    this._attr = "foo";
    this.getAttr = function(){
        return this._attr;
    }
}
MyClass.prototype.toJSON() {
    return {attr: this.getAttr()}; // everything that needs to get stored
};
MyClass.fromJSON = function(obj) {
    if (typeof obj == "string") obj = JSON.parse(obj);
    var instance = new MyClass;
    instance._attr = obj.attr;
    return instance;
};

答案 2 :(得分:1)

Scanales,我遇到了同样的问题并尝试了一种类似于Bergi建议创建新的序列化/反序列化方法的技术......但发现它对我不起作用,因为我有对象嵌套在对象中(几个深)。如果这是你的情况,那么这就是我解决它的方式。我写了一个基类(clsPersistableObject),我希望从中继承的所有对象都从该基类继承。基类有一个名为deserialize的方法,它传递JSON字符串。此方法逐个设置属性(但不会消除存在的方法),然后递归地延迟到子对象执行相同操作(根据需要多次)。

deserialize: function (vstrString) {
                //.parse: convert JSON string to object state


                //Use JSON to quickly parse into temp object (does a deep restore of all properties)
                var tmpObject = JSON.parse(vstrString);

                //objZoo2.animal.move();

                //Note: can't just do something like this: 
                //  CopyProperties(tmpObject, this);
                //because it will blindly replace the deep objects 
                //completely...inadvertently wiping out methods on it.  Instead:
                //1) set the properties manually/one-by-one.
                //2) on objects, defer to the deserialize on the child object (if it inherits clsPersistableObject)
                //2b) if it doesn't inherit it, it's an intrinsic type, etc...just do a JSON parse.

                //loop through all properties
                var objProperty;
                for (objProperty in tmpObject) {

                    //get property name and value
                    var strPropertyName = objProperty;
                    var strPropertyValue = tmpObject[objProperty]; //note: doing this .toString() will cause

                    if (objProperty !== undefined) {
                        //check type of property
                        if (typeof strPropertyValue == "object") {
                            //object property: call it recursively (and return that value)

                            var strPropertyValue_AsString = JSON.stringify(strPropertyValue);

                            //see if has a deserialize (i.e. inherited from clsPeristableObject)
                            if ("deserialize" in this[objProperty]) {
                                //yes: call it
                                this[objProperty]["deserialize"](strPropertyValue_AsString);
                            }
                            else {
                                //no: call normal JSON to deserialize this object and all below it
                                this[objProperty] = JSON.parse(strPropertyValue_AsString);
                            }  //end else on if ("deserialize" in this[objProperty]) 
                        }
                        else {
                            //normal property: set it on "this"
                            this[objProperty] = tmpObject[objProperty];
                        } //end else on if (typeof strPropertyValue == "object") 
                    } //end if (objProperty !== undefined) 
                }

            }

答案 3 :(得分:0)

你得到什么grom JSON.stringify()是一个字符串。字符串没有方法。 您需要首先评估该字符串,然后您才能获得原始对象 及其方法。

var myObj = new myClass();
var stringObj = JSON.stringify(myObj);

----编辑-----

//Sorry use this:
var getBackObj  = JSON.parse(stringObj);
//Not this
var getBackObj = eval(stringObj);

console.log(getBackObj.getAttr()); // this should work now

答案 4 :(得分:-1)

看起来你试图对一个封闭的函数进行字符串化。您可以使用()=> {}来解决范围问题。

function myClass(){
    this._attr = "foo";
    this._accessCounts = 0;
    this.getAttr = ()=>{
        this._accessCounts++;
        return this._attr;
    }
    this.getCount = ()=>{
        return this._accessCounts;
    }
}