dohun.log

[JS] 원시 값과 객체의 비교 본문

Study/JavaScript

[JS] 원시 값과 객체의 비교

dohun31 2022. 5. 10. 01:13

1. 원시 값

변경 불가능한 값

원시 타입의 값은 변경 불가능한 값이다. (only 읽기 모드)

 

어? 그럼 내가  사용했던 변수는 뭐야...(예나, 선정이 딸이에요 "변수, 원시 딸이에요..")

 

다시 개념을 정리하면 변수는 메모리 공간에 저장된 값을 식별하는 "식별자"이고, 값은 메모리 공간에 저장된 "값"이다.

 

그럼 앞의 말은 다음과 같은 의미이다.

메모리 공간에 저장된 원시 타입의 값은 변경 불가능한 값이다.

메모리 공간에 저장된 값을 변경하지 않으면 된다!

 

그러면 변수의 재할당은 어떻게 가능한걸까?

이전에 값의 재할당에서도 봤듯이 새로운 메모리 공간에 재할당하려는 값을 저장하고 변수가 새로운 메모리 공간을 가리키게 하면 된다.

 

상수는 이러한 재할당이 금지된 변수이다. (const!!)

문자열과 불변성

문자열은 원시타입이다. 그렇다면 불변성을 가진다.

 

'dohun'이라는 값을 변수 str에 선언하고 'hodun'이라는 값을 재할당하면 str 변수는 'dohun'을 가리키다가 'hodun'을 가리킨다.

let str = 'dohun';
console.log(str); // 'dohun'

str = 'hodun';
console.log(str); // 'hodun'

문자열은 유사 배열 객체이면서 iterable이다. 그렇다면 인덱스를 통해 문자에 접근하거나 객체처럼 멤버 변수와 메소드를 사용할 수 있다.

let str = 'dohun';

// 인덱스 접근 가능
console.log(str[0]); // 'd'

// 객체처럼 멤버 변수와 메소드 사용 가능
console.log(str.length); // 5
console.log(str.toUpperCase()); // 'DOHUN'

하지만 앞에서도 말했듯이 불변성을 가지므로 다음과 같이는 사용할 수 없다. 또 다음과 같이 사용할 때 문법적인 에러가 발생하지 않으므로 코테볼때 조심 또 조심!

let str = 'dohun';

str[0] = 'D';
console.log(str); // 'dohun'

 

값에 의한 전달

처음 프로그래밍 언어를 배울때 배열에서 제일 처음으로 막히고 그 다음에 call by value, call by reference에서 막혔는데 거기서 후자를 담당하고 있는 녀석이다.

let score = 80;

let copy = score;

console.log(score, copy); // 80, 80
console.log(score === copy); // true

score = 100;

console.log(score, copy); // 100, 80
console.log(socre === copy); // false

차근 차근 살펴봅시다~

let score = 80;

let copy = socre;

 

score라는 변수에 80이라는 값을 할당해주었다. 그리고 copy라는 변수에 score를 할당해주었다..?

변수에 변수를 할당하면 변수의 값이 변수에 할당이된다.

즉, score를 copy에 할당하면 score의 값인 80이 copy에 할당이 되는 것이다.

console.log(score, copy); // 80, 80
console.log(socre === copy); // true

당연히 copy에는 score에 할당된 값인 80이 저장되었기 때문에 true!

score = 100;

그런데 score의 값이 바뀐다면 copy의 값은 여전히 80일까?

console.log(score, copy); // 100, 80
console.log(score === copy); // false

답은 여전히 80이다. copy에는 score에 할당된 "값"이었던 80이 저장되었기 때문이다.

 

만약 값이 아니라 score의 주소가 저장되어 있었다면 score를 가리키고 있기 때문에 copy가 가리키는 값도 score의 값이 바뀜에 따라 같이 바뀔 것이다. (이것은 뒤에서 배울 참조에 의한 전달이다.)

 

2. 객체

변경 가능한 값

원시 값과 다르게 객체는 변경이 가능하다.

 

객체에서 원시 값을 갖는 변수의 값을 변경하려면 직접 메모리에 저장된 객체를 직접 수정하면 된다!!

 

참조에 의한 전달

let person = {
	name: 'Lee'
};

// 얉은 복사
let copy = person;

값에 의한 전달과 다르게 객체는 메모리 주소를 전달한다. (원본을 보내버림..)

따라서 person이라는 식별자와, copy라는 식별자 총 2개의 식별자가 하나의 객체를 공유한다.

 

이 때 person이나 copy 중에 어느 한쪽이라도 수정 또는 삭제를 한다면 다른 한쪽에게도 영향을 끼치게 된다.

copy.name = 'Baek';

person.address = 'Busan';

console.log(person); // {name: 'Baek', address: 'Busan'}
console.log(copy); // {name: 'Baek', address: 'Busan'}

3. 비교

  특징 전달
원시 값 불변성 값에 의한 전달
객체 가변성 참조에 의한 전달

4. 탐구

const arr = Array(3).fill(Array(3).fill(1));
arr[0][0] = 0;

console.log(arr); // ?

예상: [[0, 1, 1], [1, 1, 1], [1, 1, 1]]

결과: [[0, 1, 1], [0, 1, 1], [0, 1, 1]]

 

다음과 같이 생각하면 된다.

먼저 다음과 같은 insideArr이 생성된다. (메모리 주소는 0x00FF라고 가정)

const insideArr = Array(3).fill(1);

 그리고 arr를 insideArr로 채워준다.

const arr = Array(3).fill(insideArr);

그럼 arr에는 3개의 insideArr로 채워진다. 이 insideArr는 같은 주소를 공유하기때문에 arr[0][0]이 변하게 되면 다른 insideArr의 0번째 인덱스 값도 같이 변하게 된다!

 

의도한대로 하려면 다음과 같이 직접 새로운 객체를 생성해주면 된다.

const arr = Array(3).fill(0).map(() => Array(3).fill(1));
arr[0][0] = 0;

console.log(arr);

결과: [ [ 0, 1, 1 ], [ 1, 1, 1 ], [ 1, 1, 1 ] ]

 

😀 의도한대로 잘 된다!

Comments