본문 바로가기

코딩 노트/JAVASCRIPT

[JS - 개념] 클로저(Closure)와 예제

클로저의 이해

 

MDN에서는 클로저를 다음과 같이 정의하고 있다.

 

"A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time."
"클로저는 주변 상태(lexical environment)에 대한 참조와 함께 번들로 묶인 함수의 결합입니다. 즉, 클로저는 내부 함수에서 외부 함수에 접근 가능하게 합니다. JavaScript에서는 함수를 만들 때마다 클로저가 만들어집니다."

 

간단히 말해 클로저는 함수가 선언될 때(실행X) 외부의 lexcial environment를 참조하게 되는 현상이다.

 

 

다음 예시를 보자.

 

function add1(a, b){
	return a + b;
}

let poison = 0;

function add2 (a, b){
	return a + b + poison;
}

add1(6 , 11) //returns 17
add2(6 , 11) //returns 17

poison = 3;
add1(6 , 11) //returns 17
add2(6 , 11) //returns 20

 

함수 add1과 add2는 매개 변수 a와 b를 받아 더해주는 아주 간단한 함수이다.

다만, add2 함수에는 조금 다른 점이 있다.

함수 밖에서 선언한 poison 변수를 a와 b에 같이 더해서 반환한다는 점이다.

중간에 poison 변수를 3으로 바꾸면 20이 반환되는 것을 확인할 수 있다.

 

프로그래머 여럿이 함께 작업을 한다고 생각해보자.

누군가가 add2에 poison 변수가 있는 줄 모르고,

그 함수를 사용하던 중이었다면,

갑자기 프로그램이 이상하게 동작한다고 생각할 것이다.

 

위의 예시처럼 함수가 선언된 모양만 봐서는

함수 내부에서 바깥의 변수를 가져다 사용하는지,

안 하는지를 코드를 뜯어보기 전까지는 알 수 없다.

 

function add1(a, b){
	return a + b;
}

//Closure----------------------
let poison = 0;

function add2 (a, b){
	return a + b + poison;
}
//-----------------------------

add1(6 , 11) //returns 17
add2(6 , 11) //returns 17

poison = 3;
add1(6 , 11) //returns 17
add2(6 , 11) //returns 20

 

예시에 표시한 부분처럼 외부 변수와

이를 사용하는 함수를 합쳐서 '클로저'라고 부른다.

 

클로저라는 개념에 익숙해지려면,

어떤 것이 클로저이고,

어떤 것이 클로저가 아닌지 구분해 볼 필요가 있다.

 

다시 add2 함수를 보면,

아무렇지 않게 add2 밖에 있는 변수를

가져다 쓰는 것을 확인할 수 있는데,

사실 이것이 자바스크립트에서만 당연한 기능인 것이지,

다른 언어에서는 당연한 기능이 아니다.

 

 

 

그렇기에 다른 언어에서는

클로저 함수와 일반 함수를 명확하게 구분해 놓는 경우가 많다.

다음은 자바스크립트에서 일반 함수와 클로저 함수를 구분하는 문법이 있다는 가정을 해 본 것이다.

 

// @capture(poison)으로 클로저 함수 구분하기

function add1(a, b){
	return a + b;
}

//Closure----------------------
let poison = 0;

@capture(poison)
function add2 (a, b){
	return a + b + poison;
}
//-----------------------------

 

 

예를 들어,

위의 예시처럼 클로저 함수를 사용하려면,

'@capture()'와 같은 데코레이터를 붙이고,

() 안에는 외부에서 불러올 변수 이름을 적는 것이다.

그렇게 해서 () 안에 없는 변수는 add2 안에서

사용하지 못하도록 하는 것이다.

 

//pure 키워드로 일반 함수 표시하기

pure function add1(a, b){
	return a + b;
}

//Closure----------------------
let poison = 0;

function add2 (a, b){
	return a + b + poison;
}
//-----------------------------

 

혹은 add1 앞에 pure 키워드를 붙여서

일반 함수임을 나타낼 수도 있겠다.

 

 

이런 식으로 다른 언어에서는

일반 함수와 클로저 함수를

명확히 구분해 제공하는 경우가 많다.

 

 

하지만 자바스크립트는 사실상

모든 함수가 클로저 함수이기 때문에 구분하기가 어렵다.

 

 

 

클로저 간단한 예제

 

 

function outer(){
  const name = 'kyle';
  console.log(name)
}
outer() //kyle
console.log(name) //error

 

변수 name은 outer 함수의 실행 컨텍스트가 종료되면서 접근이 불가능해졌다.

이 코드에서 변수 'name'을 함수 밖에서 사용하고 싶다면 어떻게 해야할까?

이 때, 사용할 수 있는 것이 클로저이다.

 

 

 

function outer(){
  const name = 'kyle';
  console.log(name)
  return function inner(){
    const greeting = 'hello!'
    console.log(greeting,name)
  }
}
const getKyle = outer() //kyle 
getKyle() //hello!kyle

 

outer 함수가 위와 같이 종료되었을 때,

outer 함수가 종료됐으니, name은 이제 접근이 불가능하다고 생각할 것이다.

하지만 inner 함수에서는 name에 접근이 가능하다.

 

클로저의 특성상 inner 함수가 선언될 때,

그 주변의 lexical enviroment(여기서는 outer의 lexical enviroment)와 함께

번들로 묶였기 때문이다.

 

 

 

착각하기 쉬운 클로저

 

function outer() {
  let name = 'kyle';
  if (true) {
    let city = 'seoul';
    return function inner() {
      console.log(city);
    };
  }
}

 

위 코드는 클로저일까?

겉모습만 보면 클로저와 비슷해보이지만, 클로저가 아니다.

 

 

왜냐하면 내부에 선언된 함수가 외부 함수의 지역 변수를 사용했을 때만

클로저라고 선언되기 때문이다.

 

 

 

inner 함수에 클로저를 사용하고 싶다면,

다음과 같이 name 변수를 사용해주면 된다.

 

function outer() {
  let name = 'kyle';
  if (true) {
    let city = 'seoul';
    return function inner() {
      console.log(city);
     console.log(name);
    };
  }
}

 

 

 

 

 

 

 


자료 출처:

https://youtu.be/KmpofpqkitA

 

 

 

[JS]클로져(closure)와 클로져의 사용 예제

클로저란? MDN에서는 closure를 이와 같이 정의한다. > "A closure is the combination of a function bundled together (enclosed) with references to its surrounding state

velog.io