[#02-2] [Pre-OnBoarding] 상수와 변수
변수
변수(variable)는 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름
변수 선언
변수 선언은 var, let, const 키워드로 할 수 있으며, ES6에서 const와 let이 추가됨
Javascript 에서 변수 선언은 선언 => 초기화 단계를 거쳐 수행됨
- 선언 단계: 변수명을 등록하여 자바스크립트 엔진에 변수의 존재를 알린다.
- 초기화 단계: 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화한다.
호이스팅
- 자바스크립트 엔진은 소스코드를 한 줄씩 순차적으로 실행하기에 앞서, 변수 선언을 포함한 모든 선언문(ex. 변수 선언문, 함수 선언문 등)을 찾아내 먼저 실행한다. 즉, 변수 선언이 어디에 있든 상관없이 다른 코드보다 먼저 실행되는 특징을 호이스팅 (hoisting)이라 한다.
- 변수 선언 뿐만 아니라, var, let, const, function, function*, class 키워드를 사용해 선언한 모든 식별자(변수, 함수, 클래스 등)는 호이스팅이 된다.
변수 할당
변수 선언이 호이스팅되어 런타임 이전에 실행되지만, 값의 할당은 소스코드가 순차적으로 실행되는 런타임에 실행된다.
할당은 변수에 저장된 값을 다른 값으로 변경하는 것으로, 만약 변경할 수 없는 값이라면 이는 변수가 아니라 상수(constant)라 부른다.
함수 호이스팅
함수 선언문의 경우, 런타임 이전에 자바스크립트 엔진에서 먼저 실행되어, 함수 자체를 호이스팅 시킬 수 있다. 반면, 함수 표현식은 위에서 봤던 변수 호이스팅과 같이 런타임 이전에 해당 값을 undefined로 초기화만 시키고, 런타임에서 해당 함수 표현식이 할당되어 그때 객체가 된다.
스코프
스코프(scope)는 식별자(ex. 변수명, 함수명, 클래스명 등)의 유효범위
전역 변수는 어디에서든지 참조가 가능한 값
지역 변수는 함수 몸체 내부, 지역 변수는 자신의 지역 스코프와 그 하위 지역 스코프에서 유효
- 자바스크립트에서 모든 코드 블록(if, for, while, try/catch 등)이 지역 스코프를 만들며, 이러한 특성을 블록 레벨 스코프라 한다.
- var 키워드로 선언된 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정한다. 이를 함수 레벨 스코프라 한다.
var, let, const의 차이 (ES5 > ES6)
1. var 키워드의 문제점은 크게 세 가지
변수 중복 선언 가능하여, 예기치 못한 값을 반환할 수 있다. 함수 레벨 스코프로 인해 함수 외부에서 선언한 변수는 모두 전역 변수로 된다. 변수 선언문 이전에 변수를 참조하면 언제나 undefined를 반환한다. ES6에서 나온 let과 const키워드는 위의 세 가지 문제점을 해결했다. |
변수 중복 선언 불가
2. let
let 키워드로는 변수 중복 선언이 불가하지만, 재할당은 가능하다. |
3. const
const가 let과 다른 점이 있다면, 반드시 선언과 초기화를 동시에 진행되어야 한다. const도 let과 마찬가지로 재선언이 불가하며, 더 나아가 재할당도 불가하다. 재할당의 경우, 원시 값은 불가능하지만, 객체는 가능하다. const 키워드는 재할당을 금지할 뿐, ‘불변’을 의미하지 않는다. |
블록 레벨 스코프
let, const 키워드로 선언한 변수는 모두 코드 블록(ex. 함수, if, for, while, try/catch 문 등)을 지역 스코프로 인정하는 블록 레벨 스코프를 따른다.
변수 호이스팅
let
let 키워드로 선언한 변수는 선언 단계와 초기화 단계가 분리되어 진행된다. 즉, 런타임 이전에 자바스크립트 엔진에 의해 선언 단계가 먼저 실행되지만, 초기화 단계가 실행되지 않을 때 해당 변수에 접근하려고 하면 참조 에러가 뜬다. |
const
const 키워드는 선언 단계와 초기화 단계가 동시에 진행된다. let 키워드로 선언한 경우, 런타임 이전에 선언이 되어 자바스크립트 엔진에 이미 존재하지만 초기화가 되지 않았기 때문에 name is not defined 라는 문구가 떴다. 하지만 const 키워드로 선언한 경우, 선언과 초기화가 동시에 이루어져야 하지만 런타임 이전에는 실행될 수 없다. 따라서 초기화가 진행되지 않은 상태이기 때문에 Cannot access 'name' before initialization 에러 문구가 뜬다. |
정리
기본적으로 변수의 스코프는 최대한 좁게 만드는 것을 권장한다. 따라서, var 키워드 보다는 let과 const 키워드를 사용하며, 변경하지 않는 값(상수)이라면 let 보다는 const 키워드를 사용하는 것이 안전하다.