<html>
<body>
<ul>
<li>0번 인덱스</li>
<li>1번 인덱스</li>
<li>2번 인덱스</li>
</ul>
</body>
<script>
const items = document.querySelectAll('li');
for(var i =0; i< items.length ; i++){ //var
items[i].addEventListener('click',() => {
console.log(i);
})
}
</script>
</html>
이런식으로 addEventListener로 클릭 이벤트시 콘솔에 출력시 어떤 결과가 나올지 살펴보면 문장만 봐서는 0, 1, 2가 나와야 한다고 생각할 수 있다.
하지만 실제로 사용해보면 모든 li 태그를 클릭시 전부 2가 출력되는 걸 볼 수 있다.
이벤트를 다뤄서 그럴 수 있다고 생각할 수 있지만 JS 코드로 테스트 해볼경우도 같은 결과이다.
function addClick(items){
for(var i = 0 ; i < items.length; i++){
items[i].onSearch = function(){
return i;
}
}
return items;
}
const example = [{},{}];
const clickSet = addClick(example);
clickSet[0].onSearch();
이런식으로 실행해도 결과는 2가 나온다.
이 현상은 JS의 클로저와 변수 스코프에 관련된 일반적인 문제 중 하나이다. 이 문제는 반복문 내부에서 클로저를 사용할 때 발생할 수 있는 예기치 않은 결과가 발생할 수 있다.
코드 내부에서 반복문을 사용하여 items 배여르이 각 요소에 대해 onSearch 함수를 설정하는 부분을 보면
for (var i = 0; i < items.length; i++) {
items[i].onSearch = function () {
return i;
};
}
여기서 문제는 var 키워드로 선언된 i 변수가 함수 스코프를 벗어나지 않고 반복문 내부에 머무르기 때문이다. 따라서 반복문이 모두 실행되고 i의 최종값 2가 된 이후 클릭 이벤트가 발생, 그렇기 때문에 onSerach함수가 i의 최종값인 2를 참조한다.
해결방법은 let을 사용하면 바로 해결된다. 하지만 아직 let을 사용 못하는 경우가 항시 존재할 수 있다.
그런 경우 해결방법은 즉시호출된 함수표현식(IIFE,Immediately Invoked Function Expression)을 사용하여 해결가능하다.
IIFE를 사용하면 반복문 내에서 클로저를 생성하고 각자의 스코프를 가지게 된다.
function addClick(items){
for(var i = 0; i< items.length ; i++){
(function(index) {
items[index].onSearch
})(i);
}
return items;
}
const example = [{}, {}];
const clickSet = addClick(example);
console.log(clickSet[0].onSearch()); // 이제 0이 제대로 반환됩니다.
해당 글은 "자바스크립트 코딩의 기술 - 조 모건" 책을 보고 문제점을 다른 방식으로 풀어본 것입니다.
'Node.js' 카테고리의 다른 글
Moleculer - Node.js 프로젝트 세팅 (0) | 2024.04.13 |
---|