Posts 원시 값과 객체의 비교
원시 값과 객체의 비교
Cancel

원시 값과 객체의 비교

오늘은 원시 값과 객체 값이 어떻게 다른지 알아볼 것이다.
이것을 위해서 앞에서 내용 정리를 했었다.
기본을 알아야 이후 내용도 이해할 수 있으니까!


원시 값

원시 값은 한 마디로 “변경 불가능한 값”을 이야기 한다.
한 번 만들어진 원시 값은
읽기 전용이며 변경할 수 없다.

그런데 여기까지만 보면
아닌데? 변수 값을 우리는 바꾸는데?
라고 할 수도 있다.

변수 값이 어떻게 저장되는지 보면 이해할 것이다.
먼저, 원시 값과 변수 값은 서로 다른 개념이다.

“변수”는 값을 저장하기 위한 메모리 공간이며
“값”은 데이터를 의미한다.

처음에 변수에 대해서도 얘기했지만,
우리가 변수에 값을 선언하면
변수는 먼저 메모리 공간을 확보한다.

1~20층 짜리 메모리 공간이 있다면,
우리가 변수를 선언하면 그 층 중 하나를 가져온다.
그리고 값을 할당하면
새로운 층을 하나 가져와서 그곳에 넣는 것이다.
변수를 재할당하면
기존의 층에 다시 값을 넣는 것이 아니라,
새로운 층을 확보하고 그곳에 값을 넣는다.

이러한 값의 특성을 “불변성”이라고 한다.

image


문자열과 불변성

원시 값을 저장하기 위해서는 메모리 공간의 크기를 결정해야 한다.
또한 원시 값 타입에 대해 메모리 크기가 미리 정해져 있다.

그 중 문자열은 조금 독특하다.
문자열은 1개 문자당 2바이트의 메모리 공간에 저장된다.
그래서 문자열이 길면 메모리도 늘어나느 것이다.

하지만 숫자 값은 1이나 10000이나 똑같은 메모리를 차지한다.

또한 문자열은 유사 배열 객체로 처리가 된다.
유사 배열 객체란
인덱스로 값에 접근할 수 있고 length 프로퍼티를 갖는 것을 이야기 한다.
그래서 문자열은 아래의 코드가 가능한 것이다.

1
2
3
let str = "abc"
str[0] // "a"
str.length // 3

문자열도 원시 값이기 때문에 불변성이다.
그래서 아래 코드가 먹히지 않는다.

1
2
3
let str ="abc"
str[0] = "A"
console.log(str) // "abc"

값에 의한 전달

여기서 조금 핵심적인 이야기를 할 것이다.

1
2
3
4
5
6
7
let score = 80;
let copy = 90;

score = 100;

console.log(score) // ?
console.log(copy) // ?

위에서 console.log()값이 무엇일까?
변수에 변수를 할당 했을 때 어떤 것이 전달되는가?
이것이 핵심이다.

우선 copy에는 score의 원시 값이 복사되어 전달된다.
이런 걸 “값에 의한 전달”이라고 한다.

하지만 둘은 서로 다른 메모리 공간에 저장된, 실상은 서로 별개이다.
서로 갖고 있는 메모리 공간이 다른 것이다.

그래서 score에 100을 새롭게 할당하면
score은 다시 새로운 메모리 공간을 갖게 된다.
그래서 socre, copy는 서로 다른 메모리 공간과 서로 다른 원시 값을 갖게 된다.
결국 console.log()의 결과는 100, 80인 것이다.

또 한 가지, 중요한 점을 보자면
사실 변수도 “원시 값”을 기억하고 있는 것이 아니라,
메모리 공간의 위치를 기억하고 있는 것이다.

그래서 “값의 의한 전달”보다는 더 정확하게는
“메모리 공간의 위치, 혹은 주소”를 전달 하는 것이다.


객체

객체는 일반 원시 값과 다른 점은,
객체의 프로퍼티(키와 값)은 정해져 있지 않고,
언제든지 추가, 삭제가 가능하다.
변경이 가능한 값이다.

이렇게 동적으로 항상 메모리가 변하는 객체는
메모리 공간을 얼마나 확보해둬야 하는지 예측할 수 없다.

그래서 객체는 원시 값과 다른 방식으로 작동한다.

먼저
변수에 객체를 할당하게 되면
변수는 메모리 주소를 기억하는 것이다.
이것을 “참조 값”이라고 한다. 메모리 공간의 주소, 위치 그 자체이다.

image

사진을 보면 이해가 쉬울 것이다.

변수에서도 이야기 했지만,
변수가 할당된 “메모리 공간의 주소”를 직접 찾아가면
해당 메모리 공간에 저장된 값에 접근할 수 있다고 했었다.

그 방식으로 객체를 저장하는 것이다.

그래서 원시 값을 갖고 있는 변수는
변수는 xx값이다 라고 하는 것이고

객체 값을 갖고 있는 변수는
객체를 참조하고 있다. 라고 표현 하는 것!

그래서 객체의 값을 우리가 변경해도
메모리 주소 값은 변경되지 않는다.

원시 값의 재할당과는 완전히 다른 개념이다.


얕은 복사와 깊은 복사

위의 처럼 객체는 메모리 주소를 참조하다 보니
객체 값을 저장할 때 구조적 부작용이 있다.

얕은 복사와 깊은 복사는 우선 모두
원본과는 다른 객체로 생성이 된다.
애초에 참조 값이 다른 별개의 객체인 것이다.

하지만 객체 안에 객체가 있으면 조금 차이가 생긴다.

1
2
3
4
5
6
let a = { x: { y : 1 }}
let b = { ...a};

console.log(a === b) // true
console.log(a.x === b.x) // false

먼저 얕은 복사는 객체 안에 객체가 있을 경우
겉에 있는 객체의 참조 값을 복사한다.
그래서 처음에는 true로 나오지만
안에 들어가면 false가 나온다.

1
2
3
4
5
6
let a = { x: { y : 1 }}
let b = _cloneDeep(a)

console.log(a === b) // false
console.log(a.x === b.x) // false

하지만 깊은 복사는 안에 있는 값까지 모두 복사해서
새로운 값을 만들게 된다.

이러한 얕은 복사에는 단점이 생긴다.

1
2
3
let a = { name: "Lee"}
let b = a

이렇게 얕은 복사를 하면 b는 실제로 { name: “Lee”}를 저장하는 것이 아니다.
a의 메모리 주소를 저장하는 것이다.

그래서 a의 값을 수정하면 b의 값도 같이 수정되는 일이 발생하게 된다.
이런 것을 “참조에 의한 전달”이라고 한다.


마지막 비교

1
2
3
4
5
6
7
8
9
10
let a = {
 name : "Lee"
}
let b = {
 name : "Lee"
}
console.log(a===b)
console.log(a.name ===b.name)
}

위의 코드를 살펴보자.
우선 첫 번쨰 console.log()는 fasle이다.

객체 값을 할당하게 되면 “메모리 주소 값”을 비교하게 된다.
두 객체의 내용은 같지만 서로 다른 메모리 주소를 갖고 있기에 false가 나온다.

하지만 두 번째 console.log()는 true가 나온다.
원시 값을 비교하게 되면
메모리 주소 값을 비교하는 것이 아니라
평가되는 원시 값인 “Lee”를 비교하게 돼서 true이다.


마무리

그동안 조금 겉핥기로 알고 있었던 것들이
책을 읽으면서 더 정확하고 명확한 지식이 됐다.
이래서 블로그 보다 책을 읽으라고 하는 것 같다.

나에게 너무 많은 지식과 개념을 알려주는 책..
고맙다!

This post is licensed under CC BY 4.0 by the author.

객체에 대해 알아보자

함수에 대해서 알아보자

Comments powered by Disqus.