javascript의 스코프(scope)와 호이스팅(hoisting)에 대하여 알아보도록 하자.
javascript에서 scope(스코프)란 변수의 유효범위 라고 할 수 있으며 var는 함수 스코프, let과 const는 블록스코프를 갖는다.
var a = 1;
function output() {
var a = 2;
console.log(a);
}
output(); // output : 2
console.log(a); // output : 1
위의 예제에서 output라는 함수 안의 console.log(a);는 a를 출력하기위해 자신의 함수 스코프 안에서 변수 a가 있는지 확인하고 있을 경우 var a = 2;를 참조해 2를 출력하게 된다.
만약 output라는 함수 안의 var a = 2;가 없을경우 상위에 할당 되어 있는 var a = 1;를 참조하여 1을 출력하게 된다. 전역에 있는 console.log(a);는 전역 변수인 var a = 1;를 참조하여 1을 출력한다.
아래 예제를 살펴보자.
var a = 1;
function output() {
var a = 2;
function print(){
console.log(a);
}
return print();
}
output(); // output : 2
output함수 내부 함수인 print함수의 console.log(a);는 자신의 함수 스코프 안에서 a가 있는지 확인하고 없을경우 상위 함수인 output함수의 var a = 2;를 참조하여 2를 출력 하게 된다.
var pyo = 'jung min';
for (var pyo = 0; pyo < 5; pyo++) {
// loop
}
console.log(pyo); // output : 4
위의 예제에서 4가 출력되는 것을 확인할 수 있다.
var는 함수 스코프 단위로 유효하기 때문에 위와 같이 변수가 덮어씌워지는 문제가 발생한다 이를 해결하기 위해서는 아래와 같이 블록 스코프를 지원하는 let, const를 사용해야 한다
var pyo = 'jung min';
for (let pyo = 0; pyo < 5; pyo++) {
// loop
}
console.log(pyo); // output : jung min
호스팅(hoisting)은 변수의 선언문을 유효범위의 최상단으로 끌어올리기로 해석할 수 있다.
if (true) {
var pyo = 'min';
}
output1(); // output : jung min
output2(); // output : 4
console.log(pyo); // output : min
function output1() {
if (true) {
var pyo = "jung min";
}
console.log(pyo);
}
function output2() {
for (var pyo = 0; pyo < 5; pyo++) {
// loop
}
console.log(pyo);
}
// 호이스팅으로 변환된 코드
var pyo;
function output1() {
var pyo;
if (true) {
pyo = "jung min";
}
console.log(pyo);
}
function output2() {
var pyo;
for (pyo = 0; pyo < 5; pyo++) {
// loop
}
console.log(pyo);
}
if (true) {
pyo = 'min';
}
output1(); // output : jung min
output2(); // output : 5
console.log(pyo); // output : min
위의 예제에서 확인할 수 있듯이 변수 및 함수를 유효범위 내부의 최상단으로 위치하게 됩니다.
output1(); // output : jung min
function output1() {
console.log('jung min');
}
// 호이스팅으로 변환된 코드
function output1() {
console.log('jung min');
}
output1(); // output : jung min
선언식의 경우 호이스팅이 발생해 함수를 최상단으로 끌어올려 output1()을 먼저 호출하더라도 정상적으로 동작한다.
output1(); // Uncaught TypeError: output1 is not a function
var output1 = function() {
console.log('jung min');
}
// 호이스팅으로 변환된 코드
var output1;
output1(); // Uncaught TypeError: output1 is not a function
output1 = function() {
console.log('jung min');
}
표현식의 경우 var output1;은 변수이기 때문에 선언과 할당의 분리가 발생한다.
output1 변수가 선언되고 output1();이 실행되고 그 이후에 output1에 함수가 정의되기 때문에 함수가 아니라는 오류메시지가 출력되는 것이다.
var pyo = 'jung min';
function pyo() {
console.log('pyo');
}
function jung() {
console.log('jung');
}
console.log(typeof pyo); // output : string
console.log(typeof jung); // output : function
// 호이스팅으로 변환된 코드
var pyo;
function pyo() {
console.log('pyo');
}
function jung() {
console.log('jung');
}
pyo = 'jung min';
console.log(typeof pyo); // output : string
console.log(typeof jung); // output : function
위와 같이 호스팅 발생 시 함수 및 변수를 최상단으로 끌어올리고 그 이후에 할당되는 것을 확인할 수 있다.
javascript 작성시에 스코프(scope)와 호이스팅(hoisting)의 관계를 잘 생각하여 작성 하도록 하자.