
var, let, const
JS에서는 변수나 상수를 만들때 var, let, const
라는 키워드를 사용합니다.var
, let
은 변수 선언, const
는 상수 선언입니다.
JS 개발자들이 주로 하는 말에는 이런 말이 있습니다.*"var는 죽어도 쓰지마!!! let이랑 const만 사용해!!"*
맞는 말이지만 이유는 뭘까요??
여기서는 var
를 사용하면 어떤 문제가 생기고 let
과 const
를 사용하면 그 문제를 어떻게 보완하는지 알아보겠습니다.
먼저 var
와 let
의 차이를 알아보겠습니다.
var와 let의 차이
둘의 차이는 크게 3가지가 있습니다.
- 스코프(Scope)
- 중복 선언(Variable redeclaration)
- 호이스팅(Hoisting)
스코프(Scope)
스코프는 코드가 변수에 접근할 수 있는 범위를 뜻합니다.
스코프는 3가지 범위로 나누어져 있습니다.Function Scope/ Block Scope/ Global Scope
var 키워드로 생성된 변수는 기본적으로 Function Scope
를 가지고
let 키워드로 생성된 변수는 기본적으로 Block Scope
를 가집니다.
만약 변수가 어떤 함수나 블록에도 속하지 않고 최상위 함수 외부에 선언된 변수라면 Global Scope
를 가집니다.
function abc() {
var x = "hello";
}
console.log(x);
//ReferenceError
var
키워드를 통해 생성한 변수는 자동으로 Function Scope
를 가지는데, 함수 밖에서 x
를 참조하였기 때문에 참조 에러가 발생했습니다.
Function Scope
라는 말은 변수가 선언된 함수 내부에서만 변수에 접근이 가능하다는 것을 말합니다.
만약 아래처럼 console.log(x)
를 함수 내부에 작성하였다면 문제가 없을 것입니다.
function abc() {
var x = "hello";
console.log(x);
}
abc();
이번에는 함수 내부에 간단한 if
문 block
을 만들어보겠습니다.
function abc() {
if(true) {
var x = "hello";
console.log(x); //정상 출력
}
console.log(x); //정상 출력
}
abc();
아마 다른 프로그래밍 언어를 접해보신 분들은 위 코드가 이상하게 느껴질 수 있습니다.
if문 블럭 내부에서 선언한 변수를 if문 블럭 바깥에서 접근을 시도하면 에러를 발생시켜야 하지 않나??
하지만 정상입니다.
위에서 var
키워드로 생성한 변수는 Function Scope
를 가지기 때문에 위 코드는 정상적으로 출력이 2번 되는 것을 확인할 수 있습니다.
변수가 생성된 함수 내부라면 어디서든 해당 변수에 접근할 수 있기 때문입니다.
이번에는 위에서의 var
키워드를 let
키워드로 바꿔보겠습니다.
function abc() {
if(true) {
let x = "hello";
console.log(x); //정상 출력
}
console.log(x); //Reference Error
}
abc();
let
키워드를 사용해서 생성된 변수는 Function Scope
가 아니라 Block Scope
를 가지기 때문에 if
문 블록 바깥에서 x
에 접근하였을 때 참조 에러가 발생했습니다.
이 말은 변수가 선언된 블럭 내부에서만 변수에 접근이 가능하다는 말입니다.
블록은 중괄호로 묶인 부분을 말하는데, if
뿐만 아니라 while, for, switch…
블록들도 포함됩니다.
대부분의 다른 프로그래밍 언어에서는 보통 변수를 선언하게 되면 Block Scope
를 가지고 있습니다. 그래서 다른 프로그래밍 언어를 접해본 사람들은 let
을 사용해서 친숙하게 JS로 프로그래밍을 할 수 있을 것입니다.
또 let
은 블럭 외부로부터의 접근을 불허하기 때문에 더 안전합니다.
중복 선언(Variable redeclaration)
var x = 'hi';
//........
var x = 'hello';
console.log(x);
위 코드에서 저는 변수 x
를 var
키워드를 통해서 두 번 선언하였습니다.
결과는 hello
라고 출력되는 것을 확인할 수 있습니다.
이번에는 let
키워드를 통해서 해보겠습니다.
let x = 'hi';
//........
let x = 'hello';
console.log(x);
이번에는 에러가 발생한 것을 확인할 수 있습니다.
Identifier ‘x’ has already been declared
let
키워드는 같은 이름의 변수를 중복해서 선언하는 것을 허용하지 않기 때문에 위와 같은 이미 x
가 선언되었다는 에러 메시지가 나오는 것을 확인할 수 있습니다.
프로그램이 커지다보면 내가 이미 작성한 변수의 이름을 까먹는 일이 발생할 수 있는데, 만약 이때 중복이 허용된다면 아마 큰 일이 발생할 수 있습니다.
호이스팅
이번에는 변수 호이스팅이라는 개념에 대해서 알아보겠습니다.
먼저 다음과 같이 코드를 작성합니다.
console.log(num);
당연히 num
이라는 변수를 선언한 적이 없기 때문에 에러가 발생합니다.
이번에는 console.log(num)
밑에서 var
키워드를 통해 변수 num
을 선언해보겠습니다.
console.log(num);
var num = 20;
이번에는 에러가 발생하지 않고 undefined
라는 값이 나오는 것을 알 수 있습니다.
에러가 발생하지 않는 이유는 호이스팅때문입니다.
호이스팅이란 프로그램이 실행되기 이전에 변수의 선언과 초기화를 분리해서 변수의 선언만 프로그램 맨 위로 끌어 올려주는 것을 말합니다.
프로그램이 실행 전에 JS에 우리가 사용하는 변수의 존재를 미리 알리는 것입니다.
이번에는 아래와 같이 해봅시다.
console.log(num);
var num = 20;
console.log(num);
첫번째 console.log(num)
는 undefined
가 출력되는데, 두번째 console.log(num)
는 숫자가 잘 출력되는 것을 알 수 있습니다.
코드 상에서는 변수의 선언과 초기화가 동시에 일어난 걸로 보이지만 호이스팅 때문에 실제로는 순서가 아래와 같이 진행되었다고 생각할 수 있습니다.
var num;
console.log(num);
num = 20;
console.log(num);
사실 코드 상에서 초기화되지 않은 변수, 아무 값도 할당 되지 않은 변수에 접근한다는 것은 별로 의미가 없고 해서는 안됩니다!
이 문제를 똑같이 let
에도 적용해봅시다.
console.log(num);
let num = 20;
console.log(num);
이번에는 참조 에러가 발생하는 것을 알 수 있어요.
num
을 초기화하기 전에 접근할 수 없다고 나옵니다.
let
키워드로 선언된 변수도 맨위로 호이스팅이 되지만 var
처럼 변수를 undefined
로 초기화시키지는 않습니다.
그래서 코드 상에서 변수의 선언문 이전에 변수에 접근을 시도한다면 undefined
가 없는 것입니다.
에러가 발생하는 이유는 TDZ(Temporal Dead Zone)
때문입니다.
let
키워드로 선언한 변수도 호이스팅이 발생하지만 프로그램이 실행되면서 변수 선언문에 닿기 전까지는 TDZ
에 들어갑니다.
그래서 변수 선언문 이전에 접근을 시도한 console.log(num)
안에 있는 num
은 TDZ
에 있는 상태입니다.
JS는 TDZ
에 들어가 있는 변수에 접근하는 것을 허용하지 않습니다. 따라서 참조 에러가 발생합니다.
TDZ
덕분에 변수가 선언되기 전에 접근하는 말도 안되는 상황을 피하고 더 안전하게 코딩을 할 수 있습니다.
여기까지가 var
와 let
의 차이점이었고, var
를 사용하면 안되고 let
을 사용해야 하는 이유였습니다.
const
const
는 let
과 아주 비슷합니다.
let
처럼 Block Scope
를 기본으로 가지고, 중복 선언이 불가능 하고, 변수 선언문 이전에 접근하는게 불가능합니다.
딱 하나 다른 점이라면 const
는 상수 선언이라는 점입니다. (let
은 변수 선언)
이 말은 const
키워드를 통해 값을 할당했다면 다른 값으로 재할당 불가능하다는 점입니다.
const a = 10;
a = 20;
//Error
let
과 또 하나 다른 점은 const
는 선언만 하는 것이 불가능합니다.
let a;
a = 10;
//가능
const b;
//Error
b = 20;
이번에는 const
키워드를 사용해서 객체로 초기화 해보겠습니다.
const a = {
x: 1,
y: 2
}
여기서 a
에 다른 객체를 재할당 하는건 당연히 에러가 발생합니다.
a = {z:3} //Error
하지만 a
객체 안에 있는 속성 값을 바꾸는 건 가능합니다.
a.x = 3;
console.log(a)
console.log(a)
를 통해서 a
를 확인해보면 x
가 3으로 바뀐 것을 확인할 수 있습니다.
객체의 속성 값을 변경하는 게 가능한 이유는 이건 새로운 객체를 할당하는 게 아니라 기존의 객체의 내부 속성을 변경하는 것이기 때문에 가능합니다.
- const는 변경 불가능 이라면서! 나는 속성 변경이 불편하다! 면?
위처럼 아무리 a의 속성값을 변경하더라도 x의 값은 1로 유지되는 것을 알 수 있습니다.const a = Object.freeze({ x:1, y:2 }) a.x = 3; console.log(a)
- 하지만 이렇게 객체의 속성 변경이 가능한 게 불편하다면
Object.freeze()
라는 함수를 통해서 객체를 얼려주면 됩니다.
'웹 > Javascript' 카테고리의 다른 글
JS의 옵셔널 체이닝 (0) | 2025.03.27 |
---|---|
JS의 템플릿 리터럴 (0) | 2025.03.27 |
JS에서의 비교연산자 (0) | 2025.03.27 |
JS의 Truthy vs Falsy (0) | 2025.03.27 |
JS의 자료형 (1) | 2025.03.27 |