在Node.js中反序列化之后,将对象与其类重新关联

我正在为一些特定于应用程序的对象编写一个简单的序列化/反序列化框架。

考虑以下:

"use strict"; function Dog(name) { this._name = name; }; Dog.prototype.constructor = Dog; Dog.prototype.getName = function() { return this._name; } var d1 = new Dog('fido'); var d2 = JSON.parse(JSON.stringify(d1)); // serialize / deserialize > d1 Dog { _name: 'fido' } > d1.getName() 'fido' > d2 { _name: 'fido' } > d2.getName() TypeError: d2.getName is not a function 

在这一点上,人们可以问“ d1有什么d2缺乏?”

部分工作的一种方法是手动将d1的方法分配给d2:

 > d2.constructor = d1.constructor > d2.getName = d1.getName > d2.getName() 'fido' 

这有几个缺点。 首先,我必须手动将d1的每个方法分配给d2。 其次,d2获取自己的属性,并不使用原型机制共享插槽:

 > d2 Dog { _name: 'fido', constructor: [Function: Dog], getName: [Function] } 

所以我提炼的问题是:给定一个对象(例如d2 ),是否有办法将它与另一个对象的原型(例如d1 )相关联,以便它inheritance相同的行为?

Object.create()Object.getOwnPropertyDescriptors()是你需要的。

 const obj = JSON.parse(JSON.stringify(d1)) const d3 = Object.create(Dog.prototype, Object.getOwnPropertyDescriptors(obj)) 

这和OP的方法之间的区别在于,这个方法在原型上设置了prototype属性,而OP的方法直接在对象上设置属性。 当你使用hasOwnProperty()方法使用for-in循环遍历对象自己的属性时,你可以看到这一点:

 for (const i in d1) { if (d3.hasOwnProperty(i)) { console.log(i) } } 

用我的方法,它只输出_name ,但用OP的方法,它也输出getName

不幸的是, Object.getOwnPropertyDescriptors()是ECMAScript 2017的一部分,现在只支持Firefox,所以你需要使用Babel。


或者,您可以使用Object.setPrototypeOf() 。 它比Object.getOwnPropertyDescriptors()有更好的浏览器支持,但MDN不鼓励它,因为它很慢。

 const d3 = JSON.parse(JSON.stringify(d1)) Object.setPrototypeOf(d3, Dog.prototype) 

在写这篇文章的时候,我想到了创build一个使用反序列化的JSON来初始化对象的自定义构造函数:

 Dog.createFromJSON = function(obj) { var d = new Dog(); Object.keys(obj).forEach(function(key) { d[key] = obj[key]; }); return d; } > d3 = Dog.createFromJSON(JSON.parse(JSON.serialize(d1))) > d3 Dog { _name: 'fido' } > d3.getName() 'fido' 

更新:如何dynamic查找类并分配原型

正如@Louis所指出的,@ Gothdo的答案要求你知道反序列化对象属于哪个类。 如果您愿意将类名添加到序列化对象中,则可以使用它来dynamic确定类。 所以,举个例子,在OP的例子上展开:

 > var d1 = new Dog('fido'); > d1['_class'] = 'Dog'; > let jsonString = JSON.stringify(d1) '{"_name":"fido","_class":"Dog"}' 

使用反序列化JSON到JAVASCRIPT对象 (但针对Node.js进行了调整)中描述的技巧,可以使用string通过Node.js的global对象获取类原型的句柄:

 > global[d1['_class']].prototype Dog { getName: [Function] } 

现在,您可以使用它来使用@ Gothdo的技术来dynamic重build对象。 把它放在一起:

 /** * Dynamically create an object from a JSON string of properties. * Assumes the presence of a _class meta-property that names the * resulting class. */ function reconstitute(jsonString) { let obj = JSON.parse(jsonString); let cls = global[obj['_class']]; delete obj['_class']; // remove meta-property return Object.setPrototypeOf(obj, cls.prototype); } > reconstitute('{"_name":"fido","_class":"Dog"}') Dog { _name: 'fido' }