자바스크립트에서는 var로 변수 선언을 하였으나, 2015년 ES6가 등장하며 Const와 let이 나오게 되었다. 현재 var 키워드 대신 이 둘의 사용을 적극 권장하고 있다.
변수 선언
변수 선언은 var, let, const 키워드로 할 수 있다. 자바스크립트(이하 js)엔진은 변수 선언을 선언 -> 초기화 를 거쳐 수행된다.
- 선언 단계 : 변수 명을 등록하여 js 엔진에 변수의 존재를 알린다.
- 초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고, 암묵적으로 undefined를 할당해 초기화한다.
- 할당 단계 : 초기화 된 변숫값에 새로운 값을 할당한다.
var dante //변수 선언
console.log(dante) // output : undefined
변수가 만들어졌으므로, 그 값을 undefined으로 초기화한다. var 키워드는 선언과 초기화 단계가 동시에 진행된다.
그러나 console을 먼저 찍어도 output은 undefined으로 나온다.
console.log(dante) // output : undefined
var dante // 변수 선언
변수 할당
console.log(dante) // output : undefined 출력
var dante = 'gosu' // 변수 할당
console.log(dante) // output : gosu
변수 선언과 할당은 동시에 할 수 있으나, 실제로 각 단계가 실행되는 시점은 다르다.
js는 인터프리터 언어로 소스코드를 위에서부터 순차적으로 실행하는데, 이전에 변수 등 모든 선언문을 찾아 먼저 실행하게 된다. 이것을 '호이스팅' 이라 한다. 그렇기 때문에 함수 내부 어디서든, 변수 선언은 유효 범위 내 최상위에 선언하는 것과 같다.
또한 이미 할당된 변수에 새로운 값을 재할당할 수도 있다.
console.log(dante) // output : gosu
dante = 'hasu'
console.log(dante) // output : hasu
스코프
스코프는 변수명, 함수명, 클래스 명 등 식별자의 유효한 참조 범위를 말한다. 전역에 선언된 변수를 전역 스코프, 지역에 선언된 변수를 지역 스코프라 한다.
- 전역 변수 : 어디서든 참조 가능
- 지역 변수 : 함수 안에서 참조 가능
js에서 모든 코드 블록(if, for, while 등)은 지역 스코프를 만들고 이것을 블록 레벨 스코프라 한다. 그러나 var 키워드로 선언된 변수는 함수의 코드 블록만을 지역 스코프로 인정하며 이를 함수 레벨 스코프라 한다.
function print(){
var dante = 'gosu';
console.log(dante); //output : gosu
}
print(); //output : gosu
console.log(dante); // ReferenceError: dante is not defined
var, let, const의 차이
변수 선언 방식
1. var - 중복 선언 가능
var dante = 'gosu';
console.log(dante) // output : gosu
var dante = 'hasu';
console.log(dante); // output : hasu
var로 선언한 변수는 동일한 이름으로 여러 번 중복 선언이 가능하다.
2. let - 중복 선언 불가능, 재할당 가능
let dante = 'gosu';
console.log(dante); //output : gosu
let dante = 'hasu';
console.log(dante); //Uncaught SyntaxError: Identifier 'dante' has already been declared
dante = 'jungsu';
console.log(dante); //output : jungsu
let로 선언한 변수는 중복 선언이 불가능하나, 재할당은 가능하다.
3. const - 중복 선언, 재할당 불가능
const dante; // Uncaught SyntaxError: Missing initializer in const declaration
const dante = 'gosu';
//재할당 불가능
dante = 'hasu';
console.log(dante) // Uncaught TypeError: Assignment to constant variable
//재할당 가능
const retry = {
dante : 'gosu'
}
retry.dante = 'hasu';
console.log(retry) // output : {dante : 'gosu'}
const와 let과 달리 반드시 선언과 초기화를 동시에 진행해야 한다. 또한 재할당을 할 수 없으나, 객체 안의 값을 변경하는 것은 가능하다.
스코프(Scope)
1. var - 함수 레벨 스코프
function print() {
var dante = 'gosu';
}
print(); // output : gosu
console.log(dante); //ReferenceError: a is not defined
2. let, const - 블록 레벨 스코프
function print() {
if (true) {
let dante = 'gosu';
console.log(dante); // output : gosu
}
console.log(dante); // ReferenceError: a is not defined
}
console.log(dante); // ReferenceError: a is not defined
함수, if, for, while 등 모든 코드 블록 내부에서 선언된 변수는 블록 안에서만 유효하며 외부에서는 참조할 수 없다. (지역변수)
호이스팅(Hoisting)
1. var, let
console.log(varDante); // undefined
console.log(letDante); // ReferenceError : letDante is not defined
var varDante = 1;
let letDante = 2;
var 키워드는 코드 실행 전에 js 내부에서 undefined로 초기화를 진행하여 에러가 발생하지 않는다.
그러나 let 키워드는 선언 단계와 초기화 단계가 분리되어 진행된다. let 키워드로 선언된 변수는 초기화하기 전에는 읽거나 쓸 수 없다. 변수 스코프의 맨 위에서 변수의 초기화 완료 시점까지의 변수는 "시간상 사각지대"(Temporal Dead Zone, TDZ)에 들어간 변수라고 표현한다.
2. const
const 키워드는 선언 단계와 초기화 단계가 동시에 진행된다.
consooe.log(dante); // Uncaught ReferenceError: Cannot access 'dante' before initialization
const dante = 'gosu';
var 키워드는 버그 발생시 확인이 어려우며 메모리의 누수 위험 가능성이 크다. 이 같은 문제와 차이 때문에 var 키워드보다는 let과 const 키워드를 권장하게 된다.