λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ“‚ Language/JavaScript

JavaScript μ›μ‹œ μžλ£Œν˜•κ³Ό μ°Έμ‘° μžλ£Œν˜•μ— λŒ€ν•΄ μ‰½κ²Œ 이해해 보자.

by Dev. Ella 2023. 3. 2.

1. μ›μ‹œ μžλ£Œν˜•κ³Ό μ°Έμ‘° μžλ£Œν˜•μ΄λž€?

number, string, boolean, undefined, nullκ³Ό 같은 μžλ£Œν˜•μ€ κ³ μ •λœ μ €μž₯ 곡간을 μ°¨μ§€ν•œλ‹€. 이런 νŠΉμ§•μ„ 가진 μžλ£Œν˜•μ„ μ›μ‹œ μžλ£Œν˜•(primitive data type)μ΄λΌλŠ” μ΄λ¦„μœΌλ‘œ λΆ„λ₯˜ν•œλ‹€. λ°˜λ©΄μ— λŒ€λŸ‰μ˜ 데이터λ₯Ό 닀루기에 μ ν•©ν•œ λ°°μ—΄κ³Ό 객체, ν•¨μˆ˜ λ“±μ˜ μžλ£Œν˜•μ€ μ°Έμ‘° μžλ£Œν˜•(reference data type)이라고 λΆ„λ₯˜ν•œλ‹€.

 

μ›μ‹œ νƒ€μž… λ°μ΄ν„°λŠ” 각 λ³€μˆ˜κ°„μ˜ μ›μ‹œνƒ€μž… 데이터λ₯Ό 볡사할 경우, 데이터 값이 λ³΅μ‚¬λ˜κΈ° λ•Œλ¬Έμ— 기쑴의 데이터에 영ν–₯이 가지 μ•ŠμŒ. μ°Έμ‘° νƒ€μž… λ°μ΄ν„°λŠ” μ£Όμ†Œλ₯Ό λ³΅μ‚¬ν•œλ‹€. λ•Œλ¬Έμ— λ³΅μ‚¬ν•œ λ°μ΄ν„°μ—μ„œ μ›μ†Œλ₯Ό λ³€κ²½ν•˜κ²Œ λœλ‹€λ©΄ μ£Όμ†Œ μ•ˆμ— μžˆλŠ” 데이터가 변경이 λ˜λŠ” 것이기에 기쑴의 데이터에도 영ν–₯이 κ°€λŠ” 것이닀. μ‰½κ²Œ μ„€λͺ…ν•˜μžλ©΄, μ›μ‹œ μžλ£Œν˜•μ΄ 할당될 λ•ŒλŠ” λ³€μˆ˜μ— κ°’(value) μžμ²΄κ°€ λ‹΄κΈ°κ³ , μ°Έμ‘° μžλ£Œν˜•μ΄ 할당될 λ•ŒλŠ” λ³΄κ΄€ν•¨μ˜ μ£Όμ†Œ(reference)κ°€ λ‹΄κΈ΄λ‹€κ³  ν•  수 μžˆλ‹€. λ˜ν•œ μ°Έμ‘° μžλ£Œν˜•μ€ 기쑴에 κ³ μ •λœ 크기의 보관함이 μ•„λ‹ˆλΌ, λ™μ μœΌλ‘œ 크기가 λ³€ν•˜λŠ” νŠΉλ³„ν•œ 보관함이닀.

 

 

2. μ›μ‹œ μžλ£Œν˜•κ³Ό μ°Έμ‘° μžλ£Œν˜•μ˜ 각 νŠΉμ§•

μ›μ‹œ μžλ£Œν˜•

- μ›μ‹œ μžλ£Œν˜•μ„ λ³€μˆ˜μ— ν• λ‹Ήν•˜λ©΄ λ©”λͺ¨λ¦¬ 곡간에 'κ°’ 자체'κ°€ μ €μž₯λœλ‹€.

- μ›μ‹œ 값을 κ°–λŠ” λ³€μˆ˜λ₯Ό λ‹€λ₯Έ λ³€μˆ˜μ— ν• λ‹Ήν•˜λ©΄ μ›μ‹œ κ°’ μžμ²΄κ°€ λ³΅μ‚¬λ˜μ–΄ μ „λ‹¬λœλ‹€.

- μ›μ‹œ μžλ£Œν˜•μ€ 'λ³€κ²½ λΆˆκ°€λŠ₯ν•œ κ°’(immutable value)' 즉, ν•œ 번 μƒμ„±λœ μ›μ‹œ μžλ£Œν˜•μ€ μ½κΈ°μ „μš©(read only) 값이닀.

μ°Έμ‘° μžλ£Œν˜•

- μ°Έμ‘° μžλ£Œν˜•μ„ λ³€μˆ˜μ— ν• λ‹Ήν•˜λ©΄ λ©”λͺ¨λ¦¬ 곡간에 'μ£Όμ†Œκ°’'이 μ €μž₯λœλ‹€.

- μ°Έμ‘° 값을 κ°–λŠ” λ³€μˆ˜λ₯Ό λ‹€λ₯Έ λ³€μˆ˜μ— ν• λ‹Ήν•˜λ©΄ μ£Όμ†Œκ°’μ΄ λ³΅μ‚¬λ˜μ–΄ μ „λ‹¬λœλ‹€.

- μ°Έμ‘° μžλ£Œν˜•μ€ 변경이 κ°€λŠ₯ν•œ κ°’(mutable value)이닀.

 

 

3.  JavaScriptκ°€ μ°Έμ‘° μžλ£Œν˜•μ„ μ €μž₯ν•˜λŠ” 방법

νž™(heap) μ΄λΌλŠ” μ €μž₯곡간에 μ°Έμ‘° μžλ£Œν˜•μ„ μ €μž₯ν•œ ν›„, κ·Έ μ €μž₯곡간을 μ°Έμ‘°ν•  수 μžˆλŠ” μ£Όμ†Œκ°’μ„ λ³€μˆ˜μ— μ €μž₯ν•œλ‹€. λ”°λΌμ„œ λ³€μˆ˜μ— ν•΄λ‹Ήν•˜λŠ” μ €μž₯κ³΅κ°„μ—λŠ” μ£Όμ†Œκ°’μ΄ μ €μž₯λ˜μ–΄ 있고, κ·Έ μ£Όμ†Œκ°’μ„ 톡해 μ°Έμ‘° μžλ£Œν˜•μ—κ²Œ μ ‘κ·Όν•˜λŠ” 것이닀. 이 접근을 'μ°Έμ‘°ν•œλ‹€(refer)'κ³  ν•œλ‹€.

 

 

4.  μ›μ‹œ κ°’ 자체λ₯Ό 볡사 vs. μ£Όμ†Œκ°’μ„ 볡사

λ§Œμ•½ μ–΄λ–€ λ³€μˆ˜μ— μ €μž₯λ˜μ–΄ μžˆλŠ” μ›μ‹œ μžλ£Œν˜•μ„ λ‹€λ₯Έ λ³€μˆ˜μ— ν• λ‹Ήν•œλ‹€λ©΄, μ›μ‹œ μžλ£Œν˜•μ€ κ°’ μžμ²΄κ°€ λ³΅μ‚¬λœλ‹€. λ”°λΌμ„œ λ³€μˆ˜ numκ³Ό λ³€μˆ˜ copiedNum은 λ™μΌν•˜κ²Œ 20μ΄λΌλŠ” 값을 가진닀.

let num = 20;
let copiedNum = num;

 

μ°Έμ‘° μžλ£Œν˜•μ€ 이와 달리 μ£Όμ†Œκ°’μ„ λ³΅μ‚¬ν•œλ‹€. 즉, μ°Έμ‘°μžλ£Œν˜•μ΄ ν• λ‹Ήλœ λ³€μˆ˜λ₯Ό λ‹€λ₯Έ λ³€μˆ˜μ— ν• λ‹Ήν•˜λ©΄, 이 두 λ³€μˆ˜λŠ” 같은 μ£Όμ†Œλ₯Ό 가리킨닀.

let arr = [0, 1, 2, 3];
let copiedArr = arr;

 

μ •λ¦¬ν•˜μžλ©΄, κ°’ 자체λ₯Ό λ³΅μ‚¬ν•˜λŠ” μ›μ‹œ μžλ£Œν˜•κ³Ό 달리, μ°Έμ‘° μžλ£Œν˜•μ„ ν• λ‹Ήν•œ λ³€μˆ˜λ₯Ό λ‹€λ₯Έ λ³€μˆ˜μ— ν• λ‹Ήν•  경우 '같은 μ£Όμ†Œ'λ₯Ό μ°Έμ‘°ν•˜κ³  μžˆλŠ” 것이닀.

// μ›μ‹œ μžλ£Œν˜•μ΄ 참쑰된 λ³€μˆ˜λ₯Ό λ‹€λ₯Έ λ³€μˆ˜μ— ν• λ‹Ήν•˜κΈ°
let num = 20;
let copiedNum = num;

// μ°Έμ‘° μžλ£Œν˜•μ΄ ν• λ‹Ήλœ λ³€μˆ˜λ₯Ό λ‹€λ₯Έ λ³€μˆ˜μ— ν• λ‹Ήν•˜κΈ°
let arr = [0, 1, 2, 3];
let copiedArr = arr;

// 두 λ³€μˆ˜κ°€ 같은지 ν™•μΈν•˜κΈ° - 1
console.log(num === copiedNum); // true
console.log(arr === copiedArr); // true

// 원본을 λ³€κ²½ν•˜κΈ°
num = 30;
arr.push(4);

// 두 λ³€μˆ˜κ°€ 같은지 ν™•μΈν•˜κΈ° - 2
console.log(num === copiedNum); // false: μ›μ‹œμžλ£Œν˜•μ€ 원본(num)에 λ‹€λ₯Έ 값을 할당해도 볡사본(copiedNum)에 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠμŒ
console.log(arr === copiedArr); // true: μ°Έμ‘°μžλ£Œν˜•μ€ 원본(arr)을 λ³€κ²½ν•˜λ©΄ 볡사본(copiedArr)도 영ν–₯을 받기에 동일해짐

// 이 두 λ³€μˆ˜μ˜ ν˜„μž¬ μƒνƒœλŠ”?
console.log(copiedNum); // 20
console.log(copiedArr); // [0, 1, 2, 3, 4];

 

 

5. λ³€κ²½ λΆˆκ°€λŠ₯ν•œ κ°’ vs. 변경이 κ°€λŠ₯ν•œ κ°’

μ›μ‹œ μžλ£Œν˜•

ν•œ 번 μƒμ„±λœ μ›μ‹œ 값은 λ³€κ²½ν•  수 μ—†λ‹€. numμ΄λΌλŠ” λ³€μˆ˜λ₯Ό μ„ μ–Έν•˜κ³  숫자 20을 ν• λ‹Ήν•΄ 보겠닀.

let num = 20;

 

μ—¬κΈ°μ„œ λ³€μˆ˜ num에 ν• λ‹Ήλœ 값을 숫자 20λŒ€μ‹  λ‹€λ₯Έ κ°’μœΌλ‘œ λ³€κ²½ν•˜κ³ μž ν•œλ‹€λ©΄, λ‹€λ₯Έ 값을 λ³€μˆ˜μ— μž¬ν• λ‹Ή ν•˜λ©΄ λœλ‹€.

num = 30;

 

λ³€μˆ˜μ— ν• λ‹Ήλœ 값이 20μ—μ„œ 30으둜 λ³€κ²½λ˜μ—ˆκΈ°μ— μ›μ‹œ μžλ£Œν˜•μΈ 숫자 νƒ€μž…μ˜ 값이 λ³€κ²½λœ κ²ƒμ²˜λŸΌ 보인닀. κ·Έλ ‡λ‹€λ©΄ μ›μ‹œ μžλ£Œν˜•μ΄ λ³€κ²½ λΆˆκ°€λŠ₯ν•œ κ°’μ΄λΌλŠ” 것은 무슨 뜻인 걸까? 값을 μž¬ν• λ‹Ήν–ˆμ„ λ•Œ λ©”λͺ¨λ¦¬μ—μ„œλŠ” numμ΄λΌλŠ” λ³€μˆ˜κ°€ μ°Έμ‘°ν•˜λ˜ 곡간에 λ“€μ–΄ 있던 20이 κ·ΈλŒ€λ‘œ 30으둜 변경될 것 κ°™μ§€λ§Œ, λ©”λͺ¨λ¦¬ λ‚΄λΆ€μ—μ„œλŠ” 30μ΄λΌλŠ” μ›μ‹œ 값을 μ €μž₯ν•˜κΈ° μœ„ν•œ 'μƒˆλ‘œμš΄ 곡간을 확보'ν•œ λ’€, κ·Έ 곡간에 numμ΄λΌλŠ” 이름을 뢙이고 30을 μ €μž₯ν•˜λŠ” 것이닀. 즉, 20번 사물함이 30번으둜 λ³€κ²½λœ 것이 μ•„λ‹ˆλΌ 20번 사물함과 30번 사물함이 λ³„κ°œλ‘œ μ‘΄μž¬ν•˜λŠ” 것이닀. (숫자 νƒ€μž… 뿐만 μ•„λ‹ˆλΌ, λ¬Έμžμ—΄λ„ λ§ˆμ°¬κ°€μ§€λ‹€.)

 

copyright @unsplash

 

λ”°λΌμ„œ μ›μ‹œ μžλ£Œν˜•μ€ μ–΄λ–€ μƒν™©μ—μ„œλ„ λΆˆλ³€ν•˜λŠ” 읽기 μ „μš© 데이터인 것이닀. μ΄λŠ” μ›μ‹œ μžλ£Œν˜•μ΄ 높은 신뒰성을 κ°€μ§ˆ 수 μžˆλŠ” μš”μΈμ΄κΈ°λ„ ν•˜λ‹€. κ·Έλ ‡λ‹€λ©΄ 남아 μžˆλŠ” κ°’ 20은 μ–΄λ–»κ²Œ 될까? JavaScript 엔진은 이처럼 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 값을 μžλ™μœΌλ‘œ λ©”λͺ¨λ¦¬μ—μ„œ μ‚­μ œν•˜λ©°, μ΄λŸ¬ν•œ κΈ°λŠ₯을 가비지 μ½œλ ‰ν„°(garbage collector)라고 ν•œλ‹€. 단, garbage collectorκ°€ μ–΄λŠ μ‹œμ μ— μ§„ν–‰λ˜λŠ”μ§€λŠ” μ˜ˆμΈ‘ν•  수 μ—†λ‹€.

 

μ°Έμ‘° μžλ£Œν˜•

반면 μ°Έμ‘° μžλ£Œν˜•μ€ λ³€κ²½ κ°€λŠ₯ν•œ 값이닀. μ›μ‹œ μžλ£Œν˜•μ˜ 경우 κ°’μ˜ 크기가 거의 μΌμ •ν•˜κΈ° λ•Œλ¬Έμ— μƒˆλ‘œμš΄ 곡간을 ν™•λ³΄ν•˜μ—¬ 값을 λ³΅μ‚¬ν•˜λŠ” 방법이 μœ μš©ν•˜μ§€λ§Œ, 크기가 μΌμ •ν•˜μ§€ μ•Šμ€ μ°Έμ‘° μžλ£Œν˜•μ˜ 경우 맀번 값을 λ³΅μ‚¬ν•œλ‹€λ©΄ 그만큼 νš¨μœ¨μ„±μ€ λ–¨μ–΄μ§ˆ μˆ˜λ°–μ— μ—†λ‹€. 이런 이유둜 μ°Έμ‘° μžλ£Œν˜•μ€ 변경이 κ°€λŠ₯ν•˜λ„λ‘ μ„€κ³„λ˜μ–΄ μžˆλ‹€.

arr[3] = '3';
arr.push(4);
arr.shift();

console.log(arr); // [1, 2, '3', 4] : μœ„ μ½”λ“œκ°€ μ‹€ν–‰λ˜λ©΄, λ³€μˆ˜κ°€ μ°Έμ‘°ν•˜κ³  μžˆλŠ” μ£Όμ†Œμ— μ €μž₯λ˜μ–΄ μžˆλŠ” 값을 변경함

 

참고둜, λ¬Έμžμ—΄μ€ μ›μ‹œ μžλ£Œν˜•μ΄μ§€λ§Œ λ°°μ—΄μ²˜λŸΌ 인덱슀둜 λ¬Έμžμ—΄μ˜ 각 λ¬Έμžμ— 접근이 κ°€λŠ₯ν•˜λ‹€.

console.log(str[0]) // 's'
console.log(str[2]) // 'a'

 

ν•˜μ§€λ§Œ λ°°μ—΄κ³ΌλŠ” 달리 μΈλ±μŠ€μ— 직접 λ‹€λ₯Έ 문자λ₯Ό ν• λ‹Ήν•˜μ—¬ 값을 λ³€κ²½ν•  μˆ˜λŠ” μ—†λ‹€. μ•„λž˜ μ˜ˆμ‹œ μ½”λ“œμ™€ 같이 λ¬Έμžμ—΄λ„ μ›μ‹œ μžλ£Œν˜•μ΄κΈ° λ•Œλ¬Έμ— κ°’ 변경이 λΆˆκ°€ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. 

let str = '코딩은';
str = 'μž¬λ°Œμ–΄';

str[2] = 'μ—‰';
console.log(str); // μž¬λ°Œμ–΄

λŒ“κΈ€