[JavaScript] 스코프

Seokkitdo·2021년 8월 21일
0

JavaScript

목록 보기
4/5
post-thumbnail

스코프란 무엇일까?

식별자(변수 이름, 함수 이름, 클래스 이름 등) 가 가지는 유효한 범위

1. 스코프

스코프가 무엇인지 살펴보기 전에 어떻게 나타나는지부터 코드를 통해 보도록 하겠습니다.

message라는 변수를 선언했습니다. 그러면 다음 줄에 'Hello'가 찍히는 것을 알 수 있습니다.

이번에는 if 블록 안에 message를 선언해보도록 하겠습니다.

콘솔로 찍어보니 이번에는 message가 정의되지 않았다는 오류가 나옵니다.
왜 이런 오류가 생겨난 걸까요?

그 이유는 if 블록이 message 변수의 스코프를 생성했기 때문입니다. message 변수는 오직 이 스코프 안에서만 사용가능해졌기 때문입니다.

상위 수준에서는 변수가 생성되는 스코프에 따라 변수의 접근성이 제한됩니다. 스코프 내에서는 정의된 변수에 자유롭게 접근할 수 있습니다. 하지만 범위를 벗어나면 변수에 접근할 수 없습니다.

2. 블록 스코프

JavaScript의 코드 블록은 let 및 const를 사용하여 선언된 변수의 범위를 정의합니다.

첫 번째 콘솔의 경우 정상적으로 message의 값을 출력하고 있습니다. 그 이유는 console.log(message)는 정의된 스코프에서 메시지 변수를 참조하고 있기 때문입니다.

하지만 두 번째 콘솔의 경우 이전과 같은 에러가 발생하는데 변수의 스코프 범위 밖에서 참조하기 때문에 발생하게 된 에러입니다.
두 번째 콘솔이 존재하는 스코프에는 message라는 변수가 존재하지 않습니다.

이는 if 뿐만이 아닌 for이나 while에서도 마찬가지입니다.

이번에는 for를 통해 살펴보겠습니다.

color 와 message 변수는 for 블록 범위 안에서만 존재하고 있습니다.

while도 마찬가지입니다.

message 변수가 while 블록 안에서 정의되었기 때문에 while문 내부에 있는 console.log(message)는 참조를 할 수 있게 되지만 이 범위를 벗어날 경우 에러가 발생합니다.

추가로 자바스크립트에서는 for이나 while을 사용하지 않고도 고유한 스코프를 가진 블록 생성할 수 있습니다.

2.1 var 는 블록 스코프가 아니다!

이전 파트에서 볼 수 있듯이 코드 블록은 const 와 let 을 사용하여 선언된 변수의 범위를 만들지만 var를 사용하여 선언된 변수는 다른 모습을 보여줍니다.

var로 선언된 count를 보며 알아보겠습니다.

var 로 선언된 count 변수의 경우 if 블록 안에서 let과 const와 마찬가지로 접근이 가능한 것을 볼 수 있습니다.
하지만! 여기서 count 변수는 블록스코프 밖에서도 접근이 가능한 것을 확인할 수 있습니다.
그 이유는 var 가 블록 스코프가 아닌 함수 스코프를 따르기 때문입니다.
다음 파트에서는 함수스코프에 대해서 알아보도록 하겠습니다.

3. 함수 스코프

자바스크립트의 함수는 var, let 그리고 const를 사용하여 선언된 변수의 스코프를 정의합니다.

함수 내부에서 var를 통해 변수를 선언해보겠습니다.

run() 함수는 스코프를 생성했으며 그 안에는 message 변수가 var로 선언되어있습니다. 위에서 말했던 것처럼 함수 스코프내에서는 어디서든 접근이 가능하지만 그 범위를 벗어나게 되면 var 로 선언된 변수도 ReferenceError: message is not defined 라는 에러를 만나게 됩니다.

이는 let과 const도 마찬가지입니다.

4. 스코프는 중첩될 수 있다.

스코프의 흥미로운 특성은 중첩될 수 있다는 것입니다.

다음의 예제에서 run 함수는 함수 스코프를 생성하고 있고 그 안에 있는 if 조건문은 또 다른 스코프인 블록스코프를 생성하고 있습니다.

run() 함수 스코프 내부에는 if 조건문의 블록 스코프가 중첩되어 있습니다.
다른 스코프에 포함된 스코프를 내부 스코프라고 하며 inner scope 와 동일한 의미입니다.
위의 예제에서는 if 조건문의 블록 스코프가 run() 함수 스코프의 내부 스코프입니다.
run() 함수 스코프처럼 다른 스코프를 감싸고 있는 스코프를 외부 스코프 즉, outer scope 라고 부릅니다.
예제에서는 run()은 outer scope 이며 if 조건문 내부는 inner scope 입니다.

위의 예제에서 알 수 있는 것은 내부 스코프는 외부 스코프의 변수에 접근할 수 있다는 것입니다.
run() 함수 스코프(outer scope)에 존재하는 message 변수는 if 조건문 블록 스코프(inner scope)에 접근할 수 있다.

5. 전역(global) 스코프

전역스코프는 가장 바깥쪽에 존재하는 스코프입니다. 내부(로컬) 스코프에서 접근할 수 있습니다.

브라우저 환경에서 script 태그를 사용하여 로드된 자바스크립트 파일의 최상위 스코프는 전역입니다.

전역 스코프 내에서 선언된 변수를 전역 변수라고 부르며 전역 변수는 어떤 스코프에서도 접근할 수 있습니다.

6. 렉시컬 스코프

innerFunc 함수가 outerFunc내부에 존재하도록 두 개의 함수를 정의하겠습니다.

inner 는 outerFunc을 호출하고 있으며 outerFunc은 innerFunc를 반환하고 있습니다. inner()를 통해 innerFunc를 호출합니다.
코드 맨 하단을 보면 inner: innerFunc 함수를 호출하고 있습니다.
그런데 잘 살펴보면 innerFunc의 호출은 outerFunc() 함수 스코프를 벗어나서 이루어지고 있습니다.
여기에서 궁금한 점이 하나 생깁니다.
자바스크립트는 어떻게 innerFunc() 함수 내부에 outerVar가 outerFunc() 함수의 outerVar 변수라는 것을 이해한 걸까요?

이 질문의 정답은 렉시컬 스코프에 있습니다.

자바스크립트가 함수의 상위 스코프를 결정하는 방법은 함수가 어디서 선언되었는지에 따라 상위 스코프를 지정합니다.
함수가 어디서 호출됐는지가 아닙니다!

7. 결론

스코프는 변수의 접근가능한 범위를 관리하는 것이라고 볼 수 있습니다.
스코프 내에서 정의된 변수는 해당 범위 내에서만 접근할 수 있지만 외부에서는 접근할 수 없습니다.

자바스크립트에서는 코드 블록, 함수, 모듈로 스코프를 만듭니다.
const, let 은 코드 블록, 함수 또는 모듈로 스코프가 지정되지만
var 는 함수 또는 모듈로만 스코프가 지정됩니다.

스코프는 중첩될 수 있으며 내부 스코프에서 외부 스코프의 변수에 접근할 수 있습니다.

렉시컬 스코프는 함수가 어디서 호출되었는지가 아닌 선언된 위치를 통해 상위 스코프를 결정합니다.

참고자료

A Simple Explanation of Scope in JavaScript
스코프와 스코프 체인, 렉시컬 스코프, 클로저
함수의 범위(scope)

profile
어제보다 성장해 나가고 싶은 개발자

0개의 댓글