스코프 체인 | 너와 나의 연결 정의

    ✨ 서론

     자바스크립트를 공부하는데 있어서 시작할때 제일 중요한것은 변수가 무엇인지 그리고 어떤것들이 할당되는것을 알아야 하는것도 있지만 이 개념이 선 다음에는 함수를 알아야하고 다음으로 이 '스코프 체인'에 대해서 어느정도 원리를 알아야 한다고 생각한다. 물론 요즘에는 책이라던가 영상강의등의 여러 풍부한 자료들이 많아서 볼 자료들이 많지만 혹여나 이 포스팅을 통해서 정보를 얻어갈 수 있는 사람들이 한둘이라도 생기길 바라는 마음에 나름 학습하고 이해한 내용을 적어본다.

     

     

    왜 불렀는데 듣지를 못하니... 자니?

     스코프를 이해하기 앞서 먼저 함수의 선언과 호출에 대한 기본 개념을 알고 있어야 한다. 다음 코드를 한번 살펴보자.

    function 전애인_카톡() {
     console.log("자니..?")
    }

     

    여기의 '전애인_카톡()'이라는 함수는 아직 '선언'만 된 상태이다. 내가 이런 함수를 만들것이오 이렇게 정의할것이오라고 말 그대로 선언해주지만 딱 거기까지, 이후에 뭔 진행을 할 수가 없는 상태이다. 그렇기에 전애인이 야심한 시각까지 이상한 쌉소리카톡을 보내줘도 듣지를 못하는 상태인것. 안타까워서 들어주는척 뭔 말을 씨부리는지 알아보기 위해서는 위 함수를 '호출'해줘야 하는데, 

    function 전애인_카톡() {
     console.log("자니..?")
    }
    
    전애인_카톡(); // 결과: 자니..?

     

    선언만 해주었던 '전애인_카톡()' 이라는 함수를 직접 호출해줘야 그 안에 있는 내용을 알아먹을 수 있다. 그리고 여기서 중요한것은 함수 안의 { } 요 중괄호 부분이다. 요 부분은 '블록'이라고 불리는 부분인데 객체(object)를 표기하는 { } 과는 다르다는것을 명심해둬야 한다. 우리가 학습해야 하는 부분은 { } 요 블록을 통해서 이루어지는 스코프를 학습해야 한다. 블록은 함수만 가지고 있는것이 아니다. 자바스크립트에서 객체를 제외한 왠만한 문법들에 다 포함되어 있는것들이다. 예를들면 다음과 같은것들이 다 블록이라고 할 수가 있다.

    try {
    
    }
    
    catch () {
    
    }
    
    if () {
    
    }
    
    for () {
    
    }
    
    ...

     

    이 개념을 숙지해두고 구분이 가능해야 스코프 체인에 대한 이해가 가능하다.

     

     

    블록 레벨 스코프

     스코프는 일종의 '검색하는 방법'이라고 보면 된다. 내가 어떤 함수를 호출할건데, 선언된 함수를 어디서 어떻게 호출해야 하는지 파악하는것을 망원경으로 찾아보는것 마냥 탐색하는것이라고 보면 된다. 다음 코드를 한번 살펴보자.

    const 포켓몬트레이너 = "륜곰";
    
    function 챔피언() {
     console.log (`22년 노원구지방 포켓몬 마스터는 ${포켓몬트레이너}님이십니다~!`)
    }
    
    챔피언(); // 22년 노원구지방 포켓몬 마스터는 륜곰님이십니다~!

     

    여기서 `${}` 요 모양의 '탬플릿 리터럴(Template Literals)'이 사용되었는데 쉽게 말해서 string 안에 다른 변수나 함수의 할당값들을 복합적으로 사용할 수 있는것을 말한다. 즉 위에서 사용된 예제를 간단히 설명하자면 챔피언을 실행시켰을때 console.log 안쪽 string에 '포켓몬트레이너'라는 변수값을 넣어서 호출하려고 하고, 해당 값인 '륜곰'이 출력된 것이다. 

     

     템플릿 리터럴 설명은 간단히 이렇게 해두고, 여기서 중요한 것은 '챔피언()' 함수가 해당 함수 안에 포함되어 있지 않은 '포켓몬트레이너'라는 변수를 참조했다는 것이다. 포켓몬트레이너'라는 변수는 '챔피언()'함수 밖에 포함되어있고, 이것을 가지고 와서 실행되는 모습을 볼 수 있다. 여기서 '포켓몬트레이너'라는 변수는 '전역(global) 스코프'라고 칭할 수 있다. 코드 전역에서 땡겨와서 볼 수 있는 상위 스코프라고 볼 수 있는 것이다.

     

     앞서 우리가 스코프를 바라봐야 할때는 { } 요렇게 중괄호로 포함되어 있는 부분을 살펴보아야 한다고 했는데, 이 중괄호 { } 블록 부분이 지역을 생성하고 이를 '지역(local)스코프'라고 칭하게 된다.

     

     

      

     

    동적 스코프와 렉시컬 스코프

     자바스크립트를 공부하다보면 이런 이야기를 종종 보게 된다. 바로 '렉시컬 스코프'라는 단어. 도데체 이게 뭘까? 자바스크립트를 비롯한 대부분의 프로그래밍 언어는 '렉시컬 스코프'를 따른다. 이 개념을 잘 알아두고, 두 스코프의 차이를 간단히 설명하자면 함수의 상위 스코프를 결정함에 있어서 어디서 '호출'했는지, 어디서 '정의'했는지에 따라 어떤 스코프인지 결정이 되는데 렉시컬 스코프는 앞서 우리가 블록레벨에서 선언한 함수들 위주로 본다고 했는데 위의 말을 풀어서 쓴것이다. 다른말로 '정적 스코프'라고 불리게 되는데 함수가 선언되는 시점에 상위스코프가 정적으로 결정되기 때문에 위와 같이 부르게 된다.

     

     

    스코프의 상위요소는 무엇일까?

     자 그럼, 위의 포켓몬예시의 온전한 코드를 보면서 스코프체인을 하나씩 뜯어가보자.

    const 포켓몬트레이너 = "륜곰";
    
    function 챔피언() {
      console.log (`22년 노원구지방 포켓몬 마스터는 ${포켓몬트레이너}이십니다~!`)
      }
    
    function 특성() {
      console.log('천하장사')
    }
    
    function 여행가방() {
      console.log('몬스터도감')
      function 물속성포켓() {
        console.log('슈퍼볼')
        const 포켓몬a = "마릴리"
        특성();
      }

     

     자바스크립트의 스코프체인은 렉시컬스코프를 따라가기에, 함수가 '정의'된것들을 하나씩 따라가 봐야 하는데, 자바스크립트 파일의 가장 최상위 존재는 anonymous라고 칭하면 된다.

    예를들어 지구 최상위 존재들이신 두분이 각각 하위 자식들로 소울젬들이라던가 LCL 액체(....)들을 바라보는것이라 생각하자

     

    위 코드에서 간단히 자신을 정의한 상위존재가 ( 자식 -> 부모 ) 관계로서 설명해보자면

    • 포켓몬 트레이너 -> annoymous
    • 챔피언 -> anonymous
    • 특성 -> anonymous
    • 여행가방 -> anonymous
    • 물속성포켓 -> 여행가방 -> anonymous

    스코프는 바로 직계자식들만 바로 바라볼 수 있다는점을 이해하고 있다면 '물속성포켓()'은 상위요소로 '여행가방()'을 거쳐서 anonymous 최상위 존재로 닿을 수 있다는것을 알 수 있다.

     

     

    선언 지도 그려보기

     스코프 체인의 마지막 검색, 선언된 함수들을 보면서 선언 지도를 그려보는 것이다. 짧은 코드들이면 직관적으로 알아볼 수 있지만 이렇게 선언된것들을 하나씩 찾아가볼 수 있도록, 이 내용이 머릿속에 정리될 수 있으면 스코프 체인에 대해서 직관적으로 알아볼 수 있게 될 것이다. 다시한번 위의 예제를 훝어보자.

    const 포켓몬트레이너 = "륜곰";
    
    function 챔피언() {
      const 라이벌 = "문굘";
      console.log (`22년 노원구지방 포켓몬 마스터는 ${포켓몬트레이너}이십니다~!`)
      }
    
    function 특성() {
      console.log('천하장사')
    }
    
    function 여행가방() {
      console.log('몬스터도감')
      function 물속성포켓() {
        console.log('슈퍼볼')
        const 포켓몬a = "마릴리"
        특성();
      }

     

    여기서 선언지도를 그려보면 다음과 같다.

     자 그리고, 아까 앞서 스코프의 자식 -> 부모 관계를 다시한번 끌어와서 보자면

    • 포켓몬 트레이너 -> annoymous
    • 챔피언 -> anonymous
    • 특성 -> anonymous
    • 여행가방 -> anonymous
    • 물속성포켓 -> 여행가방 -> anonymous

     

    이와 같다. 이를 토대로, '물속성포켓()' 이라는 함수에서 특성() 함수가 접근이 가능한지 훝어보는 것이다. 탐색 과정을 리스트형태로 나열해서 풀어가보자,

    1. 물속성포켓() 함수의 부모는 여행가방() 함수, 그리고 여행가방() 함수의 부모는 anonymous
    2. 물속성포켓() 에서 특성()이 접근 가능한가? - 불가능
    3. 직계 부모인 여행가방() 함수에서 특성()이 접근 가능한가? - 불가능
    4. 상위 직계 부모인 anonymous에서 특성()이 접근 가능한가? - 가능!

     

    스코프체인은 아래에서 위로 타고 올라가는 방향으로 탐색이 되고 상위에서 하위로 내려오지 않는 특성을 가지고 있다. 그렇기때문에 계속 상위를 타고 타고 올라가서 해당 요소가 있는지 집요하게 탐색하는것이고, 결과적으로 물속성포켓() 함수에서 특성()함수가 호출될 수 있음을 의미한다. 이러한 과정이 머릿속에서 자잘하게 그려질 수 있으면 스코프체인은 쉽게 이해할 수 있게 되고 호출-선언간 관계에 대해서 보다 심도깊게 이해가 가능할 것이다.

    댓글