我想将实例类转换为普通对象,而不会丢失方法和/或继承的属性。例如:
class Human {
height: number;
weight: number;
constructor() {
this.height = 180;
this.weight = 180;
}
getWeight() { return this.weight; }
// I want this function to convert the child instance
// accordingly
toJSON() {
// ???
return {};
}
}
class Person extends Human {
public name: string;
constructor() {
super();
this.name = 'Doe';
}
public getName() {
return this.name;
}
}
class PersonWorker extends Person {
constructor() {
super();
}
public report() {
console.log('I am Working');
}
public test() {
console.log('something');
}
}
let p = new PersonWorker;
let jsoned = p.toJSON();
jsoned
应如下所示:
{
// from Human class
height: 180,
weight: 180,
// when called should return this object's value of weight property
getWeight: function() {return this.weight},
// from Person class
name: 'Doe'
getName(): function() {return this.name},
// and from PersonWorker class
report: function() { console.log('I am Working'); },
test: function() { console.log('something'); }
}
这有可能实现,如果可以,怎么做?
如果您想知道,我需要这个,因为我使用的框架不幸地接受了输入
只有一个json对象,而我正在尝试使用typescript
和类继承。
此外,我正在进行上述转换,因此性能不是一个需要考虑的问题。
如果编译器的目标选项设置为es6
,则通过迭代对象属性组成的解决方案将不起作用。在es5
上,通过迭代对象属性(使用Object.keys(instance)
)的现有实现将起作用。
到目前为止,我有这个实现:
toJSON(proto?: any) {
// ???
let jsoned: any = {};
let toConvert = <any>proto || this;
Object.getOwnPropertyNames(toConvert).forEach((prop) => {
const val = toConvert[prop];
// don't include those
if (prop === 'toJSON' || prop === 'constructor') {
return;
}
if (typeof val === 'function') {
jsoned[prop] = val.bind(this);
return;
}
jsoned[prop] = val;
const proto = Object.getPrototypeOf(toConvert);
if (proto !== null) {
Object.keys(this.toJSON(proto)).forEach(key => {
if (!!jsoned[key] || key === 'constructor' || key === 'toJSON') return;
if (typeof proto[key] === 'function') {
jsoned[key] = proto[key].bind(this);
return;
}
jsoned[key] = proto[key];
});
}
});
return jsoned;
}
但这仍然无效。结果对象仅包括所有类中的所有属性,但仅包括PersonWorker
中的方法。
我在这里缺少什么?
答案 0 :(得分:6)
已经有很多答案,但这是最简单的,使用 ... 运算符并解构对象:
const {...object} = classInstance
答案 1 :(得分:3)
好的,所以我的OP中的实现是错误的,错误只是愚蠢。
使用es6
时的正确实施是:
toJSON(proto) {
let jsoned = {};
let toConvert = proto || this;
Object.getOwnPropertyNames(toConvert).forEach((prop) => {
const val = toConvert[prop];
// don't include those
if (prop === 'toJSON' || prop === 'constructor') {
return;
}
if (typeof val === 'function') {
jsoned[prop] = val.bind(jsoned);
return;
}
jsoned[prop] = val;
});
const inherited = Object.getPrototypeOf(toConvert);
if (inherited !== null) {
Object.keys(this.toJSON(inherited)).forEach(key => {
if (!!jsoned[key] || key === 'constructor' || key === 'toJSON')
return;
if (typeof inherited[key] === 'function') {
jsoned[key] = inherited[key].bind(jsoned);
return;
}
jsoned[key] = inherited[key];
});
}
return jsoned;
}
答案 2 :(得分:3)
这就是对我有用的
const classToObject = theClass => {
const originalClass = theClass || {}
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(originalClass))
return keys.reduce((classAsObj, key) => {
classAsObj[key] = originalClass[key]
return classAsObj
}, {})
}
答案 3 :(得分:1)
我非常喜欢Alex Cory的解决方案,但这就是我想到的。期望将其作为功能分配给类,并在this
上具有相应的绑定。
const toObject = function() {
const original = this || {};
const keys = Object.keys(this);
return keys.reduce((classAsObj, key) => {
if (typeof original[key] === 'object' && original[key].hasOwnProperty('toObject') )
classAsObj[key] = original[key].toObject();
else if (typeof original[key] === 'object' && original[key].hasOwnProperty('length')) {
classAsObj[key] = [];
for (var i = 0; i < original[key].length; i++) {
if (typeof original[key][i] === 'object' && original[key][i].hasOwnProperty('toObject')) {
classAsObj[key].push(original[key][i].toObject());
} else {
classAsObj[key].push(original[key][i]);
}
}
}
else if (typeof original[key] === 'function') { } //do nothing
else
classAsObj[key] = original[key];
return classAsObj;
}, {})
}
然后,如果您使用的是TypeScript,则可以将此接口放在应转换为对象的任何类上:
export interface ToObject {
toObject: Function;
}
然后在您的课程中,不要忘记绑定this
class TestClass implements ToObject {
toObject = toObject.bind(this);
}
答案 4 :(得分:0)
这是toJSON()方法的实现。我们正在复制这些属性&amp;从当前实例到新对象的方法,并排除不需要的方法,即toJSON和constructor。
toJSON() {
var jsonedObject = {};
for (var x in this) {
if (x === "toJSON" || x === "constructor") {
continue;
}
jsonedObject[x] = this[x];
}
return jsonedObject;
}
我已经测试了Chrome中toJSON()返回的对象,我发现该对象的行为与您期望的相同。
答案 5 :(得分:0)
此方法不是递归的。
toPlainObject() {
return _.pickBy(this, item => {
return (
!item ||
_.isString(item) ||
_.isArray(item) ||
_.isNumber(item) ||
_.isPlainObject(item)
);
});
}
答案 6 :(得分:-1)
这个方案会丢失方法,但是将类实例转换为对象是一个非常简单的方案。
obj = JSON.parse(JSON.stringify(classInstance))