>웹 프론트엔드 >JS 튜토리얼 >Javascript 루프로 인해 이벤트 처리기에서 예기치 않은 동작이 발생하는 이유는 무엇입니까?

Javascript 루프로 인해 이벤트 처리기에서 예기치 않은 동작이 발생하는 이유는 무엇입니까?

DDD
DDD원래의
2024-12-22 06:26:38296검색

Why Do Javascript Loops Cause Unexpected Behavior in Event Handlers?

Javascript의 악명 높은 루프 문제 재검토

Javascript의 악명 높은 루프 문제는 계속해서 개발자를 당황하게 합니다. 다음 코드 조각을 고려하세요.

function addLinks () {
    for (var i=0, link; i<5; i++) {
        link = document.createElement("a");
        link.innerHTML = "Link " + i;
        link.onclick = function () {
            alert(i);
        };
        document.body.appendChild(link);
    }
}

이 코드는 현재 링크 ID를 표시하는 onClick 이벤트가 포함된 5개의 링크를 생성하기 위한 것입니다. 그러나 이러한 링크를 클릭하면 모두 "링크 5"가 표시됩니다.

이 문제의 근본 원인은 Javascript의 함수 수준 범위 지정에 있습니다. 루프가 완료되면 i 변수는 값 5를 유지합니다. 이는 Javascript 함수가 어휘 환경에서 닫혀 있기 때문입니다. 즉, 주변 범위에 정의된 변수에 액세스할 수 있습니다.

이 문제에 대한 해결 방법 각 반복에 대해 i의 현재 값을 캡처하는 클로저를 도입하는 것입니다.

function addLinks () {
    for (var i=0, link; i<5; i++) {
        link = document.createElement("a");
        link.innerHTML = "Link " + i;
        link.onclick = function (num) {
            return function () {
                alert(num);
            };
        }(i);
        document.body.appendChild(link);
    }
}

이 코드에서는 각 링크에 대해 새 함수 개체가 생성됩니다. 여기에는 자체 범위와 i의 현재 값이 할당되는 지역 변수 num이 있습니다. 내부 함수가 실행되면 클로저의 num 변수를 참조하여 루프에 할당된 올바른 값을 유지합니다.

이 접근 방식은 효과적이지만 새 함수가 생성되면 성능 저하가 발생합니다. 모든 이벤트 리스너에 대해. 보다 효율적인 대안은 데이터 저장을 위해 DOM 노드 자체를 사용하는 것입니다.

function linkListener() {
    alert(this.i);
}

function addLinks () {
    for(var i = 0; i < 5; ++i) {
        var link = document.createElement('a');
        link.appendChild(document.createTextNode('Link ' + i));
        link.i = i;
        link.onclick = linkListener;
        document.body.appendChild(link);
    }
}

i 값을 DOM 노드에 직접 저장함으로써 클로저가 필요하지 않으므로 코드 효율성이 향상됩니다.

위 내용은 Javascript 루프로 인해 이벤트 처리기에서 예기치 않은 동작이 발생하는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.