스코프(유효범위)는 사실 자바스크립트 뿐 아니라 모든 프로그래밍 언어의 기본적이지만 중요한 개념이다.
특히 JS의 스코프는 다른 언어의 스코프와 구별되는 특징이 있어서 주의가 필요하다. 예를들어 var,let,const로 선언한 변수의 스코프가 다르다.
스코프의 간단한 예시를 보자.
function add(x,y) {
console.log(x,y);
return x+y;
}
add(2,5);
console.log(x,y);
함수의 매개변수를 보자. 함수의 매개변수는 함수 몸체 내부에서만 참조할 수 있고 함수 몸체 외부에서는 참조할 수 없다. 매개변수의 스코프가 함수 몸체 내부로 한정되기 때문이다.
모든 식별자는 자신이 선언된 위치에 의해 다른 코드가 식별자 자신을 참조할 수 있는 유효범위가 정해진다.
스코프는 식별자가 유효한 범위를 말한다.
var x = 'gloabl'
function foo() {
var x = 'local'
console.log(x)
}
foo();
console.log(x);
위와같이 변수의 이름이 같을때 JS엔진은 스코프를 통해 어떤 변수에 참조할지를 결정한다. JS엔진은 코드의 문맥을 고려해서 이를 결정한다.
만약 스코프란 개념이 없다면 같은 이름을 갖는 변수는 충돌을 일으키기 때문에 한 프로그램에서 한개의 변수명만 사용할 수 있다.
예를들어서 컴퓨터에서 파일이름을 생각해보자. 우리는 컴퓨터에서 파일이름을 중복해서 사용하는 경우가 있다. 이것이 가능한 이유는 디렉터리란 개념이 있기 때문이다. 식별자도 마찬가지로 스코프란 개념을 활용해서 식별자의 이름을 중복해서 사용해도 분류가 가능하다.
한 스코프 내에서는 식별자가 유일해야 하지만 다른 스코프라면 같은 이름의 식별자를 사용할 수 있다!
스코프의 종류
코드는 전역과 지역으로 구분할 수 있다.
전역이란 코드의 가장 바깥 영역을 의미하며 전역은 전역 스코프를 생성한다. 즉 전역 변수는 어디서든지 참조할 수 있다.
지역이란 함수 몸체 내부를 의미하며 지역변수는 자신의 지역 스코프와 하위 지역 스코프에서 유효하게 된다.
스코프 체인
함수는 전역에서 정의할 수도 있고 함수 몸체 내부에서도 정의할 수 있는데 함수 내부에서 함수를 정의하는 것을 함수의 중첩이라고 한다.
함수가 중첩될 수 있으므로 함수의 지역 스코프도 중첩될 수 있다. 모든 스코프는 하나의 계층적 구조로 연결되며 최상위 스코프는 전역 스코프가 된다. 이런 구조를 스코프 체인이라고 한다.
이러한 구조 때문에 상위 스코프에서 선언한 변수를 하위 스코프에서 사용하는것은 가능하지만 그 반대는 되지 않는다.
함수 레벨 스코프
C나 자바 등을 비롯한 대부분의 프로그래밍 언어는 함수 몸체뿐 아니라 모든 코드 블록이 지역 스코프를 만든다. 하지만 var키워드로 선언된 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정한다.
이런 특성을 함수 레벨 스코프라고 한다.
var x = 1;
if (true){
var x = 10;
}
console.log(x); //10
var 키워드로 선언된 변수는 함수의 코드블록만을 지역 스코프로 인정하기 때문에 if안에서 변수를 선언했음에도 전역변수로 인정되서 위와같은 부작용이 나타난다.
var i = 10;
for (var i = 0 ; i < 5 ; i++) {
console.log(i) // 0 1 2 3 4
}
console.log(i); //5
위 예시도 부작용이 나타난 예시이다. 따라서 let,const 키워드를 활용해서 블록 레벨 스코프를 사용하는 방법이 있다. 이에 대해서도 후에 알아보자.
var x = 1
function foo() {
var x = 10
bar()
}
function bar() {
console.log(x)
}
foo()
bar()
위 결과를 예측하려면 먼저 생각해봐야 하는 조건이 있다.
1. 함수를 어디서 호출했는지에 따라 함수의 상위 스코프를 결정
2. 함수를 어디서 정의했는지에 따라 함수의 상위 스코프를 결정
만약 첫번째 방식으로 함수의 상위 스코프를 결정한다면 bar함수의 상위 스코프는 foo함수의 지역 스코프와 전역 스코프일 것이다.
만약 두번째 방식으로 함수의 상위 스코프를 결정한다면 bar함수의 상위 스코프는 전역 스코프일 것이다.
첫번째 방식을 동적스코프,두번째 방식을 렉시컬 스코프라고 한다. JS와 다른 대부분 언어는 렉시컬 스코프를 따른다. 즉 JS는 함수를 어디서 호출했는지가 아닌 어디서 정의했는지에 따라서 스코프를 결정하게 된다.
따라서 위 예시에서 답은 전역변수인 1을 두번 출력하는것이 정답이 된다.
'FrontEnd > Deep Dive' 카테고리의 다른 글
[JS] DeepDive(15) let,const 키워드와 블록 레벨 스코프 (0) | 2023.08.05 |
---|---|
[JS] DeepDive(14) 전역변수의 문제점 (0) | 2023.08.04 |
[JS] DeepDive(12) 함수 (0) | 2023.07.31 |
[JS] DeepDive(11) 원시 값과 객체의 비교 (0) | 2023.07.28 |
[JS] DeepDive(10) 객체 리터럴 (0) | 2023.07.27 |