【问题标题】:Why does JSON.stringify not serialize non-enumerable properties?为什么 JSON.stringify 不序列化不可枚举的属性?
【发布时间】:2013-03-31 20:01:15
【问题描述】:

我正在使用 JavaScript 将对象序列化为 JSON 字符串,

我注意到只有可枚举的对象属性会被序列化:

var a = Object.create(null,{
  x: { writable:true, configurable:true, value: "hello",enumerable:false },
  y: { writable:true, configurable:true, value: "hello",enumerable:true }
});
document.write(JSON.stringify(a)); //result is {"y":"hello"}

[pen]

我想知道为什么会这样?我搜索了MDN pagejson2 解析器文档。 我在任何地方都找不到这种行为的记录。

我怀疑这是使用for... in 循环only go through [[enumerable]] 属性的结果(至少在json2 的情况下)。这可以通过返回可枚举和不可枚举属性的Object.getOwnPropertyNames 之类的东西来完成。 不过,序列化可能会有问题(由于反序列化)。

tl;dr

  • 为什么JSON.stringify 只序列化可枚举的属性?
  • 这种行为是否记录在任何地方?
  • 如何自己实现序列化不可枚举的属性?

【问题讨论】:

  • 如果将 enumerable 设置为 false,则不会添加任何实例。在字符串化之前尝试控制台记录对象,您会看到对象本身缺少x,因此一旦字符串化它肯定不会存在。
  • @adeneo 这大概是因为它还使用了类似 stringify 而不是 getOwnPropertyNames 的东西。 Object.getOwnPropertyNames(a) 返回 ["x","y"] 如果你输入 obj.x 你会得到 "hello"。
  • 是的,我注意到了,这很好地表明您应该重新考虑并找到另一种创建对象的方法。
  • @adeneo 可枚举属性是有目的的。绝对在非常基本的样本输入中。但是,这个问题是我实际所做的非常减少的情况。感谢您的投入和时间。
  • @BenjaminGruenbaum - 作为Object.create 的附注,除非明确定义,否则 enumerable 将默认为 false。这是一个显示行为的示例 jsfiddle:jsfiddle.net/T3PGD/2

标签: javascript json serialization


【解决方案1】:

ES5 spec中指定。

如果 Type(value) 是 Object,并且 IsCallable(value) 是 false

If the [[Class]] internal property of value is "Array" then

    Return the result of calling the abstract operation JA with argument value.

Else, return the result of calling the abstract operation JO with argument value.

那么,让我们看看JO。以下是相关部分:

令 K 是一个内部字符串列表,由 所有 [[Enumerable]] 属性为 true 的 value 自身属性的名称组成。字符串的顺序应与 Object.keys 标准内置函数使用的顺序相同。

【讨论】:

  • 啊,我不知道 stringify 是规范的一部分,这正是我想要的,谢谢。
【解决方案2】:

正如@ThiefMaster 上面回答的那样,它在规范中指定

但是,如果您知道要提前序列化的不可枚举属性的名称,您可以通过将替换函数作为第二个参数传递给 JSON.stringify() (documentation on MDN) 来实现它,像这样

var o = {
  prop: 'propval',
}

Object.defineProperty(o, 'propHidden', {
  value: 'propHiddenVal',
  enumerable: false,
  writable: true,
  configurable: true
});

var s = JSON.stringify(o, (key, val) => {
  if (!key) {
    // Initially, the replacer function is called with an empty string as key representing the object being stringified. It is then called for each property on the object or array being stringified.
    if (typeof val === 'object' && val.hasOwnProperty('propHidden')) {
      Object.defineProperty(val, 'propHidden', {
        value: val.propHidden,
        enumerable: true,
        writable: true,
        configurable: true
      });

    }
  }
  return val;
});

console.log(s);

【讨论】:

  • 遗憾的是,使用此解决方案,不可枚举的属性在序列化后是可枚举的。
猜你喜欢
  • 1970-01-01
  • 2017-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-10
  • 2013-02-05
  • 2012-09-04
  • 2012-05-22
相关资源
最近更新 更多