IT story

Javascript 악명 높은 루프 문제?

hot-time 2020. 4. 26. 21:03
반응형

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);
    }
}

위의 코드는 5 개의 링크를 생성하고 각 링크를 경고 이벤트와 바인딩하여 현재 링크 ID를 표시합니다. 그러나 작동하지 않습니다. 생성 된 링크를 클릭하면 모두 "링크 5"라고 표시됩니다.

그러나 다음 코드는 예상대로 작동합니다.

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);
    }
}

위의 2 개 스 니펫은 여기 에서 인용 됩니다 . 저자의 설명처럼, 폐쇄 는 마술을 만드는 것처럼 보인다 .

그러나 그것이 어떻게 작동하고 어떻게 닫히는 가는 내가 이해하는 것 이상입니다. 왜 첫 번째는 작동하지 않고 두 번째는 작동하지 않습니까? 마법에 대한 자세한 설명을 할 수있는 사람이 있습니까?

감사.


첫 번째 예에 대한 설명을 위해 나 자신인용 :

JavaScript의 범위는 블록 수준이 아니라 함수 수준이며 클로저를 만드는 것은 둘러싸는 범위가 포함 된 함수의 어휘 환경에 추가됨을 의미합니다.

루프가 종료 된 후 함수 레벨 변수 i의 값은 5이며 내부 함수가 '보는'것입니다.

두 번째 예에서, 각 반복 단계에 대해 외부 함수 리터럴은 자체 범위와 로컬 변수를 가진 새 함수 객체로 평가되며 num값은 현재 값으로 설정됩니다 i. 으로 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);
    }
}

나는 두꺼운 사람들을 위해 간단한 설명을 작성하고 싶습니다.

우리는 페이지에 5 개의 div가 있으며 각각은 ID가 있습니다 ... div1, div2, div3, div4, div5

jQuery는 이것을 할 수 있습니다 ...

for (var i=1; i<=5; i++) {
    $("#div" + i).click ( function() { alert ($(this).index()) } )
}

그러나 실제로 문제를 해결하고 천천히 구축합니다 ...

1 단계

for (var i=1; i<=5; i++) {
    $("#div" + i).click (
        // TODO: Write function to handle click event
    )
}

2 단계

for (var i=1; i<=5; i++) {
    $("#div" + i).click (
        function(num) {
            // A functions variable values are set WHEN THE FUNCTION IS CALLED!
            // PLEASE UNDERSTAND THIS AND YOU ARE HOME AND DRY (took me 2 years)!
            // Now the click event is expecting a function as a handler so return it
            return function() { alert (num) }
        }(i) // We call the function here, passing in i
    )
}

대체를 이해하는 간단한

당신이 그 주위에 머리를 얻을 수 없다면, 이것은 이해하기 쉽고 동일한 효과를 가져야합니다 ...

for (var i=1; i<=5; i++) {

    function clickHandler(num) {    
        $("#div" + i).click (
            function() { alert (num) }
        )
    }
    clickHandler(i);

}

함수가 호출 될 때 함수 변수 값이 설정된다는 것을 기억하면 이해하기 간단해야합니다 (그러나 이것은 이전과 완전히 동일한 사고 과정을 사용합니다)


기본적으로 첫 번째 예 i에서는 onclick처리기 내부를 처리기 i외부에 직접 바인딩 onclick합니다. 따라서 핸들러 i외부가 onclick변경되면 핸들러 i내부 onclick도 변경됩니다.

두 번째 예에서는 처리기 num에서 바인딩하는 대신 onclick함수에 전달한 다음 처리기 num에서 이를 바인딩 onclick합니다. 함수에 전달하면의 값이 i바인딩되지 않고 복사 됩니다 num. 따라서 i변경 num하면 동일하게 유지됩니다. JavaScript의 함수가 "클로저"이기 때문에 복사가 발생합니다. 즉, 함수에 무언가가 전달되면 외부 수정을 위해 "닫힙니다".


다른 사람들은 무슨 일이 일어나고 있는지 설명했습니다. 여기에 다른 해결책이 있습니다.

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

    with ({ n: i }) {
      link.onclick = function() {
        alert(n);
      };
    }
    document.body.appendChild(link);
  }
}

기본적으로 가난한 사람은 구속력이 있습니다.


첫 번째 예에서는이 함수를 onclick 이벤트에 바인딩하면됩니다.

function() {alert(i);};

이것은 클릭 이벤트에서 js가 addlink 함수 i 변수의 값을 경고해야 함을 의미합니다. for loop () 때문에 값은 5입니다.

두 번째 예에서는 다른 함수와 바인딩 할 함수를 생성합니다.

function (num) {
  return function () { alert(num); };
}

의미 : 값으로 호출하면 입력 값을 알려주는 함수를 반환하십시오. 예를 들어 호출 function(3)하면가 반환 function() { alert(3) };됩니다.

반복 할 때마다 i 값으로이 함수를 호출하므로 각 링크마다 별도의 onclick 함수를 작성합니다.

요점은 첫 번째 예제에서 함수에 변수 참조가 포함되어 있고 두 번째 예제에서는 외부 함수의 도움으로 참조를 실제 값으로 대체했다는 것입니다. 변수에 대한 참조를 유지하는 대신 함수 내에서 변수의 현재 값을 "포함"하기 때문에이를 클로저라고합니다.

참고 URL : https://stackoverflow.com/questions/1451009/javascript-infamous-loop-issue

반응형