typescript 原型上的 Object.defineProperty 阻止 JSON.stringify 对其进行序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29705211/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 02:59:35  来源:igfitidea点击:

Object.defineProperty on a prototype prevents JSON.stringify from serializing it

javascriptjsontypescript

提问by Christian Droulers

I'm using TypeScript to define some classes and when I create a property, it generates the equivalent to Class1in the following plunkr:

我正在使用 TypeScript 来定义一些类,当我创建一个属性时,它会生成Class1以下 plunkr 中的等效项:

http://plnkr.co/edit/NXUo7zjJZaUuyv54TD9i?p=preview

http://plnkr.co/edit/NXUo7zjJZaUuyv54TD9i?p=preview

var Class1 = function () {
  this._name = "test1";
}

Object.defineProperty(Class1.prototype, "Name", {
  get: function() { return this._name; },
  set: function(value) { this._name = value; },
  enumerable: true
});

JSON.stringify(new Class1()); // Will be "{"_name":"test1"}"

When serializing, it doesn't output the property I just defined.

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

instance2and instance3behave as I'd expect by serializing the defined property. (see the plunkr output).

instance2instance3通过序列化定义的属性来按照我的预期行事。(参见 plunkr 输出)。

My actual question is: Is this normal?

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

If so, how do I work around it in the most efficient way?

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

回答by zzzzBov

You can define a toJSON()method on your prototype to customize how instances are serialized.

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

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

回答by André Werlang

If you like to push it forward, give a try to decorators proposal for TypeScript:

如果你想推动它,请尝试使用 TypeScript 的装饰器提案:

According to this proposal (https://github.com/wycats/javascript-decorators):

根据这个提议(https://github.com/wycats/javascript-decorators):

A decorator is:

装饰器是:

  • an expression
  • that evaluates to a function
  • that takes the target, name, and property descriptor as arguments
  • and optionally returns a property descriptor to install on the target object
  • 一种表达
  • 评估为函数
  • 将目标、名称和属性描述符作为参数
  • 并可选择返回要安装在目标对象上的属性描述符

It goes like this (high level view):

它是这样的(高级视图):

Client code:

客户端代码:

@serializable()
class Person {

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

    private _name: string;

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

    @serialize('Language')
    get lang() {
      return 'JavaScript';
    }
}

Infrastructure:

基础设施:

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

UPDATE: I extracted this sample decorator into a repository at https://github.com/awerlang/es-decorators

更新:我将此示例装饰器提取到位于https://github.com/awerlang/es-decorators的存储库中

回答by André Werlang

Yes, it is by design.

是的,这是设计使然。

As defined in ECMA, only own enumerable propertiesare serialized (stringify()is defined in terms of Object.keys(), among others).

正如 ECMA 中定义的那样,只有自己的可枚举属性被序列化(stringify()根据 等定义Object.keys())。

Property accessors are defined on prototypes, both in TypeScript and ES6.

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

And answering your last question, that is the most eficient way to perform this operation.

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

Beside that, only a) defining an toJSON() to each object part of the serialization, or b) passing a replacer function/array as 2nd argument to JSON.stringify().

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

Whitelist properties from prototype:

来自原型的白名单属性:

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

回答by BeiBei ZHU

Put something here hopefully can help others. What I have do for fix JSON.stringify not serialize properties defined on prototype

把东西放在这里希望可以帮助别人。我为修复 JSON.stringify 所做的而不是序列化原型上定义的属性

var newObject = $.extend(false, {}, orginalObj);

then I notice newObject have instance properties instead of prototype properties. I'm use typescript and get accessor.

然后我注意到 newObject 具有实例属性而不是原型属性。我正在使用打字稿并获取访问器。

回答by David Sherret

As you've discovered, it won't serialize properties defined on prototype.

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

I know it's not ideal, but another option is to do this:

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

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

Defining the property on the instance will serialize the property.

在实例上定义属性将序列化该属性。