
클로저의 의미 및 원리 이해
- 클로저란 어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상
var outer = function () {
var a = 1;
var inner = function () {
return ++a;
}
return inner;
};
var outer2 = outer();
console.log(outer2());
console.log(outer2());
클로저와 메모리 관리
- 클로저는 메모리 누수의 위험이 있다.
- 개발자가 의도적으로 참조 카운트를 0이 되지 않게 설계한 경우는 누수가 아니다.
- 필요에 의해 클로저를 사용했다면 사용이 끝난 후 식별자에 참조형이 아닌 기본형 데이터(null, undefined)를 할당하면 된다.
클로저 활용 사례
콜백 함수 내부에서 외부 데이터를 사용하고자 할 때
var fruit = ['apple' , 'banana', 'peach'];
var $ul = document.createElement('ul');
fruits.forEach(function(fruit) {
var $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListner('click', function() {
alert('your choice is' + fruit);
});
$ul.appendChild($li);
});
document.body.appendChild($ul);
- (B) 의 outerEnvironmentReference가 (A)의 LexicalEnvironment를 참조하므로 (B)함수가 참조할 예정인 변수 fruit에 대해서는 (A)가 종료된 이후에도 GC 대상에서 제외되어 계속 참조가 가능함
- 하지만 B는 재사용을 할 수 없음
var alertFruitBuilder = function(fruit) {
return function() {
alert('your choice is ' + fruit);
};
};
fruit.forEach(function(fruit) {
var $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListener('click', alertFruitBuilder(fruit));
$li.appendChild($li);
});
- 고차 함수를 활용하면 alertFruitBuilder의 실행 결과로 반환된 함수에는 클로저가 존재한다.
접근 권한 제어 (정보 은닉)
- 정보 은닉은 어떤 모듈의 내부 로직에 대해 외부로의 노출을 최소화해서 모듈간의 결합도를 낮추고 유연성을 높이고자 하는 현대 프로그래밍 언어의 중요한 개념
- 클로저를 이용하면 함수 차원에서 public한 값과 private한 값을 구분하는 것이 가능하다. 외부 스코프에서 함수 내부 변수들 중 선택적으로 일부 변수에 대한 접근 권한을 부여할 수 있는데, 바로 return 을 활용하면 된다.
부분 적용 함수
- 부분 적용 함수란 n개의 인자를 받는 함수에 미리 m개의 인자만 넘겨 기억시켰다가, 나중에 (n-m)개의 인자를 넘기면 비로소 원래 함수의 실행 결과를 얻을 수 있게끔 하는 함수
- debounce등이 있다.
커링 함수
- 커링 함수란 여러 개의 인자를 받는 함수를 하나의 인자만 받는 함수로 나눠서 순차적으로 호출될 수 있게 체인 형태로 구성한 것
- 커링은 한번에 하나의 인자만 전달하는 것이 원칙
- 중간 함수는 그 다음 인자를 받기 위해 대기만 할 뿐
- 마지막 인자가 원본함수 실행
var getInformation = function (baseUrl) {
return function (path) {
return function (id) {
return fetch(baseUrl + path + '/' + id);
};
};
};
var getInformation = baseUrl => path => id => fetch(baseUrl + path + '/' + id);
- Flux 아키텍처중 하나인 Redux의 미들웨어가 커링으로 구현되어있다.
const logger = store => next => action =>{
console.log('dispatching', action);
console.log('next state', store.getState());
return next(action);
};
const thunk = store => next => action => {
return typeof action === 'function'
? action(dispatch, store.getState)
: next(action);
};
- 두 미들웨어는 공통적으로 store, next, action 순서로 인자를 받는다. 이중 store는 프로제그 내에서한번 생성된 이후로는 바뀌지 않는 속성이고 dispatch의 의미를 가지는 next 역시 마찬가지지만, action의 경우는 매번 달라진다.
- store와 next 값이 결정되면 Redux 내부에서 logger 또는 thunk에 store, next를 미리 넘겨서 반환된 함수를 저장시켜 놓고, 이후에는 action만 받아서 처리할 수 있게끔 동작한다.