← 전체 글

JSON.stringify로 JSON 문자열화하는 방법

JSON.stringify는 값을 JSON 문자열로 변환한다. space와 replacer 인자, toJSON 훅, 조용히 버려지거나 throw하는 값을 배운다.

JSON.stringify() 는 JavaScript 값을 JSON 문자열로 바꿉니다 —— 요청 본문에 넣거나 파일에 저장하거나 localStorage 에 보관하기 위해. 단순해 보이지만 세 개의 인자, 특수 값 처리, 그리고 toJSON 훅이 개발자를 계속 걸려 넘어뜨립니다. 본 가이드는 JSON.stringify() 가 하는 모든 것, 다른 언어의 등가물, 피해야 할 함정을 다룹니다.

JSON.stringify 가 하는 일

값을 재귀적으로 순회하며 사양 준수 JSON 문자열을 만듭니다. 기본 출력은 압축이며 여분 공백이 없습니다:

const user = { name: "Ada", age: 36, active: true };

JSON.stringify(user);
// '{"name":"Ada","age":36,"active":true}'

항상 유효한 JSON 을 출력하므로 JSON 문자열을 손으로 만들지 마세요 —— concat 이나 템플릿 리터럴 사용은 [object Object] 오류후행 콤마 오류 의 가장 큰 원인입니다.

세 개의 인자

JSON.stringify(value, replacer, space) 는 값과 더불어 대부분의 개발자가 절대 쓰지 않는 두 개의 옵션 인자 —— 그러나 강력합니다 —— 를 받습니다.

space —— pretty-print

세 번째 인자가 들여쓰기를 제어합니다. 공백 수로 숫자를, 또는 '\t' 같은 문자열을 넘기세요:

JSON.stringify(user, null, 2);
// {
//   "name": "Ada",
//   "age": 36,
//   "active": true
// }

코드에서 JSON 을 pretty-print 하는 방식입니다 —— How to Format JSON 참고. 인자를 생략하거나 0 을 주면 minify; How to Minify JSON.

replacer —— 필터링과 변환

두 번째 인자는 포함할 키 배열이거나, 각 값을 변환하는 함수입니다:

// 허용 목록: 이 키만 남김
JSON.stringify(user, ['name', 'active']);
// '{"name":"Ada","active":true}'

// 함수: 한 필드를 마스크, 다른 필드는 버림
JSON.stringify(
  { name: "Ada", password: "secret", token: "abc" },
  (key, value) => {
    if (key === 'password') return '[REDACTED]';
    if (key === 'token') return undefined; // undefined 반환 시 키 생략
    return value;
  },
);
// '{"name":"Ada","password":"[REDACTED]"}'

toJSON 훅

값에 toJSON() 메서드가 있으면 JSON.stringify() 가 그것을 호출하고 반환값을 직렬화합니다. Date 객체가 자동으로 ISO 문자열이 되는 이유입니다:

JSON.stringify({ when: new Date('2026-05-24T00:00:00Z') });
// '{"when":"2026-05-24T00:00:00.000Z"}'  ← Date.prototype.toJSON 실행

// 사용자 정의 toJSON 으로 직렬화
class Money {
  constructor(cents) { this.cents = cents; }
  toJSON() { return (this.cents / 100).toFixed(2); }
}
JSON.stringify({ price: new Money(1999) });
// '{"price":"19.99"}'

버려지거나 변환되는 것

JSON 에는 여섯 가지 타입만 있으므로 JSON 대응이 없는 JavaScript 값은 조용히 버려지거나 강제 변환됩니다 —— 왕복 버그의 자주 있는 원인:

JavaScript 값JSON.stringify 의 결과
undefined(객체 안)키 생략
undefined(배열 안)null
함수생략(객체) / null(배열)
Symbol생략
NaN, Infinitynull
DateISO 문자열(toJSON 경유)
BigIntTypeError 던짐

JSON 과 JavaScript 객체의 차이에 대한 완전 목록은 JSON vs JavaScript 객체.

흔한 함정

순환 참조는 던집니다

const a = {};
a.self = a;
JSON.stringify(a);
// TypeError: Converting circular structure to JSON

// 수리: 본 객체를 추적하는 replacer, 또는 데이터 재구성

BigInt 미지원

JSON.stringify({ id: 9007199254740993n });
// TypeError: Do not know how to serialize a BigInt

// 수리: 먼저 문자열로, 또는 replacer 추가
JSON.stringify({ id: 9007199254740993n }, (k, v) =>
  typeof v === 'bigint' ? v.toString() : v
);

큰 정수는 왕복에서 정밀도를 잃습니다

253 을 넘는 숫자는 정확히 표현할 수 없습니다. 큰 정수 ID 를 stringify 한 뒤 parse 하면 값이 변할 수 있습니다. 그런 ID 는 문자열로 보관하세요.

인접 API: structuredClone, reviver, Stable Stringify

  • structuredClone —— 메모리 내 깊은 복사는 JSON.parse(JSON.stringify(x)) 를 쓰지 마세요. structuredCloneDate, Map, Set, ArrayBuffer, 순환 참조를 네이티브로 처리하며 훨씬 빠릅니다.
  • JSON.parsereviver 인자 는 여기 replacer 와 대칭. JSON 이 모델링하지 않는 타입의 무손실 왕복이 필요하면 짝지어 쓰세요 —— 예: replacer 에서 Date 를 ISO 문자열로 인코딩, reviver 에서 복원.
  • Stable-stringify 라이브러리(예: json-stable-stringify, fast-json-stable-stringify) —— 키 삽입 순서와 무관하게 같은 문자열을 만듭니다. 출력이 해시·서명·텍스트 비교될 때 사용(정식 버전은 RFC 8785 / JCS).

다른 언어의 Stringify

# Python
import json
json.dumps({"name": "Ada"})                       # 압축
json.dumps({"name": "Ada"}, indent=2)             # 미화
json.dumps({"name": "Ada"}, separators=(',', ':')) # minify

// Go
import "encoding/json"
b, _ := json.Marshal(map[string]string{"name": "Ada"})

// Ruby
require 'json'
{ name: "Ada" }.to_json

브라우저에서 JSON Stringify

JSON 값을 코드, DB 컬럼, 셸 명령에 임베드하려고 문자열 리터럴로 이스케이프해야 하나요? fixjson 의 JSON Stringify 도구 가 즉시, 브라우저에서, 어떤 서버로도 데이터를 보내지 않고 처리합니다.

자주 묻는 질문

JSON.stringify 로 pretty-print 하려면?

세 번째 인자: JSON.stringify(value, null, 2) 가 2 공백 들여쓰기, '\t' 가 탭. How to Format JSON.

왜 JSON.stringify 가 속성을 버리나요?

undefined, 함수, Symbol 값의 속성은 JSON 표현이 없어 생략됩니다. replacer 를 쓰거나 먼저 변환하세요.

BigInt 가 포함된 값을 stringify 하려면?

JSON.stringify()BigInt 에서 던집니다. bigint 값에 .toString() 을 호출하는 replacer 를 제공하고 반대쪽에서 의도적으로 다시 파싱하세요.

JSON.stringify 와 JSON.parse 의 차이는?

stringify 는 값을 JSON 문자열로, parse 는 JSON 문자열을 값으로 되돌립니다. 서로 역. 파싱 함정은 JavaScript 에서 깨진 JSON 처리.

Map 이나 Set 을 JSON.stringify 하려면?

기본적으로 둘 다 "{}" 로 직렬화됩니다 —— Map 은 자체 열거 가능한 속성이 없고 Set 은 빈 객체로 stringify 됩니다. 먼저 JSON 친화적 모양으로 변환하거나(또는 replacer 사용):

// Map → [key, value] 쌍의 배열(왕복 가능)
JSON.stringify([...myMap]);
// 또는 replacer 로:
JSON.stringify({ data: myMap }, (k, v) =>
  v instanceof Map ? Object.fromEntries(v) :
  v instanceof Set ? [...v] : v
);

돌아올 때는 JSON.parse 의 reviver 에서 new Map(arr) / new Set(arr) 로 재구축하세요. 순수 JSON 에는 Map/Set 타입이 없기 때문입니다.

지금 시도해 보세요