dovelet 문제를 이용한 closure 공부

http://119.201.123.184/30stair/x_length/x_length.php?pname=x_length

오늘은 dovelet 문제를 이용해 요즘 관심있게 보고 있는 동영상(https://youtu.be/QyUFheng6J0에서 보여준 예제를 간단하게 따라해 봤습니다.

var b; //global 변수
var execute = (function(){
    a = 4;       //이 변수는 클로저로 접근 할 수 업습니다.
    b = 3;       //이 변수는 클로저로 접근 가능합니다.
    function result(){       //이 함수는 클로저로 접근가능합니다.
        var sum = a + b;     //a, b 클로저를 사용하고있습니다.
        return sum * (Math.PI + Math.sqrt(2));    //결과값. 딱히 제가 하려던 얘기와는 상관 없습니다.
    }
    return result;  // result 레퍼런스를 반환합니다. 이순간부터 result 와 그 주변 환경은
                    //더이상 할일이 없어질 때까지, 즉 더이상 접근 방법이 없을 때까지
                    //메모리가 남이 있습니다 
    var a;        // 익명함수의 메모리에 a가 이미 등록이 되어있기 때문에 위의 a는 클로저로는 접근 할 수 없습니다.
})();

console.log(execute().toFixed(3));  //실행이 되고서 더이상 result에 대한 접근 수단이 없기 때문에 남아 있던 메모리가
                                    //반환됩니다.

한번 이 코드를 실행을 제가 아는데로 따라가 보겠습니다.

먼저 첫번째 실행환경 구축 단계에 global 에 b, execute가 등록이 됩니다.

현재 레벨에서는 d, 와 execute 변수 모두 undefined로 정의되어 있습니다.
global 환경

  • b = undefined
  • execute = undefined

이제 환경 구축단계에서 실행으로 넘어와에서 execute의 대입 연산자가 수행이되며 가로안의 함수객체의 환경 구축이

시작됩니다.

첫번째에 a와 b가 있지만 환경 구축 단계에서는 건너 뜁니다.

result를 환경에 추가하고, 맨 밑에 보면 var a가 있는데 이 역시 환경에 등록시킵니다.

global 환경

  • b = undefined
    execute = undefined -> 아직 실행이 되지 않아 execute에는 값이 저장되지 않았습니다.

익명 함수 환경

  • result(function)
  • a = undefined

이제 실행 단계에서 a는 4가 저장이되고 b에는 3이 저장이 되는데 전혀 다른 메모리에 저장이된다는 것을 알 수 있습니다.

a는 이미 익명함수 환경에 등록이 되어 있기 때문에 클로저로 접근할 수 없습니다. a 는 오직 익명 함수 내에서만

접근 가능한 변수입니다.

반면 b는 3이 저장이 되는데 이는 클로저로 접근 가능합니다. 왜냐하면 b는 익명 함수 환경내에 없기 때문에

스코프 체인을따라 글로벌 환경의 b에 3을 저장합니다.

그런뒤에 등록된 result의 를 반환하게 됩니다.

global 환경

  • b = 3
  • execute = result(function reference)

익명함수 환경

  • a = 4
  • result(function)

제가 동영상을 보면서 인상깊었던 점은 이때부터 이루어지는 메모리의 생성과 소멸이였습니다.

익명함수 내의 result함수는 실행단계에서도 메모리가 할당되어지지 않습니다.

단, result를 아직은 접근 할 수있는 수단, 즉 execute를 통해 접근이 가능하기 때문에

result의 외부환경, 즉 익명함수의 환경의 메모리는 사라지지 않고 유지되어집니다.

result함수 객체의 메모리가 할당되는 시점은 execute에 저장되어있는 result 레퍼런스를 불러왔을 때

비로소 result에 메모리가 할당이 됩니다. 그렇지만 execute() 뒤에는 더이상 result 레퍼런스에 접근할 방법이

전혀 없습니다. 이 때, 즉 더이상 메모리에 접근할 방법이 없을 때 비로소 메모리의 반환이 이루어집니다.

스택에 쌓여 있는 데로 result의 메모리가 반환되고 그 다음 익명함수의 메모리가 반환이 이루어집니다.

현재 메모리는 이렇습니다.

global 환경

  • b = 3
  • execute = result(function)

제가 위에서 굵게 썼듯이 메모리의 생성과 소멸은 그 근본을 레퍼런스에 대한 접근 여부에 달렸다는 중요한 교훈을 얻을 수

있었던 시간이었던 것 같습니다. 또한 익명 함수 안의 return 뒤에 var a를 선언 한것은 뒤통수를 한대 얻어 맞은 느낌이었고

변수 호이스팅이 왜 어떻게 이루어지는지에 대한 이해를 높이는 계기가 되었던 것 같습니다.

다음에는 이벤트 루프의 실행 과정에 대해 리뷰를 해봐야 겠습니다.

혹시 제가 쓸 때 잘못된 정보를 적었다면 지적좀 해주세요 ㅠㅠ 잘못된 정보를 제공했다면 바로 고치고 싶습니다.

난독증에 의해 끝까지 자세히 읽어보지는 못했습니다.^^

다만 읽었던 부분에서 이 변수는 클로저입니다. 이 변수는 클로저아닙니다.라고 하셨는데 보다는 result 실행 컨텍스트에서 b는 클로저에 의해 접근가능합니다.라고 식의 표현을 추천합니다. 왜냐면 클로저는 어떤 변수의 종류가 아니라 특정 컨텍스트에서 다른 스코프의 변수를 접근하게 하게 해주는 녀석(테크닉)이니까요. (wikipedia에서는 테크닉이라고 표현되어 있네요.)

어떤 의미에서 이러한 표현을 하셨는지는 알것 같습니다. 다른 사람이 읽을 때 저 표현때문에 혼란이 생길수 있을 것 같아서요.

공유 감사합니다. :+1:

2개의 좋아요

답글 주셔서 너무 감사합니다. 현재 클로저에 대한 표현은 모두 고쳤습니다.

클로저에대해 하나하나 고정관념이 깨져가는 것 같아 뭔가 기분이 좋네요 ㅎ

혹시 앞으로도 글을 써갈 텐데 잘못 된점이 보이신다면 이렇게 지적해 주시면 감사 할 것 같아요!