코딩스토리

5. 실행 컨텍스트와 클로저 본문

Web/JavaScript

5. 실행 컨텍스트와 클로저

kimtaehyun98 2021. 1. 19. 19:29

# 이 글은 INSIDE JavaScript(저자 송형주, 고현준) 책 내용을 바탕으로 작성한 글입니다.

 

 

실행 컨텍스트 개념

 

실행 컨텍스트 = 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념

 

즉, 실행 가능한 자바스크립트 코드 블록이 실행되는 환경이다.

 

이 말이 뭔말인지 잘 이해가 안 가는데.. 코드로 보자.

 

console.log("This is gloabal context");

function ExContext1(){
    console.log("This is ExContext1");
};

function ExContext2(){
    ExContext1();
    console.log("This is ExContext2");
};

ExContext2();

 

실행 결과

처음엔 책을 보고 이게 무슨 내용일까 계속 생각했는데 코드를 잘 보면 그냥 함수의 실행 과정을 통해 이해가 가능하다.

 

위 코드가 왜 저런 결과값을 내는지는 여기서 설명하는 건 진짜 의미가 없을 것 같고..

 

내 기억에 컴퓨터 구조 정리에서 프로시져 호출 순서에서 설명했던 것 같긴 한데 

 

이걸 실행 컨텍스트와 연관 지어 생각해보면 그냥 똑같다. 똑같아.. 

 

컨텍스트를 프로시져라고 생각하고 이해하면 될 것 같다.

 

활성 객체는 실행 컨텍스트가 생성된 후 여러 정보를 담을 객체를 생성하는데 이 객체는 엔진 내부에서 접근할 수 있으며 사용자가 접근할 수 있진 않다. (이 정도로 넘어가도 될 것 같다.)

 

 

스코프 체인

 

우리가 일반적으로 사용했던(??) C언어 같은 경우 {, } (중괄호)로 묶인 범위에서 선언된 변수는 해당 범위를 벗어나서는 사용할 수가 없다. -> 즉 for문안에 선언된 변수에는 밖에서 접근이 불가능하다.

 

하지만 JavaScript 에서는 오직 함수만이 유효 범위의 한 단위가 된다.

 

이게 뭔소린가?

 

잘 모르겠으니 코드로 보자..

let var1 = 1;
let var2 = 2;
function func(){
    let var1 = 10;
    let var2 = 20;
    console.log(var1);   // 출력값 = 10
    console.log(var2);   // 출력값 = 20
};
func();
console.log(var1);   // 출력값 = 1
console.log(var2);   // 출력값 = 2

 

 

var1과 var2가 전역 객체, 그리고 함수 안에 동시에 선언되었다.

 

이럴 때는 위에서 말했듯이 함수 안에서 선언되었기 때문에 유효 범위가 함수 안으로 설정되어있기 때문에 우리가 흔히 알고 있고 생각하는 답이 출력되는 것이다.

 

그럼 이제 색다른 코드를 보자.

let value = "value1";

function printValue(){
    return value;
};

function printFunc(func){
    let value = "value2";
    console.log(func());
};

printFunc(printValue);

음..

음....

음....??

 

일단 내 생각엔 value2가 출력될 것 같긴 한데..

한번 출력해보면

음..

value1이 출력된다.

 

여기서부터 멘붕.. 

 

결론부터 말하자면 식별자 인식 순서에 따라 전역 객체에서 value 값을 찾게 되고 따라서 결과값은 value1 이 된다고 한다.

 

여기서 아까 공부했던 실행 컨텍스트의 개념이 들어가는데 말로 설명해보자면

 

이 코드에서는 총 3개의 실행 컨텍스트가 생성된다.

 

1. 전역 실행 컨텍스트

 

2. printFunc 실행 컨텍스트

 

3. printValue 실행 컨텍스트

 

위에 적은 순서대로 실행 컨텍스트가 생성된다. 

 

즉 이러한 순서대로 스코프 체인이 형성이 되어있을 것이다.

 

이제 함수에서 어떠한 변수가 호출이 된다면, 형성된 스코프 체인의 첫 번째 변수 객체부터 식별자와 대응되는 프로퍼티가 있는지 탐색한다.

 

즉, 첫 번째 객체 = 전역 실행 컨텍스트 이고 이 컨텍스트 안에 value란 프로퍼티가 있는지 탐색한다는 의미이다.

 

전역 실행 컨텍스트에 value = 'value1' 이란 값을 가지고 있기 때문에 결국 출력은 value1을 출력하게 되는 것이다.

 

당연히 그림으로 봐야겠죠?

 

잘 설명되었는지 모르겠지만 실행 컨텍스트의 순서를 생각해보면 이해가 될 것이다.

 

 

 

(사실 이 부분에 대해 지금까지 JS를 공부한 시간 중 가장 오래 고민해보았다.

 

처음에 책에서 "첫 번째 변수 객체부터 식별자와 대응되는 프로퍼티가 있는지 탐색한다"라는 문장을 안 읽어보고 고민하느라 시간이 조금 걸렸는데 저 문장을 읽고 난 뒤엔... 짜증 날 정도로 시간이 아까웠다.

 

그냥 아까워서.. 푸념 좀 써봤어요...)

 

 

 

클로저

 

클로저란 이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수이다.

 

developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Closures

 

클로저 - JavaScript | MDN

클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 클로저를 이해하려면 자바스크립트가 어떻게 변수의 유효범위를 지정하는지(Lexical scoping)를 먼저 이해해야 한다. 다음을 보자: function i

developer.mozilla.org

위는 모질라에 언급된 클로저에 대한 설명이다. 

 

코드를 보고 이해가 잘 안돼서 찾아보았다.

 

굉장히 잘 설명되어 있다. 

 

클로저란 이름에 맞게 함수가 클로징 되어도 남아있다 정도로 요약할 수 있을 것 같다.

 

어느 정도 클로저에 감이 잡혔으면 이제 이 클로저를 어떻게 활용하는지 알아보자.

 

코드를 보자.

function outerFunc(arg1, arg2){
    let local = 8;
    function innerFunc(innerArg){
        console.log((arg1 + arg2)/(innerArg + local));
    }
    return innerFunc;
}

let exam1 = outerFunc(2,4);
exam1(2);

 

클로저를 사용한 코드답게 outerFunc와 innerFunc가 구현되었다.

 

먼저 exam1 이란 객체에 outerFunc(2,4)를 대입한다.

 

이 let exam1 = outerFunc(2,4) 란 코드를 통해 outerFunc의 실행 컨텍스트가 생성되고, 이때 생성되는 변수 객체가 스코프 체인에 들어갈 것이다.

 

그럼 이제 exam1에는 innerFunc()이 저장되어있을 것이다.

 

exam1(2) 란 코드를 통해 실행해보면 

 

innerFunc(2)를 호출하는 것과 같을 것이다.

이때 console.log((arg1+arg2)/innerArg+local))이란 코드를 실행하게 될 텐데, 우리가 준 인자는 2, 즉 innerArg 하나뿐이다.

 

원래라면 (기타 우리가 배워왔던 C언어 등등) 절대 불가능할 것이다.

(애초에 함수가 함수를 반환하는 것도.. 참 신기한 언어야)

 

하지만!

B.U.T

 

이 코드는 정상적인 출력을 한다.

 

바로 클로저의 개념이 여기서 사용되는 것이다.

 

outerFunc은 이미 종료되었지만, outerFunc의 프로퍼티 값에 접근이 가능하다는 것이다!

 

그렇기에 우리는 innerArg 하나만 주어도 충분히 정상적으로 코딩이 가능하다.

 

(2+4)/(2+8)의 결과값인 0.6을 출력

 

와우.. 쉽지 않은 개념이다.

 

클로저란 개념은 함수형 프로그래밍에서 매우 중요한 개념이라고 한다.

 

그렇기에 이러한 클로저를 잘 사용하려면 경험이 가장 중요하다고 한다.

 

책에는 기타 예제들이 나와있으나 난 아직 경험이 많이 많이 많이 부족하기 때문에 잠시 접어두고..

 

JavaScript 문법에 대한 공부는 일단 여기까지로 마치려고 한다. 

 

 

 

 

<후기>

 

지금까지 JavaScript를 공부한 지 대충 2주 정도 지난 것 같은데 솔직히 말하자면

 

프로그래밍 언어를 이렇게 오래 공부할지 몰랐다 ㅎ.. (심지어 이해도도 부족할 줄은...)

 

내가 많은 언어를 공부하진 않았지만 C++을 공부하는 데에는 1주, Java를 공부하고 이해해서 사용하는 데에는 3일 정도 걸렸던 것 같은데 JS는... 다른 세상 언어 같다.

 

솔직히 처음에 시작할 때 가벼운 마음으로 시작한 것도 맞다.

 

JS 조금 공부해서 프로젝트해봐야지~ 이랬던 것도 사실이다.

 

그냥 어느 정도 공부하면 할 수 있을 줄 알았지.. 이렇게 복잡할 줄 알았냐고...

 

어쨌든 내가 내린 판단은 더 이상 문법 공부를 할 바엔 차라리 실전에서 많이 부딪혀 보고 그 과정을 통해 배우는 게 좋다고 생각했다.

 

앞으로 또 책도 사고 강의도 찾아봐야겠지만 '일단 부딪히자'라는 마인드로 실전 web 공부를 할 예정이다.

 

이번 문법 공부를 통해서 내가 얼마나 부족한지를 절실하게 깨달았고.. 

 

언제 즘 나만의 web을 만들 수 있을까요..ㅠ

 

 

 

Comments