데이터 타입 (기본형과 참조형의 차이점)

Lee·2022년 9월 13일
1

프론트엔드-개념

목록 보기
1/1
post-thumbnail

변수를 복사할때 차이점

      let a = 3;
      let b = a;
      b = 5;
      console.log(a === b); // false

      let object = { aa: 1, bb: "bb", cc: "1c" };
      let object2 = object;
      object2.cc = "c";
      console.log(object === object2); // true

똑같이 변수 하나를 선언하고(여기서는 a, object) 다른 변수(b, object2)에 복사를 했다. 같은 방법을 사용했기 때문에 같은 결과가 나올것 같지만 다른 결과가 나왔다. 그 이유는 데이터 타입에 따른 메모리에 할당하는 법이 다르기 때문이다.

데이터 타입의 종류
기본형 : Number, String, Boolean, null, undefined, Symbol
참조형 : Array, Function, Date, RegExp, Map, WeakMap, Set, WeakSet

기본형(메모리에서의 동작)

우선 기본형에 대해서 살펴보자

변수 선언

let a = 1;

변수 a에 숫자형 1을 할당하는 간단한 코드이다. 이 코드는 메모리 영역을 변화시킨다.

메모리
주소1002100310041005
데이터이름: a , 값 : @5002
주소5002500350045005
데이터1

주소에 바로 값을 할당하는 것이 아닌 주솟값을 할당하고 주솟값의 위치에서 데이터를 입력한다.

이렇게 하는 이유는 데이터를 효율적으로 관리할 수 있기 때문이다.
공간을 미리 확보하고 데이터를 선언하면 나중에 데이터를 변환할때 공간을 다시 바꿔야하는 경우가 생길 수 있기 때문에 연산 비용이 들어간다.

변수 복사

let a = 1;//1단계
let b = a;//2단계

b = 3//3단계

console.log(a===b)//false a = 1, b = 3

이제 단계별로 메모리를 살펴보자

1단계

let a = 1;//1단계
메모리
주소1002100310041005
데이터이름: a , 값 : @5002
주소5002500350045005
데이터1

맨위에 표와 동일하다.

2단계

let b = a;//2단계
메모리
주소1002100310041005
데이터이름: a , 값 : @5002이름 : b, 값 : @5002
주소5002500350045005
데이터1

여기서는 변수 b에 변수 a와 같이 @5002의 주솟값을 할당한다.

3단계

b = 3//3단계
메모리
주소1002100310041005
데이터이름: a , 값 : @5002이름 : b, 값 : @5003
주소5002500350045005
데이터13

이렇게 새로운 주소에 3을 할당하고 그 주솟값을 b에 할당한다.

ab에 주솟값이 다르기 때문에 a!==b이다.

참조형(메모리에서의 동작)

이제 참조형에 대해서 알아보자

변수 선언

let object = { a : 1, b : 2, c : 3 };

변수 object에 객체를 할당한다.

메모리
주소1002100310041005
데이터이름: object , 값 : @5002
주소5002500350045005
데이터@7002~?123
주소7002700370047005
데이터이름 : a, 값 : @5003이름 : b, 값 : @5004이름 : c, 값 : @5005

기본형과 똑같이 참조형도 변수에 주솟값이 담긴다. 하지만 기본형과 다르게 직접적으로 담긴 주소(@5002)에 가보면 다른 주소의 영역(@7002~?)이 담겨져있고 7002, 7003, 7004으로 가보면 1,2,3 값들이 담겨있다.

변수 복사

let object = { a : 1, b : 2, c : 3 };//1단계
let object2 = object;//2단계

object2.c = 10//3단계

console.log(object === object2)//true 
//object === { a : 1, b : 2, c : 10 } 
//object2 === { a : 1, b : 2, c : 10 }

이상하게 분명 object2.c만 바꿨는데 object.c도 같이 변해있다. 메모리가 어떻게 동작하는지 보자

1단계

let object = { a : 1, b : 2, c : 3 };//1단계
메모리
주소1002100310041005
데이터이름: object , 값 : @5002
주소5002500350045005
데이터@7002~?123
주소7002700370047005
데이터이름 : a, 값 : @5003이름 : b, 값 : @5004이름 : c, 값 : @5005

위에 선언할때 표랑 똑같다.

2단계

let object2 = object;//2단계
메모리
주소1002100310041005
데이터이름: object , 값 : @5002이름 : object2, 값 : @5002
주소5002500350045005
데이터@7002~?123
주소7002700370047005
데이터이름 : a, 값 : @5003이름 : b, 값 : @5004이름 : c, 값 : @5005

여기서 objectobject2같은 주솟값을 갖고 있다. 같은 주솟값을 갖고 있다는 것이 중요하다.

3단계

object2.c = 10//3단계
메모리
주소10021003100410051006
데이터이름: object , 값 : @5002이름 : object2, 값 : @5002
주소50025003500450055006
데이터@7002~?12310
주소70027003700470057006
데이터이름 : a, 값 : @5003이름 : b, 값 : @5004이름 : c, 값 : @5006

10@5006에 할당했다. 여기서 봐야할 것이 object2.c = 10로 값을 변경했지만 objectobject2는 똑같은 주솟값을 갖고 있다. 그래서

console.log(object === object2)//true 
//object === { a : 1, b : 2, c : 10 } 
//object2 === { a : 1, b : 2, c : 10 }

이런 결과가 나온다.

참조형 복사하기

얕은 복사

참조형을 복사하는데 원본에 영향을 안미치게 해보자
여러 방법이 있지만 개인적으로 이방법이 편한것 같다.

let object = { a : 1, b : 2, c : 3 };
let object2 = {...object}

object2.c = 10

console.log(object===object2)//false
//object ===  { a : 1, b : 2, c : 3 }
//object === { a : 1, b : 2, c : 10 }

이 방법은 얕은 복사라고 한다.
얕은 복사에는 문제가 있다. 바로 참조형안에 참조형이 있으면 복사값이 원본값에 영향을 미친다.

let deepObj = { a : 1, b : 2, c : { A : "A", B : "B" } };
let deepObj2 = {...deepObj};

deepObj2.c.B = "KK"

console.log(deepObj)//{ a : 1, b : 2, c : { A : "A", B : "KK" } }
console.log(deepObj2)//{ a : 1, b : 2, c : { A : "A", B : "KK" } }

깊은 복사

깊은 복사는 참조형안에 참조형이 들어가 있는 형태여도 복사값이 원본값에 영향을 안미친다.

      function copyObj(obj) {
        const result = {};

        for (let key in obj) {
          if (typeof obj[key] === "object") {
            result[key] = copyObj(obj[key]);
          } else {
            result[key] = obj[key];
          }
        }

        return result;
      }

이런 함수를 하나 만들어서 사용하거나

let deepObj3 = JSON.parse(JSON.stringify(deepObj));
//이 방법은 느리다

이런식으로 하면된다.

let deepObj = { a : 1, b : 2, c : { A : "A", B : "B" } };
let deepObj2 = copyObj(deepObj);

deepObj2.c.B = "KK"

console.log(deepObj)//{ a : 1, b : 2, c : { A : "A", B : "B" } }
console.log(deepObj2)//{ a : 1, b : 2, c : { A : "A", B : "KK" } }

let deepObj3 = JSON.parse(JSON.stringify(deepObj));

deepObj3.c.B = "ABC"

console.log(deepObj)//{ a : 1, b : 2, c : { A : "A", B : "B" } }
console.log(deepObj3)//{ a : 1, b : 2, c : { A : "A", B : "ABC" } }

이 글은 정재남님께서 쓰신 코어자바스크립트 책을 참고 하였습니다.
잘못된부분이나 부족한 부분이 보이신다면 알려주시면 감사하겠습니다.

profile
프론트엔드 개발자

0개의 댓글