자바 스크립트 (2) 객체와 불변성이란?

김민섭·2022년 9월 23일
0

JavaScript

목록 보기
2/7

기본형 데이터와 참조형 데이터

참고할 사이트 https://webclub.tistory.com/638

기본형 데이터는 메모리에 값을 바로 할당하는 것.
참조형은 값이 저장된 주소값을 할당하는 것.

JavaScript 형 변환

함수와 연산자에 전달되는 값은 대부분 적절한 자료형으로 자동 변환됩니다. 이런 과정을 "형 변환(type conversion)"이라고 합니다.

alert가 전달받은 값의 자료형과 관계없이 이를 문자열로 자동 변환하여 보여주는 것이나, 수학 관련 연산자가 전달받은 값을 숫자로 변환하는 경우가 형 변환의 대표적인 예시입니다.

이 외에, 전달받은 값을 의도를 갖고 원하는 타입으로 변환(명시적 변환)해 주는 경우도 형 변환이라고 할 수 있습니다.

출처: https://ko.javascript.info/type-conversions

즉, <함수와 연산자에 전달되는 값이 적절한 형태로 자동 변환되는 것>
<의도를 갖고 원하는 타입으로 변환시키는 것> 이 두개를 가리켜 형 변환 이라고 한다.

불변 객체를 만드는 방법

  • 불변 객체란?
    단어에서도 알 수 있다시피 불변 객체는 <변하지 않는 객체>
    즉, 이미 할당된 객체가 변하지 않는다는 뜻이다.

어떻게 하면 변하지 않는 객체를 만들 수 있을까?

자바 스크립트에서는 두 가지 방법이 있다.

  • const를 사용하는 것.
    const는 변수를 상수로 선언할 수 있다.

    !! const는 재할당은 불가능 하지만 객체의 속성변경은 가능하다 !!
    속성을 변경하더라도 객체와 변수사이의 바인딩은 변경이 되지 않기 때문이다. (이 부분은 좀 더 공부가 필요하다고 생각된다.)

  • Object.freeze()를 사용하는 것
    공식 문서에는 "객체를 동결하기 위한 메소드" 라고 적혀있다.

    이 메소드의 사용법은

    let obj = {
        prop: 42
    };
    
    Object.freeze(obj)

    key, value를 가진 객체를 바인딩 후 Object.freeze(test)를 사용해 동결객체로 만들면 된다.

    Object.freeze()로 동결된 객체에는 속성을 추가하거나 제거하는 동작이 불가능하다.

위의 내용을 정리하면

const: 재할당은 허용하지 않지만 객체의 속성을 변경하는 것은 가능하다.
Object.freeze(): 객체의 속성을 변경하는 것은 불가능하지만 재할당은 가능하다.

결론

불변하는 객체를 만들기 위해서는 const와 Object.freeze를 함께 사용하면 된다.

const obj = {
    prop: 42
};

Object.freeze(obj)

얕은 복사와 깊은 복사

우선 두 개의 특징들을 정리해보았다.

  • 깊은 복사
    (1) 데이터 자체를 통째로 복사한다
    (2) 복사된 두 객체는 완전히 독립적인 메모리를 차지한다
    (3) 기본 자료형 객체들

아래의 예시처럼 string1을 string2에 할당한다. 그 이후 string1의 값을 변경해도 string2의 값에는 영향이 없다.

let string1 = "hello"
let string2 = string1;

console.log("string1: " + string1)
console.log("string2: " + string2)

string1 = "elly"
console.log("string1: " + string1)
console.log("string2: " + string2)

result
----------------------------------
string1: hello
string2: hello
string1: elly
string2: hello
  • 얕은복사
    (1) 인스턴스를 메모리에 새로 생성하지 않는다.
    (2) 값을 복사하는 것이 아니라 메모리의 주소값을 복사한다.
    (3) 참조 자료형 객체들

값을 복사하는 것이 아닌 메모리의 주소를 복사하는 것이기 때문에 아래의 예시처럼 arr1의 값이 변하면 arr2의 값도 변한다.

let arr1 = ["elly", "ios"]
let arr2 = arr1;

console.log(arr1)
console.log(arr2)

arr1[0] = "velog"

console.log(arr1)
console.log(arr2)

result
---------------------------------
[ 'elly', 'ios' ]
[ 'elly', 'ios' ]
[ 'velog', 'ios' ]
[ 'velog', 'ios' ]

그렇다면 참조 자료형은 깊은 복사가 불가능한 것일까?

내가 찾아본 방법은
JSON.parse(JSON.stringify())를 사용하는 것이다.

let arr1 = ["elly", "ios"]
let arr2 = JSON.parse(JSON.stringify(arr1))

console.log(arr1)
console.log(arr2)

arr1[0] = "velog"

console.log(arr1)
console.log(arr2)

result
------------------------
[ 'elly', 'ios' ]
[ 'elly', 'ios' ]
[ 'velog', 'ios' ]
[ 'elly', 'ios' ]

JSON.Stringify는 받아온 iterable을 String으로 변환하며, JSON.parse는 변환된 문자를 다시 객체로 되돌려 주는 역활을 한다.

하지만 이 방법에는 다음과 같은 문제점들이 존재한다고 한다.

  • BigInt (ECMA 2020 도입) 을 처리할 수 없다. (에러 반환)

  • Date와 같은 객체는 Stringify 적용 시 보여지는 방식도 변환한다.

  • 함수, 정규표현식, Infinity 등의 데이터 역시 변환이 안 된다.

  • 다른 방법에 비해 속도가 느리다.

더 나은 방법은 계속해서 찾아봐야겠다.

profile
getting ready to run

0개의 댓글