Javascript 原型上的Object.defineProperty阻止JSON.stringify序列化它

Javascript 原型上的Object.defineProperty阻止JSON.stringify序列化它,javascript,json,typescript,Javascript,Json,Typescript,我正在使用TypeScript定义一些类,当我创建一个属性时,它会在以下命令中生成与Class1等价的命令: 序列化时,它不会输出我刚才定义的属性 instance2和instance3通过序列化定义的属性,表现出我所期望的行为。(参见plunkr输出) 我的实际问题是:这正常吗 如果是这样,我如何以最有效的方式解决它?您可以在原型上定义一个方法来自定义实例的序列化方式 Class1.prototype.toJSON = function () { return { N

我正在使用TypeScript定义一些类,当我创建一个属性时,它会在以下命令中生成与
Class1
等价的命令:

序列化时,它不会输出我刚才定义的属性

instance2
instance3
通过序列化定义的属性,表现出我所期望的行为。(参见plunkr输出)

我的实际问题是:这正常吗

如果是这样,我如何以最有效的方式解决它?

您可以在原型上定义一个方法来自定义实例的序列化方式

Class1.prototype.toJSON = function () {
    return {
        Name: this.Name
    };
};
JSON.stringify(new Class1()); // Will be '{"Name":"test1"}'

正如您所发现的,它不会序列化在原型上定义的属性

我知道这并不理想,但另一个选择是:

class Class1 {
    private _name = "test1";

    Name: string; // do this to make the compiler happy

    constructor() {
        Object.defineProperty(this, "Name", {
            get: function() { return this._name; },
            set: function(value) { this._name = value; },
            enumerable: true
        });
    }
}
在实例上定义属性将序列化属性。

是的,它是按设计的

按照ECMA中的定义,只有自己的可枚举属性被序列化(
stringify()
是根据
Object.keys()
等定义的)

属性访问器是在TypeScript和ES6中的原型上定义的

回答你的最后一个问题,这是执行此操作最有效的方法

除此之外,只有a)为序列化的每个对象部分定义一个toJSON(),或者b)将替换函数/数组作为第二个参数传递给JSON.stringify()

原型的白名单属性:

JSON.stringify(instance, Object.keys(instance.constructor.prototype))

如果您想推动它向前发展,请为TypeScript提供一个“尝试装饰”方案:

根据这项建议():

装饰师是:

  • 表情
  • 它的计算结果是一个函数
  • 它将目标、名称和属性描述符作为参数
  • 并可选地返回要安装在目标对象上的属性描述符
它是这样的(高级视图):

客户端代码:

@serializable()
class Person {

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

    private _name: string;

    @serialize()
    get name() {
      return this._name;
    }

    @serialize('Language')
    get lang() {
      return 'JavaScript';
    }
}
基础设施:

const serialized = new WeakMap();

export function serializable(name?: string) {
    return function (target, propertyKey, descriptor) {
        target.prototype.toJSON = function () {
            const map = serialized.get(target.prototype);
            const props = Object.keys(map);
            return props.reduce((previous, key) => {
                previous[map[key]] = this[key];
                return previous;
            }, {});
        }

    }
}

export function serialize(name?: string) {
    return function (target, propertyKey, descriptor) {
        let map = serialized.get(target);
        if (!map) {
            map = {};
            serialized.set(target, map);
        }

        map[propertyKey] = name || propertyKey;
    }
}

更新:我将这个示例decorator提取到一个位于的存储库中,希望在这里放置一些可以帮助其他人的东西。 我为fix JSON.stringify所做的不是序列化原型上定义的属性

var newObject = $.extend(false, {}, orginalObj);
然后我注意到newObject具有实例属性而不是原型属性。
我正在使用typescript和get accessor。

我将此标记为答案,因为我最终实现了toJSON。我已经有了私有成员到公共属性的映射,因为我正在使用它将一些JSON从API映射到我的TypeScript类。在toJson方法中,我只需使用该映射创建一个新对象,该对象的所有属性都使用倒置的名称。我很快就会在博客上发表。我已经考虑过这个问题,但我想要一个使用TypeScript本身的解决方案。@ChristianDroulers是的,我也不会使用这个解决方案:)。。。添加一个toJSON方法是一个更好的选择。我很快会在博客上写的。很有趣!但在短期内,这不是一个可行的解决方案。谢谢是的,你说得对,但我觉得它很有前途,希望在生产中使用它soon@Jacks也许您是在使用类作为键而不是类的原型进行检索?我用一个有效的实现更新了我的答案,请看一看。@AndréWerlang非常感谢您的更新。是的,我确实是第一次尝试通过传递类而不是原型来检索值。但是为了验证,我试图打印整个WeakMap,这是不可能的,因为其中的键不可枚举(请参阅)。感谢您在几年后澄清此帖子:)@Apidcloud,类似这样的内容(注意我删除了块,此代码不会运行,但我添加了箭头以显示
ClassDecorator
propertydcorator
var newObject = $.extend(false, {}, orginalObj);