본문 바로가기
자바스크립트(JavaScript)/자바스크립트

JSON(JavaScript Object Notation)이란? ( 메서드 : stringify / parse )

by yerica 2025. 1. 3.

JSON 이란?

만들어낸 객체를 네트워크를 통해 어딘가에 보내거나 로깅 목적으로 객체를 출력하고 싶다면,

우리는 원하는 정보가 있는 객체 프로퍼티를 전부 문자열로 전환해야 한다.

 

만약, 우리가 만들어낸 객체가 복잡한 형태라면 어떨까? 개발 과정에서 프로퍼티가 계속 추가되거나 삭제, 수정된다면?

 

일일이 수정하는 방식은 꽤나 번거롭고 실수(오류)가 발생할 확률이 높을 것이다.

JSON 은 이와 같은 문제를 해결하기 위해 나온 범용 포맷이다.

 

JSON(JavaScript Object Notation)은 직역하자면 "자바스크립트 객체 표기법"으로
데이터를 쉽게 교환, 저장하기 위한 텍스트 기반표준이다.

 

 

RFC 4627 표준에 정의되어 있는 JSON은 본래 자바스크립트에서 사용할 목적으로 만들어진 포맷이지만,

데이터 교환을 목적으로 만들어진 언어에 종속되지 않는 포맷이다.

JSON은 간단하고 가벼운 데이터 표현 방식을 제공하는 것으로 목표로 하며,

이를 위해 JSON은 자바스크립트의 기본 자료형을 텍스트로 변환하는 규칙을 가지고 있다.

 

텍스트 기반이기 때문에 가볍고, 데이터 형식이 파싱 하기 쉬워 제공된 데이터를 이해하고 해석하기 위한 추가 코드가 필요하지 않다. 이러한 강력한 장점으로 인해 현재는 다양한 프로그래밍 언어에서 사용되고 있다.

 

라이브러리를 사용하면 자바스크립트가 아닌 언어에서도 JSON을 충분히 다룰 수 있어 최근에는 자바스크립트뿐만 아니라 타 언어 사이사이에서도 JSON을 데이터 교환 목적으로 사용하는 경우가 많아졌다.

웹 개발 외에도 구성 설정을 저장 관리하기 위해 애플리케이션 또는 IT 시스템 내에서 자주 사용된다.

예를 들어, 데이터베이스 연결 세부정보, API 키 또는 사용자 기본 설정과 같은 필수 정보를 JSON 형식으로 저장하면 개발자는 코드를 변경하지 않고도 애플리케이션 설정을 수정할 수 있다.


JSON 메서드

자바스크립트가 제공하는 JSON 관련 메서드는 다음과 같다.

  • JSON.stringify : 객체를 JSON으로 바꿀 때 사용하는 메서드.
  • JSON.parse : JSON을 객체로 바꿀 때 사용하는 메서드.

stringify 메서드를 사용하면 통해 데이터를 JSON형식의 문자열로 변경할 수 있고, 

parse 메서드를 사용하면 JSON 형태의 데이터를 가져와 다시 자바스크립트 형식으로 변경할 수 있다. 


  JSON.stringify()  

stringify는 "문자열화"를 말한다.

JSON.stringify()는 자바스크립트에서 제공하는 JSON 관련 메서드로,

매개변수로 받은 객체를 JSON 형식의 포맷으로 문자열화 시키는 역할을 한다. 

기본형
JSON.stringify(value, [replacer, space])

 

 

예를들어 다음과 같이 매개변수로 객체 user가 들어갔을 경우 객체를 구성하는 프로퍼티뿐만 아니라 이를 감싸는 중괄호까지 함께 포함된다.

아래 예시를 보면 알 수 있듯이, json 형식에서 문자열은 반드시 큰따옴표로 감싸진다.  (작은따옴표, 백틱 사용 X)

 

 

const users = {
    name : 'kim',
    age : 28
}
let json = JSON.stringify(users);

console.log(json) // 출력 : {"name":"kim","age":28}

 

이렇게 변경된 문자열을 JSON으로 인코딩 된(JSON-encoded), 직렬화 처리된(serialized), 문자열로 변환된(stringified), 결집된(marshalled) 객체라고 부른다.

객체는 이렇게 문자열로 변환된 후에야 네트워크를 통해 전송하거나 저장소에 저장할 수 있다.


매개변수

JSON.stringify()는 value, replacer, space라는 세 가지 인수를 받을 수 있다. 

  • value : 인코딩하려는 값
  • replacer : 인코딩하려는 값을 필터링하기 위한 값. 배열 혹은 매핑함수가 들어간다.
  • space : 가독성을 높이기 위해 중간에 삽입하려는 공백 값

1 ) Value

첫 번째 인수에는 인코딩하려는 값이 들어간다.

value에 들어간 값은 JSON.stringify() 메서드를 통해 JSON 규격에 맞춰 텍스트로 변환되는데,

이때 value 값으로 객체뿐 아니라 다양한 자료형이 들어갈 수 있다.

 

왜냐하면, JSON이 데이터 교환을 목적으로 만들어진 언어에 종속되지 않는 포맷이기 때문이다.

JSON은 특정 언어에 종속되지 않고 다양한 프로그래밍 언어에서 지원되기 때문에,

네트워크를 통해 데이터를 주고받을 때, JSON은 다양한 데이터 타입을 처리할 수 있어야 하고 실제로 가능하다.

다양한 자료형을 처리하여 데이터 교환에 유연성을 제공하는 것이 JSON의 장점이다.

JSON이 문자열로 변환하는 규칙
더보기

1. 객체 (Object)

: 객체는 { } 형태로 변환되며, 키는 문자열이어야 하고 값은 JSON에서 지원하는 자료형이 여야 한다.

 

console.log(JSON.stringify({ name: "Alice", age: 25 }));
// 결과: {"name":"Alice","age":25}

 

2. 배열 (Array)

: 배열은 순서가 있는 데이터로 [ ] 형태로 변환된다. 배열 안의 값들도 JSON에서 지원하는 자료형이 여야 한다.

 

console.log(JSON.stringify([1, "hello", true]));
// 결과: [1,"hello",true]

 

 3. 문자열 (String)

: 문자열은 JSON에서 큰따옴표(")로 감싸인 텍스트로 표현된다.

 

console.log(JSON.stringify("Hello, World!"));
// 결과: "Hello, World!"

 

 4. 숫자(Number)

: 숫자는 JSON에서 그대로 표현된다.

 

console.log(JSON.stringify(123));
// 결과: 123

 

5. 논리형(Boolean)

: true와 false 그대로 표현된다.

 

console.log(JSON.stringify(true));
// 결과: true

 

6. null

: null 그대로 표현된다.

 

console.log(JSON.stringify(null));
// 결과: null

 

그렇다고 해서 JSON.stringify가 모든 자바스크립트 자료형을 처리하는 있는 것은 아니다. 
자바스크립트 특유의 객체 프로퍼티는 JSON.stringify가 처리하지 않는다.
함수(무시됨)와 심볼(무시됨), 값이 undefined인 프로퍼티(무시되거나 null로 변환), 혹은 순환참조(에러발생)는 stringify로 처리 시 제외되는 것을 확인할 수 있다. (다른 곳에 이걸 보내서 어디에 쓸건데..?)

JSON.stringify는 원시값에도 적용할 수 있다.
stringify에 적용 가능한 자료형
객체   { ... } : 키-값 쌍으로 구성된 데이터
배열   [ ... ] : 순서가 있는 데이터
원시형   * 문자형(String) : 텍스트 데이터
  * 숫자형(Number) : 정수와 실수
  * 논리형(Boolean) : true 혹은 false
  * null : 빈 값을 나타내는 특수 값
stringify에 적용 불가능한 프로퍼티
함수    함수 프로퍼티(메서드)
심볼형    키(key)가 심볼(Symbol)인 프로퍼티
원시형    undefined

 

아래의 예시를 통해, 우리는 한 가지 사실을 더 알 수 있다.
바로, stringify는 중첩 객체도 알아서 문자열로 바꿔준다는 것이다.
const test = {
    object : {name : "kim"}, // {"name":"kim"}
    string : 'string', // "string"
    number : 28, // 28
    array: [1, 2, 3], // [1,2,3]
    boolean1: true, // true
    boolean2: false, // false
    empty1 : null, // null
    empty2 : undefined, // 출력 X
    [Symbol("id")]: 123, // 출력 X
    function : function Fnc(){
        console.log("hi");  
      }, // 출력 X
}
let json = JSON.stringify(test);

console.log(json);
// 출력 : {"object":{"name":"kim"},"string":"string","number":28,"array":[1,2,3],"boolean1":true,"boolean2":false,"empty1":null}

 

2) replacer

대다수의 경우 value 인수 하나만을 넘겨서 사용하지만,

순환 참조와 같이 전환 프로세스를 정교하게 다뤄야 할 경우 두 번째 인수인 replacer를 사용한다.

(순환참조의 경우 어쩌구저쩌구 생각해야 하는 게 있지만, 순환 참조를 만드는 것 자체를 권장하지 않기도 하고,,, 필요할 때 찾아보자)

replacer의 경우 인코딩 하길 원하는 프로퍼티가 담긴 배열 혹은 키(key)와 값(value)이 담겨있는 매핑 함수를 통해 원하는 값들만 인코딩하도록 만들 수 있다.

replacer에 인코딩하기 원하는 프로퍼티를 배열로 넘겼을 경우
const obj = {
    name : "lee",
    height : 164,
    weight : 50
}
let replacer1 = JSON.stringify(obj, ["name", "height"]);
console.log(replacer1); // 출력 : {"name":"lee","height":164}
인코딩하기 원하는 객체와 프로퍼티 명이 담긴 배열을 넘겼을 경우,
객체의 키와 배열 안의 값이 동일할 경우에만 인코딩 된다.

배열 안의 값이 객체 안에 존재하지 않거나, 객체의 키가 배열에 존재하지 않는 경우는 무시된다.

 

replacer에 매핑함수를 넘겼을 경우
const obj = {
    name : "lee",
    height : 164,
    weight : 50
}
function replacer(key, value){
    if(!key) return value;

    if(typeof value === 'number'){
        return value;
    }
}
let replacer2 = JSON.stringify(obj, replacer);
console.log(replacer2); // 출력 : {"height":164,"weight":50}
매핑함수는 인수로 인코딩할 객체와 프로퍼티가 들어가기 때문에 key, value가 반드시 매개변수로 존재해야 한다.
이후 매핑 함수 내부에서 조건식과 같은 로직을 거친 후 return 되는 값이 함수, 심볼, undefined가 아닌 값들을 모아서 인코딩한다. 

매핑함수에서 재밌는 점은 첫 번째 호출값으로 객체 전체가 넘어온다는 것이다.
첫 번째 호출에서 전체 객체에 대해 실행된 후, 이후 각 프로퍼티의 키와 값을 순차적으로 검사하며 실행된다.

const obj = {
    name : "lee",
    height : 164,
    weight : 50
}
function replacer(key, value){
    if(typeof value === 'number'){
        return value;
    }
}
let replacer2 = JSON.stringify(obj, replacer);
console.log(replacer2); // 출력 : undefined​


위에 replacer에서 if(!key) return value라는 코드 한 줄을 삭제했더니 undefined가 출력되었다.
중단점을 찍어보니 맨 처음 인수로 객체 전체가 넘어왔는데 객체의 타입이 object 이기 때문에 조건식에 부합하지 않아 undefined를 반환했기 때문이다.
이 첫 번째 호출에서 undefined를 반환하면 JSON.stringify는 객체 변환을 중단하고 최종 결과로 undefined를 반환한다.


조건식의 내용만 undefined를 하고 싶다면 다음과 같이 쓸 수 있다.
아래 코드에선 value가 number인 경우 undefined 시키고 나머지는 return value 하도록 작성했다.
여기서 조건식이 object여서 전체 객체를 건드릴 경우, 혹은 다른 모든 코드들을 return value 시켜주지 않는 경우에도 함수의 특성상 undefined를 반환하기 때문에 무시당할 것이다.

const obj = {
    name : "lee",
    height : 164,
    weight : 50
}
function replacer(key, value){
    if(typeof value === 'number'){
        return undefined;
    }
    return value;
}
let replacer2 = JSON.stringify(obj, replacer);
console.log(replacer2); // 출력 : {"name":"lee"}

 

3) space

세 번째 인수 space는 가독성을 높이기 위해 중간에 삽입해 줄 공백 문자 수를 나타낸다.

지금까진 space 없이 메서드를 호출했기 때문에 인코딩 된 JSON에 들여 쓰기나 여분의 공백문자가 존재하지 않았다.

이 경우 코드가 빽빽이 나열되어 있기 때문에 가독성이 떨어질 수 있다.

space는 이러한 가독성을 높이기 위한 용도로 만들어졌기 때문에, 단순히 전달할 목적이라면 잘 사용하지 않는다.

space에 4를 입력했을 경우 각각의 프로퍼티 앞에 공백 4칸이 생성된다.
const obj = {
    name : "kim",
    age : 28
}
console.log(JSON.stringify(obj, null, 4))
/* 출력 : 
{
    "name": "kim",
    "age": 28
}
*/

 


커스텀 메서드 toJSON()

toJSON() 는 객체 안에서 사용되는 메서드로 stringify와 같이 인코딩하

객체에 정의되어 있고, 그 객체를 JSON.stringify() 메서드로 객체를 인코딩할 경우 toJSON()이 자동으로 실행된다.

기본형
const number = {
    first : 1,
    toJSON(){
        return this.first;
    }
}
console.log(JSON.stringify(number)) // 출력 : 1
replacer 처럼 조건식을 걸 수도 있다.
const obj = {
    name : "kim",
    age : 28,
    toJSON(){
        let newObj = "";
        for (let key in this){
            if(typeof this[key] == 'number' && key !== 'toJSON') {
                newObj += this[key];
            }
        }
        return newObj;
    }
}
console.log(JSON.stringify(obj)) // 출력 : "28"
내장 객체 Date 같은 경우 toJSON 메서드가 내장되어 있다.
let date = {
  date: new Date(Date.UTC(2017, 0, 1)),
};

console.log(JSON.stringify(date))
/*
  {
    "date":"2017-01-01T00:00:00.000Z", // Date객체에 toJSON메서드가 내장되어 있기 때문에, 자동으로 문자열로 변환됨
  }
*/
중첩 객체에 toJSON()이 있는 경우 toJSON() 메서드를 거친 다음 반환값을 출력한다.
let number = {
  first: 1,
  toJSON() {
    return this.first;
  }
};
let test = {
  title: "숫자",
  number
};
console.log( JSON.stringify(test) );
/*
  {
    "title":"숫자",
    "number": 1
  }
*/

  JSON.parse()  

JSON.parse()를 사용하면 JSON으로 인코딩 된 객체를 다시 객체로 디코딩할 수 있다.

기본형
JSON.parse(string, [reviver]);

매개변수

JSON.parse()는 매개변수로 string과 reviver를 받는다.

  • string : JSON 형식의 문자열
  • reviver :  디코딩 되는 문자열안의 키-값을 변형할 매핑함수 function(key, value)가 들어간다.

1) String

첫번째 인수로 JSON 형식의 문자열이 들어간다.

parse()를 통해 문자열을 디코딩하면 자바스크립트 자료형으로 변환된다.

JSON 문법으로 인코딩했던 객체를 parse() 하니 문자열이 아닌 기존의 객체 배열이 출력된다.
const users = {
    name : 'kim',
    age : 28
}
let json = JSON.stringify(users);

console.log(json) // 출력 : {"name":"kim","age":28}
console.log(JSON.parse(json)) // 출력 : { name: 'kim', age: 28 }

 

중첩 객체나, 중첩 배열에서도 동일하게 parse할 경우 기존의 배열로 돌아가는 것을 확인할 수 있다.

 

만약, 디버깅 등의 목적으로 직접 JSON을 만든다면 다음 사항을 주의하면 좋다.

  1.  문자형태의 프로퍼티 명과 값은 큰따옴표로 감싸야한다.
  2.  순수한 값(bare value)만 사용할 수 있다. ( 예 : new Date()와 같은 형태는 사용 X)
  3.  JSON은 주석을 지원하지 않는다. (추가시 유효하지 않은 형식이 됨)

2) reviver

두번째 매개변수 reviver에는 함수를 인수로 받는다.

이 함수는 디코딩되는 문자열 안의 key와 value 값을 받아 변환시킬 수 있다.

 

예를 들어 내장 객체 Date 가 문자열로 변환된 후, parse를 통해 디코딩되면 Date로 돌아오는 것이 아닌 문자열 그대로 유지된다. 이때, reviver 안에 다시 Date 객체로 변환시키는 함수를 넣으면 변환되는 것을 확인 할 수 있다.
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() );