안녕하세요. 이번 글에서는 자바스크립트 함수의 범위(scope)와 호이스팅에 관해 알아볼 것입니다.
함수의 유효 범위
대부분의 프로그래밍 언어에서는 블록 내에서 정의된 변수를 블록 외부에서는 접근할 수 없다.
여기서 블록(block)이란, 코드 내에서 중괄호({})로 둘러싸인 부분을 가리킨다.
이러한 블록을 기준으로 하는 유효 범위를 블록 단위의 유효 범위라고 한다.
함수의 유효 범위(function scope)
하지만 자바스크립트는 다른 언어와는 달리 함수를 블록 대신 사용한다.
자바스크립트에서 함수는 자신이 정의된 범위 안에서 정의된 모든 변수 및 함수에 접근할 수 있다.
아마 따로 메인함수가 없어서 그런 것이 아닐까..?
'전역 함수'는 모든 전역 변수와 전역 함수에 접근할 수 있다.
반면 특정 함수 내에 정의된 '내부 함수'는 그 함수의 부모 함수(parent function)에서 정의된 모든 변수 및 부모 함수가 접근할 수 있는 모든 다른 변수까지도 접근할 수 있다. (이전 포스팅에서 함수 내부에 함수를 호출할 수 있다는 사실을 잠시 언급했었다.)
예제 1) |
//a와 b를 전역변수로 선언.
var a = 10, b = 20;
function add(){
return a+b; //전역변수 a, b에 접근.
}
document.write(add() + "<br>"); //30
function globalFunc(){ //전역함수 globalFunc()
var a = 1, b = 2;
function sub(){ //내부함수 sub()
return a-b;
}
return sub();
}
document.write(globalFunc()); //-1
document.write(sub()); //이 줄 이후부터 출력되지 않는다.
document.write("print");
위 예제 코드를 실행시켜보면, 아래와 같은 결과가 출력된다.
30
-1
sub() 함수를 출력한 줄과 print 는 출력되지 않는다. 크롬에서 F12를 누른 후 오른쪽 위의 빨간 엑스 버튼을 클릭하면 콘솔창에 다음과 같이 에러가 떠 있는 것을 확인할 수 있다.
단순히 아무것도 출력되지 않은 것이 아니라, 'sub'가 정의되지 않았다는 에러가 난 것이다.
함수 호이스팅(hoisting)
자바스크립트에서 함수의 유효 범위라는 것은 함수 안에서 선언된 모든 변수는 함수 전체에 걸쳐 유효하다는 의미이다.
그런데 이 유효 범위의 적용이 변수가 선언되기 전에도 똑같이 적용된다.
이러한 자바스크립트의 특징을 '함수 호이스팅(hoisting)'이라고 한다.
'자바스크립트 함수 안에 있는 모든 변수의 선언은 함수의 맨 처음으로 이동된 것처럼 동작한다'는 의미인데, 다음 예제를 보면 이해가 될 것이다.
예제 2) |
//전역변수 globalNum
var globalNum = 15;
function printNum(){
document.write(globalNum+"<br>"); // 15 ? -3 ?
var globalNum = -3;
document.write(globalNum +"<br>"); //-3
}
printNum();
globalNum은 전역변수이므로 printNum() 함수에서 해당 변수에 접근하는 것은 전혀 문제가 없어 보인다.
그렇다면 printNum 함수에서 처음으로 globalNum 변수를 출력했을 때 15와 -3 중 무엇이 나올까?
답은 둘 다 아니다. 다음과 같이 출력된다.
undefined
-3
처음 globalNum 변수에 접근했을 때 전역변수를 가리킨다고 생각하기 쉽다.
하지만 자바스크립트에서는 내부에서 함수 호이스팅에 의해 다음과 같이 코드가 변경되어 처리된다.
//전역변수 globalNum
var globalNum = 15;
function printNum(){
var globalNum; //함수 호이스팅에 의해 변수의 선언 부분이 함수의 맨 처음 부분으로 이동.
document.write(globalNum+"<br>"); // undefined
globalNum = -3;
document.write(globalNum +"<br>"); //-3
}
printNum();
위 코드에서 printNum 함수의 내부 첫 줄에서는 globalNum라는 지역 변수가 선언만 되고 아직 초기화가 되지 않은 상태이다. 다른 언어였다면 무조건 에러가 났을 상황이지만, JS에서는 에러가 나지는 않는다.
대신 아직 초기화되지 않은 변수에 접근했으므로, undefined 값을 반환하게 된다.
실제로 변수가 초기화되는 시점은 원래 코드에서 변수가 선언된 줄이며,
따라서 마지막 출력 부분에서는 문제없이 -3이 출력되는 것이다.
자바스크립트에서는 함수 호이스팅이 자동으로 수행되나, 항상 함수 블록의 첫 부분에 변수를 선언하는 것이 좋다.
오늘은 자바스크립트 함수의 범위(scope)와 호이스팅에 대해서 알아봤습니다.
다른 언어들에 비해 확실히 에러가 나지 않으며 자유도가 높다는 느낌?을 받았습니다.
다음 포스팅은 함수의 인자에 관한 내용이 될 것인데, 저는 처음 봤을 때 이 부분에서도 JS가 자유롭다는 느낌을 받았었습니다.
그럼 이만!
'Frontend' 카테고리의 다른 글
[JavaScript/JQuery] each() 메서드 알아보기 - $.each() 함수 (0) | 2021.08.09 |
---|---|
[JavaScript] JSON 파싱(parsing), JSON.parse() 사용법, 예제 (0) | 2021.08.06 |
[JavaScript/JQuery] 다운로드 방법, 적용 방법, CDN 사용법, jQuery 사용법 (0) | 2021.08.06 |
[JavaScript] 자바스크립트 함수 - ③매개변수, 디폴트 매개변수, 나머지 매개변수, arguments 객체 (default parameter, rest parameter, arguments) (2) | 2021.08.04 |
[JavaScript] 자바스크립트의 함수 - ①기본 (0) | 2021.08.03 |