가끔식 코딩을 하다보면 특정 변수값이 중복되는지 헷갈릴때가 있다..
스코프에 대해 정확히 이해한다면 복잡하고 장황한 코드에서 중복명의 변수,함수를 자유롭게 선언하고 사용할 수 있기 때문에 꿀이다.
JavaScript에서 스코프란 식별자가 유효한 범위를 말한다
쉽게 말해 특정 변수,함수,클래스 등에 접근할 수 있는 범위라고 볼 수 있다
스코프는 크게 전역스코프(global)과 지역스코프(local)로 나뉜다.
전역 : 코드 가장 바깥영역의 식별자(어디서든지 참조가능)
지역 : 함수 몸체내부 식별자(자신과 하위 스코프에서 참조가능)
var a = 1; // 전역 스코프
function print() {
var a = 111; // 지역 스코프
console.log(a);
}
print(); // 111 출력
console.log(a); // 1 출력
스코프들이 계층적으로 연결 된 것
실행 컨텍스트 내부에서 Outer Environment Reference(외부 환경 참조)를 통해 구현된다.
JS는 변수,함수(식별자) 값을 얻으려고 할 때 스코프 체인에서 찾는다.
첫 번째 객체에서 해당 변수를 찾고, 없으면 그 다음 객체에서 해당 변수를 찾고, 여기도 없으면 그 다음 객체에서 찾는다. 끝까지 탐색했는데도 그 변수가 없다면 reference error가 발생하게 된다.
즉, 스코프는 변수를 참조한 스코프부터 시작해, 상위 스코프로 이동하며 변수값을 찾는다!
// 전역함수
let globalVar = "I'm global";
function outer() {
let outerVar = "I'm in outer";
function inner() {
let innerVar = "I'm in inner";
console.log(innerVar); // ✅ 현재 스코프에서 찾음 → "I'm in inner"
console.log(outerVar); // ✅ 현재 스코프에 없으므로 상위 스코프(outer)에서 찾음 → "I'm in outer"
console.log(globalVar); // ✅ 현재 스코프 → outer 스코프 → 전역 스코프에서 찾음 → "I'm global"
console.log(unknownVar); // ❌ ReferenceError (어디에서도 찾을 수 없음)
}
inner();
}
outer();
JS는 함수가 선언될 때마다 상위 스코프를 기억한다. 값을 참조해야 할 수 있기 때문이다.
렉시컬 스코프는 상위 스코프가 결정되는 방식으로,
함수를 선언한 위치에 따라 상위 스크프를 결정한다.
🔥 함수의 호출위치는 중요하지 않다, 선언위치가 중요할 뿐!! 🔥
자바스크립트를 비롯한 대부분의 언어는 렉시컬 스코프를 따른다
아래 헷갈리는 예제를 보자..
let x = "global";
function foo() {
let x = "foo";
bar();
}
function bar() {
console.log(x);
}
foo(); // "global"
함수 스코프 : var 로 선언한 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정
블록 스코프 : let 과 const로 선언한 변수는 모든 코드 블록(중괄호)를 지역 스코프로 인정
함수레벨 스코프
var x = 10;
// if문은 함수가 아니므로 지역 스코프로 인정 X
// *뭔짓을 해도 위의 x값은 바뀜*
if(true){
var x = 20;
console.log(x); // 20 출력
}
// 함수이므로 지역 스코프로 인정 O
// *뭔짓을 해도 위의 x값은 안바뀜*
function ex(){
var x = 97;
console.log(x); // 97 출력
}
ex();
console.log(x); // 20 출력(의도치 않게 바뀐 x값)
블록레벨 스코프
let x = 10;
// if문은 중괄호로 감싸져 있으므로 지역 스코프로 인정 O
// *뭔짓을 해도 위의 x값은 안바뀜*
if(true){
let x = 20;
console.log(x); // 20 출력
}
// 함수이므로 지역 스코프로 인정 O
// *뭔짓을 해도 위의 x값은 안바뀜*
function ex(){
let x = 97;
console.log(x); // 97 출력
}
console.log(x); // 10 출력(바뀌지 않은 x값)