javascript

[Javascript] JSON stringify 사용법, parse 사용법(JSON과 메서드)

sewonzzang123 2022. 1. 10.
반응형

 

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과 메서드

 

ko.javascript.info

json.stringify : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

 

JSON.stringify() - JavaScript | MDN

JSON.stringify() 메서드는 JavaScript 값이나 객체를 JSON 문자열로 변환합니다.

developer.mozilla.org

json.parse : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse

 

JSON.parse() - JavaScript | MDN

JSON.parse() 메서드는 JSON 문자열의 구문을 분석하고, 그 결과에서 JavaScript 값이나 객체를 생성합니다.

developer.mozilla.org

 

반응형

댓글