자바스크립트 클로저 설명, 예시, 활용

2020. 11. 8. 15:45·개발/JavaScript

자바스크립트의 모든 함수는 함수가 선언된 당시의 주변 환경을 기억합니다. 여기서 주변 환경이란 함수가 정의된 상위 스코프, 즉 실행 컨텍스트를 의미합니다. 이는 함수를 호출하는 위치가 아닌, 선언된 위치에 따라 결정되며, 따라서 함수는 언제나 상위 스코프의 식별자를 참조하고, 이에 할당된 값을 변경할 수 있습니다.

클로저란?

클로저는 함수와 해당 함수가 참조하고 있는 주변 환경(렉시컬 환경)과의 조합이다. 다른 말로 하자면, 클로저 기능은 내부 함수에서 외부 함수 스코프에 접근할 수 있게 하는 것이다. 자바스크립트에서 클로저는 함수가 생성될 때마다, 함수가 생성되는 시점에 생성된다.

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)의 의미에 대해 살펴보도록 하겠습니다. 렉시컬의 사전적 정의는 '어휘의'입니다. 이는 사전을 뜻하는 렉시콘(Lexicon)에서 파생되었는데요. 우리는 사전을 찾아볼 때, 문장의 문맥에 따라 단어의 의미를 찾아보는 것이 아니라, 사전에 정의된 의미를 따라 문장의 의미를 파악합니다. 이것이 바로 렉시컬의 의미입니다.

 

즉, 렉시컬 환경이란 함수가 호출되는 시점에 상위 스코프가 결정되는 것이 아니라, 함수가 선언되는 시점에 정의되는 것을 의미합니다. 전자의 경우를 동적 스코프(dynamic scope), 후자의 경우를 정적 스코프(static scope)라 하기도 합니다.

 

자바스크립트는 렉시컬 스코프[정적 스코프]를 따릅니다. 따라서 함수의 호출 위치가 아닌, 함수가 정의된 위치에서 상위 스코프가 결정됩니다.

 

이제 클로저의 의미를 다음과 같이 풀어서 이해해볼 수 있습니다. '자바스크립트에서는 함수가 생성될 때마다 클로저가 생성되며, 이는 렉시컬 스코프 방식을 따른다. 즉, 클로저란 함수와 함수 생성시 형성되는 함수의 렉시컬 스코프적 조합을 일컫는다.'

클로저 예시

글로 보면 다소 난해하지만, 코드로 보면 보다 쉽게 클로저를 이해할 수 있습니다. 다음은 스택오버플로우에서 가져온 클로저의 예시를 약간 변형한 것입니다.

const outer = function() {
  const a = 1;
  const inner = function() {
    console.log(a);
  }
  return inner; // this returns a function
}

const fnc = outer(); // execute outer to get inner 
fnc(); // 1

위 예시에서는 함수 내에 함수(중첩 함수)가 선언되어 있습니다. fnc()을 호출하면 a의 값인 1이 출력됩니다. 클로저가 없는 언어에서는 변수 a는 가비지 콜렉팅 되어 outer가 종료될 때 사라집니다. 따라서 fnc 호출 시 a는 더이상 존재하지 않고, 에러가 발생합니다.

 

그러나 자바스크립트에서 내부 함수를 리턴하고, 이를 fnc에 할당하는 위의 경우, outer 함수가 종료된다 해도 지역 변수를 계속해서 사용할 수 있습니다. 클로저의 특성을 따라 inner가 정의되는 시점에 존재했던 변수가 계속 유지되는 것입니다. 즉, 외부 함수 보다 중첩 함수가 더 오래 생명 주기를 유지하는 경우, 외부 함수의 변수를 참조할 수 있는 것입니다.

 

하나씩 살펴보자면, a는 outer 스코프에 속해 있습니다. inner는 상위 스코프인 outer 스코프를 참조합니다. fnc는 inner를 참조하며, a 는 fnc 가 존재하는 한 유효합니다. a 는 해당 클로저 안에 있습니다.

 

이제, 코드를 조금 수정해보도록 하겠습니다. 다음을 실행하면 콘솔에 어떤 결과가 찍힐까요? 

const outer = function() {
  let a = 1;
  const inner = function() {
    a++;
    console.log(a);
  }
  return inner; // this returns a function
}

const fnc = outer(); // execute outer to get inner 

fnc(); // ?
fnc(); // ?

정답은 차례로 2와 3입니다. 여기서 '함수를 실행할 때마다 a가 1로 초기화되어, 두 번째 실행에서 3이 아닌 2가 나와야 하지 않을까?'할 수 있습니다. 그러나 자세히 살펴보면 outer()의 실행 결과로 inner 함수가 리턴되며, 마지막 fnc()는 외부에서 중첩 함수를 호출하고 있는 것입니다. 이때, 중첩 함수 inner는 자신의 상위 스코프인 outer를 참조하고 있으며, 이를 통해 변수 a에 접근하고 있습니다. 즉, inner 함수는 상위 스코프인 outer 함수를 기억하고 있으며 따라서 다음과 outer 함수의 변수에 접근할 수 있는 것입니다.

 

참고 자료:

  • 클로저와 즉시 실행 함수
  • What is a 'Closure'?, Stackoverflow
  • Closures, MDN

'개발 > JavaScript' 카테고리의 다른 글

자바스크립트 arguments를 사용한 가변 인자 함수 활용  (0) 2020.11.14
자바스크립트 엄격 모드 "use strict" 차이점 설명  (0) 2020.11.07
자바스크립트 타이머 setTimeout / setInterval 설명  (0) 2020.11.07
'개발/JavaScript' 카테고리의 다른 글
  • 자바스크립트 메모이제이션 설명
  • 자바스크립트 arguments를 사용한 가변 인자 함수 활용
  • 자바스크립트 엄격 모드 "use strict" 차이점 설명
  • 자바스크립트 타이머 setTimeout / setInterval 설명
휘Hwi
휘Hwi
여행, 사진, 개발, 책 이야기를 기록하는 여행자 휘의 블로그 𓂍
  • 휘Hwi
    휘: 끝나지 않은 이야기
    휘Hwi
  • 전체
    오늘
    어제
    • 분류 전체보기 N
      • 기록
        • 일상 에세이
        • 인사이트
        • 투자와 재테크
        • 코인 이야기
        • 아카이빙
        • 집무실 레터
        • 사랑에 대하여
        • 번역 이야기(完)
        • 프리랜서 일지(完)
      • 여행
        • 🌎 세계 여행기 S1 (完)
        • 🌊 삼삼한 여행기 (完)
        • 🚶 온더로드
        • 🇯🇵 일본
        • 🏝️ 발리
        • 🇻🇳 베트남
        • 🇱🇰 스리랑카
        • 🇮🇳 인도
        • 🇹🇭 태국
        • 🇸🇬 싱가포르
        • 🇦🇺 호주
        • 🇭🇰 홍콩
        • 🇰🇷 한국
        • 🍚 여행자의 한 끼
        • ℹ️ 여행 정보
      • 사진
        • 사진가
        • 사진 이론과 생각
        • 사진 관련 정보
      • 영상
        • 파이널컷 모션 공부
        • 고프로 GoPro
        • 영상 관련 정보
      • 책
        • 책 읽고 쓰기
      • 개발 N
        • 티스토리
        • Internet
        • HTML
        • CSS
        • JavaScript
        • Typescript
        • React
        • Node.js
        • Express
        • NestJS
        • Python
        • Django
        • MySQL
        • MongoDB
        • AWS
        • Deployment
        • Terminal
        • Git N
        • Glossaries
        • Articles
        • Projects
        • TIL;
      • 미분류
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
휘Hwi
자바스크립트 클로저 설명, 예시, 활용
상단으로

티스토리툴바