복습 #5 클로저

rlcjf0014·2019년 11월 19일
0

프리코스_35

목록 보기
10/15

Introduction

복습 파트 5이다! 클로저를 복습해보고 포스트 길이에 따라 새로운 포스트를 만들지, 이 포스트에 다른 내용들도 첨부할지 정할 것 같다.

Definition

일단 기본적인 클로저 개념은 외부 함수에 접근할 수 있는 내부 함수 혹은 이러한 원리를 일컫는 용어이다. 여러 예시들을 보고 강의도 다시 봐서 개념을 알지만 글로 설명하면 또 다른 방법의 복습이기에 해보려한다.

클로저 함수는 일반적으로 함수안에 있는 함수인데 스코프에서 배웠듯이 내부 함수로서 외부함수 범위에 있는 변수에 접근이 가능하지만 그 반대는 실현될 수 없다.

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

MDN에 올라온 예제인데, 보이는 바와 같이 displayName이라는 함수는 makeFunc이라는 함수안에 클로저로 들어있다. 여기서 displayName에서 접근할 수 있는 scope 총 3개이다. 자기 자신의 function scope, 그리고 자신 바깥 함수인 makeFunc의 scope 그리고 모든 걸 다 담고 있는 global scope이다.
비록 name이라는 변수는 displayName이라는 함수 바깥에 위치하지만 scope 규칙 상 변수에 접근할 수 있다.

makeFunc라는 함수를 실행하면, displayName이라는 함수를 실행하는 것이 아니라 리턴을 해준다. 그래서 만약 displayName을 실행하고 싶다면 makeFunc()() 처럼 괄호를 뒤에 하나를 더 붙혀줘야 리턴한 displayName을 한번 더 실행해 준다.

이제 여기서 한 변수에 makeFunc이라는 함수를 할당한다면 그 변수는 displayName이라는 함수를 가지게 된다.

let display = makeFunc(); 

// display 는 displayName 함수를 반환한다. 

그러므로 display()를 실행하면 displayName 함수가 실행된다.

여기서 특이한 점은, displayName 바깥 쪽에 정의가 됐던 var name = "Mozilla"는 바깥 함수 scope에 있던 지역 변수로 일반적인 프로그램에서는 makeFunc 함수의 역할이 끝나면 이 변수의 접근이 불가능하다. 하지만 자바 스크립트에서는 함수와 함수가 선언된 어휘적 환경을 클로저를 displayName이 리턴되며 형성 되기 때문에 변수 name은 사용이 가능하다. 클로저는 생성되는 시점에 있는 모든 지역변수로 구성된다. 그러므로 클로저 함수 안에서는 지역변수, 외부 함수의 변수와 전역 변수가 모두 접근 가능하다.

기본적인 개념을 익혔으니 이제 클로저를 사용한 여러 예제를 알아볼 차례이다!

Application

커링

커링은 클로저를 사용해 쉽게 구현할 수 있다.
커링은 함수 하나가 n개의 인자를 받는 대신 n개의 함수를 만들어 각각 인자를 받게 하는 것이다.

예제를 통해서 보면 더욱 이해하기가 쉽다.

function adder (x) {
  return function (y) {
    return x + y;
  }
};

여기서 adder(5)를 한다면 당연히 일반 함수를 리턴하고 아무런 숫자를 주지 않을 수 있다.
하지만 adder (5) (6)을 한다면 5는 x의 인자로, 6은 y의 인자로 받아 11이라는 값을 리턴한다.

커링을 적용하려면 아까처럼 변수에 adder함수를 할당한다.

let add5 = adder(5); 

이제 add5는 x는 5이지만 반환은 함수만 하는 변수이다. 이제 여기에 원하는 y 값을 지정한 후 실행하면 커링으로 x의 값을 고정시킨 후 값을 구할 수 있다.

console.log( add5(3) )

//값은 8이다. 

Private Method

다음 예제는 클로저 모듈 패턴을 이용해 private method를 구현해 볼 것이다. 다른 프로그램과
달리 자바스크립트는 private 개념이 없다.

var counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  };   
})

객체를 이용해 increment, decrement와 value를 key로 주고 그 값은 changeBy라는 내부 함수를 통해 privateCounter라는 변수에 값을 바꾸어준다.

counter를 리턴하면 increment, decrement와 value를 포함한 객체를 반환한다.
그래서 counter는 객체를 반환하는 함수를 가지고 있으니 객체의 key를 접근하는 것처럼

counter.increment()를 하면 increment 속 함수를, counter.decrement()를 하면 decrement 속 함수를, counter.value()를 하면 value 속 함수를 실행한다.

increment와 decrement는 changeBy라는 function을 통해 privateCounter의 값을 바꿔주고
counter.value()를 해야만 privateCounter를 반환한다.

만약 카운트를 여러개, 커링을 통해 구분하고 싶다면 다른 변수에 counter()를 할당해 주면 된다.


let count1 = counter();

let count2 = counter();

이렇게 커링을 하면 count1.increment() 를 하고 count2.decrement()를 해도 서로 각자의 privateCounter를 private하게 지니고 있어서 값이 겹치지 않는다.

클로저를 정리하다보니 포스트가 길어져 더 이어가면 안될 것 같다. 클로저를 잘 확용하자!

profile
Grow Joshua, Grow!

0개의 댓글