node.js中多态数组的序列化

时间:2013-10-17 09:22:15

标签: node.js serialization polymorphism

我正在寻找一个Javascript对象的序列化方法,该方法包含具有函数参数的不同类的其他几个对象。

这是一个简单的测试用例:

// Paper class:

function Paper(name) {
    this.name = name;
} 
Paper.prototype = {
    string: function() { return "Paper:"+this.name; }
};


// Book class:

function Book(name) {
    this.name = name;
} 
Book.prototype = {
    string: function() { return "Book:"+this.name; }
};


// Library class:

function Library(name) {
    this.items = [];
}
Library.prototype = {
    add: function(item) { this.items.push(item); },
    string: function () {
        var titles = this.items.map(function(item) { return item.string(); });
        return titles.join(",");
    },
};


///// Define a library:

var lib = new Library();
lib.add(new Paper("MyPaper"));
lib.add(new Book("MyBook"));
assert(lib.string() == "Paper:MyPaper,Book:MyBook");

///// Serialize, de-serialize and compare:

// var libString = serialize(lib);
// var newLib = deserialize(libString);
// assert(newLib.string() == "Paper:MyPaper,Book:MyBook");

注意:de / serialization的主要用法(至少在我的情况下)是用于将复杂对象移动到远程计算机。例如,我想在我的计算机上构建一个大型库,然后将其序列化,放入文件,将文件发送到另一台计算机,在那里反序列化,并拥有完全相同的库。

2 个答案:

答案 0 :(得分:1)

您需要扩展JSON语义。如果我是你,我会这样:

var protos = {}, //hash of prototypes
base = {  //base prototype
     toJSON: function () {
         var props = {}; //properties to be serialized

         for (var prop in this) { //this can be custimized, like taking `attrs` hash or something
             if (this.hasOwnProperty(prop)) props[prop] = this[prop];
         }

        props.$proto = this.$proto; //need to copy this manually since it's not an `own propery`

        return props;
    }
};

function Paper(name) {
    this.name = name;
} 

protos.paper = Paper.prototype = Object.create(base);

Paper.prototype.$proto = 'paper';

Paper.prototype.toString = function() { 
    return 'Paper: ' + this.name; 
}

function Book(name) {
    this.name = name;
} 

protos.book = Book.prototype = Object.create(base);

Book.prototype.$proto = 'book';

Book.prototype.toString = function() { 
    return 'Book: ' + this.name; 
}


function Library(name) {
    this.items = [];
}

Library.prototype = {
    add: function(item) { this.items.push(item); },
    toString: function () {
        var titles = this.items.map(function(item) { 
            return item.toString(); 
        });

        return titles.join(',');
    },
    toJSON: function () {
        return this.items.map(function(item) { return item.toJSON()});
    }
};

Library.fromJSON = function (json) {
    return json.map(function(item) {
        var object = Object.create(protos[item.$proto]);

        for (var prop in item) object[prop] = item[prop];

        return object;
    });
};

//test

var lib = new Library();
lib.add(new Paper('MyPaper'));
lib.add(new Book('MyBook'));

console.log(lib.toString());

var json = JSON.stringify(lib.toJSON());

console.log(Library.fromJSON(JSON.parse(json)).toString());

这是一个小提琴:http://jsfiddle.net/cSTT5/

答案 1 :(得分:0)

<块引用>

我想在我的电脑上建立一个大图书馆,然后将它序列化,放入一个文件,将文件发送到另一台计算机,在那里反序列化,并拥有完全相同的图书馆。

我制作了一个名为 esserializer 的 npm 模块来解决这个问题:在序列化过程中递归保存 JavaScript 类实例值,以纯 JSON 格式,连同其类名信息。然后,在反序列化阶段,esserializer 可以递归反序列化对象实例,保留所有类型/函数信息,使用相同的类定义。

对于您的场景,代码非常简单。如果序列化的字符串被带到另一台计算机,只要该计算机上存在相同的类定义,它就可以工作:

const ESSerializer = require('esserializer');

// Paper class:
function Paper(name) {
  this.name = name;
}
Paper.prototype = {
  string: function() { return "Paper:"+this.name; }
};
Paper.prototype.constructor = Paper; // We need to redefine the constructor of Paper's prototype.

// Book class:
function Book(name) {
  this.name = name;
}
Book.prototype = {
  string: function() { return "Book:"+this.name; }
};
Book.prototype.constructor = Book;

// Library class:
function Library(name) {
  this.items = [];
}
Library.prototype = {
  add: function(item) { this.items.push(item); },
  string: function () {
    var titles = this.items.map(function(item) { return item.string(); });
    return titles.join(",");
  },
};
Library.prototype.constructor = Library;

///// Define a library:
var lib = new Library();
lib.add(new Paper("MyPaper"));
lib.add(new Book("MyBook"));
// assert(lib.string() == "Paper:MyPaper,Book:MyBook");

var serializedString = ESSerializer.serialize(lib);

// Later, on another machine, deserializedObj is a perfect copy of "lib":
var deserializedObj = ESSerializer.deserialize(serializedString, [Library, Book, Paper]);
console.log(deserializedObj.string()); // Paper:MyPaper,Book:MyBook