자바스크립트 변수 선언 방식에는 var와 let,const가 있다.
var는 함수 스코프 변수를 선언할 때 사용한다.
함수 밖에서 선언한 함수 스코프 변수는 전역 범위를 가지고,
함수 안에서 사용하면 함수 밖을 제외한 내부 어디서든 접근이 가능하다.
var name = "JHJ";
function myName(){
var fName = "JMK";
console.log(name); //JHJ
if(true){
var mName = "KYO"
console.log(fName); //JMK
}
console.log(mName); //KYO
}
fuction abc() {
console.log(name); //JHJ
console.log(fname); //해당 함수내에서 선언한 변수 X.에러.
console.log(mname); //해당 함수내에서 선언한 변수 X.에러.
}
함수 스코프 레벨 변수는 메모리 누수, 디버깅이 어렵고 가독성이 떨어진다는 문제점이 있다.
이러한 문제점을 피하고자 블록 스코프 변수를 생성하기 위한 let, const 키워드가 탄생했다.
let과 const는 블록 스코프 변수를 선언할 때 사용한다.
블록은 중괄호{}로 경계를 구분한다.
블록 스코프 변수는 함수 밖에서 선언하면 함수 스코프 변수처럼 전역 접근할 수 있습니다. 블록 안에서 선언하면 자신을 정의한 블록과 하위 블록에서만 접근이 가능합니다.
let name = "JHJ";
if(true) {
let fName = "JMK";
console.log(name); // JHJ
console.log(fName); // JMK
}
console.log(name); // JHJ
console.log(fName); // 참조에러. 해당블록 안에서 선언 x
const = 값을 재할당 할 수 없는 상수를 선언할 때 사용한다
const도 블록 레벨 스코프를 가지기 때문에 let과 동일한 결과가 나오지만,
상수이기 때문에 재할당이 불가능 하며, 선언 시에 초기화를 하지 않으면 에러가 발생한다.
🎁여기서 잠깐🎁
- let은 재선언 불가, 재할당 가능.
- var는 모두 가능.
- 같은 프로젝트를 진행하고 있는 A 개발자가 var num을 사용했는데 B 개발자는 이를 모르고 var num을 똑같이 선언해서 사용하게 되면,
실행할때는 문제가 되지 않기 때문에, 서로 같은 변수명을 선언 했는지 인지하지 못하지만,
이는 나중에 문제가 될 수 있다.
그래서 var 선언을 권장하지 않는다.
let을 사용하면 재선언이 불가능하기 때문에 서로 다른 개발자들이 똑같은 변수를 선언하는 일이 적어져 안정성이 높아진다!
다시 const로 돌아와서
const name = "JHJ";
function myName() {
console.log(name) // JHJ
const fName = "JMK";
if(true) {
const mName = "KYO";
console.log(fName); // JMK. fName이 선언된 하위블록이기 때문.
}
console.log(mName); //에러. mName이 선언된 상위 블록이기 때문.
}
const d // 에러. 선언과 동시에 초기화가 안됨.
자바스크립트 코드를 인터프리터가 로드할 때, 변수의 정의가 그 범위에 따라 선언과 할당으로 분리되어 변수의 선언을 항상 컨텍스트 내의 최상위로 끌어올리는 것을 의미한다. 이는 오로지 변수에만 해당되는 것은 아니고 함수도 가능하며, 자바스크립트에서 함수의 호출을 첫 줄에서 하고 마지막 줄에 함수를 정의해도 문제없이 작동되도록 하는 유용한 특성이다.... ??
console.log(name); //undefined
var name = "JHJ";
위의 코드는 왜 undefined일까.
코드의 실제 동작은 아래와 같이 이뤄진다.
var name;
console.log(name); // undefined
name = "JHJ";
이렇게 동작하는 이유가 바로 호이스팅이 발생하기 때문이다.
변수 선언이 항상 컨텍스트 내의 최상위에 선언된 것처럼 행동하기 때문이다.
undefined가 찍히는 이유는 이렇게 호이스팅 되는데, 할당은 호이스팅 되지 않기 때문이다. 할당은 세 번째 줄에서 처리된다.
console.log(name); // ReferenceError
let name = "JHJ";
참조 에러?? 그럼 let은 호이스팅이 일어나지 않는건가?
let const도 마찬가지로 일어난다.
그럼 왜 var와 다르게 일어날까?
바로 TDZ(Temporal Dead Zone) 때문이다.
TDZ : ‘일시적인 사각지대’ 라는 뜻이며, 초기화 되지 않는 변수가 일시적으로 있는 곳이며, 변수의 스코프 시작지점부터 초기화가 시작되는 지점까지의 구간이다. let과 const는 TDZ의 영향을 받는데, 이는 변수의 생성 과정과 관련이 있다.
변수의 생성 과정은 3단계로 이뤄진다.
- 선언 단계
- 초기화 단계 (undefined를 할당)
- 할당 단계
var는 선언 단계와 초기화 단계가 동시에 일어난다.
그래서 할당하가 전에 호출하면 에러가 발생하지 않고 undefined가 나오게 되는 것이다.
let은 선언 단계와 초기화 단계가 분리 된다. 호이스팅이 일어나면서 선언 단계가 이뤄지지만, 초기화 단계는 실제 코드에 도달 했을 때 진행되기 때문에 레퍼런스 에러가 발생하게 되는 것!!
초기화 전까지는 TDZ에 존재한다.
const는 선언과 할당이 동시에 진행된다. (const는 선언과 동시에 초기화를 해줘야하는데...🌝)
쉽게 말해서 let과 const는 TDZ 안에 들어가 있어서 참조되지 않는 것이다.
ES6 이후로 실제 현업에서는 var 키워드는 절대로 쓰이지 않으며 99%이상의 경우 모든 함수를 무조건 const와 arrow syntax로 선언하기 때문에 최근 들어서는 사실상 크게 신경쓰지 않는 부분이 되었다.