코드를 실행하기 전 변수 및 함수선언을 해당 스코프의 최상단으로
끌어 올려진 것 같은
현상.
쉽게 설명할 때는, 변수나 함수의 선언이 최상단으로 끌어올려진 것. 이라고만 설명할 수 있지만 엄밀히 말한다면 끌어 올려진 것 같은 현상이 호이스팅이다.
자바스크립트 엔진은 코드를 실행하기 전 실행 가능한 코드가 실행되기 위해 필요한 환경정보를 모아놓은 객체
(실행 컨텍스트)
를 생성하는 과정을 거치는데 이 과정에서식별자(변수/함수명)들을 수집
하여 메모리에 미리 저장해두기 때문에 위에서 아래로 코드가 실행되는 자바스크립트 구조 상 변수나 함수의 선언이 위로 끌어 올려진 것 같은 현상이 나타난다.
undefined
로 초기화 된다.자바스크립트에서는 var,let,const를 이용해 변수를 선언할 수 있는데, ES6 이후의 문법에서는 var 키워드의 사용을 지양한다. 그 이유가 바로 변수의 생성단계에서부터 var를 이용한 변수선언의 단점이 발견되기 때문이다.
ES6 이전에는 변수를 선언할 때 var를 이용해 선언했다. 그러나 var를 이용한 변수선언에는 많은 단점들이 있다.
console.log(a) // undefined
var a = 1;
해당 예시에서 에러를 띄울 것 같지만, var를 이용한 변수선언은 선언과 초기화를 동시에 수행하기 때문에 에러를 띄우지 않고 초기화 된 값인 undefined
를 반환한다. 이는 코딩시 정확한 에러를 발견할 수 없고 개발자로 하여금 혼동을 야기할 수 있다.
var a = 1 // 전역변수
function foo() {
var b = 2 // 지역변수
};
console.log(b) // 2
위의 예시에서 foo라는 함수 블록({})안에서 선언된 지역변수 b는 블록밖에서는 값을 참조할 수 없어야 한다. 그 이유는 아래의 예시와 같다.
for(var i = 1; i<5; i++) {
console.log(i) // 1 2 3 4
}
console.log(i) // 5
for문 블록({})안에서 반복한 console.log(i)는 정상적으로 1 2 3 4 까지 반복하고 반복문이 종료되었다. 하지만 블록 밖에서 다시 console.log(i)를 했더니 5까지 값이 반복되었다. 이 이유는 var로 선언한 모든 변수는 전역/지역 가릴 것 없이 모두 호이스팅
된다. 이런 경우는 개발자의 의도와 맞지않는 결과를 낳을 수 있다.
var a = 1;
console.log(a) // 1
var a = 2;
console.log(b) // 2
위의 예시처럼 var를 이용해 변수를 선언하면 같은 변수명에 계속 다른값을 할당할 수 있고, 에러를 띄우지 않는다. 이 경우의 문제는 바뀌지 않아야 할 값들이 어디선가 변경될 수 있기 때문에 좋지 못한 변수선언법이라고 할 수 있다.
위와 같은 단점들 때문에 ES6부터 let을 이용한 변수 선언이 가능해졌다. let은 var의 단점을 보완하는데
console.log(a) // Uncaught ReferenceError: a is not defined
let a = 1;
var의 단점 1과 같은 예시이지만 let으로 변수를 선언했을 때는 a가 정의되지 않았다는 에러를 띄운다. 이유는 선언만 되어있고 초기화(값의 할당)
이 되지 않았기 때문이다. var는 초기화가 같이 이루어지면서 undefined라는 값을 할당하는 것과 같기 때문에 undefined를 띄우는 것이다. let을 이용한 변수선언은 초기화가 되는 문장을 만나기 전까지 변수를 참조할 수 없는데 이를 '일시적 사각지대(Temporal Dead Zone; TDZ)'
라고 한다.
for(let i = 1; i<5; i++) {
console.log(i) // 1 2 3 4
}
console.log(i) // Uncaught ReferenceError: i is not defined
마찬가지로 var의 단점2와 같은 예시지만 let을 사용해 i를 선언하면 for문 밖에 있는 console.log에서는 i가 정의되지 않았다는 에러를 띄운다. 이유는 let 또한 호이스팅되는것은 맞지만 for문 안에서 정의된 i는 지역변수
이기 때문에 호이스팅 되지 않았다. 그렇기 때문에 for문 밖에서는 i를 참조할 수 없다.
let a = 1;
console.log(a) // 1
let a = 2;
console.log(b) // Uncaught SyntaxError: Identifier 'a' has already been declared
let으로 선언된 변수 a는 그 이후에 값을 재할당 할 수 없다. 위의 예시처럼 재할당 할 경우 구문에러를 띄우고 a는 이미 선언되었다는 에러명을 보여준다.
let과 같이 ES6 이후부터 const를 이용해 변수를 선언할 수 있다. 특징은 let과 같고 차이점은 let은 mutable(변경가능), const는 immutable(변경불가능)이다.
let name = "james";
console.log(name) // james
name = "john"
console.log(name) // john
const name = "james";
console.log(name) // james
name = "john"
console.log(name) // Uncaught TypeError: Assignment to constant variable.
위의 예시처럼 let으로 선언한 변수는 재할당이 가능하지만, const로 선언한 변수는 재할당이 불가능하다. 이는 비밀번호나 회원 ID같이 바뀌면 안되거나, 중복되면 안되는 정보들을 담기 위함이라고 생각하면 된다.
호이스팅을 공부하다보니 스코프와 실행 컨텍스트를 더 잘 알고 있어야 호이스팅 및 변수에 대한 내용을 더 잘 이해할 수 있을 것 같다. 자바스크립트의 중요한 구동원리라고 하니 필히 다시 공부해야겠다.
Udemy - 혼자배우는 자바스크립트: 기본부터 포트폴리오까지 한번에 끝내기(Bitna Kim aka. 코딩하는 누나)
안녕하세요, 코드에 에러가 있는 거 같아 말씀드립니다. "단점 2. 지역변수와 전역변수의 경계가 정확하지 않다."의 예시로 있는 코드에서
console.log(b);
에서 2가 나오지 않고 에러가 납니다. 확인 부탁드립니다 :)