본문 바로가기

JavaScript/기본 이론

Chapter 12. 변수와 호이스팅

1. 변수의 이해 

변수는 해당 정리본의 초두에도 다룬적이 있지만, 간략하게 말해 데이터를 담기위한 ‘공간’을 말한다.

자바스크립트는 선언단계에서 데이터 타입이 따로 지정되지 않는다.

이유는 HTML의 데이터 체계가 다양한 종류의 데이터를 취하고 표현하기 때문인데, 이에 따라 편의성을 위해 선언단계에 데이터 타입을 지정하지 않는것이다. 

 

문제는 이러한 특성에 의해 변수의 데이터 타입을 자바스크립트가 자동으로 설정하는 것인데, 이러한 과정을 포함하는 단계가 바로 ‘호이스팅’이다. 

또한 자바스크립트 자체로 서버 언어랑 데이터 베이스 역할을 하기 때문에 자세하게 조정하는 것이 어렵다. (자세한 조정을 위해서는 별도 개념 학습이 필요한 것이다.)

결국 자바스크립트 내에서 자동으로 처리해야할 데이터가 필요하다는 것이다. 

 

2. 변수의 범위 

변수는 선언되는 위치에따라 지역 변수와 전역 변수로 나뉜다.

지역 변수는 특정 영역에서만 유효한 변수로 블록((), {} 등)안에서 선언된 변수를 말한다.

반대로 전역 변수는 특정 영역이 아닌 Script 내에서 사용이 가능한 변수로 ‘블록’ 외부에서 선언된 변수이다. 

 

본래 프로그래밍 언어에서는 이러한 변수의 범위가 굉장히 중요하게 작용하는데, 이유는 위치와 종류에 따라 ‘접근’의 유무가 결정되기 때문이다. 

하지만 자바스크립트에서는 이러한 지역과 전역의 차이가 무의미한 경우가 발생하고, 실제로 지역 변수를 전역으로 끌어서 사용해도 오류가 안생기기도 한다. 

 

3. 호이스팅(hoisting)

변수의 범위와 변수의 데이터 타입 등에 대해서 자바스크립트가 자동으로 변수의 데이터 타입도 정하고 데이터를 처리하기 위한 ‘자동 조정’의 과정이 바로 호이스팅이다.

정확히는 선언된 함수와 변수를 브라우저가 해석하는 단계에서 가장 상단으로 끌어올려 데이터 처리를 먼저 진행하는 것이다. (본래 코드는 위에서 아래로 순서대로 읽는다.)

이에 따라 모든 변수가 끌어 올려져서 ‘전역’ 처리가 되는 것이다. 

 

호이스팅은 스칼라, 하스칼, 리스프 등등의 함수형 언어에서 사용되는 기법이다.

편의를 위해 만들어진 기법이지만 전역처리되는 변수로 인해 오류를 발생시키는 원인이 된다.

 

문제는 이 과정에서 코드의 문법 오류가 아니라 논리 연산의 오류로 규정된다는 점이다.

논리 오류는 프로그램의 동작에 문제를 일으키거나 혹은 다른 결과를 출력한다.

서비스에 들어가고 논리 오류가 있었음이 발견되면 유지보수가 어렵다는 점을 기억하자. 

 

 
console.log(Name);
var Name="김";
// 위의 항목에서 호이스팅에 의해 Name은 전역으로 이동하지만 값은 할당되지 않는다. 이에 따라 undefinded로 표시된다.즉, 호이스팅은 변수의 데이터를 끌어올리지는 않는다. 

console.log(Name);// 김으로 표시됨
var Name="종";// 같은 변수를 재차 선언 > 호이스팅에 의해 정상 작동해버림, 호이스팅하여 변수를 같이 선언하고 중복은 제거함
console.log(Name);
Name2="현";
console.log(Name2);
//스코프 및 호이스팅의 복합적인 규칙으로 인해 전역변수 요소가 결정되므로 실제로는 매우 불편한 기능이다. 
exam();
function exam(){
	console.log("java라면 실행되지 않는다. 근데 js는 됨;;")
}

var Name3="iot"; // 어느 시점에서 어느 값을 참조하는지 확인하기 어렵다. 
console.log(Name3);
Name3="융합 프로그래밍"; //복잡한 규칙이 존재하지만 이를 응용하기가 어렵다.
// 따라서 ECMA 표준에서는 var 보다는 let 사용을 권장한다.

 

위의 코드와 주석에서 확인이 가능하듯이 호이스팅 과정은 변수와 함수를 전역으로 끌어올리고, 이에따라 ‘일반적으로 사용하던 코딩 규칙’과는 다르게 작동한다는 문제를 야기한다. 

다만 호이스팅이 모든 변수를 전역 처리하는 것은 아닌데, 기본적으로 스코프(변수를 사용할 범위, 자바스크립트는 함수 단위로 스코프가 적용된다.)를 기준으로 호이스팅이 진행된다.

 

ECMAScript에서는 호이스팅의 문제를 충분히 이해하였고, 이에 따른 해결책으로 let을 만들었다. 

 

통상적으로 기존 호이스팅에서 var로 선언된 변수는 함수 내에 있어도 전역 처리가 되어 for 혹은 if에서 심각한 오류를 발생시켰다.

이는 해당 var 선언이 호이스팅 과정에서 function을 기준으로 하기 때문이다. 

 

var num=0;
for(var i=0; i<10; i++){
  num+=i;
  console.log(num);
}
console.log(i);// 호이스팅으로 i 값이 전역으로 이동
if(i>5){
  console.log("JAVA라면 이것이 실행 불가나, JS는 된다. 환장하겠다.");
}// 이러한 문제로 인해 실행될 수 없는 제어문이 구동한다. 이에 for 같은 반복문에서는 let으로 사용을 권장한다. 

function add(){
  var i = 0;
  i++;
  console.log(i);
}
add();
add();
console.log(i);

 

위의 예시에서 i는 전역으로 끌려나가고 이에 따라 호이스팅 되어 값이 다른 곳에서도 호출이 가능하다.

다만 add function에서 선언된 i는 해당 블록 안에서만 사용됨을 알 수 있다.

결과적으로 호이스팅에 의한 논리 오류를 방지하려면 var이 아닌 let으로 변수를 선언해야한다. 

 

4. 클로저(closure)

클로저는 실행이 종료된 함수 내부의 변수를 참조할 수 있도록 하는 기능이다.

함수가 중첩되어 선언된 경우에 사용하는데, 내부 함수의 값에 따라 외부 함수가 기능을 수행해야 한다면 클로저를 사용해야 한다. 

다만 함수를 개별적으로 분리하여 선언하고 사용하는 것이 더 안전하고 번거롭지 않다는 점을 기억하자. 

 

5. let의 사용

var 선언은 function을 단위로 호이스팅을 한다.

심지어 var로 선언하지 않아도 호이스팅 되며 임의로 변수로 정의한다.

변수가 전역으로 가기때문에 변수 이름이 겹쳐도 상관이 없으며 변수가 끌어 올려가는 구조로 인해 코드상 변수가 ‘선언’되기 전임에도 변수에 접근이 가능하다. (데이터에는 접근하지 못한다)

 

이에 ECMAScript6에서는 let이라는 변수체계를 도입하는데, let은 블록 단위로 호이스팅이 된다.

즉, 기존에 for(var i=3; i<10; i++) 과 같이 제어문에서 선언된 변수를 다른 블록에서 참조할 수 없다는 것이다.

또한 중복으로 변수 선언이 불가능하며 변수 자체가 호이스팅이 되지 않아서 해당 변수 선언이 이루어지기 전에는 ‘변수 참조’가 불가능하다.  

 

6. const

ECMAScript6에서 도입된 상수 개념으로 한번 할당된 데이터를 변경할 수 없다.