[JavaScript] Hoisting과 전역변수

uddi·2023년 8월 3일
0

JavaScript

목록 보기
5/11

변수의 특징 중 Hoisting, 전역변수, 참조에 대해 알아보자

Hoisting

// var 나이;
function 함수(){
  (...)
   }
(...)
 var 나이 = 30;	// 나이 = 30;

위 예시처럼 변수의 선언을 변수 범위 맨위로 끌고 오는 현상을 Hoisting 현상이라고 한다

변수를 만나면 선언부분을 강제로 맨 위로 끌어올리는 것

이런 현상이 일어나는 이유는 딱히 없다 JS 언어 자체가 그렇기 때문

// var 나이;
console.log(나이);	// undefined
var 나이 = 30;
console.log(나이);	// 30

변수의 Hoisting 현상 때문에 변수 선언 전에 console 창에 출력해도 에러가 나지 않는다

변수뿐만 아니라 함수도 Hositing 됨
💡 함수실행을 함수선언 전에 해도 상관없다 => 함수실행 위치는 상관없음

📌 유의할 점

  1. let, const 변수는 Hoisting시 undefined가 자동으로 할당되지 않기 때문에 에러가 출력(temporal deadzone / uninitialized 라고 부름)

  2. function 함수(){} : 전부 Hoisting 됨
    var 함수 = function(){} : 선언 부분만 Hoisting 됨

함수();
var 함수 = function(){
  console.log(안녕);
  var 안녕 = 'Hello';
}

Q. 뭐가 출력될까?

🔑 에러

👉 var 함수 부분만 Hoisting 되므로 함수();를 호출할 때 함수 변수는 function이 할당되지 않은 상태!

변수 동시에 여러개 만드는 법

var 나이 = 20, 이름 = 'ㅁ', 성별; 처럼 JS는 한 줄로 여러 변수를 만들 수 있다

전역변수

👉 모든 곳에서 쓸 수 있는 변수

var 나이 = 20;

function 함수(){
  console.log(나이);
}

함수();

위 예시처럼 밖에서 선언한 변수는 함수 안에서 그대로 사용할 수 있다

가장 밖에 선언된 변수를 전역변수라고 한다
그 외는 지역변수

window로 전역변수 만드는 법

var 나이 = 20;
window.이름 = '김';	

window는 JS 기본 함수를 담은 object 또는 HTML DOM의 모음

window로 만든 전역 변수 안에는 값뿐만아니라 함수를 넣어도 된다
💡 전역변수 만드는 방법 중 제일 선호되는 방식

if (true){
  let a = 1;
  var b = 2;
  if(true){
    let b = 3;
  }
  console.log(b);
}

Q. 위 예시는 콘솔창에서 어떻게 나올까?

🔑 2

👉 let 변수의 범위는 { } 이기 때문에 두번째 if문은 없다고 봐도 무방함
따라서 콘솔창에 2가 출력된다

let a = 1;
var b = 2;
window.a = 3;
window.b = 4;

console.log(a + b);

Q. 무엇이 출력될까?

🔑 5

👉 b는 전역변수이므로 window.b = 4로 재할당을 해주면 값이 4로 변한다
하지만 a는 let으로 선언된 변수이기 때문에 window.a = 3으로 재할당을 해도 1로 출력된다

가장 가까운 범위에 있는 것을 출력하려고 하기 때문

연습문제 1

for (var i = 0; i < 5; i++){
  setTimeout(function(){ console.log(i) }, i * 1000);
}

Q. 출력되는 결과는 모두 5인데 왜그럴까?

🔑 위 코드에서 setTimeout문은 바로 실행되는 코드가 아니라 1~5초 뒤에 실행되는 코드. for문 위에 i가 전역변수의 형태로 반복문이 다 실행된 후의 값인 5로 (var i = 5) 남아있다
1~5초 후 console.log(i) 코드를 실행하기 위해 i를 찾으면 전역변수 i의 값은 5가 나온다 그래서 모두 5가 출력됨

💡 해결방법은 다음과 같다

for (var i = 0; i < 5; i++){
  let i = 0;
  setTimeout(function(){ console.log(i) }, i * 1000);
}

이렇게 하면 1~5초 후 i를 찾을 때 for문 안에 있는 let i를 사용할 수 있다

let 변수 활용!

연습문제 2

var 버튼들 = document.querySelectorAll('button');
var 모달창들 = document.querySelectorAll('div');

for (var i = 0; i < 3; i++){
  버튼들[i].addEventListener('click', function(){
    모달창들[i].style.display = 'block'
  });
}

Q. 에러가 나는 이유는 무엇일까?

🔑 for문은 3번을 돌리는데, for문 안에 있는 이벤트리스너 내부 코드는 '클릭' 이벤트 발생시 실행됨
나중에 버튼을 클릭하면 내부 코드가 실행되는데 모달창들[i]에서 i값을 숫자로 채우려고 하면 Hoisting으로 인해 이미 for문이 다 돌아간 후 값인 var i = 3으로 할당되어있다

즉, for문이 도는 시점과 이벤트리스너 내부 코드가 실행되는 시점이 달라서 에러가 남

💡 해결방법

var 버튼들 = document.querySelectorAll('button');
var 모달창들 = document.querySelectorAll('div');

for (let i = 0; i < 3; i++){
  버튼들[i].addEventListener('click', function(){
    모달창들[i].style.display = 'block'
  });
}

let 변수를 가까이 하자

profile
거북이는 느리지만 결국 결승선을 통과한다

1개의 댓글

comment-user-thumbnail
2023년 8월 3일

좋은 글 감사합니다. 자주 올게요 :)

답글 달기