Multi Developer SuHo

자바스크립트 Closure(클로저) 본문

JavaScript

자바스크립트 Closure(클로저)

Dreaming Developer Student 2024. 1. 19. 14:47
SMALL

안녕하세요~ 최근 코로나 걸리게 되었습니다. 몸은 많이 괜찮아진 상태이고요 틈틈히 이렇게 글을 올립니다.  다들 몸 건강하게 챙기세요~  
 글을 쓰기 앞서 모든  내용과 소스들은 다음과 같은 강의 플랫폼에서 응용하여  작성하였습니다.
출처: https://inf.run/xNcEg

 

[지금 무료] [코드팩토리] [입문] 9시간만에 끝내는 코드팩토리의 Javascript 무료 풀코스 강의 - 인

이 강의 하나만으로 인기 Javascript 프레임워크들과 Typescript를 배울 수 있는 기본을 다질 수 있습니다., 자바스크립트 문법 마스터,9시간 만에 무료로 할 수 있어요! ✨ 자바스크립트 문법,한 강의

www.inflearn.com

 

오늘 알아볼 것은 자바스크립트에서 클로저(Closure)에 대해 알아보겠습니다.  자바스크립트에서 클로저란 무엇인지, 어떻게 쓰이는 것인지 알아보겠습니다. 설명이 부족하더라도 참고만 해주시면 감사하겠습니다!! 

Closure(클로저)란? ->  클로저는 함수와 그 함수가 선언된 어휘적 환경의 조합을 말합니다.


♣ 소스코드는 강의를 듣고 응용하여 작성하게 되었습니다. 

/**
 * Closure
 * 
 * A closure is the combination of a function and the lexical 
 * environment with in which that function was declared
 * 
 * "클로저는 어떤 함수와 해당 함수가 선언된 렉시컬 환경의 조합이다."
 * 
 * "상위 함수보다 하위 함수가 더 오래 살아있는 경우를 closure 라고 한다" 
 */
function getNum(){ // getNum() 함수 선언
    var num = 100; // 변수 num에 100을 할당

    function innerGetNum(){ //innerGetNum() 함수 선언
        return num;  // num을 반환
    }
    
    return innerGetNum(); // innerGetNum()을 실행
}
// console.log(num); ->  num 값을 가져올 수 없음

// console.log(getNum()); => innerGetNum()는  렉시컬 스코프 룰에 의해서 선언한 상위 스코프에서부터 Num 값을 가져올 수 있다. -> 100을 출력 
// innerGetNum() 함수가 오래 살아있는 방법


// 위 코드에서는 return 하고서 실행한 innerGetNum()를 반환을 해줌
function getNum(){
    var num = 100;

    function innerGetNum(){
        return num;
    }
    
    return innerGetNum; // 여기서는 실행하지 않고 innerGetNum()를 반환 
}

const Winner = getNum(); // Winner라는 변수를 저장하고 getNum()를 실행

console.log(Winner); //실행을 하면 innerGetNum() 함수가 나온다. innerGetNum() 함수가 나오는 이유 ->  innerGetNum()를 실행하지 않고서 함수 자체를 반환했기 때문
console.log('----------------------------');
console.log(Winner()); // 100 반환된다.
console.log('----------------------------');
// 현재 Winner를 실행한 상황,  innerGetNum()를 실행한 상황은 언제? -> 이미 getNum()가 실행이 된 이후 그 다음 Winner()를 실행함 (이미 getNum()의 Execution context(실행 컨텍스트)가 끝이난 다음) 이미 getNum()가 콜스택(호출 스택)에서 사라진 다음에 innerGetNum()를 실행할 수 있다. ->  상위 함수보다 하위 함수가 더 오래 살아있는 경우(Closure)

/** 
 * 클로저는 언제 사용될까?  
 * 1) 데이터 캐싱
 */
function exampleFunction(){  //만약 복잡하고 오래 걸리는 계산이 있을 때
    var num = 20 * 20;  // num이라는 값을 클로저에서 기억을 함

 function innerExampleFunction(newNum){ //새로운 숫자를 반환받는다.
    return num * newNum;  // 새로운 값과 미리 계산해놓고 기억하고 있는 num 값을 곱하면 된다.
 }

   return innerExampleFunction; // 외부에서 반환해 주는 것은 innerExampleFunction을 실행하지 않고서 그대로 반환
}

const Winner2 = exampleFunction(); // 여기에서 복잡한 계산을 처리함
console.log(Winner2(20)); //8000이 출력된다
console.log('----------------------------');
console.log(Winner2(40)); //16000이 출력된다
console.log('----------------------------');
// 계산이 오래 걸린다는 가정을 했을 때 훨씬 더 효율적으로 함수를 작성할 수 있다.

// 데이터 개싱2 -> 반복적으로 특정 값을 변환을 해야 될 때(값을 변경을 해야 될 때)
function exampleFunction2(){
    var num = 9999;
    
    function reduction(){ //reduction는  num 값을 기억하고 있다
        num -=1000;
        return num;
    }

    return reduction; // 감소시킨 다음 반환을 받는다.
}

const Winner3 = exampleFunction2(); // exampleFunction 실행 ->  reduction 함수를 반환 받을 수 있다.
console.log(Winner3()); // 8999 출력
console.log(Winner3()); // 7999 출력
console.log(Winner3()); // 6999 출력
console.log(Winner3()); // 5999 출력
console.log(Winner3()); // 4999 출력
console.log(Winner3()); // 3999 출력
console.log(Winner3()); // 2999 출력
console.log('----------------------------');
/**
 * 3) 정보 은닉
 */
function People(name, year){
    this.name = name;

    var _year = year; // this 키워드로 저장을 안했기 때문에 객체를 생성할 때 People 함수를 생성한 객체는 year 값을 접근을 못한다.

    this.NameAndYear = function(){
        return `안녕하세요 저는 ${this.name}입니다. ${_year} 년생입니다.`;
    } 
}

const Steve = new People('스티브', 2005);
console.log(Steve.NameAndYear()); // 변수로 선언을 했어도 출력이 잘 된다
console.log('----------------------------');
console.log(Steve.name); // 스티브 출력
console.log('----------------------------');
console.log(Steve._year); // undefined 값 출력 -> this 키워드로 저장을 해놓지 않았기 때문에 객체의 property로 액세스(한정된 구역이나 정보에 접근할 수 있는 권한)를 할 수 없다.
// 하지만 생성이 완료된 다음에 함수의 메소드 안에서 생성자 함수도 함수 안에 정의된 새로운 함수에서 나중에 가져올 수 있다.
console.log('----------------------------');


각 소스 구문에 대한 해석은 주석으로 한줄한줄 설명해드렸습니다. 


다음 소스는 클로저에 대한 이해를 높이기 위한 소스코드 입니다. 직접  작성하여 학습해주시면 되겠습니다.  

참고 : html 로 작성

<script>
    function getNum(){
        var num = 100;

        function innerGetNum(){
            return num;
        }
        
        return innerGetNum; // innerGetNum를 반환
    }
    
  var Winner = getNum(); // Winner 변수에 저장하고 getNum()를 실행

  console.log(Winner());
</script>

 

12번째 줄에 중단점을 찍습니다.


실행을 하면, 글로벌 스코프가 있고(global scope), 글로벌 콜스택(global call stack), 글로벌 엑세큐션 컨텍스트(global execution context)가 생성이 됩니다.

 

getNum()안에 들어가서 호이스팅이 나타나는 것을 볼 수 있습니다.


반환하기 때문에 콜스택(호출 스택) innerGetNum()가 들어가지는 않습니다.

 

Call stack에 들어가진 않는 것을 볼 수 있고, 여기서 Winner()를 실행하면  innerGetNum()를 실행할 수 있다.

 

Call stackgetNum가 올라가지 않은 상태에서 innerGetNum가 올라가 있는 것을 보실 수 있습니다.

그리고 클로저가 생성이 되고 num : 100 이라는 값으로 설정되어 있는 것을 확인할 수 있습니다.

이유 -> lexical scope(렉시컬 스코프)룰에 의해서 선언할 때의 위치가 상위 스코프를 정하기 때문이다.




 상위 함수에서 하위 함수를 반환함으로써 상위 함수가 먼저 실행이 끝나고 하위 함수를 나중에 실행할 수 있는 기능 -> 클로저









이상으로 클로저에 대해 알아보았습니다!!  당분간 자바스크립트 내용이 끝나면 HTML5+CSS3 내용이 올라올 것 같습니다.

LIST