Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

얼렁뚱땅개발로그^__^

[ UDEMY ] 자바스크립트 완벽 가이드 : 초급 + 고급 마스터 과정 119 ~ 122 본문

인강

[ UDEMY ] 자바스크립트 완벽 가이드 : 초급 + 고급 마스터 과정 119 ~ 122

나니로그 2024. 1. 17. 17:34

EP. 119

원시 vs 참조 값

 

원시값

원시 데이터 타입은 객체가 아닌 데이터 타입을 뜻한다. 객체가 아닌 데이터 타입이란 변수에 저장된 실제값에 직접적으로 접근할 수 있는 단순한 데이터라는 것을 의미한다. 또 하나의 값에 대한 정의가 절대 변하지 않는 불변성을 갖고 있다.

 

원시 값은 메모리에 저장되고 상대적으로 짧게 동작하기 때문에 거의 스택에 저장된다. 거의 스택에 저장된다고 이야기하는 이유는 함수의 실행 시간이 긴 경우에는 힙으로 저장되기도 하기 때문이다.

 

  • String
  • Number
  • Booleans
  • null
  • undefined
  • Symbol
let name = 'Max';
let age = 30;

 

원시값의 불편성이란

변수는 새로운 값을 다시 할당할 수 있지만, 이미 생성한 원시 값은 객체, 배열, 함수와 달리 변형할 수 없다.

 

// 문자열 메서드

let a = 'max'
console.log(a) // max

a.toUpperCase();
console.log(a) // max

// 배열 메서드

let array = [];
console.log(array) // []

array.push('plus')
console.log(array) // ['plus']

// 할당은 변형 X , 새로운 값을 부여 O

let b = a.toUpperCase();
console.log(b) // 'MAX'

 

let num = 5;

function addNum (n) {
	n+= 2
}

addNum(num) // 매개 변수로 전달된 인수를 복사하여 로컬 복사본 생성

console.log(num) // 5

 

참조값

 

참조 값에는 원시 값을 제외한 모든 타입이 참조 타입이라고 할 수 있다.

참조값의 데이터 자체는 별도의 메모리 공간에 저장되는 데, 중요한 것은 변수가 포인터만을 저장 즉, 값 자체가 아닌 데이터에 대한 메모리 공간의 주소만 저장한다. 

브라우저는 보통 참조값을 힙으로 저장하는 데, 정확한 할당 논리는 브라우저가 책임지는 것으로 개발자나 Javascript 가 하는 것이 아니다.

  • 객체 (Object)
  • 배열 (Array)
  • 함수 (Function)

 

 

person1 과 person2 는 똑같은 객체가 저장되어 비교 연산자로 비교할 경우 당연히 true가 나올거라고 생각할 수 있다. 하지만 객체는 참조값으로 메모리 공간의 포인터를 저장했다. 그래서 아무리 두 변수의 객체가 같은 모양을 하고 있다고 하더라도 다른 메모리 공간의 포인터를 저장했기 때문에 false 가 출력된다.

 

 

상수인 hobbies 변수에 push하여 데이터를 변경할 경우 값이 변경되어 에러가 날 것이라고 예상을 하나, 에러가 나지 않고 정상적으로 작동한 것을 확인할 수 있다. 그 이유는 배열도 참조값으로 메모리 공간의 포인터를 저장하여 주소는 그대로 이기 때문이다. 

 

만약  = 로 값을 할당할 경우에는 에러가 나는 것을 확인할 수 있다. 이는 메모리의 데이터를 건든 것이 아닌 상수에 새로운 주소를 할당하려고 하기 때문이다. 

 

 

EP. 120

Garbage Collection

자바스크립트는 메모리를 자동으로 관리하는 Garbage Collector를 가지고 있는 데, 가비지 컬렉터는 메모리에 할당된 객체 중에서 더 이상 사용되지 않은 객체에 대한 힙 메모리를 주기적으로 확인한다. (사용되지 않은 객체라는 것은 참조( 변수에 저장된 메모리 주소 : 참조값 )되지 않은 객체를 말한다. ) 즉, 사용되지 않은 객체를 자동으로 탐지하고 힙( 메모리 )에서 제거하는 역할을 한다.

 

const addListenerBtn = document.getElementById('add-listener-btn');
const clickableBtn = document.getElementById('clickable-btn');
const messageInput = document.getElementById('click-message-input');

let person = {name:'Max'}

person = null 

function printMessage() {
  const value = messageInput.value;
  console.log(value || 'Clicked me!');
}

function addListener() {
  clickableBtn.addEventListener('click', printMessage);
}

addListenerBtn.addEventListener('click', addListener);

 

위 코드를 보면 person 변수를 선언하고 객체를 할당했다. 그리고 그 다음 줄에서 person 변수를 null로 재할당했다. 그렇게 되면 가비지 컬렉터는 처음 변수에 담긴 객체를 어디서도 참조하지 않다는 것을 인지하고 힙에서 제거 한다.

가비지 컬렉터가 즉각적으로 확인하고 힙에서 제거하는 것이 아니고, 알고리즘과 논리를 실행하여 자체 스케쥴에 따라 참조하고 있지 않는 객체를 발견하고 메모리에서 제거하는 것이다.

 

메모리 누수 (memory leak)

가비지 컬렉션은 자동으로 이루어지지만, 가끔씩 개발자가 메모리 누수를 일으키는 경우가 발생한다. 메모리 누수는 개발자가 의도하지 않은 객체의 참소를 유지하게 되는 경우를 말하며, 메모리 누수가 발생하면 가비지 컬렉터가 객체를 제거하지 못하고 메모리를 계속 점유하게 되는 현상이다.

 

메모리 누수가 발생하는 예시

 

1. 이벤트 리스터 등록 후 제거하지 않은 경우

const button = documenet.querySelector('#button')

fucntion clickHandler(){
	console.log('BUTTON CLICKED')
}

button.addEventListener('click', clickHandler)

 

버튼 이벤트를 등록하고 이벤트 리스너가 발생했으나, 해당 요소가 제거될 때까지 이벤트 리스터는 계속 남아있어 가비지 컬렉터가 인지하지 못하여 제거되지 않는다.

const button = documenet.querySelector('#button')

fucntion clickHandler(){
	console.log('BUTTON CLICKED')
}

button.addEventListener('click', clickHandler);


button.removeEventListener('click', clickHandler);

 그래서 removeEventListener로 이벤트를 제거하는 작업을 꼭 해줘야한다.

 

 

2. setInterval() 사용 후 clearInterval() 호출을 하지 않는 경우

let count = 0;

setInterval(()=>{
	console.log(count++);
}, 1000);

 

이렇게만 작성하고 코드를 마무리 한다면 setInterval() 함수는 계속해서 실행되고, count 변수와 같이 메모리에 계속 남아있게 된다. 그래서 setInterval() 함수를 호출할 때 반환되는 타이머 ID 값을 변수에 저장하고, clearInterval() 함수를 호출할 때 해당 변수를 사용하여 타이머를 제거해주는 방식을 추가해야한다.

 

let count = 0;

let timerId = setInterval(()=>{
	console.log(count++);
}, 1000);

clearInterval(timerId);