들어가며
ES6에서는 변수를 사용하기 위해 새로운 문법인 let과 const를 지원하면서 동시에, var의 사용을 지양하라고 권한다. 그렇다면 var는 어떤 문제가 있기에 새로운 대체 문법이 생겼는지, 어떤 차이가 있는지 살펴보자.
우선은 var의 문제점 세 가지를 살펴보자.
var의 세 가지 문제점
1. 선언을 중복해서 할 수 있다
var code = 10;
var code = 20;
console.log(`code: ${code}`); // 'code: 20'
같은 이름의 변수를 중복해서 선언해도 정상적으로 동작하며, 가장 마지막 값을 저장하고 있는다.
2. scope의 범위가 전역 / 함수로 제한된다
var code = 10;
if (true) {
var code = 0;
var codeName = 'Hello JS!';
}
console.log(`code: ${code}`); // 'code: 0'
console.log(`codeName: ${codeName}`); // 'codeName: Hello JS!'
if 구문 안에서 새로운 변수를 사용했지만 기존 변수에 데이터가 재할당 되었다. 위에서 본 '1) 선언을 중복해서 할 수 있다'와 동일하게 동작했다. 이를 통해 if 구문 안의 scope는 전역(Global)과 동일하게 취급받는 것을 알 수 있다.
3. Hoisting이 가능하다
console.log(`Before declare: ${code}`); // 'Before declare: undefined'
var code = 10;
console.log(`After declare: ${code}`); // 'After declare: 10'
JS는 변수의 선언이 실행 시점(Runtime)에 동작할 것 같지만 실행 전에 변수와 함수를 미리 실행한다. 함수만 정의해 놓았는데 자동으로 실행되는 경험이 한 번씩은 있었을 것이다. 이것은 정의된 함수가 실행 시점보다 이전에 동작하기 때문이다.
마찬가지로 변수도 실행 시점 전에 동작한다. 그래서 위 코드처럼 선언되기 전의 변수를 사용하는 코드가 가능하다. 이를 호이스팅이라고 한다.
이렇게 var의 세 가지 문제점을 살펴보았다. 이 문제점이 와닿지 않았다면 본인도 모르게 위의 문제를 회피하는 코딩 습관이 있다고 생각해도 좋다. 하지만 ES6부터 let과 const라는 좋은 대안이 생겼다. 이들이 어떻게 문제를 해결하는지 하나씩 살펴보자.
개선된 let과 const
1. 선언을 중복할 수 없다. 때에 따라선 재할당도 할 수 없다
let은 기존의 var를 대체하는 ‘변수’의 역할을 한다. const는 기존에 없던 ‘상수’의 역할을 담당하며 새롭게 등장했다.
let은 중복된 선언이 문법으로 불가능하다. 그래서 전역에서 중복된 이름이 정의된다면 바로 오류가 난다.
let code = 10;
let code = 20; // SyntaxError: Identifier 'code' has already been declared.
반면 재할당은 가능하다. 그것이 변수의 역할이니까!
let code = 10;
code = 20;
console.log(`code: ${code}`); // 'code: 20'
const는 상수의 역할이므로 선언과 동시에 할당이 되어야 하며 중복 선언, 재할당 모두 불가능하다.
const code; // SyntaxError: Missing initializer in const declaration.
const code = 10;
code = 0; // TypeError: Assignment to constant variable.
단순히 var를 let으로 선언하기만 해도 중복된 변수명으로 발생하는 문제를 예방할 수 있다.
2. block 단위의 scope를 사용할 수 있다
var는 함수와 전역, 두 경우를 제외하고 scope를 적용할 수 있는 방법이 없었다. 따라서 if, for 구문 안에서 사용한 변수는 전역 혹은 함수 안에서 살아있게 된다. 내가 사용하는 변수가 다른 개발자에 의해 값이 변경될 수 있다는 뜻이다. 생각보다 사람들이 변수명을 비슷하게 만들기 때문에 언제나 가능성은 열려있다.
var와 const는 블록 단위로 살아있는다. 그래서 codeName을 더 이상 전역에서 사용할 수 없게 된다.
let code = 10;
if (true) {
let code = 0;
let codeName = 'Hello JS!';
}
console.log(`code: ${code}`); // 'code: 10'
console.log(`codeName: ${codeName}`); // ReferenceError: codeName is not defined
const code = 10;
if (true) {
const code = 0;
const codeName = 'Hello JS!';
}
console.log(`code: ${code}`); // 'code: 10'
console.log(`codeName: ${codeName}`); // ReferenceError: codeName is not defined
변수의 scope가 좁아질수록 버그의 발생이 줄어든다. 중복된 변수명을 사용해도 범위가 좁다면 문제없이 동작한다.
3. Hoisting이 불가능하다
console.log(`Before declare: ${code}`); // ReferenceError: Cannot access 'code' before initialization
let code = 10;
console.log(`After declare: ${code}`);
let과 const는 더 이상 실행 시점에 동작하지 않는다. 이로 인해 변수의 라이프사이클이 상식적으로 되었다. 당연히 변수를 선언한 시점부터 변수를 사용할 수 있어야 자연스럽지 않을까?
마치며
간혹 프로젝트를 진행하다 보면 ‘왜 let과 const를 사용해요?’라고 묻는 개발자들이 있다. 하나씩 설명하기 귀찮아서 그냥 웃고 넘겼다. 아마 그들은 여전히 var를 쓰면서 생기는 문제로 여전히 고통받으면서 불평만 늘어놓고 있을 것이다. 나는 여전히 웃고 넘기겠지만.
이제는 선택이 아니라 필수로 적용해야 한다. 그래야 내 코드가 다른 개발자에게 영향을 주지 않는다는 확신이 생기기 때문이다. 코드 간의 결합도를 낮추는 것이 근본적인 문제 해결 방법이라는 것을 잊지 말아야 한다.
[모던 자바스크립트 관련 글]
'Development > Etc' 카테고리의 다른 글
[모던 자바스크립트] Object 기깔나게 사용하기 (0) | 2022.09.08 |
---|---|
[모던 자바스크립트] Array 스마트하게 사용하기 (0) | 2022.09.04 |
Javascript에서 성능을 측정하는 방법(실행속도 측정) (0) | 2022.03.31 |
[Intelli J] Tab 간격 변경하는 방법(feat. 코딩 스타일 추천) (0) | 2021.08.24 |
[google-java-format] Google이 작성하는 자바 코드는 어떨까? (0) | 2021.08.15 |