본문으로 건너뛰기
yceffort
PostsSeriesTagsAbout🧪 Research
EN

Tweaks

theme
accent palette
film grain
minimal mode
BACK TO INDEX
◆ ESSAY
--min
--year
KOoriginal

mailMail icongithubtwitter
yceffort
•
© 2026
•
https://yceffort.kr
BACK TO INDEX
◆ ESSAY

var let const, 그리고 호이스팅

avatar
yceffort
2020-05-20 · 6분
6min
2020year
KOoriginal
javascript

var let const, 그리고 호이스팅

var

우리가 모두 아는 var 키워드는 아래와 같은 특징을 가지고 있다.

  1. 함수레벨 스코프를 가지고 있다.

    대부분의 프로그래밍 언어들이 블록 레벨 스코프를 사용하고 있지만, var로 선언된 키워드는 함수레벨 스코프를 갖는다.

    var name = 'hello'
    
    function t() {
      var name = 'hi'
      console.log(name) // hi
    }
    
    t()
    console.log(name) // hello
    
  2. var 키워드는 생략이 가능하다.

    생략이 가능하기 때문에, 함수가 선언한 환경의 this에 영향을 받는다. 일반적인 웹 환경에서는 window일 것이다.

  3. 중복 선언이 가능하다.

    var name = 'hello'
    var name = 'hi'
    console.log(name) // hi
    
  4. 호이스팅 당한다.

    호이스팅이란

    스코프 안에 있는 선언들을 모두 스코프의 최상위로 끌어올리는 것

    이다. 자바스크립트 인터프리터가 코드를 해석할 때 함수의 선언, 할당, 실행을 모두 나눠서 처리하기 때문이다. 예를 들어보자.

    console.log(name) // undefined
    var name = 'hello'
    

    이 코드는 참조 에러가 나지 않고, undefined를 리턴한다. 그 이유는 자바스크립트가 호이스팅을 하면서 아래와 같은 방식으로 코드를 해석하기 때문이다.

    var name // undefined
    console.log(name)
    name = 'hello'
    

2. let

let은 es6에서 가장 잘 알려진 기능 중 하나다. var랑 비슷한 것 같지만, 사실 몇가지 다른 점이 있다.

  1. 블록 수준 스코프를 가지고 있다.

    아래의 예를 살펴보자.

    {
      {
        {
          var name = 'hello'
        }
      }
    }
    console.log(name) // hello
    
    {
      {
        {
          let name2 = 'hi'
        }
      }
    }
    console.log(name2) // ReferenceError: name2 is not defined
    

    let과 const는 모두 블록 수준의 스코프를 사용 하고 있다. 따라서 블록 내부에서 선언한 변수는 모두 지역변수로 취급된다. 때문에 블록 내부에서 선언한 변수들을 참고할 수가 없다.

  2. 키워드 생략이 불가능하다.

    키워드를 생략하면 var처럼 작동하게 된다.

  3. 중복선언이 불가능하다.

    그렇다.

  4. 호이스팅 당한다.

    가끔 인터넷을 뒤지다보면, let과 const는 호이스팅 당하지 않는다는 이야기가 있는데, 이는 잘못된 사실이다. 두 키워드 모두 호이스팅 당하기는 마찬가지이다.

    이것을 이해하기 위해서는, Temporary Dead Zone에 대해 알아야 한다.

Temporary Dead Zone

아래 코드를 살펴보자.

name = 'hello' // ReferenceError: Cannot access 'name' before initialization
let name = 'hi'

자. 만약 name이 호이스팅 되지 않았다면, 두 번째 let선언에서 already declared에러가 났었어야 했다. 근데 현실은 초기화 하기전에 엑세스 할 수 없다는 에러를 내뱉었다.

아래 코드는 어떨까?

function sayHello() {
  return name
}
let name = 'hi'
console.log(sayHello()) // hi

별탈없이 hi를 내뱉은 것을 볼 수 있다. 그 말인 즉, name이 분명 호이스팅 되었다는 뜻이다.

다른 이야기로 넘어가서, 자바스크립트에서는 총 3단계에 걸쳐서 변수를 생성한다.

  1. 선언(Declaration): 스코프와 변수 객체가 생성되고, 스코프가 변수 객체를 참조한다.
  2. 초기화(Initialization): 변수 객체 값을 위한 공간을 메모리에 할당한다. 이 때 할당되는 값은 undefined다.
  3. 할당(Assignment): 변수 객체에 값을 할당한다.

var는 선언과 동시에 초기화가 이루어진다. 즉, 선언과 동시에 undefined가 할당된다.

그러나 let과 const는 다르다. 선언만 될뿐, 초기화가 이루어지지 않는다. 바로 이단계에서 TDZ에 들어가게 되는 것이다. 즉, 선언은 되어있지만, 초기화가 되지 않아 이를 위한 자리가 메모리에 준비되어 있지 않은 상태라는 것이다.

const

const에서 구별되는 특징만 몇가지 살펴보자.

  1. const는 초기화와 동시에 선언이 이루어져야 한다.

    let hello
    hello = 'hello'
    
    const hi //SyntaxError: Missing initializer in const declaration
    hi = 'hi'
    
  2. const 자체가 값을 불변으로 만드는 것이 아니다.

    아래 코드는 당연히 안된다.

    const hello = 'hello'
    hello = 'hi' // TypeError: Assignment to constant variable.
    

    그렇다고 이것도 안되는 것은 아니다.

    const hello = ['hi']
    hello.push('hello')
    
    const hello = 'hello'
    var hi = hello
    hi = 'hi'
    console.log(hello) // hello
    console.log(hi) // hi
    

    객체 자체를 동결시키기 위해서는 Object.freeze를 사용하면 된다.

  3. 상수를 선언할 때 사용한다.

결론

  • 호이스팅은 변수의 선언을 최상단에 끌어올린다는 뜻이다.
  • var let const는 모두 호이스팅 된다.
  • let 선언과 동시에 TDZ에 들어가서 초기화가 필요한 별도의 상태로 관리된다.
  • const 는 선언과 동시에 초기화, 할당까지 이루어진다.
  • var는 왠만하면 쓰지말자
  • let대신 const를 사용하자. let으로 선언되어 있다면, 어디선가 이 변수가 바뀔지도 모른다는 생각을 가지고 있어야 하므로, 코드를 읽기가 어려워진다. 반면 const는 초기화, 선언, 할당까지 되어 있으니 변경되지 않을 것이다라는 확신으로 코드를 볼 수 있다. (물론 객체의 속성은 바뀔 수 있음.)

관련 글

  • #turbopack#nextjs#bundler

    Next.js turbopack에서 싱글톤이 두 개가 됐다: scope hoisting 버그와 순환 import

    Next.js 16 turbopack 프로덕션 빌드에서 모듈 스코프 싱글톤이 런타임에 두 개가 됐다. 같은 동기 구간에서 조건 판정이 뒤집히고, 응답이 도착해도 타임아웃이 나는 증상을 번들 산출물로 추적한 기록. scope hoisting의 부분 병합, 순환 import, 이미 고쳐져 있던 upstream 버그, 그리고 뒤늦게 돌린 단일 변수 실험까지.

    2026-08-19·28분
  • #javascript#animation#web-animations-api

    number-flow를 구형 브라우저로 이식하기: 다섯 가지 결정과 두 가지 번복

    number-flow가 애니메이션을 켜는 최소 버전은 Chrome 125, Safari 17.2다. 이 하한을 Chrome 66과 WebKit 16.4까지 내리는 포크를 만들면서 내린 결정들과, 뒤집게 된 판단 두 가지, 그리고 자동 강등을 포기한 Safari 버그 조사의 기록.

    2026-08-11·44분
  • #nodejs#security#javascript

    Node.js vm 모듈의 함정: 샌드박스가 아닌 이유

    집필 중인 Node.js Deep Dive의 5.2장(vm 모듈의 함정) 일부를 미리 공개합니다.

    2026-02-27·25분
  • #nodejs#javascript

    Node.js Deep Dive (가제) 베타 리더를 모십니다.

    많관부22

    2026-02-19·5분

새 글을 놓치고 싶지 않으시다면 RSS로 구독해 주세요.

RSS 구독 →

yceffort — 프론트엔드 엔지니어입니다. 발표·기술 자문·기고 문의는 이곳에서 받고 있습니다.

← Back to the blogIssue on GitHub →