1 - var 키워드로 선언한 변수의 문제점
var는 JS만의 특이한 특징을 갖고 있어 사용하는데 주의를 요구하는 키워드이다.
이를 무시하고 무분별하게 사용하게 되면 아래와 같은 문제가 발생할 수 있다.
1-1. 변수 중복 선언 허용
var 키워드를 이용해 변수를 중복 선언하면 초기화문의 유무로 다르게 동작한다.
초기화문이 있는 경우는 선언문은 자바스크립트 엔진에 의해 var 키워드가 없는 것처럼 동작한다.
초기화문이 없는 경우는 변수 선언문은 무시된다.
변수를 중복 선언하게 되면 의도치 않게 먼저 선언한 변수의 값이 변경될 수 있는 문제가 발생한다.
1-2. 함수 레벨 스코프
var 키워드로 변수를 선언하면 오직 함수의 블럭만을 지역 스코프로 인정한다.
이것은 함수 이외의 다른 블럭(조건문 등 {}로 감싸진 블럭)에서 선언된 변수는 모두 전역 변수가 되는 것이다.
var x = 1;
if(true){
var x = 10;
}
console.log(x); // 10
1-3. 변수 호이스팅
var 키워드로 선언된 변수는 변수 호이스팅에 의해 변수 선언문 이전에 참조할 수 있다.
하지만, 할당문 이전에 참조하게 되면 undefined를 반환한다.
console.log(x); // undefined
var x;
x = 10;
console.log(x); // 10
선언 단계에서 스코프(실행 컨텍스트의 렉시컬 환경)에 변수 식별자를 등록해 변수의 존재를 엔진에 알리고, 즉시 초기화 단계에서 undefined로 초기화 한다.
이후 변수 할당문에 도달하면 값이 할당된다.
변수 호이스팅에 의해 에러가 발생하지는 않지만 프로그램의 흐름상 맞지 않고, 가독성을 떨어뜨리고, 오류 발생의 가능성을 남긴다.
2 - let 키워드
ES6에 추가된 let과 const 중 let에 대해 알아보자
2-1. 변수 중복 선언 금지
var 키워드의 경우는 중복 선언이 가능해 가독성과 의도치 않은 값 변경의 간능성이 있다고 적었다.
let 키워드로 같은 이름의 변수를 중복 선언하면 문법 에러(SyntaxError)가 발생한다.
2-2. 블록 레벨 스코프
let 키워드로 선언한 변수는 모든 코드 블록을 지역 변수로 인정해 블록 레벨 스코프를 갖는다.
함수의 블록 뿐만 아니라 조건문, 반복문의 블록 등의 { } 를 포함
함수도 코드 블록이므로 스코프를 만드는데, 함수 내의 코드 블록은 함수 레벨 스코프에 중첩된다.
2-3. 변수 호이스팅
let 키워드의 호이스팅은 발생한다.
하지만 호이스팅이 없는 것처럼 동작할 뿐이다.
let 키워드로 선언한 변수는 "선언 단계"와 "초기화 단계"가 분리되어 진행한다.
선언 단계는 런타임 이전에 JS엔진에 의해 암묵적으로 선언되어 실행되지만,
초기화 단계는 변수 선언문에 도달했을 때 실행된다.
초기화 단계의 실행 전에 변수에 접근하게 되면 참조 에러(ReferenceError)가 발생한다.
스코프의 시작 지점부터 초기화 단계 시작 지점(변수 선언문)까지 변수를 참조할 수 없는 구간이 존재한다.
이러한 구간을 일시적 사각지대(TDZ: Temporal Dead Zone)이라 한다.
// 이 단계에서는 foo라는 변수는 선언되었지만 초기화가 안됬다.
// 초기화 이전에는 TDZ 구간이기에 참조할 수 없다.
console.log(foo); // ReferenceError: foo is not defined
let foo; // 변수 선언문에서 초기화 단계가 진행되어 undefined 값으로 초기화 된다.
console.log(foo); // undefined
foo = 1; // 할당문에서 할당 단계가 실행된다.
console.log(foo); // 1
let 키워드로 선언한 변수는 변수 호이스팅이 발생하지 않은 것처럼 보이지만 그렇지 않다.
let foo = 1; // 전역 변수
{
console.log(foo); // ReferenceError: foo is not defined
let foo = 2; // 지역 변수
}
위의 코드에서 호이스팅이 발생하지 않았다면 console.log(foo)는 전역 변수인 foo를 출력해야한다.
그렇지만 호이스팅이 발생했기에 블럭 스코프 내에 있는 지역변수 foo를 참조할때 참조 에러가 발생한 것이다.
Javascript에서는 모든 선언(var, let const, fucntion 등등)은 호이스팅 한다.
단, ES6에 도입된 let, const, class는 호이스팅 하지 않는것 처럼 동작한다.
2-4. 전역 객체와 let
var 키워드로 선언한 전역 변수와 전역 함수, 선언하지 않은 변수에 값을 할당하는 암묵적 전역은 전역객체 window의 프로퍼티가 된다.
암묵적 전역은 선언하지 않은 변수의 이름을 v = 2 와 같이 작성한 것으로 이는 전역 객체의 프로퍼티가 된다.
let키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아니다.
let 전역 변수는 보이지 않는 개념적인 블럭(전역 렉시컬 환경의 선언적 환경 레코드)내에 존재한다.
// 이는 브라우저 환경에서 실행해야 한다
let x = 1;
console.log(window.x); // undefined
console.log(x); // 1
3 - const 키워드
const 키워드는 상수를 선언하기 위해 사용하지만, 상수만을 위해 사용하지는 않는다.
const 키워드의 특징과 let 키워드 특징은 대부분 비슷하기에 다른 점을 중점으로 살펴보자.
3-1. 선언과 초기화
const 키워드로 선언한 변수는 반드시 선언과 초기화를 동시에 해야한다.
const 키워드는 let 키워드와 마찬가지로 블록 레벨 스코프를 가지며, 변수 호이스팅이 발생하지 않는 것처럼 동작한다.
{
console.log(foo); // ReferenceError: Cannot access 'foo' before initialization
const foo = 1;
console.log(foo); // 1
}
console.log(foo); // ReferenceError: foo is not defined
3-2. 재할당 금지
const 키워드로 선언한 변수는 재할당이 금지된다.
3-3. 상수
원시 값은 변경 불가능한 값이므로 재할당 없이 값을 변경할 수 있는 방법이 없다.
변수의 상대 개념인 상수는 재할당이 금지된 변수를 의미한다.
단, 변수는 언제든지 재할당을 통해 변수 값을 변경할 수 있지만 상수는 재할당이 금지된다.
const 키워드로 선언된 변수에 원시 값을 할당한 경우 원시 값은 변경할 수 없는 값이고 const 키워드에 의해 재할당이 금지되므로 할당된 값을 변경할 수 있는 방법은 없다.
이러한 특징을 이용해 프로그램에서 고정된 원시값(세율, 비율 등의 고정값)을 const 키워드로 사용하면 좋다.
3-4. const 키워드와 객체
const 키워드로 선언된 변수에 원시 값을 할당한 경우 값을 변경할 수 없지만,
const 키워드로 선언된 변수에 객체를 할당한 경우 값을 변경할 수 있다.
const person = {
name: "OH",
}
person.name = "Kim";
console.log(person); // { name: "Kim" }
const 키워드는 재할당을 금지할 뿐 "불변"을 의미하지는 않는다.
새로운 값을 할당하는 것은 불가능 하지만, 프로퍼티 동적 생성, 삭제, 프로퍼티 값의 변경을 통해 객체를 변경하는 것은 가능하다.
4 - var vs let vs const
변수 선언에는 기본적으로 const를 사용하자(의도치 않은 재할당을 방지해 안전)
재할당이 필요한 경우 스코프(변수의 유효범위)를 적게 한정해 let을 사용하자
- ES6를 사용하면 var 키워드는 사용X
- 재할당이 필요한 경우는 let을 사용하되 변수의 스코프는 최대한 좁게
- const 키워드는 변경이 발생하지 않고 읽기 전용으로 사용하는 원시 값과 객체에 사용
- const는 재할당을 금지해서 var나 let 보다 안전
'JavaScript > 모던 자바스크립트 Deep Dive' 카테고리의 다른 글
19. 프로토타입-1 (1) | 2024.04.02 |
---|---|
18. 함수와 일급 객체 (1) | 2024.03.26 |
14. 전역 변수의 문제점 (0) | 2024.03.06 |
13. 스코프 (0) | 2024.01.17 |
12. 함수 (1) | 2023.12.27 |