JavaScript - 스코프

춤추는개발자·2023년 3월 13일
0
post-thumbnail

오늘은 스코프에 대해서 공부하고자 합니다. 스코프는 자바스크립트에서만 해당되는 개념이 아니라 모든 프로그래밍 언어의 기본적이며 아주 중요한 개념이기 때문에 확실하게 개념을 공부할 필요가 있습니다.

자바스크립트에서의 스코프는 다른 프로그래밍 언어와는 조금 다른 특징을 가지고 있습니다.
대표적으로 var 키워드로 선언한 변수와 let, const 키워드로 선언한 변수의 스코프 다르게 동작 합니다.

스코프란?

이제 스코프가 대체 뭔지 알아봅시다. 코드에서 모든 식별자(변수,함수,클래스 이름 등)는 자신이 선언된 위치에 의해 다른 코드에서 자신을 참조할 수 있는 유효범위가 결정되는데 이 유효범위를 스코프라고 합니다.

쉽게 설명하면 우리는 현재 대한민국이라는 나라에 살고 있습니다. 세상에 교통수단은 자동차만 있고 비행기, 배 등은 없다고 생각해 봅시다. 우리는 자동차를 타고 대한민국 어디든 갈 수 있습니다. 하지만 자동차를 타고 외국에는 갈 수 없습니다. 우리의 활동범위는 대한민국 입니다. 이 활동범위가 스코프 입니다. 자바스크립트에서는 식별자가 위치하는 자리에 따라서 참조 할 수 있는 범위가 결정되는 것 입니다.

스코프의 종류

스코프는 전역 스코프와 지역 스코프가 있습니다. 이 스코프는 식별자가 선언된 위치에 따라서 자신이 유효한 범위인 스코프가 결정 됩니다.
전역이란 코드의 가장 바깥 영역을 말합니다. 전역에서 변수를 선언하게 되면 그 변수는 전역 스코프를 가지게 되고 전역 변수가 됩니다. 이 변수는 코드 어디에서든 참조 할 수 있습니다.
지역이란 함수 몸체 내부 영역을 말합니다. 지역에서 변수를 선언하게 되면 그 변수는 지역 스코프를 가지게 되고 지역 변수가 됩니다. 이 변수는 본인의 지역 스코프와 하위 지역 스코프에서 참조 할 수 있습니다.
코드를 보면

let a = "global";

function outFunc() {
  let b = "outFunc local b";
  
  console.log(a); // global
  console.log(b); // outFunc local b
  console.log(c); // Uncaught ReferenceError c is not defined
  
  
  function innerFunc() {
    let c = "innerFunc local c";
    
    console.log(a); // global
    console.log(b); // outFunc local b
    console.log(c); // innerFunc local c
  }
  innerFunc()
}

outFunc();

console.log(a); // global
console.log(b); // Uncaught ReferenceError b is not defined
console.log(c); // Uncaught ReferenceError c is not defined

위의 코드를 보면 변수 a 는 전역에 선언된 전역 변수 입니다. 따라서 전역 스코프를 가지기 때문에 코드 전역에서 참조 할 수 있습니다.
변수 b 는 outFunc 내부에서 선언된 지역 변수 입니다. 따라서 지역 스코프를 가지게 됩니다. 본인의 스코프와 outFunc 내부의 함수인 innerFunc 내부에서도 참조가 가능 합니다.
변수 c 는 innerFunc 내부에서 선언된 지역 변수 압니다. 따라서 지역 스코프를 가지게 됩니다. 변수 c는 innerFunc 내부에서만 참조가 가능 합니다.

스코프 체인

위의 코드를 보시면 함수는 전역에서 또는 함수 내부에서 정의 할 수 있습니다. 함수도 중첩이 가능하기 때문에 함수의 지역 스코프도 중첩될 수 있습니다. 스코프가 함수의 중첩에 의해 계층적 구조를 갖게 된다는 뜻 입니다.
위의 코드에서는 innerFunc 함수는 outFunc 함수의 중첩 함수이기 때문에 innerFunc 함수의 지역 스코프의 상위 스코프는 outFunc 함수의 지역 스코프 입니다. 그리고 outFunc 함수의 지역 스코프의 상위 스코프는 전역 스코프 입니다. 이렇게 모든 스코프는 하나의 계층적 구조로 연결되며 이 연결을 "스코프 체인" 이라고 합니다. 모든 스코프 체인의 최상위 스코프는 전역 스코프 입니다.

스코프 체인을 통한 변수 참조 동작원리

let a = "global";

function outFunc() {
  let b = "outFunc local b";
  
  console.log(a); // global
  console.log(b); // outFunc local b
  console.log(c); // Uncaught ReferenceError c is not defined
  
  
  function innerFunc() {
    let c = "innerFunc local c";
    
    console.log(a); // global
    console.log(b); // outFunc local b
    console.log(c); // innerFunc local c
  }
  innerFunc()
}

outFunc();

console.log(a); // global
console.log(b); // Uncaught ReferenceError b is not defined
console.log(c); // Uncaught ReferenceError c is not defined

그럼 이제 위의 코드에서 변수를 어떻게 참조하는지 동작 원리에 대해서 알아봅시다.
변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 찾고 변수를 찾았다면 그 변수를 참조 합니다.
구체적으로 innerFunc 내부에서 변수 a,b,c 를 참조할 때 자바스크립트 엔진이 어떻게 변수를 찾아 참조하는지 그 과정을 알아봅시다.

  1. a 변수를 참조할 때 : 자바스크립트엔진은 변수 a 를 innerFunc 의 지역 스코프에서 선언되었는지 검색합니다. 없다면 상위 스코프인 outFunc 의 지역스코프로 이동해서 변수 a 를 검색 합니다. 없다면 상위 스코프인 전역 스코프로 이동해서 변수 a 를 검색 합니다. 전역 스코프에는 변수 a 가 존재하기 때문에 변수 a 를 참조하고 검색을 종료 합니다.

  2. b 변수를 참조할 때 : 자바스크립트 엔진은 변수 b 를 innerFunc 의 지역 스코프에서 선언되었는지 검색 합니다. 없다면 상위 스코프인 outFunc 의 지역 스코프로 이동해서 변수 b 를 검색 합니다. outFunc 의 지역 스코프에 변수 b 가 존재 하므로 변수 b 를 참조하고 검색을 종료 합니다.

  3. c 변수를 참조할 때 : 자바스크립트 엔진은 변수 c 를 innerFunc 의 지역 스코프에서 선언되었는지 검색 합니다. innerFunc 의 지역 스코프에서 변수 c 가 존재 하므로 변수 c 를 참조하고 검색을 종료 합니다.

위에서 설명했던것과 같이 자바스크립트 엔진은 변수를 참조하는 코드의 스코프에서 시작해서 상위 스코프로 이동하면서 선언된 변수를 검색합니다. 절대 하위 스코프로 내려가서 변수를 검색하는 일은 없습니다.
결과적으로 상위 스코프에서 선언된 변수는 하위 스코프에서 자유롭게 참조가 가능 합니다.

렉시컬 스코프

let a = 1;

function hello() {
  let a = 2;
  hi();
}

function hi() {
  console.log(a);
}

hello();
hi();

위의 코드에서 함수 hello, hi 를 호출해서 호출 결과가 어떻게 될까?
결론부터 말하자면 변수 a 의 값 1 이 두번 출력 된다.
자바스크립트는 렉시컬 스코프를 따르므로 함수를 어디서 호출했는지가 아니라 함수를 어디서 정의했는지에 따라서 상위 스코프가 결정 됩니다. 함수를 어디서 호출했는지 그 위치는 스코프 결정에 아무 영향도 주지 않습니다. 함수의 상위 스코프는 함수 정의가 실행될 때 정적으로 결정 됩니다. 함수 정의가 실행되어 생성된 함수 객체는 이렇게 결정된 상위 스코프를 기억해 함수가 호출될때마다 함수 상위스코프를 참조 합니다.
위의 코드에서는 hi 함수가 전역 스코프에 정의되었기 때문에 전역 스코프에 선언되어 있는 변수 a 를 참조하게 되는 것 입니다.

마치면서

지금까지 스코프에 대해서 알아 봤습니다. 공부하면서 정리해본거라 정확하지 않은 정보가 있을수도 있습니다. 그 점은 공부를 계속 진행하면서 수정하고 더 필요한 정보는 추가 할 것 입니다. 공부를 하면서 참고한 책은 모던 자바스크립트 deep dive 입니다.

0개의 댓글