将JSON序列化为具有toJSON方法的对象数组时出现奇怪错误

时间:2017-06-16 11:20:51

标签: javascript json typescript nswag

我使用NSwag为swagger API端点生成TypeScript类型和类。生成的类包含每个对象的.toJSON()方法,在使用JSON.stringify()将对象序列化为JSON时调用该方法。

序列化单个对象时一切正常,但是当我尝试序列化一个对象数组时,它会抛出一个奇怪的错误:

angular.js:14199 TypeError: Cannot create property 'code' on string '0'
    at Dashboard.toJSON (App/models/api.js:785:34)
    at JSON.stringify (<anonymous>)

并且触发它的代码非常简单:

console.log(JSON.stringify([
        Dashboard.fromJS({
            code: "1212312",
            name: "tresads",
            description: "some description"
        }),
        Dashboard.fromJS({
            code: "1212312",
            name: "tresads",
            description: "some description"
        })
    ]));

该课程的摘录:

export class Dashboard implements IDashboard {
    code?: string | undefined;
    ...

    constructor(data?: IDashboard) {
        if (data) {
            for (var property in data) {
                if (data.hasOwnProperty(property))
                    (<any>this)[property] = (<any>data)[property];
            }
        }
    }

    init(data?: any) {
        if (data) {
            this.code = data["code"];
            ...
        }
    }

    static fromJS(data: any): Dashboard {
        let result = new Dashboard();
        result.init(data);
        return result;
    }

    toJSON(data?: any) {
        data = data ? data : {};
        data["code"] = this.code;
        ...
        return data; 
    }

    clone() {
        const json = this.toJSON();
        let result = new Dashboard();
        result.init(json);
        return result;
    }
}

明白为什么JSON.stringify()使用&#34; 0&#34;调用toJSON()方法参数β

1 个答案:

答案 0 :(得分:1)

将使用一个参数调用方法toJSON,该参数是分配this的属性名称。从本质上讲,您感兴趣的价值不是那个参数,而是this,它将被绑定到您可以转换的值。由于您使用数组调用stringify,因此toJSON将使用该数组的可枚举属性进行调用,即01,而this将是相应的仪表板对象。

另外,我的印象是你可以很好地利用Object.assign将属性从一个对象复制到另一个对象,这基本上就是你在构造函数的for循环中所做的。

所以这就是你如何做到的。我删除了打字稿装饰并使用了纯JavaScript,但原理保持不变:

&#13;
&#13;
class Dashboard {
    constructor(data) {
        // Object.assign does essentially what you want with the loop:
        Object.assign(this, data); 
    }

    init(data) {
        return Object.assign(this, data); 
    }

    static fromJS(data) {
        return new Dashboard(data);
    }

    toJSON(key) { 
        // `key` is the key/index of the property in the parent object.
        //    That probably is of no interest to you. You need `this`.
        // Extract properties into plain object, and return it for stringification
        return Object.assign({}, this);
    }

    clone() {
        return new Dashboard(this);
    }
}

console.log(JSON.stringify([
        Dashboard.fromJS({
            code: "1212312",
            name: "tresads",
            description: "some description"
        }),
        Dashboard.fromJS({
            code: "1212312",
            name: "tresads",
            description: "some description"
        })
    ]));
&#13;
&#13;
&#13;

实际上,在给定的示例中,您根本不需要toJSON,因为Dashboard实例的属性是可枚举的,因此无论如何它们都将被字符串化。如果由于某种原因你需要它来进行某种转换,那么你当然还需要包含该转换的逻辑,因为Object.assign只是一个简单的副本。