컴퓨터는 CPU를 통해서 연산하고, 메모리를 사용해 기억한다.
메모리는 데이터를 저장할 수 있는 메모리 셀의 집합체다.
메모리 셀 하나의 크기는 1바이트(8비트)이며, 컴퓨터는 메모리 셀의 크기, 즉 1바이트 단위로 데이터를 저장(write)하거나 읽는다(read).
각 셀은 고유의 메모리 주소를 갖고, 이 메모리 주소는 메모리 공간의 위치를 나타내며, 0부터 시작해서 메모리 크기만큼 정수로 표현된다.
만약 10 + 20 이라는 계산을 수행하면, 10과 20은 메모리 상의 임의의 위치에 기억(저장)되고, CPU는 이 값을 읽고 연산을 수행한다. 연산 결과로 생성된 결과 값 30도 메모리 상의 임의의 위치에 저장된다.
하지만 여기서 만들어낸 결과 값 30을 재사용할 수 없다. 재사용하려면 30이 들어있는 임의의 메모리 주소를 찾아 메모리 공간에 직접 접근해야 하지만, 자바스크립트는 개발자의 직접적인 메모리 제어를 허용하지 않는다. 왜냐하면, 메모리 주소에 잘못 접근해서 수정하게 되면 시스템을 멈추게 할 수도 있기 때문이다.
또한 동일한 CPU에 동일한 코드를 쳐도 값은 그때 그때 다른 임의의 주소에 저장되어서, 코드를 실행한 후에만 임의의 주소를 알 수 있다.
변수는 값을 저장한 메모리 공간을 식별하기 위해 붙인 이름으로 값의 위치를 가리킨다.
변수 = 메모리 공간의 주소
값을 재사용하기 위해서
메모리 값이 저장된 임의의 주소에 직접 제어하는 것은 오류를 범할 위험이 크고, 코드가 실행된 이후에야 임의의 주소를 파악할 수 있음.
할당(assignment) : 변수에 값을 저장
참조(reference) : 변수의 값을 읽는 것
식별자(identifier) : 변수 이름. 메모리 값이 아닌 주소를 기억함.
초기화(initialization) : 변수가 선언된 이후 처음으로 값을 할당하는 것으로 암묵적으로 undefined를 할당해 초기화한다.
변수 선언(declaration) : 변수 생성. 메모리 공간을 확보하고 변수 이름과 메모리 주소를 연결.
자바스크립트 엔진은 소스코드를 한 줄 씩 순차적으로 실행하기에 앞서, 먼저 소스코드의 평가 과정을 거치면서 소스코드를 실행하기 위한 준비를 한다. 소스코드의 평가 과정에서 모든 선언문(var, let, const, function, class)을 먼저 실행한다.
변수 호이스팅 : 변수 선언문이 코드의 선두로 끌어올려진 것처럼 동작. 그래서 변수를 선언하기도 전에 코드가 작동될 수 있음.
값의 재할당 : 이미 값이 할당되어 있는 변수에 새로운 값을 할당.
var 키워드로 선언한 변수는 선언과 동시에 맨 처음 undefined 값을 가져서, 엄밀히 말하면 변수에 처음으로 값을 할당하는 것도 재할당이다.
상수(constant) : 한번 정해지면 수정할 수 없는 값
가비지 컬렉터(Garbage Collector) : 메모리 공간을 주기적으로 검사해서, 더 이상 사용되지 않는 메모리를 해제하는 기능.
가장 처음 만들어진 변수 선언 방법
런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언 단계와 초기화 단계가 한번에 진행된다.
변수 중복 선언 가능 : 똑같은 이름의 변수가 있는지 모르고 변수를 중복 선언한다면, 먼저 선언된 변수의 값이 바뀔 수도 있다.
var는 전역 변수(global variable)와 지역 변수(local variable)의 구분이 애매해, 전역 변수처럼 프로그램 전체에서 실행 가능하다. 함수 내부에 위치하더라도 함수 외부에서도 실행 가능하다.
var의 단점을 보완하기 위해 나온 새로운 변수 선언 방법
중복 선언 금지
선언 단계와 초기화 단계가 분리되어 진행된다.
런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언 단계가 먼저 실행되지만, 초기화 단계는 변수 선언문에 도달했을 때 실행된다.
TDZ (temporal dead zone) : 초기화 단계 이전에 변수를 참조(read)할 수 없는 구간.
// 런타임 이전에 선언 단계가 실행되고, 아직은 변수가 초기화(initialize)되지 않았다.
// 초기화 이전의 TDZ에서는 변수를 읽을 수 없다.
console.log(fruit); // ReferenceError
let fruit; // 초기화 됨. undefined 할당됨.
console.log(fruit); // undefined
fruit = 'apple'; // 값이 할당됨
console.log(fruit) // apple
let은 전역 변수와 지역 변수의 구분이 명확하다.
let도 호이스팅이 되지만, 호이스팅이 발생하지 않는 것처럼 동작한다.
let fruit = 'apple'; // 전역 변수
{
console.log(fruit); // Reference error. 만약 호이스팅이 안되었다면 fruit의 값은 apple이다.
let fruit = 'orange'; // 지역 변수
}
재할당 금지 : 한번 원시 값을 할당하면, 변수 값을 변경할 수 없다.
하지만, const에 객체를 할당한 경우 자유롭게 변경 가능하다.
const는 반드시 선언과 동시에 값을 할당해야 한다.
코드 런타임 이전에 자바스크립트 엔진에 의해 모든 선언문을 먼저 메모리에 저장하고, 코드 실행 이전에 선언문이 프로그램 맨 위로 끌어올려진 것처럼 동작.
호이스팅으로 인해 var는 undefined를 리턴하고 let과 const는 ReferenceError를 나타낸다.
왜냐하면 var는 런타임 이전에 선언 단계와 초기화 단계가 동시에 실행되어 undefined 값이 할당되지만, let과 const는 TDZ로 인해 undefined 값의 할당을 막아서 값을 참조(read)할 수 없다.
출처 : 모던 자바스크립트 Deep Dive