【问题标题】:javaScript: Parsing a stringified object with JSON.parse removes referencesjavaScript:使用 JSON.parse 解析字符串化对象会删除引用
【发布时间】:2017-06-21 21:23:49
【问题描述】:

我正在尝试深度克隆一个对象,用 k = JSON.parse(JSON.stringify(a)) 说“a”。使用 stringify 方式很重要,因为我试图将对象保存到文件中,然后从中加载。

我偶然发现了一个克隆对象的引用问题,如下图所示:

var obj={};
obj.importantProperty={s:2};
obj.c=obj.importantProperty;
obj.d=obj.importantProperty;
console.log( obj.c === obj.d ); // Returns true

var cloned = JSON.parse(JSON.stringify(obj));
console.log( cloned.c === cloned.d ); // Returns false
我需要在使用 JSON.parse 时保留引用,在上面的示例中它们不是。在我的项目中,对象要复杂得多,但最终归结为上面的示例。

提前感谢任何帮助我的人:)

【问题讨论】:

  • JSON.parse 从字符串表示创建一个新结构。它无法理解两个对象是相同的。
  • 更多:cloned === obj -> false.
  • cloned===obj -> false 是正常的,因为克隆的对象是深度克隆,即不同的引用。感谢您的回复。

标签: javascript json parsing stringify


【解决方案1】:

执行此类操作的正确方法是单独存储公共引用对象并通过 ID 引用它。

例如,您可以将 importantProperty 对象保存在一个数组中,并使用索引作为 ID:

var importantProperties = [
  { s: 1 },
  { s: 2 },
  { s: 3 }
];

var obj = {};
obj.importantProperty = importantProperties[1];
obj.c = obj.importantProperty;
obj.d = obj.importantProperty;

然后,当您对对象进行字符串化时,您会将引用的对象替换为其索引:

var stringified = JSON.stringify(obj, function(key, value) {
  if (key) {
    return importantProperties.indexOf(value);
  }
  return value;
});
console.log(stringified);
// prints {"importantProperty":1,"c":1,"d":1}

然后,当您解析时,您只需反转该过程即可恢复引用:

var parsed = JSON.parse(stringified, function(key, value) {
  if (key) {
    return importantProperties[value];
  }
  return value;
});
console.log(parsed.c === parsed.d && parsed.d === parsed.importantProperty);
// prints true

现在,上面的示例适用于您的示例代码,假设obj 中的所有属性都是importantProperties 数组中的对象。如果不是这种情况,并且只有某些属性是 importantProperties 对象,则需要在替换/恢复时进行检查。
假设只有“importantProperty”、“c”和“d”属性是这样的对象:
if (['importantProperty', 'c', 'd'].includes(key)) 而不仅仅是if (key)

如果这还不够好,并且您不希望属性名称与值是否为 importantProperties 对象有任何关系,则需要在值中与标识符。以下是如何做到这一点的示例:

// Replacing
JSON.stringify(obj, function(k, value) {
  if (importantProperties.includes(value)) {
    return 'ImportantProperty['
      + importantProperties.indexOf(value)
      + ']';
  }
  return value;
});

// Reviving
JSON.parse(stringified, function(k, value) {
  if (/^ImportantProperty\[\d+\]$/.test(value)) {
    var index = Number( value.match(/\d+/)[0] );
    return importantProperties[index];
  }
  return value;
});

【讨论】:

    【解决方案2】:

    使用 JSON 不可能达到您想要的结果,因为 JSON 格式只能包含有限数量的数据类型 (http://json.org/),并且当您将对象字符串化为 JSON 时,一些信息会丢失。

    可能还有其他类型的序列化技术,但我建议您寻找另一种存储数据的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-04
      • 2014-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-15
      相关资源
      最近更新 更多