스코프는 '변수'와 '함수' 단위로 생김
스코프는 변수와 함수의 유효한 범위를 뜻함.
(정확히 말하자면 변수와 함수의 식별자(이름)의 유효범위)
: 어떤 변수나 함수가 참조 될 수 있는 범위를 말하는 것.
스코프 내에서 변수나 함수의 식별자(이름) 유일해야 함.
그러나 다른 스코프에서는 같은 식별자(이름)을 사용할 수 있다.
(그래도 같은 이름으로 변수를 만드는건 scope namespace가 오염되기 때문에 좋지 않음!)
let idx = 'abc'; // 1. 전역 스코프
function foo() {
let idx = 'xyz'; // 2. foo함수 내에서의 지역스코프
console.log(idx);
}
foo(); // xyz (foo함수의 지역스코프를 참조함)
console.log(idx); // abc (전역 스코프를 참조함)
변수를 참조할 때 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작해서 → "상위 스코프로" 이동하며 변수를 검색함.
(예) 15, 16번째 코드 실행 예
상위 스코프에서 선언한 변수를 하위 스코프에서 참조할 수 있다.
하지반 하위 스코프에서 선언한 변수를 상위 스코프에서 참조할 수는 없음
(예) 24번째 코드 실행 예
함수도 스코프를 갖는다.
따라서 함수도 스코프 체인 가능함. 자세한 내용은 렉시컬 스코프 참조
var는 함수 레벨 스코프, let const는 블록 레벨 스코프임
: var로 선언된 변수는 "함수 코드 블록"만 지역스코프로 인정하지만,
let와 const는 "블록 레벨 스코프"를 지원함.
예제)
var는 함수 코드 블록만 스코프로 인정해서,
for문에서 선언한 var i 는 전역변수 i를 중복 선언한 것이다.
그 결과 i의 값이 재할당 된다.
var i = 10;
for (var i = 0; i < 5; i += 1) {
console.log(i); // 0,1,2,3,4
}
console.log(i); // 5
var x = 1;
function foo() {
var x = 10;
bar();
// <함수를 어디서 호출했는지에 따라 상위 스코프를 결정된다면?>
// : bar함수의 "상위 스코프는 foo 함수"가 될 것 이다.
// 따라서 bar();의 호출 결과는 foo함수 안에 선언된 변수 x를 참조하여 10이 될 것임
}
function bar() {
console.log(x);
// <함수를 어디서 정의했는지에 따라 상위 스코프를 결정된다면?>
// 렉시컬 스코프기 떄문에 bar함수는 "전역 스코프"이다.
// 따라서 bar();의 호출 결과는 전역 변수 x를 참조하여 1이 될 것임.
}
foo(); // 1
bar(); // 1