5. 클로저

코어 자바스크립트 05_클로저


정의

  • 컨텍스트 A에서 선언한 변수 a를 참조하는 내부함수 B를 A의 외부로 전달할 경우, A가 종료된 이후에도 a가 사라지지 않는 현상.
var outer = function() {
  var a = 1;
  var inner = function() {
    return ++a;
  };
  return inner;
}
var outer2 = outer();
console.log(outer2());
console.log(outer2());
  • outer 함수의 실행이 종료돼도 inner 함수가 a를 참조하므로 변수 a는 사라지지 않는다.

클로저의 장점

: 함수 종료 후에도 사라지지 않는 지역변수를 만들 수 있다.

초기화 세팅할 때 편리!
초기화 세팅 용도로 클로저를 하나 만들고 계속 들고 있어야 할 값들을 리턴시키면 초기화 함수 종료되는 순간에 나머지는 모두 사라지고 필요한 값만 남아있다.


클로저 활용 사례

콜백 함수 내부에서 외부 데이터를 사용하고자 할 때

콜백 함수를 내부함수로 선언해서 외부변수를 직접 참조 (클로저)

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);
});
docunent.body.appendChild($ul);
  • addEventListener의 콜백 함수(B)에는 fruit라는 외부 변수를 참조하고 있으므로 클로저가 있다.

bind 메소드로 값을 직접 넘겨주기 (클로저 X)

var fruits = ['apple', 'banana', 'peach'];
var $ul = document.createElement('ul');

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);
});
docunent.body.appendChild($ul);
  • (B)를 외부로 분리.
  • addEventListnenr가 콜백함수(alertFruit)의 제어권을 가지게 되고, 첫 번째 인자에 이벤트 객체를 주입하기 때문에 bind 없이는 [object MouseEvent]가 출력된다. => bind 메소드로 this(null)와 인자(fruit)를 지정해 줌.

고차함수 활용 (클로저)

  • 고차 함수 : 함수를 인자로 받거나 함수를 반환(return)함으로써 작동하는 함수.
var fruits = ['apple', 'banana', 'peach'];
var $ul = document.createElement('ul');

var alertFruitBuilder = function(fruit) {
    return function () {
    alert('your choice is '+ fruit);
  }
};
 
fruits.forEach(function (fruit) {          
  var $li = document.createElement('li);
  $li.innerText = fruit;
  $li.addEventListener('click', alertFruitBuilder(fruit));
    $ul.appendchild($li);
});
docunent.body.appendChild($ul);
  • addEventListener의 콜백함수는 alertFruitBuilderfruit를 인자로 주고 실행시킨 값(=익명함수. 기존의 alertFruit 함수)

접근 권한 제어(정보 은닉)

  • 정보 은닉 : 어떤 모듈의 내부 로직에 대해 외부로의 노출을 최소화해서 모듈간의 결합도를 낮추고 유연성을 높이고자 하는 개념.
  • 접근 권한 : public(외부에서 접근 가능), private(내부에서만 사용. 외부에 노출X), protected 세 종류.

클로저(return) 활용한 접근 권한 제어

  • return한 변수들은 공개 멤버, 그렇지 않는 변수들은 비공개 멤버.
    (return 값이 외부에 정보를 제공하는 유일한 수단.)

getter, setter 메소드

  • return 값을 getter, setter 메소드로 설정해 접근 권한 제어.
    ( 어떤 변수에 getter만을 부여하면 읽기 전용 속성. setter까지 있어야 변수 변경 가능.)

Object.freeze() 메소드

  • 객체를 동결. 더 이상 변경될 수 없음.

부분 적용 함수

  • 고차함수를 한 번 호출하면 (계속 사용할 수 있는) 새로운 함수가 반환된다는 장점. (재활용 측면)

  • 부분 적용 함수(partially applied function) : n개의 인자를 받는 함수에 미리 m개의 인자만 넘겨 기억시켰다가, 나중에 (n-m)개의 인자를 넘기면 비로소 원래 함수의 실행 결과를 얻을 수 있게끔 하는 함수.

ex) 디바운스 Debounce

: 짧은 시간 동안 동일한 이벤트가 많이 발생할 경우 이를 전부 처리하지 않고 처음 또는 마지막에 발생한 이벤트에 대해 한 번만 처리하는 것. 프런트엔드 성능 최적화에 큰 도움을 주는 기능 중 하나.

var debounce = (eventName, func, wait) => {
	var timeoutId = null;
  	return function(event) {
    	var self = this;
      	console.log(eventName, 'event 발생');
      	clearTimeout(timeoutId);
      	timeoutId = setTimeout(func.bind(self, event), wait);
    };
};

var moveHandler = (e) => {
	console.log('move event 처리');
};

var wheelHandler = (e) => {
	console.log('wheel evnet 처리');
}

document.body.addEventListener('mousemove',debounce('move', moveHandler, 500));

document.body.addEventListener('mousewheel',debounce('wheel', moveHandler, 700));
  • 클로저로 처리된 것 : 변수 eventName, func, wait, timeoutId

커링 함수

  • 커링 함수(currying fucntion): 여러 개의 인자를 받는 함수를 하나의 인자만 받는 함수로 나눠서 순차적으로 호출될 수 있게 체인 형태로 구성한 것.
var curry3 = function (func) {
  return function (a) {
    return function (b) {
      return func(a, b);
    };
  };
};

var getMaxWith10 = curry3(Math.max)(10);
console.log(getMaxWith10(8)); // 10
console.log(getMaxWith10(25)); // 25

필요한 인자의 개수만큼 함수를 만들어 계속 리턴해주다가 마지막에 조합해서 리턴. (인자가 많아질수록 가독성이 떨어진다는 단점)

화살표 함수를 써서 간단하게 표기할 수 있다(ES6)

var curry = func => a => b => c => d => e => func(a, b, c, d, e); 
  • 각 단계에서 받은 인자들을 모두 마지막 단계에서 참조할 것이므로 가비지 컬렉팅 되지 않고 메모리에 쌓였다가 마지막 호출로 실행 컨텍스트가 종료된 후에 한꺼번에 수거.

지연 실행, 함수의 매개변수가 일부만 바뀔 때 유용

  • 커링 함수는 지연실행에 유용. (당장 필요한 정보만 받아서 전달하고, 또 필요한 정보가 들어오면 전달하는 식으로 결국 마지막 인자가 넘어갈 때까지 함수 실행을 미루는 것)
  • 프로젝트 내에서 자주 쓰이는 함수의 매개변수가 항상 비슷하고 일부만 바뀌는 경우에도 커링 함수가 유용.

좋은 웹페이지 즐겨찾기