前端面试题 - 94. json序列化、反序列化

436 阅读3分钟

get 属性可以被序列化出来吗?

JavaScript 中的对象可以通过序列化转换成字符串形式,比如使用 JSON.stringify() 方法将对象序列化为 JSON 字符串。在对象被序列化时,其可枚举属性的值会被包含在序列化后的字符串中,而不可枚举属性和方法则不会被序列化。

对于普通的 JavaScript 对象而言,它的属性默认都是可枚举的,因此在被序列化时,其所有属性都会被包含在序列化后的字符串中。而 get 关键字定义的操作符只是属性访问器的一种方式,本质上仍然是一个属性,因此也是可枚举的,可以被序列化出来。

以下是一个简单的示例:

const obj = {
  get prop() {
    return 'value';
  }
};

const jsonString = JSON.stringify(obj);
console.log(jsonString); // {"prop":"value"}

以上代码中,我们将一个包含 get 关键字定义的属性访问器的对象进行了序列化,并将序列化后的结果输出到控制台。由于该属性是可枚举的,因此在序列化时也被包含在了字符串中。

哪些属性不能被JSON.stringify序列化

在序列化 JavaScript 对象时,一些属性可能无法被 JSON.stringify() 方法序列化为字符串。以下是一些常见的不能被序列化的属性:

  1. Symbol 类型的属性:Symbol 类型的属性会被忽略。
  2. 函数类型的属性:函数类型的属性会被忽略。
  3. undefined 类型的属性:undefined 类型的属性会被跳过。
  4. 循环引用的对象:包含循环引用的对象无法被序列化。
  5. Date 类型的属性:Date 类型的属性会被转换为 ISO 8601 格式的字符串。
  6. NaN 和 Infinity 等特殊数字值:这些特殊的数字值会被转换成 null。
  7. 不可枚举的属性:如果对象的某个属性设置了 enumerable 为 false,那么该属性不会被序列化到字符串中。

以下是一个示例代码,展示了一些不能被序列化的属性:

const obj = {
  a: 'a',
  b: Symbol('b'),
  c: function() {},
  d: undefined,
  e: NaN,
  f: Infinity,
  g: {h: 'h'},
  i: new Date(),
};
// 设置不可枚举的属性
Object.defineProperty(obj, 'j', {value: 'j', enumerable: false});

const jsonString = JSON.stringify(obj);
console.log(jsonString); // {"a":"a","g":{"h":"h"},"i":"2021-10-12T14:15:16.169Z"}

以上列举的属性不能被序列化,主要是因为它们的值不适合作为字符串来进行序列化处理。

  1. Symbol 类型的属性:Symbol 类型是一种唯一标识符,其值不能被转换成字符串。因此,Symbol 类型的属性无法被序列化。
  2. 函数类型的属性:函数类型的属性也不能被转换成字符串,同时也不存在将函数类型的属性序列化后再进行反序列化的必要性。
  3. undefined 类型的属性:undefined 类型表示未定义,其值也不能被转换成字符串。
  4. 循环引用的对象:在存在循环引用的情况下,序列化器会陷入死循环,无法正常结束序列化操作。
  5. Date 类型的属性:Date 类型的属性需要以特定格式的字符串表示,否则在反序列化时可能会出现错误。
  6. NaN 和 Infinity 等特殊数字值:这些特殊的数字值无法被转换成合法的 JSON 字符串,因此会被转换成 null。
  7. 不可枚举的属性:如果某个属性设置了 enumerable 为 false,那么该属性不应该被视为对象的公共状态,因此也不应该被序列化。

综合来说,JSON.stringify() 方法本质上是将 JavaScript 对象转换为字符串表示,但是这并不意味着所有类型的属性都能被成功地序列化为字符串。