클로저(Closuer)

Jelkov Ahn·2021년 8월 5일
1
post-thumbnail

Achievement Goals

  • 클로저 함수의 정의와 특징에 대해서 이해할 수 있다
  • 클로저가 갖는 스코프 범위를 이해할 수 있다
  • 클로저를 이용해 유용하게 쓰이는 몇 가지 코딩 패턴을 이해할 수 있다

(1) 클로저란?

  • 클로저(closure)는 내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것을 가르킨다.

  • 클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. "변수 및 함수 선언의 형태" (by mdn)

  • 클로저는 자바스크립트를 이용한 고난이도의 테크닉을 구사하는데 필수적인 개념으로 활용된다.

  • 클로저는 여러가지 프로그램에서 사용되는 거라서, 클로자가 무엇인지 정의하기는 쉽지 않지만, 외부함수에 접근할수 있는 변수가 있는 내부함수. 이렇게 생각하면 된다.

  • [아래 코드] 클로저를 사용하는 함수: cafe // 클로저로 간주: return하는 함수
    내부함수라서 클로저가 아니라 , 내부함수에서 외부에 접근할수 있으니깐 return하는 함수가 클로저로 간주된다.

let cafe = function() {
  let coffee = {};
  return function(tea) {
    if (coffee[tea]){
      return true;
    }
    coffee[tea] = true;
    return false;
 }
  • uncaptulation을 하기 위해서 실제적으로 사용된다.
    • 우리가 쿠팡에서 구매할때는 구매하기 버튼 하나를 누르지만 그안에 많은 uncaptulation을 해놓는 것이다. 클로저를 이용해 가능하다.

(2) 클로저 함수의 기본 형태

(2-1) 함수를 리턴하는 함수

//리턴 값이 함수
const adder = x => y = > x+y;
adder(5)(7);//12

typeof adder(5)// 'function'
adder(5) // y= 5+y

// 위의 함수를 함수 형태로 표현할 경우
const adder = function(x) {
  return function(y) {
   return x + y;
  }
 }

(2-2) 리턴하는 함수에 의해스코프가 구분됨

  • 클로저는 리턴하는 함수에 의해 스코프(변수의 접근 범위)가 구분됩니다.
  • 클로저의 핵심은 스코프를 이용해서, 변수의 접근 범위를 닫는(closure; 폐쇄) 데에 있습니다.
    따라서, 함수를 리턴하는 것만큼이나, 변수가 선언된 곳이 중요합니다.
  • [그림] 이해
    • 외부 함수는 y에 접근이 불가능하다. (x)
    • 내부 함수는 x에 접근이 가능하다.(O)

(3) 클로저의 활용

(3-1) 데이터를 보존하는 함수

  • 일반적인 함수는 함수 실행이 끝나면 함수 내부의 변수를 사용할 수 없다.
    하지만 클로저는 외부 함수의 실행이 끝나더라도, 외부 함수 내 변수가 메모리 상에 저장이 된다.

변수 add5 에는 클로저를 통해 리턴한 함수가 담겨 있습니다.

const adder = x => y = > x+y;

const adder = function (x) {
  return function (y) {
   return x + y;
  }
 }
 
const add5 = adder(5); // 5가 남아있다.

외부 함수의 실행이 끝나더라도, adder 함수에서 인자로 넘긴 5라는 값을 x 변수에 계속 담은 채로 남아있습니다.

그래서 다음과 값을 넣었을때 함수 실행이 끝나도, 계속 활용이 가능합니다.

add5(4) // 9
add5(9) // 14
  • EX) HTML 문자열 생성기

    const tagMaker = tag => content => `<${tag}>${content}</${tag}>`
    
    const divMaker = tagMaker('div');// div가 남아있다.
    divMaker('hello') // '<div>hello</div>'
    divMaker('hi') // '<div>hi</div>'
    
    const anchorMaker = tagMaker('a') // a가 남아있다.
    anchorMaker('go') // '<a>go</a>'
    anchorMaker('book') // '<a>book</a>'
  • 클로저는 이처럼 특정 데이터를 스코프 안에 가두어 둔 채로 계속 사용할 수 있게 해줍니다.

(3-2) 정보의 접근 제한

  • 클로저 모듈 패턴
const makeCounter = () => {
 let value = 0 ;
 
 return {
   increase: () => {
    value = value +1
   },
   decrease: () => {
    value = value -1
   },
   getValue: () => value
 }
}

const counter1 = makeCounter();
counter1 // { increase: f, decrease: f, getValue: f}

  • makeCounter()를 실행한것을 변수에 담으면 그 변수는 makeCounter가 가지고 있는 내부함수를 객체 형태로 나타 냅니다.

  • 캡슐화 (정보의 접근제한)
    스코프('외부 스코프에서는 내부 스코프의 변수에 접근할 수 없다')의 규칙에 의해서 makeCounter라는 함수를 바꾸지 않고 value라는 변수에 값을 새롭게 할당할수 없습니다.

  • 캡슐화를 하는 이유
    value 값이 전역변수가 되는걸 막기 위해서 입니다.
    (makeCounter라는 함수가 value 값을 보존하고 있기 때문에, 전역 변수로 따로 만들 필요가 없습니다.)
    전역 변수가 많으면 좋지 않은 이유는,
    전역 변수는 다른 함수 혹은 로직 등에 의해 의도되지 않은 변경을 초래하기 때문입니다.따라서 이에 따른 오류로부터 보다 안전하게 값을 보호할 수 있습니다.

  • 정리
    클로저를 통해 불필요한 전역 변수 사용을 줄이고, 스코프를 이용해 값을 보다 안전하게 다룰 수 있습니다.

  • 모듈화; 재사용성 (여러 개의 counter를 만들 수 있다.)

    • counter1의 변수와 counter2의 변수는 서로 영향을 주지 않습니다.
const counter1 = makeCounter();
counter1.increase();
counter1.increase();
counter1.decrease();
counter1.getValue(); //1

const counter2 = makeCounter();
counter2.decrease();
counter2.decrease();
counter2.decrease();
counter2.getValue(); // -3

출처: 코드스테이츠

profile
끝까지 ... 가면 된다.

0개의 댓글