Closure and Currying

Donghun Seol·2022년 9월 24일
0

클로저와 커링

An Introduction to Closures and Currying in JavaScript

클로저란? Closure

클로저란 함수와 그 함수가 선언된 lexical environment의 조합으로 설명될 수 있다.
lexical env는 함수가 생성될때 그 스코프에 속한 지역변수들로 구성되는 환경이다. 함수 속에 다른 함수가 정의될 경우 포함된 함수는 클로저로 정의할 수 있다. 부모함수가 호출될때 클로저에 대해 새로운 실행 환경이 생성된다.

클로저의 기본 형태

// 클로저의 기본 형태
function closuredFunc (){
    function closure(){
    // some logic
    }
}

클로저의 활용 예시

function closure(){
    function first() { console.log('I was declared first')}
    function second() { console.log('I was declared second')}
    function third() { console.log('I was declared third')}
    return [first, second, third]
}

// 클로저 속의 함수들을 변수에 대입하여 글로벌 컨텍스트에서 호출 가능해진다.
let f = closure()

let one = f[0]
let two = f[1]
let three = f[2]

one() // logs I was declared first
two() // logs I was declared second
three() // logs I was declared third

왜 클로저를 사용하는가?

ES6 이전, 클래스가 도입되기 이전에는 class의 private 메서드나 필드를 구현하기 위해 module pattern을 사용했는데, 여기서 클로저가 활용되었다.

아래의 예제에서 counter1과 counter2변수에 makeCounter()를 각각 대입해주면 부모함수인 makeCouter()가 호출되고, 그에 따라 독립적인 lexical context가 생긴다. 따라서 클래스의 데이터필드와 같이 privateCouter라는 변수를 독립적으로 조작할 수 있게 된다. 또한 privateCouter라는 private한 데이터필드는 명시된 getter와 setter만으로 조작가능하게 할 수 있다.

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

var counter1 = makeCounter();
var counter2 = makeCounter();

counter1.value(); // returns 0
counter1.increment(); // adds 1
counter1.increment(); // adds 1
counter1.value(); // returns 2
counter1.decrement(); //subtracts 1
counter1.value(); // returns 1
counter2.value(); // returns 0

function factory와 currying

Currying은 다른 함수를 함수의 리턴값으로 하는 함수작성 패턴이다.
쉽게 말하면 커리함수란 함수를 결괏값으로 리턴한다.(더 어렵나?)
커리함수(Curried function)은 클로져들을 체이닝함으로서 구성된다.

아래의 예시에서 greeting은 function factory로서 다른 함수들을 생성한다.
ES6의 arrow function이 적용된 훨씬 간단한 문법으로 구현 가능해졌다

let greeting = function (a) {
    return function (b) {
        return a + ' ' + b
	}
}

let hello = greeting('Hello')
let morning = greeting('Good morning')

hello('Austin') // returns Hello Austin
hello('Roy') // returns Hello Roy
morning('Austin') // returns Good morning Austin
morning('Roy') //returns Good Morning Roy

// functional programming paradigm and arrow function applied.
let greeting = (a) => (b) => a + ' ' + b 

greeting('Hello There')('General Kenobi') 
//returns Hello There General Kenobi

결론

ES6에서 class문법이 도입되었으므로 굳이 클로저를 활용해서 유사-클래스를 구현할 필요는 없어보인다. 하지만 function factory와 같은 간단하고 재사용성이 높은 코드를 구현하기 위해서는 클로저의 개념에 대해서 이해 필요하다. 또한 functional programming에서 클래스의 private기능들을 활용하기 위해서는 클로저에 대한 이해가 필수적이라 할 수 있다.

profile
I'm going from failure to failure without losing enthusiasm

0개의 댓글