JSON으로 변환하여 보내려는 큰 객체가 있습니다. 그러나 그것은 원형 구조를 가지고 있습니다. 순환 참조가 존재하는 것을 던지고 문자열로 지정할 수있는 것을 보내려고합니다. 어떻게합니까?
감사.
var obj = {
a: "foo",
b: obj
}
obj를 다음과 같이 문자열 화하고 싶습니다.
{"a":"foo"}
답변
JSON.stringify
맞춤 교체와 함께 사용하십시오 . 예를 들면 다음과 같습니다.
// Demo: Circular reference
var circ = {};
circ.circ = circ;
// Note: cache should not be re-used by repeated calls to JSON.stringify.
var cache = [];
JSON.stringify(circ, (key, value) => {
if (typeof value === 'object' && value !== null) {
// Duplicate reference found, discard key
if (cache.includes(value)) return;
// Store value in our collection
cache.push(value);
}
return value;
});
cache = null; // Enable garbage collection
이 예에서 교체기는 100 % 정확하지 않습니다 ( “중복”의 정의에 따라 다름). 다음과 같은 경우 값이 삭제됩니다.
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, ...);
그러나 개념은 다음과 같습니다. 사용자 정의 대체기를 사용하고 구문 분석 된 오브젝트 값을 추적하십시오.
es6로 작성된 유틸리티 기능으로 :
// safely handles circular references
JSON.safeStringify = (obj, indent = 2) => {
let cache = [];
const retVal = JSON.stringify(
obj,
(key, value) =>
typeof value === "object" && value !== null
? cache.includes(value)
? undefined // Duplicate reference found, discard key
: cache.push(value) && value // Store value in our collection
: value,
indent
);
cache = null;
return retVal;
};
// Example:
console.log('options', JSON.safeStringify(options))
답변
Node.js에서 util.inspect (object)를 사용할 수 있습니다 . 원형 링크를 “[Circular]”로 자동 대체합니다.
내장되어 있지만 (설치가 필요하지 않음) 가져와야합니다.
import * as util from 'util' // has no default export
import { inspect } from 'util' // or directly
// or
var util = require('util')
사용하려면 간단히 전화하십시오.
console.log(util.inspect(myObject))
또한 검사 할 옵션 객체를 전달할 수 있습니다 (위 링크 참조).
inspect(myObject[, options: {showHidden, depth, colors, showProxy, ...moreOptions}])
아래 의견을 읽고 댓글을 달아주세요.
답변
아무도 아직 MDN 페이지에서 적절한 솔루션을 게시하지 않은 이유가 궁금합니다 …
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
JSON.stringify(circularReference, getCircularReplacer());
확인 된 값은 배열이 아닌 세트에 저장해야합니다 ( 모든 요소에서 대체 프로그램이 호출 됨 ) . 체인에서 JSON.stringify
각 요소 를 시도 하여 순환 참조로 이어질 필요는 없습니다 .
허용 된 답변과 마찬가지로이 솔루션은 원형 값 뿐만 아니라 반복되는 모든 값을 제거 합니다. 그러나 적어도 지수 복잡성은 없습니다.
답변
그냥 해
npm i --save circular-json
그런 다음 js 파일에서
const CircularJSON = require('circular-json');
...
const json = CircularJSON.stringify(obj);
https://github.com/WebReflection/circular-json
참고 :이 패키지와는 아무 관련이 없습니다. 그러나 나는 이것을 위해 사용합니다.
2020 업데이트
CircularJSON은 유지 관리 중이며 flatted 는 후속 버전입니다.
답변
나는 Trindaz의 솔루션을 더 좋아했지만 더 장황했지만 버그가있었습니다. 나는 그것을 좋아하는 사람을 위해 그들을 고쳤다.
또한 캐시 객체에 길이 제한을 추가했습니다.
인쇄중인 객체가 실제로 큰 경우-무한히 큰 의미-알고리즘을 제한하고 싶습니다.
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);
};
답변
@RobW의 대답은 정확하지만 더 성능이 좋습니다! 해시 맵 / 세트를 사용하기 때문에 :
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
try {
// If this value does not reference a parent it can be deduped
return JSON.parse(JSON.stringify(value));
}
catch (err) {
// discard key if value cannot be deduped
return;
}
}
// Store value in our set
cache.add(value);
}
return value;
});
};
답변
JSON.decycle
Douglas Crockford가 구현 한 방법 도 있습니다 . 그의 cycle.js를 참조하십시오
. 이를 통해 거의 모든 표준 구조를 문자열화할 수 있습니다.
var a = [];
a[0] = a;
a[1] = 123;
console.log(JSON.stringify(JSON.decycle(a)));
// result: '[{"$ref":"$"},123]'.
retrocycle
메소드를 사용 하여 원본 객체를 다시 만들 수도 있습니다 . 따라서 객체를주기 위해 객체에서 사이클을 제거 할 필요가 없습니다.
그러나 이는 DOM 노드 (실제 사용 사례의 일반적인주기 원인) 에는 작동 하지 않습니다 . 예를 들어 다음과 같은 상황이 발생합니다.
var a = [document.body];
console.log(JSON.stringify(JSON.decycle(a)));
그 문제를 해결하기 위해 포크를 만들었습니다 ( cycle.js fork 참조 ). 이것은 잘 작동합니다 :
var a = [document.body];
console.log(JSON.stringify(JSON.decycle(a, true)));
내 포크 JSON.decycle(variable)
에서 원본과 같이 작동하며 variable
DOM 노드 / 요소 가 포함되어 있으면 예외가 발생합니다 .
사용 JSON.decycle(variable, true)
하면 결과를 되돌릴 수 없다는 사실을 받아들입니다 (복귀 화는 DOM 노드를 다시 만들지 않습니다). DOM 요소는 어느 정도 식별 가능해야합니다. 예를 들어 div
요소에 id가 있으면 string으로 대체됩니다 "div#id-of-the-element"
.