[Javascript] var, let, const에 대하여

박기영·2022년 12월 10일
0

Javascript

목록 보기
28/45

스코프를 공부하던 중, var, let, const의 스코프가 다르다는 것을 알게되었다.
사실, 필자가 프론트엔드 공부를 시작한 시점에는 이미 let, const가 일반적으로 사용되는 시기였기 때문에 var를 단 한번도 사용한 적이 없다.
그래도 언젠가 취업했을 때 레거시 코드에서 등장할 수도 있고, 자바스크립트의 시초가 되는 것이기도하니 차이를 공부해놓고자 한다.

스코프

우선, 이들의 차이를 알아보기 전에 어떤 놈이 어떤 스코프를 가지는지 명시하고 넘어가려고한다.
더 자세한 설명은 필자의 스코프에 대한 게시글을 참고해주세요.

var : 함수 레벨 스코프(Function-level scope)
let, const : 블록 레벨 스코프(Block-level scope)

함수 레벨 스코프는 말그대로 함수 내에서 선언된 것은 함수 내에서만 유효하다는 것이다.
블록 레벨 스코프는 {...}, 즉, 중괄호로 감싸진 범위 내에서만 유효하다는 것이다.

var

var의 특징에 대해서 알아보자.

스코프 : 함수 레벨 스코프
재선언 : 가능
재할당 : 가능

아래 코드를 통해 살펴보자.

var a = 10;

console.log(a); // 10

var a = 20;

console.log(a); // 20

a = 30;

console.log(a); // 30

분명, 맨 위에서 변수 a를 선언하고 할당했음에도 불구하고,
바로 다음에 다시 선언을 할 수가 있다.
또한, 재할당도 할 수 있다.

이번에는 스코프에 관련된 부분을 살펴보자.

for (var i = 0; i < 3; i++) {
  console.log(i);
}

console.log(i); // 3

함수 레벨 스코프를 가지기 때문에 for문 외부에서도 변수에 접근이 가능하다.
사실 이 부분은 약간 헷갈릴 수 있다.
아래 예시를 보자.

function varTest() {
  var test = 1;
  
  console.log(test);
}

varTest(); // 1

console.log(test); // ReferenceError: test is not defined

정말. 말그대로. 함수 내부에서 선언된 것함수 내부에서만 사용할 수 있다.
그 외에는 접근이 가능하다.(방금 for문 예시처럼)

let

let의 특징에 대해서 알아보자.

스코프 : 블록 레벨 스코프
재선언 : 불가능
재할당 : 가능

아래 코드를 통해 살펴보자.

let a = 10;

console.log(a); // 10

a = 20;

console.log(a); // 20

재할당은 가능하다.
그러나 재선언을 하게된다면?

let a = 10;

console.log(a);

a = 20;

console.log(a);

let a = 30; // SyntaxError: Identifier 'a' has already been declared

console.log(a);

에러가 발생한다.
같은 스코프 내에서는 변수를 재선언 할 수가 없다.
그러면 스코프가 달라질 때는 어떻게 될까?

function declaration() {
  let a = 10;

  console.log(a); // 10

  a = 20;

  console.log(a); // 20
}

function wantReDeclaration() {
  let a = 30;
  
  console.log(a); // 30
}

declaration();
wantReDeclaration();

같은 변수명을 가짐에도 코드가 작동한다.
이는 let블록 레벨 스코프를 가지기 때문이다.
중괄호({...}) 내에서 선언된 변수는 중괄호를 빠져나가면 유효하지 않기 때문이다.

따라서, var 변수에서 살펴봤던 for문 예시는 아래와 같이 작동한다.

for (let i = 0; i < 3; i++) {
  console.log(i);
}

console.log(i); // ReferenceError: i is not defined

for문의 중괄호를 빠져나오자, 유효하지않은 변수로 변한 것을 확인 할 수 있다.

const

const의 특징에 대하여 알아보자.

스코프 : 블록 레벨 스코프
재선언 : 불가능
재할당 : 불가능

아래 코드를 통해 살펴보자.

const a = 10;

console.log(a); // 10

a = 20; // TypeError: Assignment to constant variable.

console.log(a);

재할당이 안되는 것을 확인 할 수 있다.
물론, 재선언도 안된다.

const a = 10;

console.log(a); // 10

const a = 20; // SyntaxError: Identifier 'a' has already been declared

console.log(a);

그렇다면 스코프를 다르게 했을 때는 어떨까?

function declaration() {
  const a = 30;
  
  console.log(a); // 30
}

function wantReDeclaration() {
  const a = 10;

  console.log(a); // 10
}

declaration();
wantReDeclaration();

스코프를 다르게 했더니 재선언이 가능하다.
이는 const블록 레벨 스코프를 가지기 때문에 가능한 것이다.
중괄호를 벗어나면 그 유효성을 잃는다.

호이스팅(hoisting)

호이스팅이란 변수,함수 선언이 해당 스코프의 최상단으로 끌어 올려진 것 같은 현상을 말한다.
자세한 설명은 필자의 호이스팅에 대한 게시글을 참고해주세요.

아무튼, 이 얘기가 갑자기 왜 나오느냐?
varlet,const의 변수 선언에서의 동작 차이를 설명하기 위해서이다.

변수는 2단계를 거쳐서 생성된다.

  • 1단계 : 선언(Declaration)
    변수 이름을 실행 컨텍스트에 등록해서 자바스크립트 엔진에 변수의 존재를 알린다.

  • 2단계 : 초기화(Initailization)
    값을 저장하기 위한 메모리 공간을 확보하고, 암묵적으로 undefined를 할당해 초기화한다.

아래 코드를 살펴보자.

console.log(a); // undefined

var a;

요상한 코드다. 선언되기도 전에 변수를 사용했다.
그러나, 에러는 발생하지않는다.
호이스팅에 의해 var의 선언이 최상단으로 끌어올려졌기 때문이다.(실제로는 그런 것처럼 보이는 것이다)

그런데...선언이 최상단으로 끌어올려진 것이지 초기화는 아니지않나?
undefined가 된거지?

이게 바로 varlet,const의 차이이다.

var는 선언과 동시에 초기화까지 진행된다.
그러나 let은 선언과 초기화가 별개로 작동한다.

console.log(b); // ReferenceError: Cannot access 'b' before initialization

let b;

초기화되지 않았기 때문에 undefined가 출력되지 않고, 에러가 발생하는 것이다.

let의 초기화는 let이 존재하는 코드에 도착했을 때 이루어진다.
즉, 아래와 같이 코드를 작성해야, let의 선언과 초기화가 동시에 된다는 것이다.

let b;

console.log(b); // undefined

호이스팅으로 인해 선언이 먼저 완료가 되며,
let 선언 코드 라인에 도착해서 초기화를 통해 undefined를 할당한다.

const는 할당까지 해주지 않으면 문법적으로 에러가 발생한다.

console.log(c);

const c; // SyntaxError: Missing initializer in const declaration

이 에러는 콘솔과 const 선언의 순서를 바꿔도 마찬가지이다. 문법적인 에러이기 때문이다.
const를 사용할 때는 변수 선언 및 할당을 전부 해줘야 문법 에러가 나지 않는다.

참고 자료

하나몬님 블로그 - 스코프와 변수 선언
하나몬님 블로그 - 호이스팅
eunjinii님 블로그
LeoHeo님 깃허브

profile
나를 믿는 사람들을, 실망시키지 않도록

0개의 댓글