【问题标题】:JavaScript: Stringify a shallow copy of a circular referenced object?JavaScript:字符串化循环引用对象的浅拷贝?
【发布时间】:2017-03-19 08:51:17
【问题描述】:

有没有办法只获得下面的浅层副本而只获得一层深度?我有办法使用完全不同的设计来解决这个问题,但我想知道是否有其他人遇到过我之前尝试转换为字符串的内容。

var SomeObjClass = function() {
    var self = this;
    this.group = {
        members: [self]
    };
};
var p = new SomeObjClass();
var str = JSON.stringify(p);

【问题讨论】:

  • 错误?将循环结构转换为 JSON
  • 你能提供一个预期结果的例子吗?
  • 没有什么可复制的。进行浅克隆与重新调用构造函数以创建新对象相同。我假设您还没有粘贴其他代码。
  • 预期结果为:console.log(str); Object { group: { members: { Object: { group: { members: {} } } } } } 这是我要求的“浅克隆”。问题是 toJSON 会递归直到堆栈溢出。

标签: javascript json stringify


【解决方案1】:

有点不清楚您在问什么,但如果您的目标是简单地对圆形对象进行字符串化,则必须覆盖 toJSON 以指定您希望如何表示您的对象

function SomeObjClass () {
  var self = this;
  this.group = {
    members: [self]
  };
}

SomeObjClass.prototype.addMember = function(m) {
  this.group.members.push(m);
};

// when stringifying this object, don't include `self` in group.members
SomeObjClass.prototype.toJSON = function() {
  var self = this;
  return {
    group: {
      members: self.group.members.filter(function (x) {
        return x !== self
      })
    }
  };
}

var a = new SomeObjClass();
var b = new SomeObjClass();
a.addMember(b);

console.log(JSON.stringify(a))

这可能是我可以在不查看更多代码的情况下为您提供的最好的帮助。我不知道您是如何使用此代码的,但无论如何,这可能不是您班级的最佳设计。如果您分享课程的其余部分和使用它的代码,我们或许可以更有效地帮助您。

【讨论】:

  • 这是一种方法,但我想知道 toJSON 是否有特定的参数,我可以在调用中修改我要求的“浅克隆”,但在这种情况下,您将覆盖它本机所做的事情.我会对此表示赞同,并且可能会忽略这种设计模式并寻找替代方法。这篇文章的全部原因是,虽然循环引用在客户端中很好,但当尝试通过网络将数据从一个客户端发送到另一个客户端时,由于循环引用而导致堆栈溢出。
【解决方案2】:

如果您查看有关JSON.stringify 的MDN 参考资料,您会看到它接受replacer 函数作为第二个参数。这个函数对你想要字符串化的元素进行一点按摩很有用。

它可以帮助您避免循环问题。

例如:

function avoidCircularReference(obj) {
  return function(key, value) {
    return key && typeof value === 'object' && obj === value ? undefined : value;
  };
}

var SomeObjClass = function() {
    var self = this;
    this.group = {
        members: [self, {a:'f', b: [self]}]
    };
};
var p = new SomeObjClass();
var str = JSON.stringify(p, avoidCircularReference(p));
console.log(str);

但是,正如文档中所述并显示运行示例:

注意:您不能使用替换函数从数组中删除值。如果返回 undefined 或函数,则使用 null。

因此,您必须以某种方式处理这些空值。无论如何,您可以使用此功能并根据您的需要“调整”它。例如并应用于您的示例:

function avoidCircularReference(obj) {
  var removeMeFromArray = function(arr) {
    var index = arr.indexOf(obj);
    if (index > -1) {
      arr.splice(index, 1);
    }
  };

  return function(key, value) {
    if (Object.prototype.toString.call(value) === "[object Array]") {
      removeMeFromArray(value);
    }
    return value;
  };
}

var SomeObjClass = function() {
  var self = this;
  this.group = {
    members: [self, {
      a: 'f',
      b: [self]
    }]
  };
};
var p = new SomeObjClass();
var str = JSON.stringify(p, avoidCircularReference(p));
console.log(str);

【讨论】:

    【解决方案3】:

    为了解决问题并保持JSON.stringify 的简单性,我使用以下方法(这里在我的脱水方法中)

    public dehydrate(): string {
        var seenObjects = [];
        function inspectElement(key, value) {
            if (detectCycle(value)) {
                return '[Ciclical]';
            } else {
                return value;
            };
        };
        function detectCycle(obj): boolean {
            if (obj && (typeof obj == 'object')) {
                for (let r of seenObjects) {
                    if (r == obj) {
                        return true;
                    };
                };
                seenObjects.push(obj);
            };
            return false;
        };
        let json: string = JSON.stringify(this, inspectElement,'  ');
        return json;
    };
    

    请注意,虽然这是 TypeScript,但在方法内部使用强类型来实现结果会导致我们有些困惑。

    不幸的是,我不得不使用 for 而不是数组搜索,因为它对我根本不起作用。

    【讨论】:

      【解决方案4】:

      这是一个对我有用的实现。它依赖于相等性的参考比较,这应该没问题。

      我在替换器返回值中包含了违规对象的索引,因此原则上,您可以在反序列化时恢复循环对象。

      function safeJsonStringify(value) {
        const visitedObjs = [];
        function replacerFn(key, obj) {
          const refIndex = visitedObjs.indexOf(obj);
          if (refIndex >= 0) return `cyclic-ref:${refIndex}`;
          if (typeof obj === 'object' && obj !== null) visitedObjs.push(obj);
          return obj;
        }
        return JSON.stringify(value, replacerFn);
      }
      // Take it for a spin:
      const cyclic = { greeting: 'Hello!' };
      cyclic.badRef = cyclic;
      console.log(safeJsonStringify(cyclic));

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-28
        • 2017-08-30
        • 1970-01-01
        • 2012-01-29
        • 1970-01-01
        • 1970-01-01
        • 2015-08-01
        • 2012-04-12
        相关资源
        最近更新 更多