[모던 자바스크립트 Deep Dive]04장 변수
4.1 변수란 무엇인가? 왜 필요한가?
다음 연산을 실행하기 위해 자바스크립트는 아래와 같은 동작을 수행해야 한다.
1
10 + 20;
- 코드를 계산(평가, evaluation)
10
,20
(리터럴, literal)과+
(연산자, operator) 의미 파악10 + 20
(표현식, expression) 의미 해석(파싱, parsing)- 피연산자(operand)와 연산 결과 등을 메모리에 저장
컴퓨터는 어떻게 기억하는가
- 메모리
- 데이터를 저장할 수 있는 메모리 셀의 집합체
- 메모리 셀
- 하나의 크기는 1바이트(8비트)
- 컴퓨터는 메모리 셀의 크기 단위로 데이터를 저장하고 읽음
- 각 셀은 고유의 메모리 주소(메모리 공간의 위치)를 가짐
- 0부터 메모리의 크기만큼 정수로 표현
자바스크립트는 직접적인 메모리 제어를 허용하지 않는다.
- 메모리 주소를 통해 직접 값에 접근하는 것은 치명적 오류 가능성이 매우 높음
- 메모리 주소는 코드가 실행될 때마다 임의로 결정되므로 코드를 실행하기 전에는 값이 저장될 메모리 주소를 알 수 없기 때문에 메모리 주소를 통해 값에 직접 접근할 수 없음
위 두 문제를 해결하기 위해 변수가 등장한다.
변수
- 값의 위치를 가리키는 상징적인 이름
- 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름
- 기억하고 싶은 값을 메모리에 저장, 저장된 값을 읽어 들여 재사용 용이
- 할당(assignment): 변수에 값을 저장
- 참조(reference): 변수에 저장된 값을 읽음
4.2 식별자
- 어떤 값을 구별해서 식별할 수 있는 고유한 이름, 메모리 주소에 붙인 이름
- 식별자는 어떤 값이 저장된 메모리 주소를 저장
- 식별자는 값이 저장된 메모리 주소와 매핑 관계를 맺고 이 매칭 관계도 메모리에 저장됨
- 변수, 함수, 클래스 등의 이름은 식별자(identifier)다.
- 식별자는 네이밍 규칙을 준수해야 한다.
- 선언(declaration)에 의해 존재를 알린다.
4.3 변수 선언
- 변수 선언(variable declaration)은 변수 생성이다.
- 변수를 사용하려면 반드시 선언해야 한다.
- 변수 선언시에는
var
,let
,const
키워드를 사용한다.- 키워드: 자바스크립트 엔진이 수행할 동작을 규정한 명령어
- 변수 선언 과정
- 선언 단계: 변수 이름을 등록해 변수의 존재를 자바스크립트 엔진에게 알림
- 초기화 단계: 값을 저장하기 위한 메모리 공간 확보(allocate)
- 초기화: 값이 할당되기 전에는 자바스크립트 엔진에 의해
undefined
라는 값이 할당되어 초기화 진행 - 메모리 공간은 확보가 되면 해제(release)되기 전까지는 누구도 사용할 수 없는 안전한 공간이다.
- 초기화: 값이 할당되기 전에는 자바스크립트 엔진에 의해
- 변수 이름과 확보된 메모리 공간 주소를 연결(name binding)
초기화 단계를 거치지 않는다면
이전에 존재하던 값이 메모리 공간에 남아 있을 수 있어 이를 참조하면 쓰레기 값(garbage value)가 나올 수 있다.
선언하지 않은 식별자에 접근한다면
ReferenceError
발생
실행 컨텍스트(execution context)
- 변수 이름이 등록되는 곳
- 자바스크립트 엔진이 소스코드를 평가하고 실행하기 위한 환경 제공
- 코드의 실행 결과를 관리
- 식별자는 실행 컨텍스트에 등록되며 자바스크립트 엔진은 이를 통해 식별자와 스코프 관리
- 변수 이름과 변수 값은 키/값 형식의 객체로 등록되어 관리
4.4 변수 선언의 실행 시점과 변수 호이스팅
1
2
3
console.log(score); // undefined, 즉 ReferenceError 발생 X
var score; // 변수 선언
변수 선언의 실행 시점
- 런타임이 아닌 그 이전 단계
- 런타임: 소스 코드가 한 줄씩 순차적으로 실행되는 시점
변수 선언이 런타임 이전에 실행되는 이유
- 자바스크립트 엔진이 소스코드의 평가 과정을 거친 뒤 소스코드를 한 줄씩 순차적으로 실행하기 때문
- 소스코드의 평과 과정: 자바스크립트 엔진이 모든 선언문을 소스코드에서 찾아내 먼저 실행
- 선언문: 변수 선언문, 함수 선언문, 클래스 선언문 등
- 소스코드의 평과 과정 이후 선언문을 제외한 소스코드를 한 줄씩 순차적 실행
변수 호이스팅
- 위와 같이 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징
4.5 값의 할당
1
2
var score; // 변수 선언
score = 80; // 값의 할당
1
var score = 80; // 변수 선언과 값의 할당
자바스크립트 엔진은 변수 선언과 값의 할당(assignment)을 하나의 문(statement)로 단축 표현해도 각각을 2개의 문으로 나누어 각각 실행
- 변수 선언: 런타임 이전에 실행
- 값의 할당: 런타임에 실행
1 2 3 4 5
console.log(score); // undefined var score = 80; // 변수 선언과 값의 할당 console.log(score); // 80
변수에 값을 할당하는건 이전 값이 저장되어 있던 메모리 공간을 지우는것이 아닌, 새로운 메모리 공간을 확보함으로써 이루어진다.
4.6 값의 재할당
- 재할당: 이미 값이 할당되어 있는 변수에 새로운 값을 할당
- 상수: 값을 재할당 할 수 없는, 단 한 번만 값을 할당할 수 있는 변수
const
키워드로 선언한 변수는 재할당이 금지되어 상수를 표현 할 수 있다.
메모리 공간에 남겨진 값은 어떻게 되는가
- 변수에 값을 재할당하면 특정 메모리 공간에 저장되어 있던 원래의 값은 변수를 잃는다.
- 메모리 공간의 값이 어떤 식별자와도 연결되어있지 않다면 가비지 콜렉터에 의해 메모리에서 자동 해제된다.
- 해제되는 시점은 예측할 수 없다.
가비지 콜렉터
- 애플리케이션이 할당(allocate)한 메모리 공간을 주기적으로 검사해 더 이상 사용하지 않는 메모리를 해제(release)하는 기능
- 더 이상 사용하지 않는 메모리: 어떤 식별자도 참조하지 않는 메모리 공간
- 이를 통해 메모리 누수(memory leak)를 방지
- 자바스크립트는 가비지 콜렉터를 내장한 매니지드 언어이다.
언매니지드언어와 매니지드 언어
- 언매니지드 언어(unmanaged language)
- C 언어 등
malloc()
과free()
같은 저수준(low-level) 메모리 제어 기능 제공- 이를 통해 개발자가 명시적으로 메모리를 할당하고 해제
- 메모리 제어를 개발자가 주도
- 개발자 역량에 따라 최적의 성능 확도 또는 치명적 오류 생산
- 매니지드 언어(managed language)
- 자바스크립트 등
- 언어 차원에서 메모리 할당 및 해제를 위한 관리 담당
- 개발자의 직접적 메모리 제어 허용 안함
- 개발자의 역량에 크게 의존하지 않아 일정한 생산성 확보 가능
- 하지만 성능에 어느정도 손실이 존재
- 사용하지 않는 메모리 해제는 가비지 콜렉터가 수행
- 이 또한 개발자가 관여 못함
4.7 식별자 네이밍 규칙
- 식별자(identifier): 어떤 값을 구별해서 식별해낼 수 있는 고유한 이름
식별자 네이밍 규칙
- 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어, 달러 기호를 쓸 수 있다.
- 식별자는 숫자로 시작할 수 없다.
- 예약어는 식별자로 사용할 수 없다.
변수 선언시 비권장 사항
- 변수는 쉼표로 구분해 하나의 문에서 여러 개를 선언할 수 있지만 가독성이 나쁘므로 권장하지 않는다.
- ES5부터 한국어나 일본어 식별자도 사용할 수 있지만 권장하지 않는다.
- 명확하지 않은 변수 이름은 권장하지 않는다.
네이밍 컨벤션
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 카멜 케이스 (camelCase)
var firstName;
// 스네이크 케이스 (snake_case)
var first_name;
// 파스칼 케이스 (PascalCase)
var FirstName;
// 헝가리언 케이스 (typeHungarianCase)
var strFirstName; // type + identifier
// DOM 노드
var $elem = document.getElementById("myId");
// RxJS 옵저버블
var observable$ = fromEvent(document, "click");
식별자에는 일반적으로 다음 컨벤션을 사용한다.
- 카멜 케이스
- 변수의 이름
- 함수의 이름
- 파스칼 케이스
- 생성자 함수
- 클래스의 이름
This post is licensed under CC BY 4.0 by the author.