\(@^0^@)/
[BOOK] 코어 자바스크립트, 클로저 2 본문
728x90
오늘 읽은 범위 : (클로저) p.125 ~ p.145
< 책에서 기억하고 싶은 내용 >
클로저
콜백 함수 내부에서 외부 데이터를 사용하고자 할 때
// 콜백 함수와 클로저
var fruits = ['apple', 'banana', 'peach'];
var $ul = document.createElement('ul');
fruits.forEach(function (fruit) { // A 함수
var $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListener('click', function() { // B 함수
alert('your choice is ' + fruit);
});
$ul.appendChild($li);
});
document.body.appendChild($ul);
- 콜백 함수 A는 내부에서 외부 변수를 사용하지 않고 있으므로 클로저가 없지만
- 콜백 함수 B는 addEventListener에 fruit라는 외부 변수를 넘겨줘서 참조하고 있으므로 클로저가 있다.
- B 함수가 참조할 예정인 변수 fruit에 대해서는 함수 A가 종료된 후에도 GC대상에서 제외되어 계속 참조 가능.
- 하지만 B함수의 쓰임새가 콜백 함수에 국한되지 않는 경우라면 반복을 줄이기 위해 B를 외부로 분리하는 것이 나음.
- bind 메서드를 활용하여 분리
var alertFruit = function (fruit) {
alert('your choice is ' + fruit);
};
fruits.forEach(function (fruit) {
var $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListener('click', alertFruit.bind(null, fruit));
$ul.appendChild($li);
});
document.body.appendChild($ul);
- 고차 함수를 활용하여 분리
var alertFruit = function (fruit) {
return function () {
alert('your choice is ' + fruit);
}
};
fruits.forEach(function (fruit) {
var $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListener('click', alertFruit.bind(null, fruit));
$ul.appendChild($li);
});
document.body.appendChild($ul);
클로저를 이용한 접근 권한 제어 (정보 은닉)
- 정보 은닉은 어떤 모듈의 내부 로직에 대해 외부로의 노출을 최소화해서 모듈 간의 결합도를 낮추고 유연성을 높이고자 하는 현대 프로그래밍 언어의 중요한 개념 중 하나.
- 자바스크립트는 기본적으로 변수 자체에 이러한 접근 권한을 직접 부여하도록 설계되어있지 않다.
그렇다고 접근 권한 제어가 불가능한 것은 아니다.
클로저를 이용하면 함수 차원에서 public 한 값과 private 한 값을 구분하는 것이 가능. - 외부에 제공하고자 하는 정보들을 모아서 return 하고, 내부에서만 사용할 정보들은 return하지 않는 것으로 접근 권한 제어가 가능하다.
return 한 변수들은 공개 멤버(public member)가 되고, 그렇지 않은 변수들은 비공개 멤버(private member)가 된다. - 클로저를 활용해 접근권한을 제어하는 방법
- 함수에서 지역변수 및 내부 함수 등을 생성한다.
- 외부에 접근권한을 주고자 하는 대상들로 구성된 참조형 데이터(대상이 여럿일 때는 객체 또는 배열, 하나일 때는 함수)를 return 한다.
==> return 한 변수들은 공개 멤버가 되고, 그렇지 않은 변수들은 비공개 멤버가 된다.
부분 적용 함수
- n개의 인자를 받는 함수에 미리 m개의 인자만 넘겨 기억시켰다가, 나중에 (n-m) 개의 인자를 넘기면 비로소 원래 함수의 실행 결과를 얻을 수 있게끔 하는 함수
- 디바운스
- 디바운스는 짧은 시간 동안 동안 동일한 이벤트가 많이 발생할 경우 이를 전부 처리하지 않고 처음 또는 마지막에 발생한 이벤트에 대해 한 번만 처리하는 것으로 성능 최적화에 큰 도움을 주는 기능.
- 실무에서 부분 함수를 사용하기에 적합한 예.
- scroll, wheel, mousemove, resize등에 적용하기 좋다.
var debounce = function (eventName, func, wait) {
var timeoutId = null;
return function (event) {
var self = this;
conosle.log(eventName, 'event 발생');
clearTimeout(timeoutId);
timeoutId = setTimeout(func.bind(self, event), wait);
};
}
var moveHandler = function (e) {
console.log('move event 처리');
};
var wheelHandler = function (e) {
console.log('wheel event 처리');
}
document.body.addEventListener('mousemove', debounce('move', moveHandler, 500));
document.body.addEventListener('mousewheel', debounce('wheel', wheelHandler, 700));
- 디바운스 함수는 eventName과 실행할 함수, 발생한 이벤트인지 여부를 판단하기 위한 대기시간(wait)을 받는다.
- 내부에서는 timeoutId 변수를 생성하고, 클로저로 EventListener에 의해 호출될 함수를 반환한다.
- 반환될 함수 내부에서는, setTimeout을 사용하기 위해 this를 별도의 변수에 담고, clearTimeout을 이용해 초기화.
- setTimeout으로 wait 시간만큼 지연시킨 다음, 원래의 함수를 호출하는 형태.
- 최초 이벤트가 발생하면 timeout의 대기열에 담긴다. 그런데 시간(wait)이 경과하기 이전에 다시 동일한 이벤트를 발생시킨다면, 저장했던 시간 대기열을 초기화하고 다시 새로운 대기열에 담는다.
결국 각 이벤트가 바로 이전 이벤트로부터 시간(wait) 이내에 발생하는 한, 마지막에 발생한 이벤트만이 초기화되지 않고 무사히 실행된다. - 디바운스 함수에서 클로저로 처리되는 변수에는 eventName, func, wait, timeoutId가 있다.
커링 함수
- 여러 개의 인자를 받는 함수를 하나의 인자만 받는 함수로 나눠서 순차적으로 호출될 수 있게 체인 형태로 구성한 것
- 커링은 한 번에 하나의 인자만 전달하는 것을 원칙으로 한다.
또한 중간 과정상의 함수를 실행한 결과는 그다음 인자를 받기 위해 대기만 할 뿐으로, 마지막 인자가 전달되기 전까지는 원본 함수가 실행되지 않는다. - 부분 적용 함수는 여러 개의 인자를 전달할 수 있고, 실행 결과를 재실행할 때 원본 함수가 무조건 실행된다.
부분 적용 함수와 달리 커링 함수는 필요한 상황에 직접 만들어 쓰기 용이하다.
// 커링 함수
var curry5 = function (func) {
return function (a) {
return function (b) {
return function (c) {
return function (d) {
return function (e) {
};
};
};
};
};
};
var getMax = curry5(Math.max);
console.log(getMax(1)(2)(3)(4)(5));
// 화살표 함수
var curry5 = func => a => b => c => d => e => func(a, b, c, d, e);
- 화살표 함수로 구현하면 커링 함수를 이해하기에 훨씬 수월하다.
- 화살표 순서에 따라 함수에 값을 차례로 넘겨주면 마지막에 func가 호출될 거라는 흐름이 한눈에 파악됨.
- 지연 실행(lazy execution) : 당장 필요한 정보만 받아서 전달하고 또 필요한 정보가 들어오면 전달하는 식으로, 결국 마지막 인자가 넘어갈 때까지 함수 실행을 미루는 함수형 프로그래밍.
- 원하는 시점까지 지연시켰다가 실행하는 것이 요긴한 상황이라면 커링을 쓰기에 적합하다.
var getInformation = function (baseUrl) {
return function (path) {
return function (id) {
return fetch(baseUrl + path + '/' + id);
};
};
};
// ES6 화살표함수
var getInformation = baseUrl => path => id => fetch(baseUrl + path + '/' + id);
- 프로젝트 내에서 자주 쓰이는 함수의 매개변수가 항상 비슷하고 일부만 바뀌는 경우에도 커링 함수에 적합하다.
- 최근 여러 프레임워크나 라이브러리 등에서 커링을 상당히 광범위하게 사용하고 있다. 예) Redux의 미들웨어
클로저 정리
- 클로저란 어떤 함수에서 선언한 변수를 참조하는 내부 함수를 외부로 전달할 경우,
함수의 실행 콘텍스트가 종료된 후에도 해당 변수가 사라지지 않는 현상. - 내부 함수를 외부로 전달하는 방법에는 함수를 return 하는 경우뿐 아니라 콜백으로 전달하는 경우도 포함.
- 클로저는 그 본질이 메모리를 계속 차지하는 개념이므로 더는 사용하지 않게 된 클로저에 대해서는 메모리를 차지하지 않도록 관리해줄 필요가 있다.
[ 출처 : 코어 자바스크립트 ]
[ 참고
- https://www.youtube.com/watch?v=bwwaSwf7vkE
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures
- https://hyunseob.github.io/2016/08/30/javascript-closure/
]
728x90
'BOOKS > 코어 자바스크립트' 카테고리의 다른 글
[BOOK] 코어 자바스크립트, 프로토타입 2 (0) | 2022.04.14 |
---|---|
[BOOK] 코어 자바스크립트, 프로토타입 1 (0) | 2022.04.07 |
[BOOK] 코어 자바스크립트, 클로저 1 (0) | 2022.03.29 |
[BOOK] 코어 자바스크립트, 콜백 함수 (0) | 2022.03.18 |
[BOOK] 코어 자바스크립트, this(2) (0) | 2022.03.14 |