简体   繁体   English

JavaScript:将循环引用对象的浅拷贝字符串化?

[英]JavaScript: Stringify a shallow copy of a circular referenced object?

Is there a way to get just a shallow copy of the below to only get one layer deep?有没有办法让下面的浅拷贝只得到一层深? I have a means to fix this using a completely different design but I was wondering if anyone else had ran into what I am trying to convert to a string before.我有一种使用完全不同的设计来解决这个问题的方法,但我想知道是否有其他人遇到过我之前尝试转换为字符串的问题。

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

It's a little unclear what you're asking, but if your goal is to simply stringify a circular object, you'll have to override toJSON to specify how you'd like your object to be represented有点不清楚您在问什么,但是如果您的目标是简单地将循环对象字符串化,则必须覆盖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))

This is probably the best I can help you without seeing more of your code.这可能是我在没有看到更多代码的情况下可以为您提供的最好帮助。 I don't know how you're using this code, but whatever the case, this is probably not the best design for your class.我不知道您如何使用此代码,但无论如何,这可能不是您班级的最佳设计。 If you share the rest of the class and the code that uses it, we can probably help you more effectively.如果您分享课程的其余部分和使用它的代码,我们可能会更有效地帮助您。

If you check MDN reference about JSON.stringify , you'll see that it accepts as a second parameter a replacer function.如果检查有关MDN参考JSON.stringify ,你会看到它接受作为第二个参数replacer的功能。 This function is useful to massage a bit the elements that you want stringified.这个函数对于稍微调整你想要字符串化的元素很有用。

It could help you to avoid your circular problem.它可以帮助您避免循环问题。

For instance:例如:

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

However, and as stated in the documentation and shown running the example:但是,如文档中所述并显示运行示例:

Note: You cannot use the replacer function to remove values from an array.注意:您不能使用 replacer 函数从数组中删除值。 If you return undefined or a function then null is used instead.如果您返回 undefined 或函数,则使用 null 代替。

So you'd have to deal in some way with these nulls.所以你必须以某种方式处理这些空值。 Anyway, you could play with this function and "adapt" it to your needs.无论如何,您可以使用此功能并根据您的需要“调整”它。 For instance and applied to your example:例如并应用于您的示例:

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

To solve the problem and keep the JSON.stringify simplicity, I use the following approach (here in my dehydrate method)为了解决问题并保持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;
};

Note that although this is TypeScript, using strong types to achieve the results inside the method would lead us to some confusion.请注意,虽然这是 TypeScript,但在方法内部使用强类型来实现结果会导致我们有些困惑。

Unfortunately I had to use for instead of array search because it simply didn't work to me.不幸的是,我不得不使用for而不是数组搜索,因为它对我不起作用。

This is an implementation that worked for me.这是一个对我有用的实现。 It relies on reference comparison for equality, which should be fine for this purpose.它依赖于引用比较来实现相等性,这对于这个目的应该没问题。

I include the index of the offending object in the replacer return value so that in principle, you could restore the cyclic object when deserializing.我在替换器返回值中包含了违规对象的索引,这样原则上,您可以在反序列化时恢复循环对象。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM