[모던 자바스크립트 Deep Dive] 04장. 변수

tamagoyakii·2022년 10월 13일
0
post-thumbnail

사실 책의 진도는 이미 10장까지 나갔다... 나름의 핑계를 대자면 그동안 42서울 생활에 몰두하느라 공부한 내용 정리를 할 시간이 많지가 않았다. 포스팅할 때 시간이 오래 걸리는 편이라 임시 글에 계속 넣어놓고 글을 마무리 못하는 일들이 참 많다...

하지만 최근에 휴파님이 "완벽주의가 되지 말고 완료주의가 되세요..."라고 말씀해 주셨는데, 그 말을 듣고 포스팅을 더 이상 미루지 말아야겠다는 결심을 했다. 부족하더라도 끝까지 써내는 데에 의의를 두고 밀린 내용들을 빠르게 정리해 보려고 한다.

4.1 변수란 무엇인가? 왜 필요한가?

사람은 계산과 기억을 모두 두뇌에서 하지만, 컴퓨터는 CPU를 사용해 연산하고, 메모리를 사용해 데이터를 기억한다. 메모리는 메모리 셀(memory cell)의 집합체로, 메모리 셀 하나의 크기는 1바이트(8비트)이며, 컴퓨터는 메모리 셀의 크기, 즉 1바이트 단위로 데이터를 저장하고 읽는다. 각 셀은 고유의 메모리 주소를 갖고 있는데, 이 주소는 메모리 공간의 위치를 나타내며, 0부터 시작하여 메모리 크기만큼 정수로 표현된다.

메모리 주소를 통해 값에 직접 접근하는 것은 오류를 발생시킬 위험이 있기 때문에, 프로그래밍 언어는 기억할 값을 메모리에 저장하고 그 값을 읽어 사용하기 위해 "변수"라는 메커니즘을 제공한다. 변수란 하나의 값을 저장하기 위해 확보된 메모리 공간을 식별하기 위해 붙인 이름을 뜻한다. 즉, 변수는 값의 위치를 가리키는 상징적인 이름이다.

위에서 이야기한 것처럼 메모리 공간에 저장된 값을 식별할 수 있는 고유의 이름을 변수 이름(변수명)이라고 하며, 변수에 저장된 값은 변수 값이라고 한다. 또, 변수에 값을 저장하는 것을 할당(assignment), 변수 값을 읽는 것을 참조(reference)라고 한다.

4.2 식별자

변수 이름은 식별자(identifier)라고도 불린다. 식별자는 값이 저장된 메모리 주소를 기억하고 있어야 하며, 이 매핑 정보도 메모리에 저장되어야 한다.

식별자가 변수 이름만 뜻하는 것은 아니다. 변수, 함수, 클래스 등의 이름은 모두 식별자다. 즉, 메모리에 존재하는 어떤 값을 식별할 수 있는 이름은 모두 식별자라고 불린다.

위에 언급한 모든 식별자들은 네이밍 규칙을 준수해야만 한다. 개발자의 의도를 명확하게 나타내는 네이밍은 코드를 이해하기 쉽게 만들며, 협업에 큰 도움이 된다. 따라서 식별자의 이름을 지을 때는 매우 심사숙고해야만 한다.

4.3 변수 선언

변수 선언(variable declaration)이란 변수를 생성하는 것을 말한다. 변수 선언을 통해 확보된 메모리 공간은 메모리가 해제되기 전까지는 안전하게 보호된다.

변수를 선언하기 위해서는 var, let, const 키워드가 사용된다. let과 const 키워드는 ES6부터 도입되었는데, var 키워드의 여러 가지 단점을 보안하기 위해서인 것 같다. 구멍이 숭숭 뚫려있는 var 키워드를 먼저 살펴보자.

💡 키워드(keyword)란?

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

다음은 var 키워드를 이용해 변수를 선언하는 방법이다.

var score;

위의 과정에서 우리는 변수를 선언했을 뿐, 변수에 값을 할당하지는 않았다. 이처럼 변수 값이 할당되지 않았을 때 자바스크립트 엔진은 undefined라는 값을 암묵적으로 할당하여 변수를 초기화한다. 즉, 자바스크립트 엔진은 변수를 선언할 때 아래의 두 단계를 거친다.

  1. 선언 단계 : 변수 이름을 등록한다.
  2. 초기화 단계 : 메모리 공간을 확보하고 undefined를 할당하여 초기화한다.

C언어의 경우, 변수를 선언할 때 초기화가 이루어지지 않기 때문에 초기화를 위한 식을 빼먹는 경우 아래와 같은 상황이 발생하기도 한다.

int a;

a += 3;
printf("%d\n", a) // 348834

이는 a라는 변수에 쓰레기 값(garbage value)이 들어갔기 때문이다. var 키워드는 선언과 동시에 이루어지는 암묵적 초기화로 이러한 위험을 방지한다.

💡 변수 이름은 어디에 등록될까?

변수 이름을 비롯한 모든 식별자는 실행 컨텍스트(execution context)에 등록된다. 실행 컨텍스트는 자바스크립트 엔진이 소스코드를 평가하고 실행하기 위한 환경을 제공하고, 코드의 실행 결과를 관리하는 영역이다. 이에 대한 자세한 내용은 <23장. 실행 컨텍스트>에서 자세히 다룰 예정이다.

변수를 사용하기 위해서는 반드시 선언이 필요하다. 선언하지 않은 변수를 참조할 경우 RefernceError(참조 에러)가 발생한다.

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

console.log(score);	// undefined

var score;			// 변수 선언문

위의 코드에는 변수 선언문보다 변수를 참조하는 코드가 앞에 있다. 바보 같은 C언어였다면 에러가 났을 것이다. 하지만 인터프리터 언어인 자바스크립트는 런타임(runtime)이 아닌 소스 코드의 평가 과정에서 변수 선언을 포함한 모든 선언문을 먼저 실행한다. 때문에 변수 선언이 어디에 위치하는지와 상관없이 어디서든 변수를 참조할 수 있다. 이를 변수 호이스팅(variable hoisting)이라고 한다.

4.5 값의 할당

var score;				// 변수 선언
score = 100;			// 값의 할당

var subject = "english"	// 변수 선언과 값의 할당

변수에 값을 할당할 때는 할당 연산자 =을 사용하여 우변의 값을 좌변의 변수에 할당한다. 위와 같이 선언과 할당을 동시에 할 수도 있다.

하지만 선언과 할당을 한 문장으로 단축하여 표현해도 자바스크립트 엔진은 선언과 할당을 2개의 문으로 나누어 실행한다. 즉, 평가 과정에서 변수가 선언되고 undefined로 초기화된 후 실행 과정에서 값이 할당되는 것이다.

4.6 값의 재할당

var score = 100;
score = 80;

위의 식처럼 값이 이미 할당된 변수에 새로운 값을 할당하는 것을 재할당이라고 한다. var 키워드와 let 키워드는 값의 재할당이 가능하지만, const 키워드는 값의 재할당이 불가능하다. 이런 경우 변수가 아니라 상수(constant)라고 부른다. 상수는 값이 한번 정해지면 변하지 않는다.

다시 위의 식을 살펴보자. 값의 재할당이 일어나는 경우 score 변수는 메모리 공간에 저장된 100이라는 값을 지우고 80이라는 값을 새롭게 저장하는 것이 아니라, 새로운 메모리 공간에 80이라는 값을 저장한 뒤 score 식별자가 가리키는 메모리 공간을 바꾼다. 이때 기존의 100이라는 값이 저장된 공간은 아무 식별자와도 연결되어 있지 않게 된다. 이렇게 사용되지 않는 메모리 공간은 후에 가비지 콜렉터(garbage collector)에 의해 자동 해제된다. 단, 해제되는 시점은 알 수 없다.

4.7 식별자 네이밍 규칙

식별자는 어떤 값을 구별할 수 있는 고유의 이름이라고 했다. 식별자는 다음과 같은 네이밍 규칙을 준수해야 한다.

  1. 식별자는 특수문자를 제외한 문자, 숫자, 언더 스코어(_), 달러 기호($)를 포함할 수 있다.
  2. 단, 식별자는 숫자로 시작할 수 없다.
  3. 예약어는 식별자로 사용할 수 없다.

예약어란 프로그래밍 언어에서 사용되고 있거나, 사용될 예정인 단어를 말한다. 다음은 자바스크립트의 예약어다.

다음과 같은 자바스크립트 내장 객체, 속성 및 메서드의 이름도 식별자 이름으로 사용될 수 없다.

하나 이상의 단어로 식별자 이름을 지을 때 단어를 한눈에 구분하기 위해 규정한 규칙을 네이밍 컨벤션(naming convention)이라고 한다. 많이 사용되는 네이밍 컨벤션 유형에는 4가지가 있다.

// 카멜 케이스(camelCase) : 변수, 함수
var finstName;

// 스네이크 케이스(snake_case)
var first_name;

// 파스칼 케이스(PascalCase) : 생성자 함수, 클래스
var FirstName;

// 헝가리언 케이스(typeHungarianCase)
var strFirstName;								// type + identifier
var $elam = document.getElementById('myId');	// DOM 노드
var observable$ = fromEvent(document, 'click');	// RxJS 옵저버블

일반적으로 자바스크립트에서는 카멜 케이스와 파스칼 케이스가 많이 사용된다. ECMAScript 사양에 정의된 객체와 함수들도 카멜 케이스와 파스칼 케이스를 사용하고 있다.

0개의 댓글