【问题标题】:Serializing a javascript class object?序列化一个javascript类对象?
【发布时间】:2018-12-29 21:10:59
【问题描述】:

要求很简单。这是一堂课……

class myobj {

    constructor(var1, var2) {
        this.var1 = var1;
        this.var2 = var2;
    }

    addThemUp() {
        return this.var1 + this.var2;
    }

}

现在我做其中之一......

var myInstance = new MyObj(3, 7);

可爱。但是现在我需要序列化它,以便我可以保存它并稍后加载它。有点像...

serialise(myInstance);
// Save to a file
// ... do some other stuff ...
// load from file
myInstance = unserialise(fileData);
// - or - 
unserialise(fileData, myInstace);
// etc...

如何?我不在乎表示形式采用什么形式,因为它将由同一页面加载。如果只保存值,则将它们加载回对象的通用方法会很好,因为同一页面具有类“模板”来查找函数的定义。

对象很大且不断变化,因此从 JSON 中手动复制值以保留函数实际上是不可维护的。但是,可以使用任意数量和类型的变量来做到这一点的解决方案会很有用。

我还必须坚持使用普通的单文件 javascript,尽管是在现代浏览器中。

TL;DR:如何在不丢失功能的情况下对对象进行序列化和反序列化?

【问题讨论】:

    标签: javascript json object serialization


    【解决方案1】:

    您可以使用JSON.stringify,但请注意它只序列化属性,而不是方法。所以要反序列化一个对象,只需创建一个虚拟实例并使用Object.assign 来使用检索到的对象更新属性:

    function serialize(instance) {
        var str = JSON.stringify(instance);
        // save str or whatever
    }
    
    function unserialize(str, theClass) {
        var instance = new theClass();                  // NOTE: if your constructor checks for unpassed arguments, then just pass dummy ones to prevent throwing an error
        var serializedObject = JSON.parse(str);
        Object.assign(instance, serializedObject);
        return instance;
    }
    

    示例:

    function serialize(obj) {
        var str = JSON.stringify(obj);
        return str;
    }
    
    function unserialize(str, theClass) {
        var instance = new theClass();
        var serializedObject = JSON.parse(str);
        Object.assign(instance, serializedObject);
        return instance;
    }
    
    // TEST CLASS
    
    class TestClass {
        constructor(a, b) {
            this.a = a;
            this.b = b;
        }
    
        sum() {
            return this.a + this.b;
        }
    }
    
    // USAGE
    
    var instance = new TestClass(5, 7);
    
    var str = serialize(instance);
    
    var retrievedInstance = unserialize(str, TestClass);
    
    console.log(retrievedInstance.sum());

    【讨论】:

    • 将 Object.assign 与 JSON.stringify 一起使用肯定可以为具有本机类型变量的对象完成这项工作,因此非常感谢您。这些是否有可能在该对象中也具有功能的对象中递归地工作,还是我必须自己遍历拥有的对象并分配每个对象?如果我这样做,这不是世界末日,至少我不会对其中的每个变量都这样做!
    • @IamPancakeMan 我制作了一个名为 esserializer 的 npm 模块,它可以递归反序列化对象实例,并保留所有类型/函数信息。我很快就会在这里发布这个解决方案的答案。
    【解决方案2】:

    没有办法序列化函数。

    可以将构造函数设置为始终获取一个对象并使用 Object.assign() 将所有输入分配给实例

    将可枚举属性字符串化为 json,然后在需要时再次解析 json 并将存储的对象再次传递给 new MyObj

    class MyObj {
    
      constructor(obj) {
        const defaults = {var1: 10,var2: 10};
        Object.assign(this, obj || defaults);
      }
    
      addThemUp() {
        return this.var1 + this.var2 + (this.var3 || 0) + (this.var4 || 0);
      }
    
      addSomeProps() {
        if (!this.var3 && !this.var4) {
          this.var3 = 10;
          this.var4 = 10
        }
      }
    
      serialize() {
        return JSON.stringify(this)
      }
    
    }
    
    const myInstance = new MyObj();
    console.log('myInstance before more props added', myInstance)
    myInstance.addSomeProps()
    ///stringify the instance object
    const json = myInstance.serialize();
    // same variables needed to pass to constructor
    const storedObj = JSON.parse(json)
    // create new instance
    const instance2 = new MyObj(storedObj);
    
    console.log('instance 2', instance2)
    // try out the methods 
    console.log('add in instance 2:', instance2.addThemUp())

    【讨论】:

      【解决方案3】:

      你可以使用 JSON.stringify(myInstance); (序列化对象)并使用 JSON.parse(mymyInstance) 将其作为对象返回

      【讨论】:

        【解决方案4】:

        当您以 JSON 形式序列化对象时,您的类信息将丢失。 为了防止它发生,你必须手动添加一个属性来保存你原来的类信息;像类名。 然后您可以在反序列化时使用该信息位,并将所有信息恢复到原始类对象。 这是将 JSON 带回其原始类对象的一般方法:

        class Foo{
            constructor(var1, var2){
                // save your class name as property
                this.classname = this.constructor.name;
        
                this.var1 = var1;
                this.var2 = var2;
            }
        
            hoo(var3, var4){
                this.var3 = var3;
                this.var4 = var4;
            }
        
            serialize(){
                return JSON.stringify(this);
            }
        }
        
        let foo = new Foo(1, 2);
        foo.hoo(3, 4);
        
        //Now we have JSON string:
        //'{"classname":"Foo","var1":1,"var2":2,"var3":3,"var4":4}'
        let json = foo.serialize();
        
        function deserialize(json){
            //o is [Object object], but it contains every state of the original object
            let o = JSON.parse(json);
            //Get original class instance
            let original_class = eval(o.classname);
        
            //Create new object of the original class, then restore back property values
            //NOTE: You may not need to pass any parameter to the constructor, since
            //every state of the original object will be restored from o.
            return Object.assign(new original_class(), o);
        }
        
        let _foo = deserialize(json);
        console.log(_foo instanceof Foo); // returns true;
        

        我还创建了一个small module,它与 Node.js 一起工作并处理嵌套对象,所以如果您有兴趣,请检查代码。

        【讨论】:

          【解决方案5】:

          我制作了一个名为 esserializer 的 npm 模块来解决这个问题:在序列化期间保存 JavaScript 类对象值,然后递归反序列化对象实例,并保留所有类型/函数信息。

          在你的情况下,代码会很简单:

          var ESSerializer = require('esserializer');
          var MyObj = require('MyObj');
          
          var myInstance = new MyObj(3, 7);
          var serializedText = ESSerializer.serialize(myInstance);
          //...do something, or send the above serializedText to another JavaScript environment.
          var deserializedObj = ESSerializer.deserialize(serializedText, [MyObj]);
          

          deserializedObj 是一个 MyObj 实例,它包含所有值/函数/超类信息。

          这个模块是一个开源项目。如果你有兴趣,可以查看GitHub repo,看看它是如何工作的。

          【讨论】:

          【解决方案6】:

          这个问题的回答有点生硬,...

          但有效:)

          使用 TypeScript -> https://github.com/typestack/class-transformer

          【讨论】:

            猜你喜欢
            • 2012-01-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多