October 31, 2021
클로저 : 생명주기가 종료된 외부 함수의 식별자를 참조할 수 있는 중첩 함수로, 정보 은닉을 위해 사용합니다.커링 : 여러 인자를 받는 함수를 하나의 인자만 받는 함수들의 연결로 변환하는 방법으로, 함수의 재사용성을 높입니다.예시를 통해 클로저가 무엇인지와 클로저를 이용해서 정보를 은닉하는 방법을 확인해봅시다.
const getClosure = function() {
  let num = 0
  return function() {
    return ++num
  }
}
const increase = getClosure()
console.log(increase()) // 1
console.log(increase()) // 2
++num // ReferenceError: num is not definedgetClosure 함수를 호출하면 익명 함수를 반환하고 생명 주기를 마감(실행 컨텍스트 스택에서 pop)합니다. 외부 함수(getClosure)는 생명 주기를 마감했지만 중첩 함수(익명 함수)에서는 상위 스코프의 변수인 num을 참조하고 있습니다.
그러므로 이 중첩 함수는 클로저입니다.
외부에서 num 변수에 접근할 수 없습니다. (정보 은닉)
즉시 실행 함수를 사용하여 동일하게 작동하도록 구현할 수 있습니다.
const increase = (function() {
  let num = 0
  return function() {
    return ++num
  }
})()
console.log(increase()) // 1
console.log(increase()) // 2
++num // ReferenceError: num is not defined커링은 클로저의 특징을 이용한 기법입니다.
예시를 통해 확인해봅시다.
const greetCurried = function(greeting) {
  return function(name) {
    console.log(greeting + ', ' + name)
  }
}
const greetHello = greetCurried('Hello')
greetHello('seona') // Hello, seona
greetHello('minsung') // Hello, minsung
greetCurried('Hi there')('minsu') // Hi there, minsu커링을 이용하면 이처럼 부분적으로 정의한 함수를 다시 정의해서 사용하는 것이 가능해 중복을 최소화할 수 있습니다.
함수 호출 시 위의 예시에서의 ‘Hello’처럼 매개 변수가 항상 비슷하다면 커링을 사용할 만한 후보라고 할 수 있습니다. 매개변수를 내부적으로 저장하여, 매번 인자를 전달하지 않아도 됩니다.
const greetDeeplyCurried = greeting => separator => emphasis => name =>
  console.log(greeting + separator + name + emphasis)
const greetAwkwardly = greetDeeplyCurried('Hello')('...')('?')
greetAwkwardly('seona') // Hello...seona?
const sayHello = greetDeeplyCurried('Hello')(', ')
sayHello('.')('seona') // Hello, seona.
const askHello = sayHello('?')
askHello('seona') // Hello, seona?화살표 함수를 사용하면 코드도 짧아지고, 가독성도 높일 수 있습니다.
클로저 사용 시에는 메모리 누수를 주의해야 한다. 클로저인 내부 함수가 참조하는 외부 함수의 식별자들을 더 이상 사용하지 않아도 가비지 콜렉터가 수집하지 못한다.
필요성이 사라진 시점에는 참조 카운트를 0으로 만들어 GC(가비지 컬렉터)가 수거해가도록 해서 메모리를 회수하여야 한다. 식별자에 null이나 undefined를 할당하는 방법으로 문제를 해결할 수 있다.
const outer = (function() {
  let a = 1
  const inner = function() {
    return ++a
  }
  return inner
})()
console.log(outer())
console.log(outer())
outer = null // outer 식별자의 inner 함수 참조를 끊음