JSON
JSON
JSON 네임스페이스 객체는 JavaScript Object Notation(JSON)으로 값들을 파싱하고 변환하는 정적 메서드를 포함합니다. 데이터 직렬화와 역직렬화의 표준 수단을 제공합니다.
본문
JSON 네임스페이스 객체는 JSON 값들을 파싱하고 JSON으로 변환하는 정적 메서드를 담고 있습니다. 대부분의 전역 객체와 달리 JSON은 생성자가 아닙니다. new 연산자와 함께 사용할 수 없고, 함수처럼 호출할 수도 없습니다. JSON의 모든 속성과 메서드는 정적입니다(Math 객체와 마찬가지로).
JavaScript와 JSON의 차이
JSON은 객체, 배열, 숫자, 문자열, 불리언, null을 직렬화하기 위한 문법입니다. JavaScript 문법에 기반하지만 JavaScript와는 구별됩니다. 대부분의 JavaScript는 JSON이 아닙니다. 예를 들면:
- 객체와 배열 — 속성 이름은 큰따옴표 문자열이어야 하며, 후행 쉼표(trailing comma)는 금지됩니다.
- 숫자 — 앞자리 0(leading zeros)은 금지됩니다. 소수점 뒤에는 최소한 한 자리 숫자가 와야 합니다.
NaN과Infinity는 지원되지 않습니다.
모든 JSON 텍스트는 유효한 JavaScript 표현식입니다. 단, JSON 슈퍼셋(superset) 개정 이후에만 그렇습니다. 개정 이전에는 U+2028 LINE SEPARATOR와 U+2029 PARAGRAPH SEPARATOR가 JSON의 문자열 리터럴과 속성 키에 허용되지만, JavaScript 문자열 리터럴에서 같은 용도로 쓰면 SyntaxError가 발생합니다.
기타 차이로는 큰따옴표 문자열만 허용된다는 점과 undefined나 주석을 지원하지 않는다는 점이 있습니다. JSON 기반의 더 사람 친화적인 설정 형식을 원한다면 Babel 컴파일러가 사용하는 JSON5와 더 널리 쓰이는 YAML이 있습니다. 또한 같은 텍스트가 JavaScript 객체 리터럴과 JSON에서 서로 다른 값을 나타낼 수 있습니다.
전체 JSON 문법
유효한 JSON 문법은 IETF JSON 표준(RFC)에서 가져온 ABNF 문법으로 공식 정의됩니다. 핵심 규칙은 다음과 같습니다.
JSON-text = ws value ws
object = begin-object [ member *( value-separator member ) ] end-object
member = string name-separator value
array = begin-array [ value *( value-separator value ) ] end-array
number = [ minus ] int [ frac ] [ exp ]
string = quotation-mark *char quotation-mark
value = false / null / true / object / array / number / string
유효한 공백 문자는 탭(U+0009), 캐리지 리턴(U+000D), 줄바꿈(U+000A), 공백(U+0020)뿐입니다. 무의미한 공백은 JSONNumber(숫자에는 공백이 없어야 함)나 JSONString(문자열의 해당 문자로 해석되거나 오류를 유발)을 제외하고 어디에든 나타날 수 있습니다.
정적 속성
JSON[Symbol.toStringTag]—[Symbol.toStringTag]속성의 초기 값은 문자열"JSON"입니다. 이 속성은Object.prototype.toString()에서 사용됩니다.
정적 메서드
JSON.isRawJSON()— 값이JSON.rawJSON()이 반환한 객체인지 검사합니다.JSON.parse()— 문자열 텍스트를 JSON으로 파싱하고, 선택적으로 생성된 값과 그 속성을 변환한 뒤 그 값을 반환합니다.JSON.rawJSON()— JSON 텍스트 조각을 담은 "원시 JSON" 객체를 만듭니다. JSON으로 직렬화할 때 원시 JSON 객체는 이미 JSON 조각인 것처럼 취급됩니다. 이 텍스트는 유효한 JSON이어야 합니다.JSON.stringify()— 지정된 값에 해당하는 JSON 문자열을 반환합니다. 선택적으로 일부 속성만 포함하거나 사용자 정의 방식으로 속성 값을 대체할 수 있습니다.
예제
예제 JSON — 아래 JSON 문자열을 JSON.parse() 메서드로 JavaScript 객체로 변환할 수 있습니다.
const jsonText = `{
"browsers": {
"firefox": {
"name": "Firefox",
"pref_url": "about:config",
"releases": {
"1": { "release_date": "2004-11-09", "status": "retired", "engine": "Gecko", "engine_version": "1.7" }
}
}
}
}`;
console.log(JSON.parse(jsonText));
손실 없는 숫자 직렬화 (Lossless number serialization) — JSON은 임의 정밀도의 숫자 리터럴을 포함할 수 있습니다. 하지만 JavaScript는 고정 정밀도의 부동소수점 표현을 사용하므로 모든 JSON 숫자를 정확히 표현할 수는 없습니다. 예를 들어 12345678901234567890 === 12345678901234567000은 JavaScript에서 true인데, 둘이 동일한 부동소수점 표현을 갖기 때문입니다.
큰 정수를 BigInt로 정확히 저장해 직렬화 후 다시 파싱해도 같은 값을 얻으려면 다음 방법을 쓸 수 있습니다.
- JSON 문자열 사용 — 수신 시스템이 JavaScript와 같은 JSON 처리 능력이 없고 고정밀 숫자를 지원하지 않는다면, 숫자를 문자열로 직렬화한 뒤 수신측에서 문자열로 처리합니다.
BigInt.prototype.toJSON메서드를 추가하거나JSON.stringify()의replacer함수를 사용합니다. 결과는{"gross_gdp":"12345678901234567890"}처럼 값이 문자열이 됩니다. - JSON 숫자 사용 — 수신 시스템이 고정밀 숫자를 네이티브로 지원한다면(예: Python 정수),
JSON.rawJSON()을 사용해 JSON 소스 텍스트를 정확히 지정함으로써 정밀도 손실 없이 숫자로 직렬화할 수 있습니다. 결과는{"gross_gdp":12345678901234567890}처럼 값이 숫자가 됩니다.
JavaScript에서 고정밀 숫자를 포함한 JSON을 파싱할 때는 주의가 필요합니다. JSON.parse()가 reviver 함수를 호출할 때 받는 값은 이미 파싱되어 정밀도를 잃었기 때문입니다. reviver 함수의 context.source 파라미터를 사용해 직접 다시 파싱할 수 있습니다.
const parsedData = JSON.parse(str, (key, value, context) => {
if (key === "gross_gdp") {
return BigInt(context.source);
}
return value;
});
// { gross_gdp: 12345678901234567890n }
더 알아보기
JSON.parse()— JSON 문자열을 파싱JSON.stringify()— 값을 JSON 문자열로 직렬화YAML,JSON5— 더 사람 친화적인 설정 형식- JSON 공식 사이트