code

JavaScript는 지역 변수로 클로저를 지원하지 않습니까?

codestyles 2020. 12. 25. 09:51
반응형

JavaScript는 지역 변수로 클로저를 지원하지 않습니까?


이 질문에 이미 답변이 있습니다.

이 코드에 대해 매우 의아해합니다.

var closures = [];
function create() {
  for (var i = 0; i < 5; i++) {
    closures[i] = function() {
      alert("i = " + i);
    };
  }
}

function run() {
  for (var i = 0; i < 5; i++) {
    closures[i]();
  }
}

create();
run();

내 이해에서 0,1,2,3,4를 인쇄해야합니다 (이것이 클로저 개념이 아닙니까?).

대신 5,5,5,5,5를 인쇄합니다.

Rhino와 Firefox를 사용해 보았습니다.

누군가 나에게이 행동을 설명 할 수 있습니까? 미리 Thx.


추가 익명 함수를 추가하여 Jon의 대답을 수정했습니다.

function create() {
  for (var i = 0; i < 5; i++) {
    closures[i] = (function(tmp) {
        return function() {
          alert("i = " + tmp);
        };
    })(i);
  }
}

설명은 JavaScript의 범위가 블록 수준이 아니라 함수 수준이며, 클로저를 생성한다는 것은 포함 범위가 포함 된 함수의 어휘 환경에 추가된다는 것을 의미합니다.

루프가 종료 된 후 함수 수준 변수 i는 값을 가지며 5이것이 내부 함수가 '보는'것입니다.


참고로, 특히 루프에서 불필요한 함수 객체 생성에주의해야합니다. 비효율적이며 DOM 개체가 포함 된 경우 순환 참조를 생성하기가 쉽기 때문에 Internet Explorer에서 메모리 누수가 발생합니다.


나는 이것이 당신이 원하는 것이라고 생각합니다.

var closures = [];

function createClosure(i) {
    closures[i] = function() {
        alert("i = " + i);
    };
}

function create() {
    for (var i = 0; i < 5; i++) {
        createClosure(i);
    }
}

해결책은 배열 푸시를 래핑하는 자체 실행 람다를 사용하는 것입니다. 또한 i를 해당 람다에 대한 인수로 전달합니다. 자체 실행 람다 내의 i 값은 원래 i의 값을 숨기고 모든 것이 의도 한대로 작동합니다.

function create() {
    for (var i = 0; i < 5; i++) (function(i) {
        closures[i] = function() {
            alert("i = " + i);
        };
    })(i);
}

Another solution would be to create yet another closure which captures the correct value of i and assigns it to another variable which would "get caught" in the final lambda:

function create() {
    for (var i = 0; i < 5; i++) (function() {
        var x = i;

        closures.push(function() {
            alert("i = " + x);
        });
    })();
}

Yes closures are working here. Each time you loop the function you are creating grabs the i. Each function you create shares the same i. The problem you are seeing is that since they all share the same i they also share the final value of i since it is the same captured variable.

Edit: This article by Mr. Skeet explains closures in some depth and addresses this issue in particular in a way that is much more informative then I have here. However be careful as the way that Javascript and C# handle closures have some subtle differences. Skip to the section called "Comparing capture strategies: complexity vs power" for his explanation on this issue.


John Resig's Learning Advanced JavaScript explains this and more. It's an interactive presentation that explains a lot about JavaScript, and the examples are fun to read and execute.

It has a chapter about closures, and this example looks a lot like yours.

Here's the broken example:

var count = 0; 
for ( var i = 0; i < 4; i++ ) { 
  setTimeout(function(){ 
    assert( i == count++, "Check the value of i." ); 
  }, i * 200); 
}

And the fix:

var count = 0; 
for ( var i = 0; i < 4; i++ ) (function(i){ 
  setTimeout(function(){ 
    assert( i == count++, "Check the value of i." ); 
  }, i * 200); 
})(i);

Just defining an inner function, or assigning it to some variable:

closures[i] = function() {...

does not create a private copy of the whole execution context. The context isn't copied until the nearest outer function is exiting (at which point those external variables could be garbage collected, so we'd better grab a copy).

This is why wrapping another function around your inner function works - the middle guy actually executes and exits, cuing the innermost function to save his own copy of the stack.


Here is what you should do to achieve your result:

<script>
var closures = [];
function create() {  
    for (var i = 0; i < 5; i++) {   
        closures[i] = function(number) {      
        alert("i = " + number);   
        };  
    }
}
function run() {  
    for (var i = 0; i < 5; i++) {   
        closures[i](i); 
    }
}
create();
run();
</script>

ReferenceURL : https://stackoverflow.com/questions/643542/doesnt-javascript-support-closures-with-local-variables

반응형