Skip to content

Instantly share code, notes, and snippets.

@LeoHeo
Last active February 13, 2024 08:21
Show Gist options
  • Save LeoHeo/7c2a2a6dbcf80becaaa1e61e90091e5d to your computer and use it in GitHub Desktop.
Save LeoHeo/7c2a2a6dbcf80becaaa1e61e90091e5d to your computer and use it in GitHub Desktop.
javascript var, let, const 차이점

var, let, const 차이점은?

  • varfunction-scoped이고, let, constblock-scoped입니다.

  • function-scopedblock-scoped가 무슨말이냐?

var(function-scoped)

jsfiddle 참고주소

// var는 function-scope이기 때문에 for문이 끝난다음에 i를 호출하면 값이 출력이 잘 된다.
// 이건 var가 hoisting이 되었기 때문이다.
for(var j=0; j<10; j++) {
  console.log('j', j)
}
console.log('after loop j is ', j) // after loop j is 10


// 아래의 경우에는 에러가 발생한다.
function counter () {
  for(var i=0; i<10; i++) {
    console.log('i', i)
  }
}
counter()
console.log('after loop i is', i) // ReferenceError: i is not defined

그럼 항상 function을 만들어서 호출해야 할까? 그건 아니다.

javascript에서는 immediately-invoked function expression (or IIFE, pronounced "iffy")라는것이 있다.

IIFEfunction-scope인거 처럼 만들 수가 있다.

// IIFE를 사용하면
// i is not defined가 뜬다.
(function() {
  // var 변수는 여기까지 hoisting이 된다.
  for(var i=0; i<10; i++) {
    console.log('i', i)
  }
})()
console.log('after loop i is', i) // ReferenceError: i is not defined

근데 javascript는 여기서 좀 웃긴 부분이 있다.

위에서 잠깐 말했지만 IIFEfunction-scope처럼 보이게 만들어주지만 결과가 같지는 않다.

// 이 코드를 실행하면 에러없이 after loop i is 10이 호출된다.
(function() {
  for(i=0; i<10; i++) {
    console.log('i', i)
  }
})()
console.log('after loop i is', i) // after loop i is 10

위에 코드가 아무 에러 없이 실행되는 이유는 i가 hoisting이 되어서 global variable이 되었기 때문이다.

그래서 아래와 같이 된 것이다.

var i
(function() {
  for(i=0; i<10; i++) {
    console.log('i', i)
  }
})()
console.log('after loop i is', i) // after loop i is 10

IIFE는 쓰는데 이렇게 hoisting이 된다면 무슨 소용이 있겠는가?!

그래서 이런 hoisting을 막기 위해 use strict를 사용한다.

// 아까랑 다르게 실행하면 i is not defined라는 에러가 발생한다.
(function() {
  'use strict'
  for(i=0; i<10; i++) {
    console.log('i', i)
  }
})()
console.log('after loop i is', i) // ReferenceError: i is not defined

어떤가? 뭔가 변수 선언때문에 너무 많은 일을 한다고 생각하지 않는가?

그럼 let, const에 대해서 알아보자.

let, const(block-scoped)

  • es2015에서는 let, const가 추가 되었다.

javascipt에는 그동안 var만 존재했기 때문에 아래와 같은 문제가 있었다.

// 이미 만들어진 변수이름으로 재선언했는데 아무런 문제가 발생하지 않는다.
var a = 'test'
var a = 'test2'

// hoisting으로 인해 ReferenceError에러가 안난다.
c = 'test'
var c

위와 같은 문제점으로 인해 javascript를 욕 하는 사람이 참 많았다.

하지만 let, const를 사용하면 var를 사용할때보다 상당히 이점이 많다.

두개의 공통점은 var와 다르게 변수 재선언 불가능이다.

letconst의 차이점은 변수의 immutable여부이다.

let은 변수에 재할당이 가능하지만,

const는 변수 재선언, 재할당 모두 불가능하다.

// let
let a = 'test'
let a = 'test2' // Uncaught SyntaxError: Identifier 'a' has already been declared
a = 'test3'     // 가능

// const
const b = 'test'
const b = 'test2' // Uncaught SyntaxError: Identifier 'a' has already been declared
b = 'test3'    // Uncaught TypeError:Assignment to constant variable.

let, const가 hoisting이 발생하지 않는건 아니다.

varfunction-scoped로 hoisting이 되었다면

let, constblock-scoped단위로 hoisting이 일어나는데

c = 'test' // ReferenceError: c is not defined
let c

위에 코드에서 ReferenceError가 발생한 이유는 tdz(temporal dead zone)때문이다.

let은 값을 할당하기전에 변수가 선언 되어있어야 하는데 그렇지 않기 때문에 에러가 난다.

이건 const도 마찬가지인데 좀 더 엄격하다.

// let은 선언하고 나중에 값을 할당이 가능하지만
let dd
dd = 'test'

// const 선언과 동시에 값을 할당 해야한다.
const aa // Missing initializer in const declaration

이렇게 javascript에 tdz가 필요한 이유는 동적언어이다 보니깐 runtime type check 가 필요해서이다.

Reference

@Bigone0617
Copy link

좋은 설명 감사합니다 :)

@thiporia
Copy link

감사히 잘 읽었습니다. : )

@niklasjang
Copy link

감사합니다. Gist는 PR이 없어서 여기에 코멘트를 남깁니다.

Pull Request

Change

위에 코드가 아무 에러 없이 실행되는 이유는 i가 hoisting이 되어서 global variable이 되었기 때문이다.

그래서 아래와 같이 된 것이다.

to

위에 코드가 아무 에러 없이 실행되는 이유는 i가 hoisting이 되어서 global variable이 되었기 때문이다.

hoisting이란 "변수의 선언문을 유효 범위의 최상단으로 끌어올리는 행위"를 말한다. IIFE를 사용할 때는 function을 사용하지 않는 것과 같이 global variable로 hoisting이 이루어진다.

그래서 아래와 같이 된 것이다.

@soorichu
Copy link

와우 이제야 이해했어요! 감사합니다~~

@blueboy1593
Copy link

감사합니다~

@ryuseongryong
Copy link

감사합니다 성장하시는 개발자님

@chomookun
Copy link

chomookun commented Feb 23, 2020

아.. 제가 잘못본듯.ㅋ

@TuenTuenna
Copy link

명쾌한 설명에 무릎을 탁! 치고 갑니다 ㅎㅎ

@j3470
Copy link

j3470 commented Mar 25, 2020

군더더기 없이 깔-끔합니다. 덕분에 확실히 알고 갑니다. 감사... 압도적 감사! ㅎㅎ..

@ilgwonPark2
Copy link

감사히 잘 읽었습니다!
핵심이 잘 녹아져있어요

@haerang94
Copy link

잘 읽었습니다

@atelier2430
Copy link

막연하게 떠다니던 개념이 잡혔어요 감사합니다!

@AnneMayor
Copy link

깔끔하게 정리 잘하셔서 이해하기 쉬웠습니다
감사합니다

@Kibmer
Copy link

Kibmer commented Sep 10, 2020

잘봤습니다~

@YoungHaKim7
Copy link

감사합니다. 너무 너무 잘 이해 됐습니다. 정리 너무 좋습니다.

@hyunsoojin
Copy link

감사합니다~

@hyun031916
Copy link

좋은 설명 감사합니다~ 이해가 잘 되었어요!

@SEUNGHYEOK1992
Copy link

좋은 설명 감사합니다.ㅠㅠ

@SunggukCho
Copy link

예시와 설명이 너무 깔끔하네요
감사합니다!

@LEE-YONG-UN
Copy link

LEE-YONG-UN commented Jun 4, 2021

감사합니다. 도움되었습니다!

@leobang17
Copy link

감사합니다 설명 깔끔하네요.

@overnew
Copy link

overnew commented Jul 28, 2021

깔끔한 설명 감사드립니다.

@dinggididudara
Copy link

👍

@YounglanHong
Copy link

명쾌한 설명 감사합니다. 덕분에 TDZ에 대해서도 이해했어요:)

@moungJae
Copy link

감사합니다!

@SeoSangmin
Copy link

좋은 글 감사합니다!

@younho9
Copy link

younho9 commented Dec 31, 2021

// 이 코드를 실행하면 에러없이 after loop i is 10이 호출된다.

(function() {
  for(i=0; i<10; i++) {
    console.log('i', i)
  }
})()
console.log('after loop i is', i) // after loop i is 10

위에 코드가 아무 에러 없이 실행되는 이유는 i가 hoisting이 되어서 global variable이 되었기 때문이다.
그래서 아래와 같이 된 것이다.

여기 부분은 i가 hoisting 되어서 global variable이 되었다기보다 키워드 없이 선언된 변수는 암시적으로 전역 객체에 프로퍼티로 할당되기 때문인 것 같습니다.

function fn() {
    foo = 123; // window.i = 123 과 동일
}

fn();
console.log(foo); // 123

@PARKGAIN
Copy link

글 잘보고 갑니다 감사합니다!

@ChaeJiHyeon
Copy link

감사합니다

@Rayched
Copy link

Rayched commented Jul 24, 2023

좋은 글 감사합니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment