JavaScript - 스코프(Scope)

James Orr From Unsplash

ToC


전역 변수와 지역 변수

전역변수(Global Variable)과 지역변수(Local Variable)의 차이는 변수가 선언된 블록 내에서만 사용하느냐 아니면 어디서나 사용가능하느냐의 차이이다.

1
2
3
4
5
6
let globalVar = "Hello Global";

function myFunc() {
let localVar = "Hello local";
}
myFunc();

위의 코드를 보며 정리해보자.

globalVar은 스코프가 전역으로 선언된 변수이다. 반면 localVar은 함수 myFunc()에서 선언되서 해당 함수내에서만 사용할 수 있는 변수이다.

스코프가 전역으로 변수가 선언되었다는 이야기는 어디서나 변수를 호출할 수 있다는걸 의미한다. 자주 사용되거나 공통적으로 사용되는 변수가 아니라면 굳이 전역변수를 선언하기보다는 지역 변수를 사용하는 것이 더 좋을듯하다.

어디서나 접근되고 호출할 수 있다는 점은 편의성 측면에서 장점같지만 반대로 원하지않는 변수가 언제 어디서나 값이 재할당될수도 있으므로 위험성도 갖기 때문이다.


스코프와 스코프 체인

스코프(Scope)는 위에서 설명했듯 변수또는 함수등 식별자에 대한 유효범위를 의미한다.

스코프 체인이란 변수를 찾기위해 스코프를 안에서 바깥쪽으로 탐색하는 과정을 의미한다.

1
2
3
4
5
6
let globalVar = "Hello World";
function myFunc() {
let localVar = "Hello JavaScript";
alert(globalVar);
}
myFunc();

위의 코드를 살펴보자.

첫번째 줄 코드에서 전역변수를 선언했고, 두번째줄에는 변수를 인자로 받아서 alert()하는 함수를 선언했다. 마지막 줄에는 이 함수를 호출함으로써 브라우저에서 변수를 출력하도록 하였다.

myFunc()가 호출되면서 alert(globalVar)가 실행되는데 이 때 자바스크립트는 먼저 가장 가까운 스코프에서부터 변수를 찾게된다.

globalVar를 호출한 alert() 함수가 선언되어 있는 스코프인 myFunc()에서 먼저 globalVar를 찾고 여기서 못찾으면,

이렇게 상위 스코프로 올라가서 전역 스코프에서 globalVar를 찾는다.

이렇게 식별자를 찾기위해 스코프를 안에서 바깥쪽으로 단계적으로 탐색하는 과정스코프 체이닝이라 한다.

반면 반대로 아래와 같은 경우는 스코프 탐색이 불가능하다.

마지막줄 코드에서 localVar 를 브라우저 경고창으로 띄우는 코드인데, alert()가 선언된 스코프에서 찾았지만, 해당 스코프에서는 localVar를 찾을 수 없었을것이다.

myFunc()안에 localVar이 선언되어 있음에도 이를 찾지못한건 스코프체인은 안에서 바깥으로 즉 상위로만 뻗어나가며 탐색을 할뿐, 하위 스코프로 바깥에서 안으로 탐색하지는 않기 때문이다.


렉시컬 스코프

렉시컬 스코프란, 정적 스코프를 의미한다.

렉시컬 스코프를 설명하기 앞서 먼저, 스코프의 생성 시점에 대해 알아보자.

1
2
3
4
5
6
7
8
9
10
11
12
let name = "youngjin";

function sayHello() {
let name = "devandy";
callMyName();
}

function callMyName() {
alert("Hello "+name);
}

sayHello();

위의 코드에서 sayHello()가 호출되면 브라우저 경고창에서 어떤 문자열이 출력될까?

정답은 "Hello youngjin"이 출력된다.

callMyName()이 호출되는 시점이 아닌 선언시점에 스코프가 생성되면서 전역변수 name이 할당되면서 youngjin을 가져와서 출력한 것이다.

이렇게 스코프의 생성시점은 호출시점이 아닌 선언시점이라는 것을 기억해두자.

이제 렉시컬 스코프에 대해 알아보자. 아래의 예제 코드를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
var x = 1;
function foo() {
var x = 10;
bar();
}

function bar() {
console.log(x);
}

foo();
bar();

위의 코드에서 콘솔에 출력되는 숫자는 몇일까?

답은 아래와 같다.

1
2
1
1

이걸 설명하기 위해 스코프의 생성시점을 위에서 먼저 설명한 것이다. foo()bar()를 호출하는 함수이므로 결국 bar()를 두번 호출하는 코드이다.

그런데 위에서 스코프의 생성시점이 호출시점이 아닌 선언시점이라고 했기때문에 bar()에서 실행되는 콘솔 함수는 전역변수의 x를 가져와서 실행된다.

이렇게 함수의 스코프를 결정하는 방식이 선언시점렉시컬 스코프라고한다.

이와반대로 동적 스코프(Dynamic Scope)는 스코프를 결정하는 방식이 함수의 호출시점에 해당한다고 한다.

References