반응형

자바스크립트에는 클로저(Closure)라는 개념이 있습니다. 클로저라는 개념에 대해 찾아보시면 아시겠지만 굉장히 다양한 의미로 해석되고 있는데요.

 

지금부터 클로저를 최대한 이해하기 쉽게 설명을 드리면서 실제로 클로저가 사용되는 사례를 알아보도록 하겠습니다.

 

클로저란?

먼저 Closure라는 뜻을 사전에서 찾아보시면 폐쇄라는 뜻을 가지고 있습니다. 마찬가지로 자바스크립트(JS)의 클로저도 폐쇄와 유사한 의미를 가지고 있습니다. 폐쇄 즉, 갇히는 것이죠.

 

한 마디로 클로저란, 함수가 선언될(생성될) 그 당시에 주변의 환경과 함께 갇히는 것을 말합니다.

또 다른 말로 설명하면, 함수가 속한 렉시컬 스코프(Lexical Environment)를 기억하여, 함수가 렉시컬 스코프 밖에서 실행될 때도 이 스코프에 접근할 수 있게 해주는 기능입니다.

 

여기서 렉시컬 스코프란 개념이 생소하실 수도 있을 것 같은데요. 렉시컬 스코프란 함수가 선언이 되는 위치에 따라서 상위 스코프가 결정되는 스코프입니다. 함수가 선언이 될 때, 스코프가 생성됩니다. 스코프(범위)의 개념까지는 여기서 다루지 않겠습니다. (검색하시면 금방 나옵니다)

 

또 다른 클로저의 뜻으로는 내부함수는 외부함수의 지역변수에 접근할 수 있는데 외부함수의 실행이 끝나서 외부함수가 소멸된 이후에도 내부함수가 외부함수의 변수에 접근할 수 있는 것을 말합니다.

 

예시를 통해 알아보도록 하죠.

function sayHello () {
  const a = 'Hello';
  const b = 'World';
  
  function sumString () {
    console.log(a + ' ' + b);
  }
  
  return sumString;
}

const myFunc = sayHello();

myFunc(); // 'Hello World'

 

예제를 살펴보면, myFunc라는 변수는 sayHello 함수를 호출하고 있습니다. 그래서 myFunc를 실행하게 되면 어떠한 문제 없이 Hello World가 잘 출력됩니다. 여기서 살펴볼 점은 myFunc의 부분은 변수 ab가 담겨 있는 sayHello 함수 스코프의 바깥에 있는데도 불구하고 ab를 합친 Hello World를 잘 출력한다는 것입니다.

 

그 이유가 바로 클로저(Closure) 때문입니다. 모든 자바스크립트 함수는 선언(생성)될 당시에 클로저가 형성되어 주변 환경, 즉 렉시컬 스코프를 기억할 수 있게 되는 것이죠.

 

실제 클로저 활용 사례

클로저에 대한 개념을 간단하게 알아보았으니 실제로 어디에 활용되는지 알아보도록 하겠습니다. 

 

콜백함수 내부에서 외부 데이터를 사용할 때

콜백함수 내부에서 외부 데이터를 사용할 때 클로저가 발생하는데요. 대표적인 콜백함수 중 하나인 이벤트 리스너가 활용된 예시를 한번 살펴보도록 하겠습니다.

const fruits = ['apple', 'banana', 'peach'];
const ul = document.createElement('ul');

const fruitBuilder = function (fruit) {
  return function () {
    console.log('your choice is ' + fruit);
  }
}

fruits.forEach(function (fruit) {
  let li = document.createElement('li');
  li.innerText = fruit;
  li.addEventListener('click', fruitBuilder(fruit));
  ul.appendChild(li);
})

document.body.appendChild(ul);

해당 예제를 분석해보면 apple, banana, peach가 담긴 배열을 순회하여 li 태그를 만들어 리스트 형태로 노출 시킨 후에 해당 단어를 클릭하면 your choice is apple 과 같은 형태로 출력되는 코드입니다.

 

살펴보면 fruitBuilder라는 함수는 또 다른 익명 함수를 반환합니다. 그리고 forEach문 안에 fruitBuilder 함수를 실행하면서 fruit 값을 인자로 전달하는데요. 그렇게 되면 함수의 실행 결과 즉 console.log('your ~')가 담긴 익명함수를 리스너에 콜백함수로써 전달합니다. 이후에 언젠가 클릭 이벤트가 발생하게 되면 함수의 실행 컨텍스트가 열리면서 fruitBuilder의 인자로 넘어온 fruit을 참조하게 됩니다.

 

결론은 fruitBuilder의 실행 결과로 반환된 함수에는 클로저가 존재하게 되는 것입니다.

 

클로저 사례는 위 사례 뿐만 아니라 좀 더 다양한 것들이 있는데요. 추후에 몇 가지를 더 소개해보는 시간을 가져보도록 하겠습니다.

 


참고

  • 도서 - 코어자바스크립트

 

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기