Node.js

JS - var 를 for문에서 함수와 사용시 문제점 및 해결

jaewoo 2023. 8. 26. 19:25
<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