모던 자바스크립트 Deep Dive 독후감 P. 34 ~ 49

2023. 11. 30. 16:32Javascript Deep Dive

 

포스팅을 시작하기에 앞서

본 글을 포함하여, 앞으로 포스팅할 [모던 자바스크립트 Deep Dive] 서적 관련 글들은, 철저하게 필자 본인의 학습 내용 정리 및 기록을 위한 용도이며 글에 왜곡되고 잘못된 정보가 존재할 수 있음을 말씀드립니다.

 

Javascript 학습이 목적이신 분이라면 본 서적을 구매하여 직접 읽어보시는 것을 권해드립니다.

 

 

사람과 컴퓨터

 

10 + 20 이라는 표현식이 있다고 했을 때, 사람과 컴퓨터는 모두 마찬가지로 '10','20','+' 의 의미를 알고 있어야하며 '10 + 20'이라는 표현식 자체도 해석(파싱)할 수 있어야 한다.

자바스크립트 엔진이 10 + 20이라는 식의 의미를 해석하면 각 10, 20 이라는 피연산자를 기억한다.

 

사람은 기억과 계산을 모두 뇌에서 하지만, 컴퓨터는 기억과 계산을 수행하는 부품이 나눠져 있다.
컴퓨터는 CPU를 사용해 연산하고, 메모리를 사용해 데이터를 기억한다.

 

메모리는 데이터를 저장할 수 있는 메모리 셀의 집합체다. 메모리 셀 하나의 크기는 1바이트(8비트)이며, 컴퓨터는 메모리 셀 단위로 데이터를 저장하거나 읽어들인다. 그리고 각 셀은 고유의 메모리 주소를 갖는다.

 

다시 '10 + 20' 연산으로 돌아와서, 피연산자 10과 20은 메모리 상의 임의의 위치( 메모리 주소 )에 저장되고 CPU는 이 값을 읽어 들여 연산을 수행한다. 연산 결과로 생성된 숫자 값 30도 메모리 주소에 저장된다.

 

변수란 왜 필요한가?

'10 + 20' 이라는 연산을 했다는 것은 이 연산 결과가 필요하고 이를 사용해 무언가를 하겠다는 의도가 있었을 것이다.

만약 프로그램이 단순히 한번의 계산을 수행해주는 계산기일 경우 연산 결과를 한번만 사용하기 때문에 문제가 없겠지만, 대부분의 실제 프로그램들은 이보다 훨씬 복잡하고 유기적이기 때문에 '30'이라는 연산 결과를 필연적으로 재사용하고 싶을 것이다. 그리고 이를 위해서는 연산 결과가 저장된 메모리 공간에 직접 접근하는 것 외에는 방법이 없다.

 

하지만 메모리 주소를 통해 값에 직접 접근하는 것은 매우 위험한 일이다. 만약 실수로 운영체제가 사용하고 있는 값을 변경하면 시스템을 멈추게 하는 치명적인 오류가 발생할 수도 있기 때문이다.

 

따라서 프로그래밍 언어는 기억하고 싶은 값을 메모리에 저장하고, 저장된 값을 읽어 들여 재사용하기 위해 변수라는 매커니즘을 제공한다.

 

변수의 정의

변수는 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름을 말한다.

즉 변수란, 프로그래밍 언어에서 값을 저장하고 참고하는 메커니즘으로, 값의 위치를 가리키는 상징적인 이름이다.

 

이 변수는 컴파일러나 인터프리터에(자바스크립트의 경우 인터프리터) 의해 값이 저장된 메모리 공간의 주소로 치환되어 실행된다. 덕분에 개발자가 직접 메모리 주소에 접근하지 않고 변수를 통해 안전하게 값에 접근할 수 있다.

 

식별자

변수 이름을 식별자라고도 한다. 값은 메모리 공간에 저장되어 있고, 식별자는 메모리 공간에 저장되어 있는 값을 구별해서 식별해낼 수 있어야 하기 때문에  해당 값이 저장되어 있는 메모리 주소를 기억(저장)해야 한다.

 

즉 아래 코드의 식별자 `name`은 "이대준"이란 값을 저장하고 있는 것이 아니다. "이대준"이란 값은 메모리 공간의 특정 주소(이를 테면 0x0669F913)에 저장 되어있고, `name`은 0x0669F913이란 주소를 기억(저장)하고 있는 것이다.

const name = "이대준"

 

요약하자면 "식별자 === 메모리 주소에 붙인 이름" 이다.

변수 선언

변수 선언이란 값을 저장하기 위한 메모리 공간을 확보하고 변수 이름(식별자)와 확보된 메모리 공간의 주소를 연결해서 값을 저장할 수 있게 준비하는 것이다.

 

변수 선언에 의해 확보된 메모리 공간은 확보가 해제되기 전까지는 누구도 확보된 메모리 공간을 사용할 수 없도록 보호된다.

 

보통 변수를 선언하는 동시에 값을 할당하는 방식을 많이 사용하는데, 변수를 선언만 하고 변수에 값을 할당하지 않으면 자바스크립트 엔진이 확보된 메모리 공간에 undefined라는 값을 암묵적으로 할당한다.

자바스크립트 엔진은 변수 선언을 다음과 같은 2단계에 거쳐 수행한다.

- 선언 단계 : 변수 이름을 등록해서 자바스크립트 엔진에 변수의 존재를 알린다.

- 초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화한다.

 

var 키워드를 사용한 변수 선언은 선언 단계와 초기화 단계가 동시에 진행된다.

만약 초기화 단계를 거치지 않으면 확보된 메모리 공간에는 이전에 다른 애플리케이션이 사용했던 쓰레기 값이  남아 있을 수 있는데, 위와 같은 특성 덕분에 자바스크립트의 var 키워드는 이러한 위험으로부터 안전하다.

 

변수 선언의 실행 시점과 변수 호이스팅

변수 선언은 소스코드가 순차적으로 실행되는 시점, 즉 런타임에서가 아닌 그 이전 단계에서 실행된다.

자바스크립트 엔진은 소스코드를 순차적으로 실행하기에 앞서 소스코드의 평가 과정을 거치며 소스코드를 실행하기 위한 준비를 한다. 이때 자바스크립트 엔진은 변수 선언을 포함한 모든 선언문을 소스코드에서 찾아내 먼저 실행하는데,

 

이처럼 선언문이 마치 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 호이스팅(hoisting)이라 한다.

 

예전에 이 호이스팅(hoisting)이란 것을 처음 알았을 때, 너무 신기해서 직접 이러한 특성을 테스트 해보기 위해 코드를 짜고 실행해본적이 있었다. 그런데 그 때는 호이스팅이 제대로 이루어지지 않아서 의문이 남았었는데
바로 이 다음 내용을 통해 오늘 그 의문을 해결 할 수 있었다.

 

 

값의 할당

위의 내용처럼 변수 선언은 런타임 이전에 먼저 실행된다. 하지만 값의 할당은 다른 코드와 마찬가지로 런타임에 순차적으로 실행된다.

 

 

내가 호이스팅을 확인해보기 위해 실행했던 코드

var Name = "호이스팅";

console.log(Name);

 

나는 호이스팅을 처음 알았을 때 위 코드의 출력 결과로 "호이스팅"을 기대했지만 출력 결과는 'undefined' 였다.

 

아! ReferenceError가 발생하지 않은 것이 호이스팅이 이루어졌다는 증거였구나!

 

var Name = "호이스팅"; 은 곧 var Name; Name = "호이스팅"; 과 정확히 동일하게 동작한다 했고, 선언(var Name;)은 런타임 이전에, 할당(Name = "호이스팅")은 런타임에서 실행되니 자바스크립트가 선언시에 암묵적으로 초기화하여 할당한 undefined가 출력된 것이었구나!!! 대박.

 

+ 위와 같이 호이스팅을 테스트해보고 싶다면 let이나 const 키워드가 아닌 var 키워드를 사용해야 한다. let과 const 키워드는 "임시적 사각지대(Temporal Dead Zone, TDZ)"라고 불리는 구간에서 초기화되기 전까지 접근할 경우 ReferenceError가 발생한다. 아마 초기화되지 않은 변수의 사용을 방지하기 위해 의도적으로  추가된 것 같다. (뇌피셜)

 

 

+ 변수에 값을 할당할 때는 이전 값 undefined가 저장되어 있던 메모리 공간을 지우고 그 메모리 공간에 할당 값 80을 새롭게 저장하는 것이 아니라 새로운 메모리 공간을 확보하고 그곳에 할당 값 80을 저장하는 것이라 한다. 그리고 변수의 선언과 값의 할당을 하나의 문장으로 단축 표현해도 자바스크립트 엔진은 변수의 선언과 값의 할당을 2개의 문으로 나누어 각각 실행하기 때문에 마찬가지이다.

 

ex)

var score = 80;

 

1. 식별자 "score"는 undefined가 할당된 메모리 주소(0x1234)를 저장함.

2. 새로운 메모리 공간을 확보하고, 80이란 값을 할당한 뒤 식별자 "score"는 그 곳의 주소(0x5678)를 다시 저장.

 

 

값의 재할당

바로 위에서 설명했듯이 변수를 재할당 할 때는, 처음 값을 할당했을 때와 마찬가지로 이전 값이 저장되어 있던 메모리 공간을 지우고 그 메모리 공간에 재할당 값을 새롭게 저장하는 것이 아닌, 새로운 메모리 공간을 확보하고 그 메모리 공간에 숫자 값을 저장한다.

 

그리고 엄밀히 따지자면 변수에 값을 처음으로 할당하는 것 또한 재할당(undefine -> 할당할 값)이라 볼 수 있다.

 

그렇다면 값을 재할당하고 난 뒤 더이상 어떠한 식별자도 가리키고 있지 않는 이전 변수들은 어떻게 될까? 이렇게 기존 메모리 공간을 지우지 않고 새로운 메모리 공간을 확보하기만 한다면 메모리 공간이 남아나지 않는것 아닌가?

 

그렇기 때문에 값의 재할당으로 생겨난 불필요한 잉여값들은 가비지 컬렉터에 의해 메모리에서 자동 해제된다.

가비지 콜렉터는 애플리케이션이 할당한 메모리 공간을 주기적으로 검사하여 더 이상 사용되지 않는 메모리를 해제하는 기능이다. 

+ 자바스크립트는 매니지드 언어(managed language)이기 때문에 가비지 콜렉터가 내장되어 있지만, C와 같은 언매니지드 언어(unmanaged language)는 free()라는 함수로 메모리를 명시적으로 해제해줘야 한다. 그리고 언매니지드 언어는 메모리 할당 또한  malloc()이라는 함수로 명시적으로 할당해줘야 한다.

 

 

단어 정리

할당 : 변수에 값을 저장하는 것

참조 : 변수에 저장된 값을 읽어 들이는 것

키워드 : 키워드는 자바스크립트 코드를 해석하고 실행하는 자바스크립트 엔진이 수행할 동작을 규정한 일종의 명령어. ex) var 키워드를 만나면 자바스크립트 엔진은 뒤에 오는 변수 이름으로 새로운 변수를 선언한다.

실행 컨텍스트 : 자바스크립트 엔진이 소스코드를 평가하고 실행하기 위해 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역. 자바스크립트 엔진은 실행 컨텍스트를 통해 식별자와 스코프를 관리한다.

예약어 : 프로그래밍 언어에서 사용되고 있거나 사용될 예정인 단어. ex) await, continue, function, this 등등

 

 

감명 깊었던 내용들

! : 식별자 (변수 이름) 은 값을 저장하고 있는 것이 아닌 변수가 저장된 메모리의 주소를 저장(기억)하고 있는 것이다.

! : 평가 과정 때 이루어지는 호이스팅은 선언만을 먼저할 뿐, 할당은 런타임 때 다른 코드들과 똑같이 순차적으로 이루어진다.

! : 자바스크립트 엔진이 값을 재할당하는 방식

 

 

 

오늘도 3개의 단원을 읽고 포스팅하고 싶었지만, 당장 다음주 기말고사 때문에 오늘은 여기서 마무리하려 합니다. ㅜㅜ

 

오늘도 내일도 화이팅~!