JSON.stringify, évitez TypeError: conversion d'une structure circulaire en JSON

J'ai un gros objet que je veux convertir en JSON et envoyer. Cependant il a la structure circulaire. Je veux lancer toutes les références circulaires existantes et envoyer tout ce qui peut être stringifié. Comment je fais cela ?

Merci.

var obj = {
  a: "foo",
  b: obj
}

Je veux stringifier obj en:

{"a":"foo"}
396
demandé sur Brock Adams 2012-07-23 20:30:22

19 réponses

Utilisez JSON.stringify avec un remplaçant personnalisé. Par exemple:

// Demo: Circular reference
var o = {};
o.o = o;

// Note: cache should not be re-used by repeated calls to JSON.stringify.
var cache = [];
JSON.stringify(o, function(key, value) {
    if (typeof value === 'object' && value !== null) {
        if (cache.indexOf(value) !== -1) {
            // Duplicate reference found
            try {
                // If this value does not reference a parent it can be deduped
                return JSON.parse(JSON.stringify(value));
            } catch (error) {
                // discard key if value cannot be deduped
                return;
            }
        }
        // Store value in our collection
        cache.push(value);
    }
    return value;
});
cache = null; // Enable garbage collection

Le remplaçant dans cet exemple n'est pas correct à 100% (selon votre définition de "dupliquer"). Dans le cas suivant, une valeur est ignorée:

var a = {b:1}
var o = {};
o.one = a;
o.two = a;
// one and two point to the same object, but two is discarded:
JSON.stringify(o, ...);

Mais le concept est le suivant: utilisez un remplaçant personnalisé et gardez une trace des valeurs d'objet analysées.

414
répondu Rob W 2018-05-30 18:32:20

Dans Le Noeud.js, vous pouvez utiliser util.inspecter(objet). Il remplace automatiquement les liens circulaires par "[circulaire]".


Bien qu'il soit intégré (aucune installation n'est requise) , vous devez l'importer

import * as util from 'util' // has no default export
import { inspect } from 'util' // or directly
// or 
var util = require('util')
Pour l'utiliser, il suffit d'appeler
console.log(util.inspect(myObject))

Sachez également que vous pouvez passer l'objet options à inspecter (Voir le lien ci-dessus)

inspect(myObject[, options: {showHidden, depth, colors, showProxy, ...moreOptions}])



s " il vous plaît, lire et donner des félicitations aux commentateurs ci-dessous...

413
répondu Erel Segal-Halevi 2018-07-02 09:24:18

Faites juste

npm i --save circular-json

, Puis dans votre fichier js

const JSON = require('circular-json');
...
const json = JSON.stringify(obj);

Vous pouvez aussi faire

const CircularJSON = require('circular-json');

Https://github.com/WebReflection/circular-json

NOTE: je n'ai rien à voir avec ce paquet. Mais je ne les utilise.

44
répondu user1541685 2016-07-22 16:44:29

J'ai vraiment aimé la solution de Trindaz-plus verbeuse, mais elle avait quelques bugs. Je les ai réparés pour ceux qui l'aiment aussi.

De plus, j'ai ajouté une limite de longueur sur mes objets cache.

Si l'objet que j'imprime est vraiment grand - je veux dire infiniment grand-je veux limiter mon algorithme.

JSON.stringifyOnce = function(obj, replacer, indent){
    var printedObjects = [];
    var printedObjectKeys = [];

    function printOnceReplacer(key, value){
        if ( printedObjects.length > 2000){ // browsers will not print more than 20K, I don't see the point to allow 2K.. algorithm will not be fast anyway if we have too many objects
        return 'object too long';
        }
        var printedObjIndex = false;
        printedObjects.forEach(function(obj, index){
            if(obj===value){
                printedObjIndex = index;
            }
        });

        if ( key == ''){ //root element
             printedObjects.push(obj);
            printedObjectKeys.push("root");
             return value;
        }

        else if(printedObjIndex+"" != "false" && typeof(value)=="object"){
            if ( printedObjectKeys[printedObjIndex] == "root"){
                return "(pointer to root)";
            }else{
                return "(see " + ((!!value && !!value.constructor) ? value.constructor.name.toLowerCase()  : typeof(value)) + " with key " + printedObjectKeys[printedObjIndex] + ")";
            }
        }else{

            var qualifiedKey = key || "(empty key)";
            printedObjects.push(value);
            printedObjectKeys.push(qualifiedKey);
            if(replacer){
                return replacer(key, value);
            }else{
                return value;
            }
        }
    }
    return JSON.stringify(obj, printOnceReplacer, indent);
};
41
répondu guy mograbi 2013-10-09 00:06:33

Notez qu'il existe également une méthode JSON.decycle implémentée par Douglas Crockford. Voir sa cycle.js . Cela vous permet de stringifier presque n'importe quelle structure standard:

var a = [];
a[0] = a;
a[1] = 123;
console.log(JSON.stringify(JSON.decycle(a)));
// result: '[{"$ref":"$"},123]'.

Vous pouvez également recréer l'objet original avec la méthode retrocycle. Vous n'avez donc pas besoin de supprimer des cycles d'objets pour les stringifier.

Cependant, cela ne fonctionnera pas pour les nœuds DOM (qui sont la cause typique des cycles dans les cas d'utilisation réels). Par exemple, cela lancera:

var a = [document.body];
console.log(JSON.stringify(JSON.decycle(a)));

J'ai fait une fourchette pour résoudre ce problème (Voir mon cycle .js fourche). Cela devrait fonctionner correctement:

var a = [document.body];
console.log(JSON.stringify(JSON.decycle(a, true)));

Notez que dans ma fourchette JSON.decycle(variable) fonctionne comme dans l'original et lancera une exception lorsque le variable contient des nœuds/éléments DOM.

Lorsque vous utilisez JSON.decycle(variable, true) vous acceptez le fait que le résultat ne sera pas réversible (retrocycle ne recréera pas les nœuds DOM). Les éléments DOM devraient cependant être identifiables dans une certaine mesure. Par exemple, si un div élément possède un id il sera remplacé avec une chaîne "div#id-of-the-element".

29
répondu Nux 2018-07-04 10:06:03

Je recommande de vérifier JSON-stringify-safe de @isaacs - il est utilisé dans NPM.

BTW-si vous n'utilisez pas Node.js, vous pouvez simplement copier et coller les lignes 4-27 de la partie pertinente du code source .

Pour installer:

$ npm install json-stringify-safe --save

À utiliser:

// Require the thing
var stringify = require('json-stringify-safe');

// Take some nasty circular object
var theBigNasty = {
  a: "foo",
  b: theBigNasty
};

// Then clean it up a little bit
var sanitized = JSON.parse(stringify(theBigNasty));

Cela donne:

{
  a: 'foo',
  b: '[Circular]'
}

Notez que, tout comme avec le JSON vanille.fonction stringify comme @ Rob W mentionné, vous pouvez également personnaliser le comportement de désinfection en passant dans une fonction "replacer" comme deuxième argument de stringify(). Si vous avez besoin d'un exemple simple de la façon de le faire, je viens d'écrire un remplaçant personnalisé qui contraint les erreurs, les expressions rationnelles et les fonctions dans des chaînes lisibles par l'homme ici.

21
répondu mikermcneil 2015-05-13 01:53:45

La réponse de@RobW est correcte, mais c'est plus performant ! Parce qu'il utilise un HashMap / set:

const customStringify = function (v) {
  const cache = new Set();
  return JSON.stringify(v, function (key, value) {
    if (typeof value === 'object' && value !== null) {
      if (cache.has(value)) {
        // Circular reference found, discard key
        return;
      }
      // Store value in our set
      cache.add(value);
    }
    return value;
  });
};
17
répondu Alexander Mills 2018-09-19 02:40:01

Pour les futurs googlers cherchant une solution à ce problème lorsque vous ne connaissez pas les clés de toutes les références circulaires, vous pouvez utiliser un wrapper autour du JSON.fonction stringify pour exclure les références circulaires. Voir un exemple de script à https://gist.github.com/4653128.

La solution se résume essentiellement à garder une référence aux objets précédemment imprimés dans un tableau, et à vérifier cela dans une fonction de remplacement avant de renvoyer une valeur. C'est plus constrictif que d'exclure seulement les références circulaires, car il exclut également l'impression d'un objet deux fois, dont l'un des effets secondaires est d'éviter les références circulaires.

Exemple d'emballage:

function stringifyOnce(obj, replacer, indent){
    var printedObjects = [];
    var printedObjectKeys = [];

    function printOnceReplacer(key, value){
        var printedObjIndex = false;
        printedObjects.forEach(function(obj, index){
            if(obj===value){
                printedObjIndex = index;
            }
        });

        if(printedObjIndex && typeof(value)=="object"){
            return "(see " + value.constructor.name.toLowerCase() + " with key " + printedObjectKeys[printedObjIndex] + ")";
        }else{
            var qualifiedKey = key || "(empty key)";
            printedObjects.push(value);
            printedObjectKeys.push(qualifiedKey);
            if(replacer){
                return replacer(key, value);
            }else{
                return value;
            }
        }
    }
    return JSON.stringify(obj, printOnceReplacer, indent);
}
10
répondu Trindaz 2015-06-12 11:56:12

Utilisez le JSON.méthode stringify avec un remplaçant. Lisez cette documentation pour plus d'informations. http://msdn.microsoft.com/en-us/library/cc836459%28v=vs.94%29.aspx

var obj = {
  a: "foo",
  b: obj
}

var replacement = {"b":undefined};

alert(JSON.stringify(obj,replacement));

Trouver un moyen de remplir le tableau de remplacement avec des références cycliques. Vous pouvez utiliser la méthode typeof pour trouver si une propriété est de type 'object' (référence ) et une vérification d'égalité exacte ( = = = ) pour vérifier la référence circulaire.

4
répondu TWickz 2012-07-23 17:26:56
var a={b:"b"};
a.a=a;
JSON.stringify(preventCircularJson(a));

Évalue à:

"{"b":"b","a":"CIRCULAR_REFERENCE_REMOVED"}"

Avec la fonction:

/**
 * Traverses a javascript object, and deletes all circular values
 * @param source object to remove circular references from
 * @param censoredMessage optional: what to put instead of censored values
 * @param censorTheseItems should be kept null, used in recursion
 * @returns {undefined}
 */
function preventCircularJson(source, censoredMessage, censorTheseItems) {
    //init recursive value if this is the first call
    censorTheseItems = censorTheseItems || [source];
    //default if none is specified
    censoredMessage = censoredMessage || "CIRCULAR_REFERENCE_REMOVED";
    //values that have allready apeared will be placed here:
    var recursiveItems = {};
    //initaite a censored clone to return back
    var ret = {};
    //traverse the object:
    for (var key in source) {
        var value = source[key]
        if (typeof value == "object") {
            //re-examine all complex children again later:
            recursiveItems[key] = value;
        } else {
            //simple values copied as is
            ret[key] = value;
        }
    }
    //create list of values to censor:
    var censorChildItems = [];
    for (var key in recursiveItems) {
        var value = source[key];
        //all complex child objects should not apear again in children:
        censorChildItems.push(value);
    }
    //censor all circular values
    for (var key in recursiveItems) {
        var value = source[key];
        var censored = false;
        censorTheseItems.forEach(function (item) {
            if (item === value) {
                censored = true;
            }
        });
        if (censored) {
            //change circular values to this
            value = censoredMessage;
        } else {
            //recursion:
            value = preventCircularJson(value, censoredMessage, censorChildItems.concat(censorTheseItems));
        }
        ret[key] = value

    }

    return ret;
}
4
répondu eshalev 2015-07-08 11:37:21

Je sais que c'est une vieille question, mais je voudrais suggérer un paquet NPM que j'ai créé appelé smart-circular, qui fonctionne différemment des autres façons proposées. C'est particulièrement utile si vous utilisez des objets grands et profonds.

Certaines fonctionnalités sont:

  • Remplacer des références circulaires ou simplement des structures répétées à l'intérieur de l'objet par le chemin menant à sa première occurrence (pas seulement la chaîne [circulaire]);

  • En regardant pour les circularités dans une recherche en largeur, le paquet garantit que ce chemin est aussi petit que possible, ce qui est important lorsqu'il s'agit d'objets très grands et profonds, où les chemins peuvent être agaçants et difficiles à suivre (le remplacement personnalisé dans JSON.stringify fait un DFS);

  • Permet des remplacements personnalisés, pratiques pour simplifier ou ignorer des parties moins importantes de l'objet;

  • Enfin, les chemins sont écrits exactement de la manière nécessaire pour accéder au champ référencé, ce qui peut vous aider à déboguer.

3
répondu Danilo Augusto 2015-08-18 10:08:28

Je résous ce problème comme ceci:

var util = require('util');

// Our circular object
var obj = {foo: {bar: null}, a:{a:{a:{a:{a:{a:{a:{hi: 'Yo!'}}}}}}}};
obj.foo.bar = obj;

// Generate almost valid JS object definition code (typeof string)
var str = util.inspect(b, {depth: null});

// Fix code to the valid state (in this example it is not required, but my object was huge and complex, and I needed this for my case)
str = str
    .replace(/<Buffer[ \w\.]+>/ig, '"buffer"')
    .replace(/\[Function]/ig, 'function(){}')
    .replace(/\[Circular]/ig, '"Circular"')
    .replace(/\{ \[Function: ([\w]+)]/ig, '{ $1: function $1 () {},')
    .replace(/\[Function: ([\w]+)]/ig, 'function $1(){}')
    .replace(/(\w+): ([\w :]+GMT\+[\w \(\)]+),/ig, '$1: new Date("$2"),')
    .replace(/(\S+): ,/ig, '$1: null,');

// Create function to eval stringifyed code
var foo = new Function('return ' + str + ';');

// And have fun
console.log(JSON.stringify(foo(), null, 4));
1
répondu MiF 2016-02-26 09:17:10

Le deuxième argument de JSON.stringify () aussi vous permet de spécifier un tableau de noms de clés qui doivent être conservés à partir de chaque objet qu'il rencontre dans vos données. Cela peut ne pas fonctionner pour tous les cas d'utilisation, mais c'est une solution beaucoup plus simple.

Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

var obj = {
    a: "foo",
    b: this
}

var json = JSON.stringify(obj, ['a']);
console.log(json);
// {"a":"foo"}

Remarque: étrangement, la définition d'objet de L'OP ne lance pas d'erreur de référence circulaire dans le dernière Chrome ou Firefox. La définition dans cette réponse a été modifiée de sorte que a fait jeter une erreur.


1
répondu Aaron Cicali 2018-08-01 22:09:42

Une autre solution pour résoudre ce problème, avec ce genre d'objets que l'utilisation de cette bibliothèque

Https://github.com/ericmuyser/stringy

C'est simple et vous pouvez en quelques étapes simples résoudre cela.

0
répondu Ehsan Aghaei 2015-05-20 10:52:23

J'ai trouvé la bibliothèque circular-json sur github et cela a bien fonctionné pour mon problème.

Quelques bonnes fonctionnalités que j'ai trouvées utiles:

  • prend en charge l'utilisation multi-plateforme mais je ne l'ai testé qu'avec node.js jusqu'à présent.
  • L'API est la même, donc tout ce que vous devez faire est de l'inclure et de l'utiliser comme remplacement JSON.
  • Il a sa propre méthode d'analyse afin que vous puissiez convertir les données sérialisées 'circulaires'en objet.
0
répondu JacopKane 2015-08-04 19:42:24

Sur la Base des autres réponses, je me retrouve avec le code suivant. Cela fonctionne assez bien avec des références circulaires, des objets avec des constructeurs personnalisés.

De l'objet donné à sérialiser,

  • Cache tout l'objet que vous rencontrez en traversant l'objet et attribue à chacun d'eux un hashID unique (un nombre d'incrémentation automatique fonctionne également)
  • Une fois qu'une référence circulaire est trouvée, marquez ce champ dans le nouvel objet comme circulaire et stockez le hashID de l'objet d'origine comme un attribut.

Lien Github - DecycledJSON

DJSHelper = {};
DJSHelper.Cache = [];
DJSHelper.currentHashID = 0;
DJSHelper.ReviveCache = [];

// DOES NOT SERIALIZE FUNCTION
function DJSNode(name, object, isRoot){
    this.name = name;
    // [ATTRIBUTES] contains the primitive fields of the Node
    this.attributes = {};

    // [CHILDREN] contains the Object/Typed fields of the Node
    // All [CHILDREN] must be of type [DJSNode]
    this.children = []; //Array of DJSNodes only

    // If [IS-ROOT] is true reset the Cache and currentHashId
    // before encoding
    isRoot = typeof isRoot === 'undefined'? true:isRoot;
    this.isRoot = isRoot;
    if(isRoot){
        DJSHelper.Cache = [];
        DJSHelper.currentHashID = 0;

        // CACHE THE ROOT
        object.hashID = DJSHelper.currentHashID++;
        DJSHelper.Cache.push(object);
    }

    for(var a in object){
        if(object.hasOwnProperty(a)){
            var val = object[a];

            if (typeof val === 'object') {
                // IF OBJECT OR NULL REF.

                /***************************************************************************/
                // DO NOT REMOVE THE [FALSE] AS THAT WOULD RESET THE [DJSHELPER.CACHE]
                // AND THE RESULT WOULD BE STACK OVERFLOW
                /***************************************************************************/
                if(val !== null) {
                    if (DJSHelper.Cache.indexOf(val) === -1) {
                        // VAL NOT IN CACHE
                        // ADD THE VAL TO CACHE FIRST -> BEFORE DOING RECURSION
                        val.hashID = DJSHelper.currentHashID++;
                        //console.log("Assigned", val.hashID, "to", a);
                        DJSHelper.Cache.push(val);

                        if (!(val instanceof Array)) {
                            // VAL NOT AN [ARRAY]
                            try {
                                this.children.push(new DJSNode(a, val, false));
                            } catch (err) {
                                console.log(err.message, a);
                                throw err;
                            }
                        } else {
                            // VAL IS AN [ARRAY]
                            var node = new DJSNode(a, {
                                array: true,
                                hashID: val.hashID // HashID of array
                            }, false);
                            val.forEach(function (elem, index) {
                                node.children.push(new DJSNode("elem", {val: elem}, false));
                            });
                            this.children.push(node);
                        }
                    } else {
                        // VAL IN CACHE
                        // ADD A CYCLIC NODE WITH HASH-ID
                        this.children.push(new DJSNode(a, {
                            cyclic: true,
                            hashID: val.hashID
                        }, false));
                    }
                }else{
                    // PUT NULL AS AN ATTRIBUTE
                    this.attributes[a] = 'null';
                }
            } else if (typeof val !== 'function') {
                // MUST BE A PRIMITIVE
                // ADD IT AS AN ATTRIBUTE
                this.attributes[a] = val;
            }
        }
    }

    if(isRoot){
        DJSHelper.Cache = null;
    }
    this.constructorName = object.constructor.name;
}
DJSNode.Revive = function (xmlNode, isRoot) {
    // Default value of [isRoot] is True
    isRoot = typeof isRoot === 'undefined'?true: isRoot;
    var root;
    if(isRoot){
        DJSHelper.ReviveCache = []; //Garbage Collect
    }
    if(window[xmlNode.constructorName].toString().indexOf('[native code]') > -1 ) {
        // yep, native in the browser
        if(xmlNode.constructorName == 'Object'){
            root = {};
        }else{
            return null;
        }
    }else {
        eval('root = new ' + xmlNode.constructorName + "()");
    }

    //CACHE ROOT INTO REVIVE-CACHE
    DJSHelper.ReviveCache[xmlNode.attributes.hashID] = root;

    for(var k in xmlNode.attributes){
        // PRIMITIVE OR NULL REF FIELDS
        if(xmlNode.attributes.hasOwnProperty(k)) {
            var a = xmlNode.attributes[k];
            if(a == 'null'){
                root[k] = null;
            }else {
                root[k] = a;
            }
        }
    }

    xmlNode.children.forEach(function (value) {
        // Each children is an [DJSNode]
        // [Array]s are stored as [DJSNode] with an positive Array attribute
        // So is value

        if(value.attributes.array){
            // ITS AN [ARRAY]
            root[value.name] = [];
            value.children.forEach(function (elem) {
                root[value.name].push(elem.attributes.val);
            });
            //console.log("Caching", value.attributes.hashID);
            DJSHelper.ReviveCache[value.attributes.hashID] = root[value.name];
        }else if(!value.attributes.cyclic){
            // ITS AN [OBJECT]
            root[value.name] = DJSNode.Revive(value, false);
            //console.log("Caching", value.attributes.hashID);
            DJSHelper.ReviveCache[value.attributes.hashID] = root[value.name];
        }
    });

    // [SEPARATE ITERATION] TO MAKE SURE ALL POSSIBLE
    // [CYCLIC] REFERENCES ARE CACHED PROPERLY
    xmlNode.children.forEach(function (value) {
        // Each children is an [DJSNode]
        // [Array]s are stored as [DJSNode] with an positive Array attribute
        // So is value

        if(value.attributes.cyclic){
            // ITS AND [CYCLIC] REFERENCE
            root[value.name] = DJSHelper.ReviveCache[value.attributes.hashID];
        }
    });

    if(isRoot){
        DJSHelper.ReviveCache = null; //Garbage Collect
    }
    return root;
};

DecycledJSON = {};
DecycledJSON.stringify = function (obj) {
    return JSON.stringify(new DJSNode("root", obj));
};
DecycledJSON.parse = function (json, replacerObject) {
    // use the replacerObject to get the null values
    return DJSNode.Revive(JSON.parse(json));
};
DJS = DecycledJSON;

Exemple D'Utilisation 1:

var obj = {
    id:201,
    box: {
        owner: null,
        key: 'storm'
    },
    lines:[
        'item1',
        23
    ]
};

console.log(obj); // ORIGINAL

// SERIALIZE AND THEN PARSE
var jsonObj = DJS.stringify(obj);
console.log(DJS.parse(jsonObj));

Exemple D'Utilisation 2:

// PERSON OBJECT

function Person() {
    this.name = null;
    this.child = null;
    this.dad = null;
    this.mom = null;
}
var Dad = new Person();
Dad.name = 'John';
var Mom = new Person();
Mom.name = 'Sarah';
var Child = new Person();
Child.name = 'Kiddo';

Dad.child = Mom.child = Child;
Child.dad = Dad;
Child.mom = Mom;

console.log(Child); // ORIGINAL

// SERIALIZE AND THEN PARSE
var jsonChild = DJS.stringify(Child);
console.log(DJS.parse(jsonChild));
0
répondu bytestorm 2016-03-14 16:00:58

Je sais que cette question Est ancienne et a beaucoup de bonnes réponses mais je poste cette réponse à cause de sa nouvelle saveur (es5+)

Object.defineProperties(JSON, {
  refStringify: {
    value: function(obj) {

      let objMap = new Map();
      let stringified = JSON.stringify(obj,
        function(key, value) {

          // only for objects
          if (typeof value == 'object') {
            // If has the value then return a reference to it
            if (objMap.has(value))
              return objMap.get(value);

            objMap.set(value, `ref${objMap.size + 1}`);
          }
          return value;
        });
      return stringified;
    }
  },
  refParse: {
    value: function(str) {

      let parsed = JSON.parse(str);
      let objMap = _createObjectMap(parsed);
      objMap.forEach((value, key) => _replaceKeyWithObject(value, key));
      return parsed;
    }
  },
});

// *************************** Example
let a = {
  b: 32,
  c: {
    get a() {
        return a;
      },
      get c() {
        return a.c;
      }
  }
};
let stringified = JSON.refStringify(a);
let parsed = JSON.refParse(stringified, 2);
console.log(parsed, JSON.refStringify(parsed));
// *************************** /Example

// *************************** Helper
function _createObjectMap(obj) {

  let objMap = new Map();
  JSON.stringify(obj, (key, value) => {
    if (typeof value == 'object') {
      if (objMap.has(value))
        return objMap.get(value);
      objMap.set(value, `ref${objMap.size + 1}`);

    }
    return value;
  });
  return objMap;
}

function _replaceKeyWithObject(key, obj, replaceWithObject = obj) {

  Object.keys(obj).forEach(k => {

    let val = obj[k];
    if (val == key)
      return (obj[k] = replaceWithObject);
    if (typeof val == 'object' && val != replaceWithObject)
      _replaceKeyWithObject(key, val, replaceWithObject);
  });
}
0
répondu Morteza Tourani 2017-01-25 10:31:14

Essayez ceci:

var obj = {
    a: "foo",
    b: obj
};

var circular_replacer = (value) => {
    var seen = [];
    if (value != null && typeof value == "object") {
        if (seen.indexOf(value) >= 0) return;
        seen.push(value);
    }
    return value;
};

obj = circular_replacer(obj);
0
répondu IamMHussain 2018-02-02 10:35:11

Si

console.log(JSON.stringify(object));

Résultats dans un

TypeError: valeur d'objet cyclique

Ensuite, vous pouvez imprimer comme ceci:

var output = '';
for (property in object) {
  output += property + ': ' + object[property]+'; ';
}
console.log(output);
-1
répondu Thorsten Niehues 2013-10-26 11:02:28