ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Section 8. 자바스크립트 Object 깊게 다루기 (JSON)
    자바스크립트 2023. 4. 6. 11:56

    I. JSON JavaScript Object Notation

    이런 형태로 작성된 문서를 XML이라고 한다. XML은 간단히 말해서 복잡할 수 있는 정보를 서버와 클라이언트에서 주고 받기 적합한 형태로 표현한 것이라고 한다. tag를 사용하여 정보와 구조가 명확하게 드러나는 특징이 있다.

    하지만 가독성이 조금 떨어질 수 있는데 여기서 강점을 가질 수 있는 것이 바로 JSON이다. 

    JSON은 보다 간결한 형태로 구조화된 정보를 표기한다. 

    JSON은 정리를 하자면 다음과 같다

    • 복잡한 구조를 가질 수 있는 데이터를 한 줄의 문자열로 표현한 것.
    • 서버와 클라이언트 등 데이터들을 주고받는 주체들 사이에 널리 사용된다.

     

    II. JSON 객체의 정적 메서드

    1. stringify - 객체를 문자열로 직렬화 serialize 하는 메서드

    const person = {
      name: '김달순',
      age: 23,
      languages: ['Korean', 'English', 'French'],
      education: {
        school: '한국대',
        major: ['컴퓨터공학', '전자공학'],
        graduated: true,
      }
    };
    
    const personStr = JSON.stringify(person);
    
    console.log(typeof personStr); //string
    console.log(personStr);
    //{"name":"김달순","age":23,"languages":["Korean","English","French"],
    "education":{"school":"한국대","major":["컴퓨터공학","전자공학"],"graduated":true}}

    객체 personStr이 문자열로 직렬화가 되어서 출력이 되었다. 

     

    데이터 형태별 직렬화 결과는 다음과 같다

    [
      JSON.stringify(1), //1                  
      JSON.stringify(Infinity), //null
      JSON.stringify(NaN), //null
      JSON.stringify('가나다'), //"가나다"
      JSON.stringify(true), //true
      JSON.stringify(null), //null
      JSON.stringify(undefined), //undefined
      JSON.stringify([1, 2, 3]), //[1,2,3]
      JSON.stringify({x: 1, y: 2}), //{"x":1,"y":2}
      JSON.stringify(new Date()), //"2023-04-06T02:02:13.397Z"
    ]
    .forEach(i => console.log(i));

    Infinity와 NaN은 직렬화 처리가 되지 않아 null이 된 것을 알 수 있고 Date는 부분적으로만 직렬화가 된 것을 알 수 있다.

     

    값이 함수인 프로퍼티는 직렬화되지 않는다

    const obj = {
      x: 1,
      y: 2,
      z: function () { return this.x + this.y }
    }
    console.log(obj.z()) //3
    
    const objStr = JSON.stringify(obj); 
    console.log(objStr); //{"x":1,"y":2}

    z는 직렬화가 되지 않는다.

     

    2번째 인자 : replacer 함수

    직렬화될 방식을 지정하는 함수이다.

    const obj = {
      a: 1,
      b: '2',
      c: 3,
      d: true,
      e: false
    }
    
    // 1. key와 value 매개변수
    const objStr1 = JSON.stringify(obj, (key, value) => {
      if (key && key < 'a' || key > 'c') {
        // 해당 프로퍼티 생략
        return undefined;
        // ⚠️ 조건에 key && 을 붙이지 않으면 항상 undefined가 반환됨
        // key가 공백('')일 때(value는 객체 자체) undefined를 반환하므로...
        // key와 value를 로그로 출력해보며 확인해 볼 것
      }
      if (typeof value === 'number') {
        return value * 10;
      }
      return value;
    });
    console.log(objStr1); //{"a":10,"b":"2","c":30}

    key가 a보다 작거나 c보다 크면 undefined를 반환하라고 해서 d와 e는 직렬화가 되지 않는 것을 확인할 수 있다. 즉, undefined를 반환하라는 것은 생략하라는 의미이다.

    그리고 값이 숫자인 경우에는 10을 곱해서 반환하라고 해서 값에 10이 곱해져서 직렬화가 된 것을 볼 수 있다. 

    이렇게 어떤 객체를 직렬화 할때 조건을 넣어 줄 수 있다.

     

    아니면 어떤 프로퍼티만 직렬화가 되게끔 명시를 하는 방법도 있다.

    // 2. 반환한 key의 배열 매개변수
    const objStr2 = JSON.stringify(obj, ['b', 'c', 'd']);
    console.log(objStr2); //{"b":"2","c":3,"d":true}

     

    3번째 인자 : 인덴트

    만약에 직렬화된 문자열이 조금 알아보기 쉽게 되었으면 좋겠다~ 라고 한다면 3번째 인자를 통해 인덴트 한다.

    const obj = {
      a: 1,
      b: {
        c: 2,
        d: {
          e: 3
        }
      }
    };
    
    [
      JSON.stringify(obj, null), //{"a":1,"b":{"c":2,"d":{"e":3}}}
      JSON.stringify(obj, null, 1),
      JSON.stringify(obj, null, 2),
      JSON.stringify(obj, null, '\t')
    ]
    .forEach(i => console.log(i));

    이처럼 3번째 인자에 어떤 조건을 주느냐에 따라서 직렬화의 모양을 바꿀 수 있다.

     

    객체의 toJSON 프로퍼티

    const obj = {
      x: 1,
      y: 2,
      toJSON: function () {
        return '철권8 언제 나와?';
      }
    }
    
    console.log(
      JSON.stringify(obj)
    ); //"철권8 언제 나와?"

    toJSON은 어떤 객체가 직렬화가 될때 이런 값을 리턴해라~ 라고 정의 해주는 것이다. 

    어떤 객체에다가  toJSON 프로퍼티를 함수로 넣어주게 되면 직렬화가 될때 그 함수가 실행 된다. 

     

    2. parse - 역직렬화

    [
      JSON.parse('1'),
      JSON.parse('"가나다"'), // ⚠️ 안쪽에 따옴표 포함해야 함
      JSON.parse('true'),
      JSON.parse('null'),
      JSON.parse('[1, 2, 3]'),
      JSON.parse('{"x": 1, "y": 2}') // ⚠️ key도 따옴표로 감싸야 함
    ]
    .forEach(i => console.log(i));
    
    //1
    //가나다
    //true
    //null
    //[1, 2, 3]
    //{x: 1, y: 2}

     

    직렬화와 반대로 작동하는 것을 볼 수 있다. 

    자바스크립트 코드가 문자열로 들어가는 것이기 때문에 코드가 문자열일 경우는 따옴표로 감싸주어야 한다.

     

    2번째 인자 : receiver 함수

    const objStr = '{"a":1,"b":"ABC","c":true,"d":[1,2,3]}';
    
    const obj = JSON.parse(objStr, (key, value) => {
      if (key === 'c') { 
        // 해당 프로퍼티 생략
        return undefined;
      }
      if (typeof value === 'number') {
        return value * 100;
      }
      return value;
    });
    
    console.log(obj); // ⚠️ 내부까지 적용(배열 확인해 볼 것)
    //a: 100, b: 'ABC', d: Array(3)}

    내부까지 적용이 된 것을 볼 수 있다.

     

    III. 깊은 복사 deep copy

    JSON을 이용하면 깊은 복사가 가능하다.

    const obj1 = {
      a: 1,
      b: {
        c: 2,
        d: {
          e: 3,
          f: {
            g: 4
          }
        }
      }
    }
    
    const obj2 = JSON.parse(JSON.stringify(obj1));
    
    console.log(obj1);
    console.log(obj2);
    
    obj1.a++;
    obj1.b.c++;
    obj1.b.d.e++;
    obj1.b.d.f.g++;
    
    console.log(obj1);
    console.log(obj2);

    obj2에 obj1을 직렬화 한것에 역직렬화를 한것을 할당했고 obj1의 프로퍼티를 1씩 증가시킨다음 둘다 출력을 해보면 다음과 같다.

    obj2는 obj1의 영향을 받지 않은 것을 볼 수 있다. 

    이유는 obj2는 obj1과 같은 값을 참조하는 게 아니라 문자열을 받아서 그걸 해석해서 값이 나온(역직렬화) 완전 새로운 것을 obj2에 할당 했기 때문이다. 완전히 다른 객체가 할당이 된 것.

     

    함수, Date, Symbol, BigInt 프로퍼티는 JSON 방식으로는 불가 또는 제한적이라는 사실을 알고 넘어가자.

     

    structuredClone이라는 것이 있다. 특징은 다음과 같다

    • 아직은 일부 브라우저 및 환경에서만 지원한다.
    • JSON 방식보다 빠르고 효율적인 깊은 복사가 된다.
    • Date와 BigInt를 제대로 복사한다.

    일단은 이런게 있다는 사실만 알고 넘어가자.

Designed by Tistory.