본문 바로가기

Dev/[Javascript]

[javascript] 스코프(Scope)

반응형

INTRO


개발을 진행하면서, 모호했던 javascript의 개념들을

다시 한번 정리하기 위한 포스팅이다.

 

자바스크립트의 스코프(Scope)에 대해서 알아본다.

 


 

0. 서론

- 자바스크립트 뿐만 아니라 모든 언어에서는 이 스코프 개념이 존재한다.

- 직역하면 '범위' 라는 의미로, 실제 소프트웨어에서도 범위라는 개념으로 사용된다.

- 우리가 흔히 들어본 전역변수/지역변수 개념이 이 범위 단위로 나뉜다고 생각하면 된다.

let a = 10; // 전역 범위에 선언된 전역 변수

function func() {
  let a = 20; // 지역 범위에 선언된 지역 변수
  console.log(a); // 20이 출력된다. 지역 스코프는 전역 스코프보다 우선순위가 높다.
}

func();

 

1. 스코프의 특징

- 위에서 언급한 바와 같이, 크게 전역 스코프와 지역 스코프로 나뉜다.

- 전역 스코프에 선언된 변수는 코드 어디에서나 참조가 가능하며,

- 지역 스코프에 선언된 변수는 해당 스코프 내 혹은 하위 스코프에서만 참조가 가능하다.(반대로 지역 스코프에 선언된 변수를 전역 스코프에서는 참조할 수 없다.)

function func() {
  let a = 20; // 지역 범위에 선언된 지역 변수
}
console.log(a); // ReferenceError: a is not defined

- 여기까지는 지역/전역에 대한 개념이 있다면 이해하기 쉬운 내용이다.

- 아래부터는 스코프 개념 안에서도,

- 자바스크립트 한정으로 다른 언어들과는 조금 다르게 적용되는 개념에 대해 정리해보도록 한다.

 

2. 함수 레벨 스코프와 블록 레벨 스코프(function level scope / block level scope)

- 지역 스코프 개념에는 함수 레벨 스코프와 블록 레벨 스코프라는 개념이 또 등장한다.

- C 언어나 Java등 많은 언어에서는 블록 레벨 스코프 방식을 사용한다.

- javascript의 경우에는 함수 레벨 스코프와 블록 레벨 스코프를 전부 사용할 수 있다.

(ES6 이전 var키워드밖에 없었을 경우에는 함수 레벨 스코프만 사용 가능했으나, ES6의 let, const 키워드의 등장으로 블록 레벨 스코프를 사용할 수 있다.)

// 함수
function test1() {

}

// 블록
if (true) {

}

 

함수 레벨 스코프(function level scope)

- 아래 코드를 보면, (2) 부분의 코드에서 i 를 참조할 수 있다.

- 그러나 (3) 부분에서는 i를 참조할 수 없다.

// var 키워드로 선언된 변수는 함수 레벨 스코프를 따른다.
function func() {
  for (var i = 0; i < 10; i++) {
    console.log(i); //(1)
  }
  console.log(i); // (2)
}
console.log(i); // (3)

func();

- 이는 함수 내 for 문은 블록에 해당하고, var 키워드의 특성상 함수 단위로 스코프가 나뉘기 때문에 블록으로는 스코프를 구분할 수 없다.

- 따라서 i 변수는 블록에서 선언되었기 때문 func() 함수 내 (2)에서는 에서는 접근이 가능하다.

- 그러나 함수 외부의 (3) 에서는 접근이 불가능하다.

- 함수 단위로 스코프가 나뉘었고, 상위 스코프에서는 하위 스코프의 변수를 참조할 수 없기 때문이다.

 

블록 레벨 스코프(block level scope)

- 이제 블록 레벨 스코프를 알아보자

- 아래 코드를 보면, (2), (3) 모두 i 변수를 참조할 수 없다.

// ES6 이후 등장한 let, const 키워드는 블록 단위로 스코프가 나뉜다.
function func() {
  for (let i = 0; i < 10; i++) {
    console.log(i); //(1)
  }
  console.log(i); // (2)
}
console.log(i); // (3)
func();

- 블록 단위로 나뉘었기 때문에 i의 스코프는 for 블록 한정이고, 상위 스코프에서 참조할 수 없게 된다.

- 가급적 블록 단위로 (최대한 작은 단위로) 변수를 선언하는것이 코드의 실수를 줄이는 방법이다.

 

- 여기까지 정리한 지역/전역 스코프와 그 하위 개념인 함수/블록 레벨 스코프는 변수나 함수가 '선언' 된 시점에 모두 결정된다.

- 이 개념을 정적혹은 렉시컬 스코프라고 한다.

- 아래에서는 정적 스코프와 동적 스코프의 차이를 알아보고, 자바스크립트에서의 중요한 개념인 렉시컬 스코프에 대해 정리한다.

 

3. 정적(렉시컬) 스코프와 동적 스코프(static(lexical) scope / dynamic scope)

- 위에서 언급했듯이 우리가 알고 있는 대부분의 언어에서는 이 스코프 개념이 존재한다.

- 그리고 많은 언어(모든 언어는 아님) 가 이 정적 스코프 개념을 채택한다.

(동적 스코프가 적용되는 언어는 비교적 오래된 소수의 언어이다.)

- 정적 스코프는 렉시컬 스코프라고도 불린다.(아래부터는 렉시컬 스코프라고 부름)

- 두 개념의 차이는 선언되는 시점에 범위가 결정되는가? /  실행되는 시점에 범위가 결정되는가? 이다.

// (예를 들어 설명한것이다.)
let a = 10;

function func1() {
  return a;
}
function func2() {
  let a = 30;
  return func1();
}

console.log(func2());
// 렉시컬 스코프를 사용하는 언어의 결과 : 10
// 동적 스코프를 사용하는 언어의 결과 : 30

- 자바스크립트는 렉시컬 스코프 방식으로 동작한다.

- 정적으로 스코프가 결정되고나면, 상위 스코프에 대한 정보도 함께 가지고 있게 된다.

- 이걸 스코프 체인이라고 부르는데, 

- func1 함수를 보면 함수 내부에는 a가 선언되어있지 않다.

- 따라서 상위 스코프인 전역 스코프로 올라가서 a를 찾아서 참조한다.

- 이러한 과정들이 '선언' 할 때 결정된다는 것을 중요하게 알고 넘어가야 한다.

 

4. 그래서 자바스크립트에서 렉시컬 스코프는 어떤 동작을 하는가?

- 아래 예를 보면, (1) 의 name은 park이 찍힐까 choi가 찍힐까?

var name = 'choi';
function hasParam(word) {
  console.log(word + ' ' + name); //(1) 
}

function emptyParam() {
  var name = 'park';
  console.log(name);
  hasParam('hello');
}

emptyParam();

- 정답은 동적 스코프를 따를 경우 park이, 렉시컬 스코프를 따를 경우 choi가 찍히게 되며,

- 'hello choi' 라는 결과가 출력될것이다.

- 무조건 '선언' 될 때 스코프가 결정된다. 

 

 

 

마무리

 

참고 : https://www.zerocho.com/category/JavaScript/post/5740531574288ebc5f2ba97e

 

 

 

 

-퍼가실 때는 출처를 꼭 같이 적어서 올려주세요!

 

반응형