Home
PostsAbout
javascript

var, let, const

면접 단골 질문 var, let, const

2024-11-24

스코프 관점

var adult = true;

if (adult) {
	var myName = "카일";
	let age = 39;
	console.log('쉿! 비밀입니다!');
}

console.log(myName);
// 카일

console.log(age);
// 오류 발생!

var로 선언한 변수는 접근 범위가 함수 스코프인데 반해 let으로 선언한 변수는 변수 접근 범위가 블록입니다. 변수의 접근 범위를 블록으로 한정 지으면 프로그램 내 변수의 영향 범위를 제한해 변수 이름 중복을 막아준다는 측면에서 유용합니다.

💡 You Don’t Know JS의 저자 카일 심슨은 var를 피하고 let이나 const를 사용하라고 제안하는 경우에 대해서 부정적인 입장입니다. 그는 이런 제안이 지나치게 한정을 짓는 제안이고 도움이 되지 않는 제안이라 생각하며 var를 사용하지 말라고 제안하는 건 여러분이 학습 능력과 여러 기능을 조합해서 사용하는 능력이 없다고 간주하는 것과 같다고 주장합니다.

호이스팅

var, let, const 모두 호이스팅됩니다. 그렇기 때문에 다음과 같은 코드를 작성할 수도 있습니다.

pleaseDontDoThis = '이렇게 하지 마세요';

// 훨씬 나중에 변수를 선언
var pleaseDontDoThis;

하지만 이런 식으로 호이스팅을 응용해 코드를 역순으로 배치하는 방식은 함수 호이스팅 측면에서는 가독성에 도움을 주지만, 변수 호이스팅 측면에서는 가독성에 좋지 않습니다.

호이스팅은 JS만의 독특한 특징입니다. 특정 스코프 내에 선언한 변수가 선언된 위치와 상관없이 해당 스코프 시작 부분에서 선언한 것마냥 처리되어 호이스팅이란 이름이 붙었습니다.

var 키워드로 선언한 변수는 호이스팅되었을 때 자동으로 undefined로 초기화됩니다. 그렇기 때문에 실제 값이 할당되기 이전에도 변수에 접근할 수 있습니다.

하지만 let, const 키워드로 선언한 변수는 똑같이 호이스팅이 되긴 하지만 undefined로 초기화되지는 않습니다. 그 이유는 무엇일까요? 그 이유는 TC39의 논의 속에 있습니다.

{
	// 여기에 무엇이 출력되어야 할까요?
	console.log(studentName);
	
	// 수많은 코드가 있다고 가정
	const studentName = '보라';
	
	// ...
}

const로 선언한 studentName이 var 선언처럼 블록 상단으로 호이스팅될 뿐만 아니라 자동으로 undefined로 초기화된다고 가정해봅시다. 블록 전반부에서 studentName의 값은 undefined입니다. const studentName = … 에 도달하면 studentName에 “보라”가 할당됩니다. 이 지점부터는 studentName에 재할당이 불가능해집니다.

하지만 이는 우리가 생각하는 상수는 오직 하나의 값이라는 상식에 위배됩니다. studentName은 호이스팅되지만 undefined로 초기화할 수도 없고 스코프 전체에서 변수의 값이 일관되어야 한다는 문제에 봉착했습니다. 그럼 변수가 처음 존재하는 시점과 값이 할당되는 시점 사이에 붕 뜨는 시간은 어떻게 처리해야 하는 걸까요?

TC39는 이 시간을 TDZ라 부르기로 결정합니다. 그리고 TDZ에 있는 변수에 접근하는 걸 허용하지 않고, 접근하려 할 때는 TDZ 오류를 발생시키자고 결정합니다.

곁다리 let

위와 같은 이유로 TC39는 const 를 호이스팅하기로 함과 동시에 TDZ를 만들기로 결정하였습니다. 그와 곁들여서 let 에도 TDZ를 만드는게 좋다고 결정내렸습니다. 카일 심슨은 let 에 TDZ를 도입하면 기술적, 사회 공학적 측면에서 장점이 있다고 말합니다. let 에 TDZ를 도입하면 개발자들이 코드를 블록 상단에 선언하는 기존의 관행을 줄여 코드 가독성을 높이고 변수의 범위를 더 명확하게 할 수 있습니다. 또한 변수를 신중하게 사용하고 변수의 스코프와 초기화 시점에 더 주의하게 된다는 효과도 있습니다.

Dan의 On let vs const

Dan이 블로그에 작성한 글 중에 prefer-const ESLint rule에 대한 이야기가 있습니다. 다음은 그 이야기에 대한 요약입니다.

Why prefer-const

  • One Way to Do It: let 을 사용해야 할지 const 를 사용해야 할지 고민할 필요가 없습니다.
  • Reassignments May Cause Bugs: 재할당은 버그로 이어질 가능성이 있습니다.
  • Learning About Mutation: const 를 사용하면 재할당과 mutation의 차이점을 배울 수 있습니다.
  • Meaningless Assignments: 리액트의 useState 의 동작 원리를 빠르게 배울 수 있습니다.
  • Performance Benefits: 어떤 변수가 변하지 않을 것이라고 알려주는 것은 JS 엔진이 코드를 더 빠르게 실행할 수 있게 합니다.

Why Not prefer-const

  • Loss of Intent: 매번 const 만 사용하다보면 정작 중요하게 상수라고 표현해야하는 곳의 의미 전달을 하기가 쉽지 않습니다.
  • Confusion with Immutability: 개발을 이제 시작하는 초보자들에게 immutability와 재할당 사이에 혼란을 줄 수 ㄷ있습니다.
  • Pressure to Avoid Redeclaring: const 를 우선으로 사용하도록 강제하는 코드 베이스에서는 조건부로 값을 할당할 때에도 let 을 사용하기 꺼려지게 만듭니다.
  • Reassignments May Not Cause Bugs: 재할당이 버그를 야기하는 일이 생각보다 많지 않습니다.
  • No Performance Benefits: 이미 엔진은 어떤 변수가 한 번만 할당될 것인지 알고 있습니다. 심지어 varlet 을 사용하더라도요. 오히려 const 를 사용함으로써 엔진이 별도의 체크를 한 번 더 해야할 수도 있습니다.

My Conclusion

  • 신경쓰지 않습니다. 그냥 코드 베이스대로 따라서 사용할 것입니다.
  • 만약 당신이 이것에 대해 신경을 쓴다면 린터를 사용해서 이러한 고민을 덜어내세요.
  • 마지막으로 혹시 린터가 오히려 당신과 당신의 팀에게 혼란만 준다면, 그 린터는 생각보다 별로일 수도 있습니다. 삭제하십쇼.

참고 자료