开发者问题收集

将 JavaScript 类实例转换为普通对象保存方法

2016-01-09
45952

我想将实例类转换为普通对象,而不丢失方法和/或继承的属性。例如:

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'); }
}

这可以实现吗?如果可以,如何实现?

如果您想知道,我需要这个,因为我正在使用一个框架,不幸的是,它只接受对象作为输入,而我正在尝试使用 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 中的方法。 我这里遗漏了什么?

3个回答

已经有很多答案了,但这是迄今为止最简单的答案,通过使用 扩展语法 解构 对象:

const {...object} = classInstance
Hovoh
2021-03-24

这就是对我有用的

更新答案(带递归)

const keys = x => Object.getOwnPropertyNames(x).concat(Object.getOwnPropertyNames(x?.__proto__))
const isObject = v => Object.prototype.toString.call(v) === '[object Object]'

const classToObject = clss => keys(clss ?? {}).reduce((object, key) => {
  const [val, arr, obj] = [clss[key], Array.isArray(clss[key]), isObject(clss[key])]
  object[key] = arr ? val.map(classToObject) : obj ? classToObject(val) : val
  return object
}, {})

var classs = new Response()
var obj = classToObject(classs)
console.log({ obj, classs })

原始答案

const classToObject = theClass => {
  const originalClass = theClass || {}
  const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(originalClass))
  return keys.reduce((classAsObj, key) => {
    classAsObj[key] = originalClass[key]
    return classAsObj
  }, {})
}

在此处输入图片描述

Alex Cory
2019-10-26

好的,所以我的 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;
}
eAbi
2016-01-10