在Javascript中反序列化多态JSON



我的客户端代码从服务器获取JSON '对象',然后对其进行解析。解析后的对象包含一个'type'属性,该属性应该控制对象的类。

$.getJSON("foo.json").done(function(data, textStatus, xhr) {
    $.each(data.objects, function(key, val)
    {
      if (val.type = "A") // make val into an object of class A, somehow?
        ...
      else if (val.type = "B") // make val into an object of class B somehow?
        ... etc...
    }
}    

如何创建正确类型的JavaScript对象而不显式地复制每个属性,或者-或者-将解析对象转换为不同的类型?

我读了一些关于__proto__的书,但我觉得它是一个大锤子,应该是一个小坚果…

我看到过关于Java和Jackson的类似问题,但是Javascript没有…

你可以这样做

function ObjectFactory() {
    this.newInstance = function(val) {
      if (val.type == "A") return new A(val);
      if (val.type == "B") return new B(val);
    }
}    
function A(data) {
    // do something with the data
    this.property = data.property;
}
function B(data) {
    // do something with the data
    this.property = data.property;
    this.bSpecificProperty = data.bSpecificProperty;
}
$.getJSON("foo.json").done(function(data, textStatus, xhr) {
    var objectFactory = new ObjectFactory();
    var objects = $.map(data.objects, objectFactory.newInstance);
    console.log(objects);
}   

如果你能给出一个更好的例子,说明什么是正确的类型,以及一些样本数据,我可以提供一个更好的答案。

您没有指定要实现的模式(如果有的话),但正如另一个答案所暗示的那样,您将不得不在对象的构造过程中采用某种约定。您不必显式地解释每个类型…如果你对$.extend的完整性满意,你也可以懒得合并你的JSON数据?

我还将包括一个辅助函数,用于在给定范围内解析"类型"—在项目中使用命名空间对象是一种常见的做法,以避免污染全局范围。例如:
function namespace(str, scope){
    scope = scope || window;
    var parts = str.split('.');
    while(parts.length) 
        scope = scope[parts.shift()];
    return scope;
}
Foo = {};
Foo.Bar = function(conf){
    // some kind of constructor
    $.extend(this, conf);
};
// test...
var json = {
    type: 'Foo.Bar',
    var1: 1,
    var2: 2,
    var3: 3
};
var obj = new (namespace(json.type))(json);
console.log(obj, obj instanceof Foo.Bar);

小提琴…或者适合你自己的代码:

$.getJSON("foo.json").done(function(data, textStatus, xhr){
    data.objects = $.map(data.objects, function(obj){
        return new (namespace(obj.type))(obj);
    });
});   

最新更新