JSON(JavaScript Object Notation)은 값이나 객체를 나타내주는 범용 포맷으로, RFC 4627 표준에 정의되어 있습니다.
JSON은 본래 자바스크립트에서 사용할 목적으로 만들어진 포맷입니다.
그런데 라이브러리를 사용하면 자바스크립트가 아닌 언어에서도 JSON을 충분히 다룰 수 있어서, JSON을 데이터 교환 목적으로 사용하는 경우가 많습니다.
자바스크립트가 제공하는 JSON 관련 메서드는 다음과 같습니다.
- JSON.stringify - 객체를 JSON으로 바꿔줍니다.
- JSON.parse - JSON을 객체로 바꿔줍니다.
JSON.stringify
let student = {
name:'John',
age: 30,
isAdmin: false,
courses: ['html','css','js'],
wife:null
}
let json = JSON.stringify(student);
console.log(typeof json); // string
console.log(json);
/* JSON으로 인코딩된 객체:
{
"name": "John",
"age": 30,
"isAdmin": false,
"courses": ["html", "css", "js"],
"wife": null
}
*/
JSON.stringify(student)를 호출하자 student가 문자열로 바뀌었습니다.
JSON으로 인코딩된 객체는 일반 객체와 다른 특징을 보입니다.
- 문자열은 큰따옴표로 감싸야 합니다. JSON에선 작은따옴표나 백틱을 사용할 수 없습니다. ('John' >> "John" 으로 변경된 것을 통해 이를 확인할 수 있습니다.)
- 객체 프로퍼티 이름은 큰따옴표로 감싸야 합니다. (age:30 >> "age":30 으로 변경된 것을 통해 이를 확인할 수 있습니다.)
JSON.stringify는 객체 뿐만 아니라 원시값에도 적용할 수 있습니다.
- 객체 {}
- 배열 []
- 원시형 : 문자형, 숫자형, 불린형 값(true/false), null
JSON은 데이터 교환을 목적으로 만들어진 언어에 종속되지 않는 포맷입니다. 따라서 자바스크립트 특유의 객체 프로퍼티는 JSON.stringify가 처리할 수 없습니다.
JSON.stringify 호출 시 무시되는 프로퍼티는 다음과 같습니다.
- 함수 프로퍼티 (메서드)
- 심볼형 프로퍼티 (키가 심볼인 프로퍼티)
- 값이 undefined인 프로퍼티
let user = {
sayHi(){ // 무시
alert('hello');
},
[Symbol('id')]:123, // 무시
something: undefined // 무시
};
console.log( JSON.stringify(user) ); // {} (빈 객체가 출력됨.)
JSON.stringify의 장점 중 하나는 중첩 객체도 알아서 문자열로 바꿔 준다는 점입니다.
이 때, 주의해야 하는 사항은 순환 참조가 있으면 원하는 대로 객체를 문자열로 바꾸는게 불가능합니다.
let meetup = {
title: "Conference",
room: {
number: 23,
participants: ["john", "ann"]
}
};
alert( JSON.stringify(meetup) );
/* 객체 전체가 문자열로 변환되었습니다.
{
"title":"Conference",
"room":{"number":23,"participants":["john","ann"]},
}
*/
// !!!
let room = {number:23};
let meetup = {
title:"Conference",
participants:["john","ann"]
};
meetup.place = room;
room.occupiedBy = meetup;
JSON.stringify(meetup); // Error: Converting circular structure to JSON ...
room.occupiedBy는 meetup을, meetup.place는 room을 참조하기 때문에 JSON으로의 변환이 실패했습니다.
replacer로 원하는 프로퍼티만 직렬화하기
JSON.stringify의 전체 문법은 아래와 같습니다.
let json = JSON.stringify(value[, replacer, space])
value
- 인코딩 하려는 값
replacer
- JSON으로 인코딩 하길 원하는 프로퍼티가 담긴 배열. 또는 매핑 함수 function(key, value)
space
- 서식 변경 목적으로 사용할 공백 문자 수
- 대다수의 경우, JSON.stringify엔 인수를 하나만 넘겨서 사용합니다.
그런데 순환 참조를 다뤄야 하는 경우같이 전환 프로세스를 정교하게 조정하려면 두 번째 인수를 사용해야 합니다. - JSON으로 변환하길 원하는 프로퍼티가 담긴 배열을 두 번째 인수로 넘겨주면 이 프로퍼티들만 인코딩할 수 있습니다.
let room = {number:23};
let meetup = {
title:"Conference",
participants:[{name:'John'},{name:'Alice'}],
place: room // meetup은 room을 참조합니다.
}
room.occupiedBy = meetup; // room references meetup
console.log(JSON.stringify(meetup, ['title','participants']);
// {"title":"Conference","participants":[{},{}]}
배열에 넣어준 프로퍼티가 잘 출력된 것을 확인할 수 있습니다. 그런데 배열에 name을 넣지 않아서 출력된 문자열의 participants가 텅 비어버렸습니다.
규칙이 너무 까다로워서 발생한 문제입니다.
순환 참조를 발생시키는 프로퍼티 room.occupiedBy만 제외하고 모든 프로퍼티를 배열에 넣어보았습니다.
let room = {
number: 23
};
let meetup = {
title: "Conference",
participants: [{name: "John"}, {name: "Alice"}],
place: room // meetup references room
};
room.occupiedBy = meetup; // room references meetup
alert( JSON.stringify(meetup, ['title', 'participants', 'place', 'name', 'number']) );
/*
{
"title":"Conference",
"participants":[{"name":"John"},{"name":"Alice"}],
"place":{"number":23}
}
*/
// 위 결과는 배열이 좀 길다는 느낌이 듭니다.
// replacer자리에 배열 대신 함수를 전달해 문제를 해결 해 보았습니다.
alert( JSON.stringify(meetup, function replacer(key, value) {
alert(`${key}: ${value}`);
return (key == 'occupiedBy') ? undefined : value;
}));
/* replacer 함수에서 처리하는 키:값 쌍 목록
: [object Object]
title: Conference
participants: [object Object],[object Object]
0: [object Object]
name: John
1: [object Object]
name: Alice
place: [object Object]
number: 23
*/
첫 alert 창에 예상치 못한 문자열 (": [object Object]") 이 뜨는걸 볼 수 있는데, 이는 함수가 최초로 호출될 때 {"":meetup} 형태의 "래퍼 객체"가 만들어지기 때문입니다.
replacer 함수가 가장 처음으로 처리해야 하는 (key, value) 쌍에서 키는 빈 문자열, 값은 변환하고자 하는 객체(meetup) 전체가 되는 것입니다.
이렇게 replacer 함수를 사용하면 중첩 객체 등을 포함한 객체 전체에서 원하는 프로퍼티만 선택해 직렬화 할 수 있습니다.
space로 가독성 높이기
JSON.stringify(value, replacer, space)의 세 번째 인수 space는 가독성을 높이기 위해 중간에 삽입해 줄 공백 문자 수를 나타냅니다.
지금까지는 space 없이 메서드를 호출했기 때문에 인코딩된 JSON에 들여쓰거나 여분의 공백문자가 하나도 없었습니다.
space는 가독성을 높이기 위한 용도로 만들어졌기 때문에 단순 전달 목적이라면 space없이 직렬화하는 편입니다.
let user = {
name: "John",
age: 25,
roles: {
isAdmin: false,
isEditor: true
}
};
alert(JSON.stringify(user, null, 2));
/* 공백 문자 두 개를 사용하여 들여쓰기함:
{
"name": "John",
"age": 25,
"roles": {
"isAdmin": false,
"isEditor": true
}
}
*/
/* JSON.stringify(user, null, 4)라면 아래와 같이 좀 더 들여써집니다.
{
"name": "John",
"age": 25,
"roles": {
"isAdmin": false,
"isEditor": true
}
}
*/
JSON.parse
JSON.parse를 사용하면 JSON으로 인코딩 된 객체를 다시 객체로 디코딩 할 수 있습니다.
let value = JSON.parse(str, [reviver]);
str
- JSON형태의 문자열
reviver
- 모든 (key, value) 쌍을 대상으로 호출되는 function(key,value) 형태의 함수로 값을 변경시킬 수 있습니다.
let data = '{"title":"Conference","participants":[{"name":"John"},{"name":"Alice"}],"place":{"number":23}}';
console.log(JSON.parse(data));
/*
{
title:'Conference',
participants:[{name:'John'},{name:'Alice'}],
place:{number:23}
}
*/
reviver 사용하기
서버로 부터 문자열로 변환되 meetup 객체를 전송받았다고 가정합니다.
전송받은 문자열은 다음과 같습니다.
// title: (meetup 제목), date: (meetup 일시)
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
이제 이 문자열을 역 직렬화(deserialize) 해서 자바스크립트 객체를 만들어봅시다.
JSON.parse로 호출을 해 보겠습니다.
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
let meetup = JSON.parse(str);
alert( meetup.date.getDate() ); // 에러! TypeError
meetup.date의 값은 Date 객체가 아니고 문자열이기 때문에 발생한 에러입니다.
그렇다면, 문자열을 Date로 전환해줘야 한다는 것을 JSON.parse 에게 알릴 수 있을까요?
이럴 때, JSON.parse의 두 번째 인수 reviver를 사용하면 됩니다. 모든 값은 "그대로", 하지만 date만큼은 Date 객체를 반환하도록 함수를 구현해 보았습니다.
let str = '{"title":"Conference","date":"2022-01-10T12:00:00.000Z"}';
let meetup = JSON.parse(str, function(key, value) {
if (key == 'date') return new Date(value);
return value;
});
alert( meetup.date.getDate() ); // 10
잘 되는 것을 확인 할 수 있습니다.
요약
- JSON은 독자적인 표준을 가진 데이터 형식으로, 대부분의 언어엔 JSON을 쉽게 다룰 수 있게 해주는 라이브러리가 있습니다.
- JSON은 일반 객체, 배열, 문자열, 숫자, 불린값, NULL을 지원합니다.
- JSON.stringify를 사용하면 원하는 값을 JSON으로 직렬화 할 수 있고, JSON.parse를 사용하면 JSON을 본래 값으로 역 직렬화 할 수 있습니다.
- 위 두 메서드에 함수를 인수로 넘겨주면 원하는 값만 읽거나 쓰는 게 가능합니다.
- JSON.stringify는 객체에 toJSON 메서드가있으면 이를 자동으로 호출해줍니다.
출처 : https://ko.javascript.info/json#comments
json.stringify : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
json.parse : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
'javascript' 카테고리의 다른 글
[Javascript] 'try...catch'와 에러 핸들링 (0) | 2022.01.11 |
---|---|
[Javascript] label(레이블) 구문 (0) | 2022.01.11 |
[Javascript] ... 사용 방법 [구조 분해 할당 (배열, 객체 분해하기)] (0) | 2022.01.10 |
[javascript] 화살표 함수 (()=>, Arrow Function) (0) | 2022.01.09 |
[javascript] Symbol (0) | 2022.01.08 |
댓글