자바스크립트 입문_콜백함수 내부에서 외부 데이터를 사용하고자 할때

자바스크립트 2021. 5. 9. 13:56

(본 포스팅은 위키북스의 '코어자바스크립트' 책을 공부하면서 작성되었습니다_내돈내산)

 

- 이벤트 리스너에 관한 클로저 예시(1) -

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

fruits.forEach(function(fruit){
  let $li = document.createElement('li');
  $li.innerText = fruit;
  $li.addEventListener('click', function(){
    alert('your choice is ' + fruit);			// 클로저
  });
  $ul.appendChild($li);
});
  • forEach의 콜백함수가 addEventListener를 이용할때 외부의 변수를 참조하게 됨.

- 이벤트 리스너에 관한 클로저 예시(2) : bind사용-

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

let alertFruit = function(fruit) {
  alert('your choice is ' + fruit);
};
fruits.forEach(function(fruit){
  let $li = document.createElement('li');
  $li.innerText = fruit;
  $li.addEventListener('click', alertFruit);	// [object MouseEvent] 출력
  $ul.appendChild($li);
});
document.body.appendChild($ul);
alertFruit(fruits[1])
  • 위의 코드는 맨 마지막줄 코드는 'banana'에 대한 alert구문이 정상적으로 실행되지만 addEventListener의 경우 'li' 태그를 클릭했을때 [object MouseEvent]라는 값이 출력됨.
  • 이는 콜백함수의 제어권을 addEventListener가 가진 상태이며, 이는 콜백함수를 호출할 때 첫번째 인자에 '이벤트 객체'를 주입하기 때문. 이 문제를 bind를 이용해 해결이 가능함.
let fruits = ['apple', 'banana', 'peach'];
let $ul = document.createElement('ul');

let alertFruit = function(fruit) {
  alert('your choice is ' + fruit);
};
fruits.forEach(function(fruit){
  let $li = document.createElement('li');
  $li.innerText = fruit;
  $li.addEventListener('click', alertFruit.bind(null, fruit)); // bind 사용
  $ul.appendChild($li);
});
document.body.appendChild($ul);
alertFruit(fruits[1])
  • 위와같은 방법으로 해결이 가능하지만 이렇게 하는 경우,
     - 이벤트 객체가 인자로 넘어오는 순서가 바뀌는 점.
     - 함수 내부에서의 this가 원래의 그것과 달라지는 점.
    두가지의 감안이 필요함.
  • 이런 변경사항이 발생하지 않게 '고차함수'를 활용할 수 있음.
...
let alertFruitBuilder = function(fruit){
  return function() {
    alert('your choice is ' + fruit);
  };
};
fruits.forEach(function(fruit){
  let $li = document.createElement('li');
  $li.innerText = fruit;
  $li.addEventListener('click', alertFruitBuilder(fruit));
  $ul.appendChild($li);
});
...
  • 위에서 사용했던 alertFruit 함수 대신에 alertFruitBuilder 라는 함수를 작성하였음.
  • 이 함수 내부에서는 기존의 alertFruit였던 함수를 반환하게 됨.
  • forEach문의 addEventListener안의 alertFruitBuilder 콜백 함수를 실행하면서 외부변수인 fruit를 outerEnvironmentReference에 의해 참조하게 됨. 즉 alertFruitBuilder의 실행결과로 반환된 함수에는 클로저가 존재하게 됨. 
admin