const jsonElement = {
"String\\nKey": 'string"Value',
Int: 10,
Array: ["string\\nValue", 20],
EmptyArray: [],
};
// 아래의 string 으로 출력하기
{
'String<br>Key': 'string"Value',
'Int': 10,
'Array': [
'string
Value',
20
],
'EmptyArray': [ empty array ],
}
언뜻 보기엔 쉬워보이지만 하나하나 생각하자니 어려웠다…
처음 접근을 `Object.entries(jsonElement)` 의 배열을 받아 `reduce` 메소드로 string 값으로 치환하면서 정규식에 따라 replace하려고 했는데 parsing 할수록 복잡해지고 결과마다 indent도 추가되니 어려워졌다.
정규식? JSON 메소드?
json을 파싱할 때 떠오르는 방법은
- 정규식 이용 (replace)
- JSON 메소드(stringify, parse)
라이브러리를 제외한 두 가지 정도가 생각난다.
그런데 JSON 메소드들을 쓸 때 보면 항상 첫 번째 인자만 넣어봤지 두 번째, 세 번째 인자가 있는지 몰랐다.
`String.replace` 메소드의 두 번째 인자에는 `replacer` 라는 콜백함수가 들어가는데 `JSON.stringify` 와 `JSON.parse` 도 비슷한 방식으로 쓰여진다.
JSON.stringify(value[, replacer[, space]])
찾아보니 mdn에서 `JSON.stringify`의 자세한 쓰임을 알 수 있었는데
처음 접근한 방법으로도 충분히 가능하지만 `stringify` 메소드를 사용하면 더욱 편리하다.
세 번째 인자에는 간격space이 들어가는데 기존에 localStorage에 넣는다면 필요없지만, `"/t" , 1, " "` 같은 값을 집어넣으면 우리가 보통 JSON을 읽을 때 처럼 어느정도 들여쓰기가 된 상태로 pretty 하게 리턴되는 문자열을 볼 수 있다.
// JSON.stringify(obj, null, "/t")
// space 값에 따라 보기 좋게 들여쓰기 된다. 1 ~ 10(space), " " , tab(\\t) 만큼
// replace 함수를 쓰지 않을 경우 null을 명시해주면 된다.
{
"name": "John",
"age": 25,
"roles": {
"isAdmin": false,
"isEditor": true
}
}
replacer 주의점
const replacer = (key, value) => {
// float, double이면 소수점 2번째 자리까지 출력
// toFixed는 반올림이 되기 때문에 내림하려고 로직을 넣음
if (typeof value === "number" && !Number.isInteger(value)) {
return (Number(Math.floor(value * 100).toFixed(2)) / 100).toFixed(2);
}
// 빈 배열일 때
if (Array.isArray(value) && value.length === 0) {
return "[ empty array ]";
}
// 빈 객체일 때
if (JSON.stringify(value) === "{}") {
return `{ empty json }`;
}
// default
return value;
};
위의 코드와 같이 replacer 메소드는 key와 value를 받고 프로퍼티를 순환하며 수정된 value를 리턴하게 된다!
이때 주의할 점이 있는데.
- return 시 value만 수정되며, key 를 바꿀 순 없다.
- 순환 횟수가 프로퍼티의 길이가 아니다. (그 이상이다.)
- 중간에 undefined을 반환하면 반복이 끝나고 종료된다.
이 함수는 최초로 호출될 때 { "": 해당하는 객체 } 형태의 래퍼 객체가 만들어진다.
이후에 첫 프로퍼티를 계속 순환하는데. 만약 객체를 만나면 그 안의 프로퍼티까지 순회한다.
let meetup = {
title: "Conference",
participants: [{name: "John"}, {name: "Alice"}],
};
JSON.stringify(meetup, ["title", "participants"])
// '{"title":"Conference","participants":[{},{}]}'
JSON.stringify(meetup, ["title", "participants", "name"], 2)
/* {
"title": "Conference",
"participants": [
{
"name": "John"
},
{
"name": "Alice"
}
]
}
*/
replacer는 배열로도 받을 수 있다.
배열의 값들에 해당하는 객체의 프로퍼티를 재귀적으로 처리한다.
prettier ignore 설정
사실 원하는 대로 완전히 똑같이 맞추게하려면 생각보다 어렵다. 사소한 것들 하나하나 신경써야하기 때문…!
code runner나 node로 출력을 하려면 저장을 해야하는데 보통 저장 할 때마다 prettier에서 설정한 값대로 tab이나 들여쓰기가 자동으로 수정되기 때문에 원하는 string을 만들기 어렵기도 하다.
설정값을 바꿔도 되지만 원하는 파일에만 prettier를 안쓰고 싶으면 `.prettierignore` 파일을 만들어 특정파일을 무시해주자!
참고
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
'개발 (Dev) > Javscript' 카테고리의 다른 글
자바스크립트 원시값과 객체비교 & 얕은 복사와 깊은 복사 (1) | 2024.01.13 |
---|