[JavaScript] var, let, const 차이점
<JavaScript>
프로그래머스 문제를 풀면서 var을 사용하는 사람도 있고 let를 사용하는 사람이 있어 var과 let 추가로 const의 변수 선언 방식의 차이점이 궁금하여 조사했다.
# 변수 선언 방식
1. var - 중복 선언 가능 / 재할당 가능
var name = 'first';
console.log(name); // first
var name = 'second';
console.log(name); // second
var은 동일한 변수명으로 중복 선언이 가능하며, 마지막의 할당된 값이 변수에 저장된다.
위의 코드를 보면 에러가 발생하지 않고 다른 값이 출련된다.
이런 var의 특징은 간단한 테스트, 작은 프로젝트에서는 괜찮을 수 있겠으나, 코드량이 많아지는 프로젝트에서는 기존의 선언한 코드를 잊고 값을 재할당하여 꼬이는 문제와 코드량이 많아져 같은 이름의 변수명이 여러번 선언되었다면 문제가 발생하는 위치를 파악하는데 어려움이 생긴다.
2. let - 중복 선언 불가능 / 재할당 가능
let name = 'first';
console.log(name); // first
let name = 'second';
console.log(name);
// Uncaught SyntaxError: Identifier 'name' has already been declared
name = 'third';
console.log(name); // third
let은 해당 변수가 이미 선언되었다는 에러 메시지가 출력되며, 중복 선언이 불가능하다.
name = 'third' 와 같이 변수 선언 및 초기화 이후 다른 값을 재할당 할 수는 있다.
3. const - 중복 선언 불가능 / 재할당 불가능
const name = 'first';
console.log(name); // first
const name = 'second';
console.log(name);
// Uncaught SyntaxError: Identifier 'name' has already been declared
name = 'third';
console.log(name);
// Uncaught TypeError: Assignment to constant variable
const는 해당 변수가 이미 선언되었다는 에러 메시지가 출력되며, 중복 선언이 불가능하다.
var과 let와 다르게 name = 'third' 와 같이 변수 선언 및 초기화 이후에 다른 값을 재할당 할 수는 없다.
function func() {
const list = ["A", "B", "C"]
list = "D";
console.log(list);
// TypeError: Assignment to constant variable
list.push("D");
console.log(list); // ["A", "B", "C", "D"]
}
그러나 '값의 재할당'만 불가능할 뿐, 위의 예제처럼 배열과 오브젝트의 값을 변경하는것은 가능하다.
const name = 1;
const name2; // SyntaxError: Missing initializer in const declaration
추가로 const는 선언할 때 반드시 초기화(값 할당)를 해주어야 한다.
# 스코프
스코프란 유효한 참조범위를 의미한다.
1. var - 함수 레벨 스코프(function-level scope)
function hello(){
var a = 10;
console.log(a);
}
hello(); // 10
console.log(a); //ReferenceError: a is not defined
---------------------------------------------------------------------------
if(true) {
var a = 10;
console.log(a); // 10
}
console.log(a); // 10
var은 함수 내에서 선언된 변수는 함수 안에서만 유효하며 외부에서는 참조가 불가능하다.(지역변수)
하지만 함수 외부에서 선언한 변수의 겨우에는 '전역변수'로 취급한다.
2. let, const - 블록 레벨 스코프(block-level scope)
if(true) {
let a = 10;
console.log(a); // 10
}
console.log(a); // ReferenceError: a is not defined
---------------------------------------------------------------------------
function hello() {
let a = 10;
console.log(a); // 10
}
console.log(a); // ReferenceError: a is not defined
let와 const는 함수, if문, for문, while문, try/catch문 등의 모든 코드 블록 ({...}) 내부에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다. 즉, 코드 블록 내부에서 선언한 변수는 지역 변수로 취급된다.
# 호이스팅
호이스팅이란 함수 내부에 있는 선언들을 끌어올려서 함수 유효범위의 최상단에 선언하는 것을 의미한다. 물리적으로 끌어올리는 것이 아니다. JavaScript의 Parser가 함수 실행 전 해당 함수를 한 번 훑는 과정에서 내부적으로 끌어올려 처리한다.
console.log(foo); // undefined
var foo;
console.log(bar); // Error: Uncaught ReferenceError: bar is not defined
let bar;
var과 let,const(둘의 처리 방식 동일)를 살펴보면, var 로 선언된 변수와는 달리 let 로 선언된 변수를 선언문 이전에 참조하면 참조 에러(ReferenceError)가 발생한다.
이는 let 로 선언된 변수는 스코프의 시작에서 변수의 선언까지 일시적 사각지대(Temporal Dead Zone; TDZ)에 빠지기 때문이다.
변수는 선언단계 > 초기화 단계 > 할당 단계에 걸쳐 생성되는데
var 으로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다. 하지만, let 으로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행된다.
// var
// 스코프의 선두에서 선언 단계와 초기화 단계가 실행된다.
// 따라서 변수 선언문 이전에 변수를 참조할 수 있다.
console.log(foo); // undefined
var foo;
console.log(foo); // undefined
foo = 1; // 할당문에서 할당 단계가 실행된다.
console.log(foo); // 1
---------------------------------------------------------------------------
// let
// 스코프의 선두에서 선언 단계가 실행된다.
// 아직 변수가 초기화(메모리 공간 확보와 undefined로 초기화)되지 않았다.
// 따라서 변수 선언문 이전에 변수를 참조할 수 없다.
console.log(foo); // ReferenceError: foo is not defined
let foo; // 변수 선언문에서 초기화 단계가 실행된다.
console.log(foo); // undefined
foo = 1; // 할당문에서 할당 단계가 실행된다.
console.log(foo); // 1
# 재할당이 많은 특수한 경우 let를 사용하며, 기본적으로는 const를 사용한다.
<참조>
1. https://velog.io/@bathingape/JavaScript-var-let-const-%EC%B0%A8%EC%9D%B4%EC%A0%90
2. https://80000coding.oopy.io/e1721710-536f-43f2-823b-663389f5fbfa