TIL : var, let, const

Perfume·2020년 9월 13일
0

JavaScript

목록 보기
8/13
post-thumbnail

👤 💬 "var, let, const에 대해 설명하세요."

프론트엔드 면접을 준비해본 사람이라면 누구나 한번쯤 정리해봤을 질문이다. 자주 사용하는 키워드기 때문에 잘 알고 있다고 생각하지만, 막상 설명하려고 하면 횡설수설하기 쉬운 질문이기도 하다. 그래서 오늘은 var, let,const에 대해 조금 더 상세하게 정리해보려고 한다.

(22.03.18 수정)

✨ var가 쫓겨난 이유

일단 var,let,const는 셋다 변수를 선언할 때 사용하는 키워드다. 오늘날 개발자들은 주로 let과 const를 사용한다. 특히 나처럼 ES6 이후에 개발 공부를 시작한 사람이라면 var를 사용해본 경험이 아예 없을 수도 있다.

ES5까지 변수를 선언할 수 있는 방법은 var를 사용하는 것이었다. 그렇게 유일무이한 변수 선언 키워드로 활약하던 var는 어쩌다 let과 const에게 자리를 물려주고 레거시 코드에나 등장하는 쇠락한 신세가 되었을까?

🔹 1. 변수 중복 선언 허용

var 키워드로 선언한 변수는 중복 선언이 가능하다. 그래서 동일한 이름의 변수가 이미 선언되어 있는 것을 모르고 변수를 중복 선언하면서 값까지 할당하면 의도치 않게 먼저 선언된 변수 값이 변경되는 부작용이 발생한다.

var x = 1;
// .
// .
// x= 1일 때를 기준으로 작성된 여러 코드들 
// .
var x = 20;

console.log(x); // 20

x값이 1일 때를 기준으로 이미 코드를 다 짜놨는데, x라는 변수명을 사용한 걸 깜빡하고 똑같은 이름으로 새로운 값을 할당했다고 상상해보자. 분명 에러가 날 것이다. 게다가 이런 식으로 발생한 에러는 디버깅도 쉽지 않다.

🔹 2. 함수 외부에서 선언했나요? 그럼 앞으로도 쭉 전역변수!

var 함수 레벨 스코프이기 때문에 var로 선언한 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정한다. 그래서 함수 외부에서 선언했다면 코드 블록 내에서 선언해도 모두 전역 변수가 된다.

이 말이 조금 어려울 수 있는데, 아래 코드를 보자.


var x = 1;

if(true) {
var x = 10;
}

console.log(x); // 10

코드 첫줄에서 x가 함수 바깥, 즉 전역 변수로 선언되었다. 이 경우 x는 낙인처럼 영원히 전역 변수 취급을 받는다. 그래서 두번째 x를 분명 if문 안에 선언했는데도 if문 밖에 x= 10이라는 값이 반영되었다.

for문으로 보면 이 문제가 더욱 심각하다.

var i = index;

for(var i = 0; i <5; i++) {
console.log(i); // 0 1 2 3 4
}

console.log(i); //5

이처럼 for문 안에서 i를 선언해서 사용했을 뿐인데 이 값이 전역(글로벌)로 반영되고 말았다. 이처럼 함수 레벨 스코프는 전역 변수를 남발할 가능성을 높인다. 그럼 전역 변수가 대체 왜 나쁜 걸까?

글로벌 스코프에 함부로, 마구잡이로 변수를 선언하면 안되는 이유는 크게 2가지이다.

1) 메모리 공간의 낭비로 인한 메모리 누수의 가능성

2) 변수 간 충돌 가능성

하나의 웹 페이지, 앱 안에는 수 많은 자바스크립트 파일이 포함되게 된다. 이 때 수 많은 자바스크립트 파일 간에 서로 같은 변수가 단 한 개도 없으리라고 확신할 수 있을까? 절대 그렇지 않을 것이다. 만약 글로벌 실행 컨텍스트가 아니라, 다른 실행 컨텍스트 내에서 변수를 선언할 경우에는 기본적으로 해당 변수에 대한 스코프가 해당 실행 컨텍스트 내부에 한정되기 때문에, 만일 다른 파일에 동일한 변수명이 존재한다고 해도 충돌이 발생할 일은 없다.

그러나 전역에 변수를 생성하면 만일 다른 파일과 변수명이 겹칠 경우, 예상치 못한 버그가 발생된다. 가장 마지막에 불러온 파일을 기준으로 읽히기 때문에 원하지 않는 결과가 발생될 가능성이 높으므로 글로벌에서의 변수 선언은 최대한 피해야 한다.

참조: https://soldonii.tistory.com/65

🔹 3. 호이스팅

var 키워드로 변수를 선언하면 변수 호이스팅에 의해 변수 선언문이 스코프의 선두로 끌어 올려진 것처럼 동작한다. 즉, 변수 호이스팅에 의해 var 키워드로 선언한 변수는 변수 선언문 이전에 참조할 수 있다. 단, 할당문 이전에 변수를 참조하면 언제나 undefined를 반환한다.

이 부분은 호이스팅을 다루는 글에서 자세히 설명하도록 하겠다.

🔹 정리

내키는 대로 중복선언해도 다 받아들여주고, 함수 안에서 선언해도 밖에서 선언한 것과 같은 대접을 해주며, 변수를 선언하기 전에도 참조할 수 있게 해주는 var의 유연함은 오히려 개발을 어렵게 만들었다. 에러가 잘 나는 데다가 발생한 에러가 어디서 왜 생긴 건지 찾기 어려웠기 때문이다.

그래서 var보다 엄격하고 단호한 letconst가 등장했다.

✨let

let은 유연한 var와 깐깐한 const 사이 어디쯤에 있다.

🔹 1. 중복 선언 금지!

var의 단점을 극복하기 위해 let과 const가 등장한 만큼, 이 둘은 많은 문제를 자아내는 변수의 중복 선언을 허용하지 않는다. 그래서 let 키워드로 이름이 같은 변수를 중복 선언하면 문법 에러가 발생한다.

let myLove = cat;

let myLove = kitten; // SyntaxError: Identifier 'myLove' has already been declared

이처럼 에러가 생기기 때문에 실수로 동일한 변수명을 사용했을 때 알 수 있다.

🔹 2. 선언한 위치에 따르는 블록 레벨 스코프

아까 var와 달리 let은 모든 코드 블록(함수, if문, for문, while문 등)을 지역 스코프로 인정하는 블록 레벨 스코프를 따른다.

let myLove = cat; // 전역 변수

{
	let myLove = homie; // 지역 변수
    let myCat = cherie; // 지역 변수
}

console.log(myLove); // cat;
console.log(myCat); // ReferenceError: myCat is not defined

만약 var였다면 myLove라는 변수명이 이미 전역변수로 선언되었기 때문에 코드블록 안에서 선언해도 그 값이 전역변수로 반영됐을 것이다. 하지만 let은 전역에서 선언된 myLove와 코드 블록 내에서 선언된 myLove를 별개의 변수로 취급한다.

🔹 3. 호이스팅? 있는데요.. 없어요

면접에서 var,let,const의 차이점에 대해 설명하라는 질문을 받았을 때 var는 호이스팅이 일어나지만 let과 const는 일어나지 않는다고 대답했다가 "음, 아닙니다. let과 const도 호이스팅이 일어나요." 라는 말을 들었다. 인터넷에서 본 글을 어렴풋이 기억해서 대답했다가 곤란을 겪은 것이다.

let 키워드로 선언한 변수도 호이스팅이 발생한다. 다만 발생하지 않는 것처럼 동작할 뿐이다.

✨ Const

const는 앞서 말한 let의 특징을 똑같이 가지고 있다. 변수를 중복 선언 할 수 없으며, 블록 레벨 스코프를 따르고, 호이스팅이 일어나지 않는 것처럼 동작한다. 하지만 크게 두 가지 부분에서 let과 분명한 차이가 있다.

🔹 초기값 필수!

const 키워드로 변수를 선언하려면 반드시 선언 단계에서 초기값을 할당해줘야 한다.

const homie = 'world best cat!';

만약 저 'world best cat'이라는 초기값이 없이 const homie;라고 선언하면

SyntaxError: Missing initializer in const declaration

라는 에러를 만날 수 있다. 반면 let은 초기값 없이 let homie;라고 선언만 해도 에러가 나지 않는다.

🔹 재할당 금지!

let은 var보다는 엄격하지만, 어느 정도 융통성을 가지고 있다.

👤💬 오늘 저녁에 떡볶이 먹자!
😸 그래! 저녁 메뉴 = 떡볶이
👤💬 아니다, 팟타이 먹자.
😸 그래! 저녁 메뉴 = 팟타이

하지만 const는 몹시 단호하다.

👤💬 오늘 저녁에 떡볶이 먹자!
😸 그래! 저녁 메뉴 = 떡볶이
👤💬 아니다, 팟타이 먹자.
😺 떡볶이라며? 저녁 메뉴 = 떡.볶.이.

위 대화를 코드로 바꾸면

const 저녁 메뉴 = '떡볶이'
저녁 메뉴 = '팟타이'

가 될 것이고,

"TypeError: Assignment to constant variable" 라는 에러 메시지를 보게 될 것이다.

이처럼 const로 선언한 변수는 값을 변경할 수 없다. 정확히 말하면 '원시 값을 할당한 경우' 값을 변경할 수 없다. 만약 const 키워드로 선언된 변수에 객체를 할당한 경우 값을 변경할 수 있다. 원시 값의 경우 재할당 없이는 값을 변경할 방법이 없지만 객체는 재할당 없이도 직접 변경이 가능하기 때문이다.

그렇기 때문에 const 키워드는 재할당을 금지할 뿐 "불변"을 의미하지 않는다.

✨ 최종 정리

이야기가 길었다. 사실 핵심은 간단하다.

"되도록 const를 써라!"

앞서 말했듯이 var는 변수 선언문이 있기도 전에 참조할 수 있게 하며, 재선언과 재할당이 가능하다. let은 var만큼 유연하진 않지만, 재할당이 가능하다. 재선언이나 재할당이 가능한 유연성은 오히려 개발에 독이 된다. 인간은 실수를 하는 생물이기 때문이다. (유연한 자바스크립트 대신 엄격하게 타입을 지정해줘야하는 타입스크립트가 부흥한 것을 보라) 그렇게 때문에 되도록 const를 사용해 변수를 선언하고, 재할당이 필요한 변수만 let을 이용해 선언하자. 심지어 생각보다 재할당이 필요한 경우가 많지 않다.

📚 참고도서

모던 자바스크립트 딥다이브

사실 이 포스팅은 저 책을 참고한 수준이 아니라 저 책을 옮겨 놓고 내 사족을 덧붙인 수준이다.

profile
공부하는 즐거움

0개의 댓글