복잡한 객체를 다룰 때, 객체를 보내거나 출력하는 상황에서 객체는 문자열로 전환되어야 한다. 이러한 상황을 유연하게 대처하기 위해 json
이 등장했다.
JSON(Javascript Object Notation)은 값이나 객체를 나타내주는 범용 포맷이다.
본래 자바스크립트에서 사용할 목적으로 만들어진 포맷이지만, 다른 언어에서도 사용하게 되어 JSON을 데이터 교환 목적으로 많이 사용한다.
자바스크립트가 제공하는 JSON
관련 메서드는 아래와 같다.
JSON.stringify
: 객체를 JSON
으로 바꿔준다.JSON.parse
: JSON
을 객체로 바꿔준다.let student = {
name: 'John',
age: 30,
isAdmin: false,
courses: ['html', 'css', 'js'],
wife: null
};
let json = JSON.stringify(student);
alert(typeof json); // 문자열이네요!
alert(json);
/* JSON으로 인코딩된 객체:
{
"name": "John",
"age": 30,
"isAdmin": false,
"courses": ["html", "css", "js"],
"wife": null
}
*/
JSON.stringify(student)
를 호출하자 student가 문자열로 바뀌었다.
이렇게 변경된 문자열은 JSON
으로 인코딩된, 직렬화 처리된, 문자열로 변환된, 결집된 객체라고 부른다. 객체는 이렇게 문자열로 변환된 후 비로소 네트워크를 통해 전송하거나 저장소에 저장할 수 있다.
JSON
으로 인코딩된 객체는 일반 객체와 다른 특징을 보인다.
JSON
에선 작은따옴표나 백틱을 사용할 수 없다. JSON.stringify
는 객체뿐만 아니라 원시값에도 적용할 수 있다.
적용할 수 있는 자료형은 아래와 같다.
예시 :
// 숫자를 JSON으로 인코딩하면 숫자입니다.
alert( JSON.stringify(1) ) // 1
// 문자열을 JSON으로 인코딩하면 문자열입니다(다만, 큰따옴표가 추가됩니다).
alert( JSON.stringify('test') ) // "test"
alert( JSON.stringify(true) ); // true
alert( JSON.stringify([1, 2, 3]) ); // [1,2,3]
JSON
은 데이터 교환을 목적으로 만들어진 언어에 종속되지 않는 포맷이다. 따라서 자바스크립트 특유의 객체 프로퍼티는 JSON.stringify
가 처리할 수 없다.
JSON.stringify
호출 시 무시되는 프로퍼티는 아래와 같다.
undefined
인 프로퍼티let user = {
sayHi() { // 무시
alert("Hello");
},
[Symbol("id")]: 123, // 무시
something: undefined // 무시
};
alert( 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"]},
}
*/
정리하자면,
위와 같이 문자열로 변환된 후 객체는 네트워크를 통해 전송되거나 저장소에 저장될 수 있다.
JSON으로 인코딩된 객체는 문자열을 큰따옴표로만 감싸야 한다.
JSON의 프로퍼티 이름도 큰따옴표로 감싸야한다.
JSON.stringfy는 객체, 배열, 원시형(문자, 숫자, 불린, null)에도 적용할 수 있다.
함수 프로퍼티(메서드), 심볼형 프로퍼티, 값이 undefined인 프로퍼티는 호출 시 무시된다.
JSON.stringfy는 중첩 객체도 문자열로 변환해준다.
JSON.stringify
문법 :
let json = JSON.stringify(value[, replacer, space])
value
인코딩 하려는 값
replacer
JSON으로 인코딩 하길 원하는 프로퍼티가 담긴 배열. 또는 매핑함수 funtion(key, value)
space
서식 변경 목적으로 사용할 공백 문자 수
대다수의 경우 JSON.stringify
엔 인수를 하나만 넘겨서 사용한다. 하지만 순환 참조를 다뤄야 하는 경우 같이 전환 프로세스를 정교하게 조정하려면 두 번째 인수를 사용한다.
replacer
에 전달되는 함수(replacer 함수)는 프로퍼티 (키, 값)
쌍 전체를 대상으로 호출되는데, 반드시 기존 프로퍼티 값을 대신하여 사용할 값을 반환해야 한다. 특정 프로퍼티를 직렬화에서 누락시키려면 반환 값을 undefined
로 만들면 된다.
아래 예시는 occupiedBy
를 제외한 모든 프로퍼티의 값을 변경 없이 “그대로” 직렬화하고 있다. occupiedBy
는 undefined
를 반환하게 해 직렬화에 포함하지 않은 것도 확인해 보자.
let room = {
number: 23
};
let meetup = {
title: "Conference",
participants: [{name: "John"}, {name: "Alice"}],
place: room // meetup은 room을 참조합니다
};
room.occupiedBy = meetup; // room은 meetup을 참조합니다
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
*/
JSON.stringify(value, replacer, space)
의 세 번째 인수 space
는 가독성을 높이기 위해 중간에 삽입해 줄 공백 문자 수를 나타낸다.
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
}
}
*/
toString
을 사용해 객체를 문자형으로 변환시키는 것처럼, 객체에 toJSON
이라는 메서드가 구현되어 있으면 객체를 JSON
으로 바꿀 수 있다. JSON.stringify
는 이런 경우를 감지하고 toJSON
을 자동으로 호출해준다.
let room = {
number: 23
};
let meetup = {
title: "Conference",
date: new Date(Date.UTC(2017, 0, 1)),
room
};
alert( JSON.stringify(meetup) );
/*
{
"title":"Conference",
"date":"2017-01-01T00:00:00.000Z", // (1)
"room": {"number":23} // (2)
}
*/
let room = {
number: 23,
toJSON() {
return this.number;
}
};
let meetup = {
title: "Conference",
room
};
alert( JSON.stringify(room) ); // 23
alert( JSON.stringify(meetup) );
/*
{
"title":"Conference",
"room": 23
}
*/
위와 같이 toJSON
은 JSON.stringify(room)
를 직접 호출할 때도 사용할 수 있고, room
과 같은 중첩객체에도 구현하여 사용할 수 있다.
JSON.parse
를 사용하면 JSON
으로 인코딩된 객체를 다시 객체로 디코딩 할 수 있다.
문법 :
let value = JSON.parse(str, [reviver]);
str
JSON 형식의 문자열
reviver
모든 (key,value)
쌍을 대상으로 호출되는 function(key, value)형태의 함수로 값을 변경시킬 수 있다.
💡 JSON은 주석을 지원하지 않는다.
함수라면, 변환 결과를 반환하기 전에 이 인수에 전달해 변형한다.
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
let meetup = JSON.parse(str);
alert( meetup.date.getDate() ); // 에러!
meetup.date
의 값은 Date
객체가 아니고 문자열이기 때문에 발생한 에러이다.
문자열을 Date
로 전환해줘야할 때 reviver
을 사용하면 된다.
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
let meetup = JSON.parse(str, function(key, value) {
if (key == 'date') return new Date(value);
return value;
});
alert( meetup.date.getDate() ); // 이제 제대로 동작하네요!