Bunlar, birkaç farklı yol göstermek için bazı hızlı çekimlerdir. Onlar hiçbir şekilde "tam" değildir ve bir feragatname olarak, bunu böyle yapmanın iyi bir fikir olduğunu düşünmüyorum. Ayrıca sadece çok hızlı bir şekilde birlikte yazdım çünkü kod çok temiz değil.
Ayrıca not olarak: Tabii ki serileştirilebilir sınıfların, herhangi bir türün serileştirilmesinin farkında olduğum diğer tüm dillerde olduğu gibi varsayılan kuruculara sahip olması gerekir. Elbette, argüman içermeyen varsayılan olmayan bir kurucu çağırırsanız Javascript şikayet etmez, ancak sınıf bunun için daha iyi hazırlanır (artı, gerçekten "daktilo yolu" olmaz).
Seçenek # 1: Hiç çalışma zamanı bilgisi yok
Bu yaklaşımdaki sorun çoğunlukla herhangi bir üyenin adının sınıfıyla eşleşmesi gerektiğidir. Bu, sizi otomatik olarak sınıf başına aynı türden bir üyeyle sınırlar ve birkaç iyi uygulama kuralını ihlal eder. Buna şiddetle tavsiye ediyorum, ama sadece burada listeliyorum, çünkü bu cevabı yazdığımda ilk "taslak" idi (bu yüzden isimler "Foo" vb.).
module Environment {
export class Sub {
id: number;
}
export class Foo {
baz: number;
Sub: Sub;
}
}
function deserialize(json, environment, clazz) {
var instance = new clazz();
for(var prop in json) {
if(!json.hasOwnProperty(prop)) {
continue;
}
if(typeof json[prop] === 'object') {
instance[prop] = deserialize(json[prop], environment, environment[prop]);
} else {
instance[prop] = json[prop];
}
}
return instance;
}
var json = {
baz: 42,
Sub: {
id: 1337
}
};
var instance = deserialize(json, Environment, Environment.Foo);
console.log(instance);
Seçenek # 2: name özelliği
Seçenek # 1'deki sorundan kurtulmak için, JSON nesnesindeki bir düğümün türü hakkında bir tür bilgiye ihtiyacımız var. Sorun, Typcript'te, bu şeylerin derleme zamanı yapıları olması ve çalışma zamanında onlara ihtiyaç duymamızdır - ancak çalışma zamanı nesneleri, ayarlanana kadar özelliklerinin farkında değildir.
Bunu yapmanın bir yolu sınıfları isimlerinden haberdar etmektir. Yine de JSON bu özelliği gerekir. Aslında, sadece json'da ihtiyacınız var:
module Environment {
export class Member {
private __name__ = "Member";
id: number;
}
export class ExampleClass {
private __name__ = "ExampleClass";
mainId: number;
firstMember: Member;
secondMember: Member;
}
}
function deserialize(json, environment) {
var instance = new environment[json.__name__]();
for(var prop in json) {
if(!json.hasOwnProperty(prop)) {
continue;
}
if(typeof json[prop] === 'object') {
instance[prop] = deserialize(json[prop], environment);
} else {
instance[prop] = json[prop];
}
}
return instance;
}
var json = {
__name__: "ExampleClass",
mainId: 42,
firstMember: {
__name__: "Member",
id: 1337
},
secondMember: {
__name__: "Member",
id: -1
}
};
var instance = deserialize(json, Environment);
console.log(instance);
Seçenek # 3: Üye türlerini açıkça belirtme
Yukarıda belirtildiği gibi, sınıf üyelerinin tür bilgisi çalışma zamanında mevcut değildir - yani biz bunu mümkün kılmadıkça. Bunu sadece ilkel olmayan üyeler için yapmamız gerekiyor ve gitmeye hazırız:
interface Deserializable {
getTypes(): Object;
}
class Member implements Deserializable {
id: number;
getTypes() {
// since the only member, id, is primitive, we don't need to
// return anything here
return {};
}
}
class ExampleClass implements Deserializable {
mainId: number;
firstMember: Member;
secondMember: Member;
getTypes() {
return {
// this is the duplication so that we have
// run-time type information :/
firstMember: Member,
secondMember: Member
};
}
}
function deserialize(json, clazz) {
var instance = new clazz(),
types = instance.getTypes();
for(var prop in json) {
if(!json.hasOwnProperty(prop)) {
continue;
}
if(typeof json[prop] === 'object') {
instance[prop] = deserialize(json[prop], types[prop]);
} else {
instance[prop] = json[prop];
}
}
return instance;
}
var json = {
mainId: 42,
firstMember: {
id: 1337
},
secondMember: {
id: -1
}
};
var instance = deserialize(json, ExampleClass);
console.log(instance);
Seçenek # 4: Ayrıntılı, ama düzgün yol
Güncelleme 01/03/2016: @GameAlchemist'in yorumlarda belirttiği gibi ( fikir , uygulama ) 1.7'den itibaren, aşağıda açıklanan çözüm sınıf / özellik dekoratörleri kullanılarak daha iyi bir şekilde yazılabilir.
Serileştirme her zaman bir sorundur ve bence en iyi yol en kısa yol değildir. Tüm seçenekler arasından tercih ettiğim şey budur çünkü sınıfın yazarı, serileştirilmiş nesnelerin durumu üzerinde tam kontrole sahiptir. Tahmin etmek zorunda kalsaydım, er ya da geç diğer tüm seçeneklerin başınızı belaya sokacağını söyleyebilirim (Javascript bununla başa çıkmak için yerel bir yol bulmazsa).
Gerçekten, aşağıdaki örnek esneklik adaletini yapmaz. Gerçekten sadece sınıfın yapısını kopyalar. Burada aklınızda bulundurmanız gereken fark, sınıfın tüm sınıfın durumunu kontrol etmek istediği herhangi bir JSON'u kullanmak için tam kontrole sahip olmasıdır (bir şeyler hesaplayabilirsiniz vb.).
interface Serializable<T> {
deserialize(input: Object): T;
}
class Member implements Serializable<Member> {
id: number;
deserialize(input) {
this.id = input.id;
return this;
}
}
class ExampleClass implements Serializable<ExampleClass> {
mainId: number;
firstMember: Member;
secondMember: Member;
deserialize(input) {
this.mainId = input.mainId;
this.firstMember = new Member().deserialize(input.firstMember);
this.secondMember = new Member().deserialize(input.secondMember);
return this;
}
}
var json = {
mainId: 42,
firstMember: {
id: 1337
},
secondMember: {
id: -1
}
};
var instance = new ExampleClass().deserialize(json);
console.log(instance);