json - 将 Typescript 类转换为字符串,使用 getter 和 setter 而不是私有(private)变量

标签 json string typescript class tostring

我有以下 Typescript 代码:

class Foo {
    private _id: number;
    private _desc: string;

    constructor(id: number, desc: string) {
        this._id = id;
        this._desc = desc;
    }

    public get id(): number {
        return this.id;
    } 

    public set id(value: number) {
        this._id = value;
    }

    public get desc():string {
        return this.desc;
    } 

    public set desc(value: string) {
        this._desc = value;
    }
}

let foo = new Foo(1, 'something');

我想从 Typescript 类中获取一个字符串,我的意思是使用 getter 和 setter。然后我应该得到以下字符串:

{"id":1,"desc":"something"}

根据这个answer我可以将以下方法添加到类中:

public toJSONString(): string {
    return JSON.stringify(this, Object.keys(this.constructor.prototype));
}

有效。

如果 Typescript 类包含任何其他子类,则它不起作用。

如果我有以下代码:

class Foo {
    private _id: number;
    private _desc: string;
    private _user: Bar;

    constructor(id: number, desc: string, user: Bar) {
        this._id = id;
        this._desc = desc;
        this._user = user;
    }

    public get id(): number {
        return this._id;
    } 

    public set id(value: number) {
        this._id = value;
    }

    public get desc():string {
        return this._desc;
    } 

    public set desc(value: string) {
        this._desc = value;
    }

    public get user(): Bar {
        return this._user;
    } 

    public set user(value: Bar) {
        this._user = value;
    }

    public toJSONString(): string {
        return JSON.stringify(this, Object.keys(this.constructor.prototype));
    }
}

class Bar {
    private _name: string;
    private _surname: string;

    constructor(name: string, surname: string) {
        this._name = name;
        this._surname = surname;
    }

    public get name(): string {
        return this._name;
    } 

    public set name(value: string) {
        this._name = value;
    }

    public get surname():string {
        return this._surname;
    } 

    public set surname(value: string) {
        this._surname = value;
    }
}

let foo = new Foo(1, 'something', new Bar('foo', 'bar'));

如果我使用 toJSONString 方法,我会得到以下字符串:

{"id":1,"desc":"something","user":{}}

而不是这个:

{"id":1,"desc":"something","user":{ "name": "foo", "surname": "bar"}}

那么,如何从具有其他子类的 Typescript 类中获取字符串?

(如果您需要这里是第一个代码的 playground,这里是第二个代码的 playground)

最佳答案

这里有两点需要牢记:

  1. 当您定义 getter 和 setter 时,它们不会在转换为 Javascript 后成为实例方法,而是使用 Object.defineProperty 添加到原型(prototype)中。这意味着您无法仅使用 JSON.stringify 获取它们

  2. 将替换数组传递给 JSON.stringify 并告诉它仅使用原型(prototype)值可以完成这项工作,但它有点不适用于嵌套对象。事实是 JSON.stringify 将只解析具有该名称的属性,无论它位于对象结构中的什么位置。

例如

let a = {
    user: "Foo",
    data: {
        name: "Bar"
    }
};

JSON.stringify(a, ["user", "data"]);

将输出 {"user":"Foo","data":{}} 因为即使嵌套对象的键是 data,对象本身也不是具有名为 userdata
的属性 但是

let a = {
    user: "Foo",
    data: {
        user: "Bar"
    }
};

JSON.stringify(a, ["user", "data"]);

将输出 {"user":"Foo","data":{"user":"Bar"}} 因为嵌套对象有一个名为 user,就像它的 parent 一样

我认为这种行为可能会令人困惑,但可以通过创建一个方法来实现解决方案,该方法获取您感兴趣的所有对象的所有属性。我还没有在 Typescript 中找到一种方法来检查类是否实现一个接口(interface)(或扩展一个类),所以我不得不对我所知道的工作进行一些工作,即使它不是那么“优雅”。

abstract class Stringifyiable {
    private isStringifyiable(value): boolean {
        return value != null && (typeof value === 'object' || typeof value === 'function') && value['getJsonKeys'] && typeof value['getJsonKeys'] === 'function';
    }

    public getJsonKeys(): string[] {
        let keys = Object.keys(this.constructor.prototype);
        keys.forEach(key => {
            if (this.isStringifyiable(this[key])) {
                keys = keys.concat(this[key].getJsonKeys());
            }
        });

        return keys;
    }

    public toJSONString(): string {
        return JSON.stringify(this, this.getJsonKeys());
    }
}



class Foo extends Stringifyiable {
    private _id: number;
    private _desc: string;
    private _user: Bar;

    constructor(id: number, desc: string, user: Bar) {
        super();
        this._id = id;
        this._desc = desc;
        this._user = user;
    }

    public get id(): number {
        return this._id;
    } 

    public set id(value: number) {
        this._id = value;
    }

    public get desc():string {
        return this._desc;
    } 

    public set desc(value: string) {
        this._desc = value;
    }

    public get user(): Bar {
        return this._user;
    } 

    public set user(value: Bar) {
        this._user = value;
    }
}



class Bar extends Stringifyiable {
    private _name: string;
    private _surname: string;

    constructor(name: string, surname: string) {
        super();
        this._name = name;
        this._surname = surname;
    }

    public get name(): string {
        return this._name;
    } 

    public set name(value: string) {
        this._name = value;
    }

    public get surname():string {
        return this._surname;
    } 

    public set surname(value: string) {
        this._surname = value;
    }
}

let foo = new Foo(1, 'something', new Bar('foo', 'bar'));
//this will output {"id":1,"desc":"something","user":{"name":"foo","surname":"bar"}}
foo.toJSONString();

小心循环引用,因为它会进入无限循环(不过我相信它可以修复)。

关于json - 将 Typescript 类转换为字符串,使用 getter 和 setter 而不是私有(private)变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54220472/

相关文章:

c++ - 返回从缓冲区读取的字符串和没有动态分配的函数?

typescript - 带有 Webpack 和 Typescript 的 Karma 不执行任何测试

arrays - 为剩余参数强制至少一个参数

http - angular2 – 多次处理相同的响应错误

ios - 如何使用 AFNetworking 发布 JSON 参数?

php - 创建一个简单的 AJAX/jQuery/PHP SELECT */JSON

javascript - 将每个键有多个值的对象转换为 JS 中的对象数组

c# - 如何从 C# Web 服务以 JSON 形式返回数据表/数据集

objective-c - 在 Objective-C 中定义一个全局可访问的字符串

r - 在 R 中的行首添加字符