글을 시작하며
안녕하세요 이번 글에서는 ES6에서 새롭게 등장한 let
const
키워드와
우리네 기억속에서 사라질... var
키워드의 특징과 차이점에 대해서 알아보고자 합니다
주니어 프론트엔드 개발자의 단골 면접 질문인 호이스팅과도 연관이 있기 때문에
이번 글을 통해서 기초 공사를 탄탄하게 하시면 면접에서도 잘 활용할 수 있으실 겁니다!
1. 변수 선언 방식
우리는 지금부터 변수를 선언하고 할당하는 방식에 따라 자유로운 영혼 레벨을 부여할 것입니다.
변수 선언 키워드 | 중복 선언 가능 | 재할당 가능 | 자유로운 영혼 레벨 |
---|---|---|---|
var | O | O | 🤸🤸🤸 |
let | X | O | 🤸🤸 |
const | X | X | 🧘 |
var (중복 선언 O, 재할당 O)
var name = '명수';
console.log(name); // 명수
var name = '준하';
console.log(name); // 준하
name = '명수';
console.log(name); // 명수
var는 매우 자유롭죠? 명수였다가 준하였다가 명수였다가 …
하지만 자유에는 책임이 따르는 법! 같은 이름의 변수가 여러번 선언되어 사용되면 어떤 부분에서 값이 변경되고 문제가 발생하는지 파악하기가 힘듭니다.
이를 보완하기 위해 추가된 변수 선언 키워드가 바로 let과 const입니다.
let (중복 선언 X, 재할당 O)
var name = '명수';
console.log(name); // 명수
var name = '준하';
console.log(name);
// Uncaught SyntaxError: Identifier 'name' has already been declared
name = '준하';
console.log(name); // 준하
let은 var와 달리 중복 선언을 하면 이미 선언되었다는 에러 메세지를 출력합니다.
중복 선언은 불가능하지만 변수에 값을 재할당하는 것은 가능한 녀석입니다.
const (중복 선언 X, 재할당 X)
변수 선언 키워드 중에 가장 까다로운 녀석이라고 할 수 있죠.
중복 선언과 재할당 모두 불가능합니다. 하지만 값이 변할 위험이 없기 때문에 자유로운 var 보다 안전합니다.
var name = '명수';
console.log(name); // 명수
var name = '준하';
console.log(name);
// Uncaught SyntaxError: Identifier 'name' has already been declared
name = '준하';
console.log(name);
// Uncaught TypeError: Assignment to constant variable
2. 스코프 (Scope)
세 키워드는 스코프 범위
가 다릅니다.
여기서 스코프란 어떤 개념일까요?
- 스코프란 식별자(변수, 함수, 클래스 등)에 접근할 수 있는 유효 범위를 뜻합니다.
- 스코프의 범위는 블록(중괄호) 또는 함수에 의해 나눠집니다.
var (함수 레벨 스코프)
function function_level() {
if (true) {
var name = '명수';
console.log(name); // 명수
}
console.log(name); // 명수
}
function_level();
console.log(name); // ReferenceError: name is not defined
- 함수 안에서 선언된 변수는 함수 내에서만 유효합니다. 블록 내부, 외부에 관계 없이 유효합니다.
- 함수 외부에서는 참조할 수 없죠
- 단점: 전역 함수 외부에서 생성한 변수는 모두 전역 변수가 됩니다.
전역 변수를 남발
할 가능성을 높입니다.
let / const (블록 레벨 스코프)
function block_level() {
if (true) {
var name = '명수';
console.log(name); // 명수
}
console.log(name); // ReferenceError: name is not defined
}
block_level();
console.log(name); // ReferenceError: name is not defined
- 모든 코드 블록(중괄호) 내부에서 선언된 변수는 코드 블록 내부에서만 유효합니다.
- 블록 외부에서는 참조할 수 없습니다.
3. 호이스팅 (Hoisting)
호이스팅이란 무엇인지 먼저 아는게 필요하겠죠?
호이스팅이란 함수 안에 있는 모든 변수, 함수 선언들을 스코프의 최상단에 선언한 것처럼 동작하는 방식입니다.
네.. 맞아요.. 어려운 개념입니다.
아직 감이 잡히질 않네요. 자바스크립트에서 호이스팅이 어떻게 동작하는지 먼저 알아보도록 하겠습니다!
자바스크립트에서의 호이스팅 동작 방식
- 자바스크립트 parser가 함수가 실행되기 전에 해당 함수 전체를 훑습니다.
- 함수 내에 존재하는 변수와 함수 선언에 대한 정보를 기억하고 실행합니다.
- 사실 유효 범위는 함수 블록 안이었지만, 필요한 값들은 블록 위의 최상단으로 끌어올립니다.
- 실제 코드가 끌어올려지는 것은 아니고 자바스크립트 parser 내부적으로 끌어올려서 처리하는 것이기 때문에 실제 메모리 변화는 없습니다.
백문이 불여일견! 코드로 보시면 이해가 더 잘 되실 겁니다.
var 선언문 호이스팅
console.log(name); // undefined
var name = '명수';
console.log(name); // 명수
변수 name이 선언되기 전에 참조를 했는데 에러가 발생하지 않고 undefined가 출력되었습니다.
왜 그럴까요?
코드 실행 전에 자바스크립트 내부에서 미리 변수 name을 선언해서 (마치 스코프 최상단에서 선언 된 것처럼요) undefined로 초기화를 해두었기 때문입니다.
함수 선언문 호이스팅
test(); // test
function test() {
console.log('test');
}
함수 선언문 또한 함수 선언 전에 호출을 해도 에러가 발생하지 않고 test를 출력합니다.
let / const 선언문 호이스팅
console.log(name); // ReferenceError: name is not defined
const name = '명수';
console.log(name); // 명수
반면, let과 const의 경우 변수 name이 선언되기 전에 참조하면 에러가 발생합니다.
왜 이런 차이가 발생했을까요?
var
의 경우 변수를선언함과 동시에 초기화
가 이루어지지만,let과 const
의 경우선언만 하고 초기화는 하지 않습니다.
- 초기화는 위에서부터 순차적으로 코드를 실행하는 과정에서 변수 선언문을 만났을 때 수행됩니다.
- 따라서 위의 코드에서는
선언은 되었으나 초기화를 하지 않았기 때문에 에러
가 발생하는 것이었습니다. - 선언과 초기화 사이에 일시적으로 변수를 참조할 수 없는 구간을
TDZ
(Temporal Dead Zone)이라고 부릅니다.
Okay!
- var: 변수를 선언과 동시에 초기화합니다.
- let/const: 변수를 선언만하고 초기화는 하지 않습니다.
- 위에서부터 순서대로 코드를 실행하다가 변수 선언문을 만났을 때 초기화를 합니다.
- 그렇다면 선언과 초기화 사이의 간극이 있죠? 이 간극을 TDZ라고 합니다.
- ☠️Temporal Dead Zone☠️ 이라는 의미처럼 TDZ에서는 일시적으로 변수를 참조할 수 없습니다.
- 따라서 TDZ 때문에 변수를 참조할 수 없는 구간이 생겨서 호이스팅이 동작하지 않는 것처럼 보입니다.
아직 한 발 남았습니다..
함수 표현식 호이스팅
test(); // error
var test = function () {
console.log('test');
};
test(); // test
함수 선언이 아닌 함수 표현식에서도 let과 const와 동일하게 TDZ가 발생하기 때문에 에러가 발생합니다.
그렇다면 뭘 쓰는게 좋을까요?
- 재할당이 필요없는 경우 기본적으로
const
를 사용하는 것이 좋습니다. 의도치 않은 재할당을 방지하니까 안전하기 때문이죠. - 재할당이 필요한 경우 let을 사용하는 것이 좋습니다. 단, 변수의 스코프는 예측 가능하도록 최대한 좁게 만드는 것이 좋습니다!
면접 대비 해볼까요?
Q. 스코프 관점에서의 var, let, const의 차이를 설명해주세요.
- var는 함수 레벨 스코프를 따르며 let과 const의 경우 블록 레벨 스코프를 따릅니다.
- 함수 레벨 스코프의 경우 함수 내부에서 선언한 변수만 지역 변수이며 함수 외부에서 작성한 변수의 경우 전역 변수가 됩니다.
따라서 전역 변수를 남발할 가능성이 있고 이에 따라 의도치 않은 재할당이 발생할 위험이 있습니다. - 블록 레벨 스코프란 블록 내부에서 선언한 변수는 블록 내부에서만 지역 변수의 역할을 하는 방식입니다.
Q. 호이스팅 관점에서의 var, let, const의 차이를 설명해주세요.
-
var는 선언과 동시에 초기화가 이뤄지기 때문에, 선언 전에 참조를 해도 에러가 발생하지 않습니다.
이와 같이 변수나 함수의 선언이 코드의 최상단에서 선언한 것처럼 동작하는 방식을 호이스팅이라고 합니다. -
이와 달리 let과 const는 선언과 초기화 단계가 별개로 동작합니다. var과 달리 초기화는 코드 실행하는 과정에서 선언문을 만났을 때 동작합니다.
-
이처럼 선언과 초기화 사이의 간극을 TDZ라고 하는데, TDZ에서는 변수를 참조할 수 없기 때문에 호이스팅이 동작하지 않는 것처럼 보입니다.
자바스크립트 개념 자바드림 🤝