변수 선언자 var 의 스코프와 스코프 체인
자바스크립트의 변수 선언 방식은 기존 사용하던 var 와 ES6에서 새로 도입된 let 2가지가 있습니다.
새로운 표준이기 때문에 let 사용을 권장하지만, 사용 방식에 따라서는 var가 더 유리한 경우도 있고, 아직 여전히 var를 많이 사용합니다.
var는 개념상 단순하고, 함수 안에 정의한 변수의 경우 함수 안에서는 전역으로 사용하기 때문에 함수의 선언에 대해 고민하지 않아도 되는 장점이 있습니다.
습관처럼 사용해왔기 때문에 당연한 듯이 쓰지만 var는 생각보다 복잡한 사용 체계를 가지고 있습니다.
함수 안의 로컬 변수
var는 let과 달리 블록, 구문 단위의 스코프(Scope) 구분이 없습니다.
함수 안 어디에서 정의되었든지 자바스크립트의 호이스팅(Hoisting)에 의해 변수 정의는 함수 맨 위로 끌어올려지기 때문에 함수 내부 전역으로 처리됩니다.
var name = '어피치';
function run(){ if(true){ var name = '라이언'; } console.log(name); // '라이언' 출력 return name;}
run();console.log(name);
함수 안의 중복 선언 변수
자바스크립트는 변수명을 중복 선언해도 에러가 나지 않습니다.
중복 선언된 경우 가장 가까운 위치에 선언된 변수를 사용합니다.
var name = '어피치';
function run(){ var name = '라이언'; var name = '프로도'; console.log(name); // '프로도' 출력 return name;}
run();console.log(name);
함수 스코프 체인
함수가 중첩되거나, 함수에서 다른 함수를 호출하는 경우 함수 스코프 체인에 따라 변수 선언을 찾게 됩니다.
호출한 함수를 역으로 따라 올라가면서 변수를 찾고, 최종적으로는 전역 변수를 찾게됩니다.
var a = 1;var b = 5;function outerFunc () { function innerFunc () { a = b; } console.log(a); a = 3; b = 4; innerFunc(); console.log(a); var b = 2;}outerFunc();
위 코드는 아래와 같은 순서로 차례로 실행됩니다.
1. 1, 2행 전역 변수 a = 1, b = 2 생성
2. 14행 outerFunc() 호출
3. 12행 outerFunc 변수 정의를 찾아 로컬 변수 b 를 호이스팅해 b = undefined 정의
4. 7행 변수 a를 outerFunc()에서 검색. outerFunc() 에 없으므로 전역 변수를 검색해 전역변수 값 a = 1 출력
5. 8행 변수 a를 outerFunc()에서 검색. outerFunc() 에 없으므로 전역 변수를 검색해 전역변수 값 a = 3 변경
6. 9행 변수 b를 outerFunc()에서 검색. outerFunc() 로컬 변수 정의를 찾음. b = 4 변경
7 10행 innerFunc() 호출
8. 5행 변수 a 를 innerFunc()에서 검색. 없으므로 스코프 체인에 따라 innerFunc()를 호출한 outerFunc()를 검색. 없으므로 상위엔 전역 변수를 검색해 a 를 찾음.
9. 5행 변수 b 를 innerFunc()에서 검색. 없으므로 스코프 체인에 따라 innerFunc()를 호출한 outerFunc()를 검색. 로컬 변수 b를 찾음. 로컬 변수 b의 값 4를 전역 변수 a에 적용
10. innerFunc() 종료
11. 11행 변수 a를 outerFunc()에서 검색. outerFunc() 에 없으므로 전역 변수를 검색해 전역변수 값 a = 4 출력
12. outerFunc() 종료