Front-end/깊게 파고들기

Javascript 클로저(Closure) 정리

아지송아지 2022. 4. 5. 11:46

안녕하세요

오늘은 Closure에 대해 알아보겠습니다.

이전 var, let, const 차이점 글을 먼저 보시면 클로저를 이해하는데 도움이 되실 겁니다.

 

이번 글은 예시가 많습니다.

 

MDN에는 클로저를 다음과 같이 정의하였습니다.

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

 

 

Lexical scoping


 

"lexical"이란, 변수가 소스 코드 내 어디에서 선언되었는지 고려한다는 의미입니다.

"scope"는 유효 범위입니다.

즉 렉시컬 스코핑은 어떻게 변수의 유효 범위를 지정하는가입니다.

 

function outer() {
  var name = "song"; 
  
  function inner() { // inner()은 내부 함수이며, 클로저다.
    alert(name);
  }
  
  inner();
}
outer();

outer()함수를 실행하면 outer안에 있는 inner를 실행합니다.

inner는 부모 함수에 있는 name 변수를 가져와 alert 시켜줍니다.

 

inner라는 함수가 어디서 만들어졌는지가 중요합니다.

name이라는 변수는 outer의 지역 변수입니다. 따라서 outer 외부에서는 사용할 수 없지만, 내부에서는 어디든 사용 가능합니다. 그러므로 inner안에서도 해당 변수 name은 유효합니다.

 

 

클로저(Closure)


여기까지 이해하셨으면 클로저도 쉽게 이해하실 겁니다.

function outer() {
  var name = "song";
  
  function inner() {
    alert(name);
  }
  return inner;
}

var myFunc = outer();

//유효범위의 어휘적 환경을 유지
myFunc();

렉시컬 스코핑에서 나왔던 코드와 비슷한 코드입니다.

myFunc은 outer함수를 실행시켜 inner함수를 반환받았습니다.

myFunc을 실행시키면 "song"이 alert됩니다.

 

이는 inner가 만들어진 시점을 보존하고 있기 때문입니다.

1. inner를 호출하면 먼저 내부에서 name값을 찾습니다.

2. 내부에는 없기 때문에 그 부모인 outer함수에서 name값을 찾습니다.

3. outer함수에서 name값을 찾아 alert창을 띄웁니다.

이러한 원리입니다.

 

 

다음 예시 코드를 보겠습니다.

const a = 1;

function outer(){
  const b = 2;
  const c = 3;
  
  function inner(){
    const b = 4;
    console.log(a, b, c);
  }
  inner();
}

outer();

1. inner함수는 먼저 내부에서 a, b, c를 찾습니다.

 

2. 내부에는 b만 찾았으니 나머지 a, c를 외부에서 찾습니다.

 

3. outer함수에서 c를 찾고, 전역에서 a를 찾았습니다.

 

4. 찾은 a, b, c를 콘솔에 찍어줍니다.

 

 

 

하나의 예시를 더 보겠습니다.

function sum(a){
  return function add(b){
    return a + b;
  }
}

const test = sum(2);
console.log(test(3)); // 5

test(3)은 왜 5일까요?

test는 아래와 같은 함수를 반환받았습니다.

 

function add(b){
	return 2 + b;
}

add() 함수가 만들어진 시점에서의 sum의 a값 2를 유지하고 있습니다.

 

 

정보의 은닉

function makeCounter(){
    let count = 0; // 은닉화
    return function(){
        return count++;
    }
}

let counter = makeCounter();

console.log(counter()); // 0
console.log(counter()); // 1
console.log(counter()); // 2

위 코드와 같이 내부에 있는 함수는 count를 기억하여 외부에 있는 값을 변경할 수 있습니다.

count의 값을 원하는 대로 바꿀 수는 없지만 하나씩 증가는 가능합니다.

 

 

 

정리


이렇게 함수가 생성될 당시의 외부 변수를 기억하여 생성 이후에도 계속 접근 가능한 것이 클로저입니다.

 

 

MDN의 클로저 정의를 다시 한번 보겠습니다.

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

클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다.

즉, 자신이 생성될 때의 환경을 기억하는 함수입니다.

 

 

 

 

참고 : 

https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures

https://poiemaweb.com/js-closure

https://www.youtube.com/watch?v=tpl2oXQkGZs