프로그래밍 언어/HTML,CSS,JS

JavaScript 클로저에 대한 설명

Rateye 2021. 11. 10. 10:36
728x90
반응형
질문 : JavaScript 클로저 vs. 익명 함수

제 친구와 저는 현재 JS에서 클로저가 무엇이고 무엇이 아닌지에 대해 논의하고 있습니다. 우리는 그것을 정말로 정확하게 이해하기를 원합니다.

이 예를 들어 보겠습니다. 카운팅 루프가 있고 콘솔에 카운터 변수를 지연 인쇄하려고합니다. 따라서 setTimeout클로저 를 사용하여 카운터 변수의 값을 캡처하여 N x 값 N을 인쇄하지 않도록합니다.

폐쇄 또는 폐쇄가 될 것 근처에 아무것도없는 잘못된 해결책 :

for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}

i 값의 10 배, 즉 10을 인쇄합니다.

그래서 그의 시도는 :

for(var i = 0; i < 10; i++) {
    (function(){
        var i2 = i;
        setTimeout(function(){
            console.log(i2);
        }, 1000)
    })();
}

예상대로 0에서 9까지 인쇄합니다.

i 를 잡기 위해 클로저 를 사용하지 않는다고 말했지만 그는 그가 그렇다고 주장한다. 나는 그가 for 루프 본문을 다른 setTimeout 안에 넣음으로써 클로저 를 사용하지 않는다는 것을 증명했다 (익명 함수를 setTimeout 전달), 10 번 10 번 다시 인쇄. 그의 함수를 var 에 저장하고 루프 이후에 실행하는 경우에도 마찬가지입니다. 또한 10 번 인쇄합니다. 따라서 제 주장은 i 의 값을 실제로 캡처 하지 않아 그의 버전이 클로저가 아니라는 것입니다.

내 시도는 :

for(var i = 0; i < 10; i++) {
    setTimeout((function(i2){
        return function() {
            console.log(i2);
        }
    })(i), 1000);
}

i (클로저 내에서 i2 라고 함)를 캡처 하지만 이제 다른 함수를 반환 하고이를 전달합니다. 제 경우에는 setTimeout에 전달 된 함수가 실제로 i 캡처합니다.

이제 누가 클로저를 사용하고 있고 누가 사용하지 않습니까?

두 솔루션 모두 콘솔에서 지연된 0에서 9까지 인쇄하므로 원래 문제를 해결하지만이 두 솔루션 중 어떤 솔루션 이 클로저 를 사용하여이를 수행하는지 이해하고 싶습니다.

답변

편집자 주 : JavaScript의 모든 기능은이 게시물 에서 설명한대로 클로저입니다. 그러나 우리는 이론적 관점에서 흥미로운 이러한 기능의 하위 집합을 식별하는 데에만 관심이 있습니다. 이후로 클로저 라는 단어에 대한 모든 참조는 달리 명시되지 않는 한이 기능의 하위 집합을 참조합니다.

클로저에 대한 간단한 설명 :

  1. 함수를 선택합니다. F라고 합시다.
  2. F의 모든 변수를 나열한다.
  3. 변수는 두 가지 유형일 수 있습니다:
    1. 지역 변수(경계 변수)
    2. 지역 변수가 아닌 변수(자유 변수)
  4. F에 자유 변수가 없으면 닫힘이 될 수 없습니다.
  5. F에 자유 변수가 있는 경우(F의 상위 범위에서 정의됨):
    1. 자유 변수가 바인딩된 F의 상위 범위는 하나만 있어야 합니다.
    2. F가 상위 범위 외부에서 참조되면 해당 자유 변수에 대한 폐쇄가 됩니다.
    3. 이 자유 변수를 폐쇄 F의 위쪽 값이라고 합니다.

이제 이것을 사용하여 누가 클로저를 사용하고 누가 사용하지 않는지 알아 봅시다 (설명을 위해 함수의 이름을 지정했습니다).

사례 1 : 친구의 프로그램

for (var i = 0; i < 10; i++) {
    (function f() {
        var i2 = i;
        setTimeout(function g() {
            console.log(i2);
        }, 1000);
    })();
}

fg 두 가지 기능이 있습니다. 클로저인지 확인해 보겠습니다.

f :

  1. 변수 나열:
    1. i2는 로컬 변수입니다.
    2. i는 자유 변수입니다.
    3. setTimeout은 자유 변수입니다.
    4. g는 로컬 변수입니다.
    5. console는 자유 변수입니다.
  2. 각 자유 변수가 바인딩되는 상위 범위 찾기:
    1. i는 글로벌 범위에 구속되어 있습니다.
    2. setTimeout은 글로벌 범위에 바인딩되어 있습니다.
    3. 콘솔이 글로벌 범위에 바인딩됨
  3. 함수는 어느 범위에서 참조됩니까? 글로벌 범위.
    1. 그러므로 나는 f에 의해 종결되지 않는다.
    2. 따라서 setTimeout은 f로 닫히지 않습니다.
    3. 따라서 콘솔은 f로 닫히지 않습니다.

따라서 함수 f 는 클로저가 아닙니다.

g :

  1. 변수 나열:
    1. console은 자유 변수입니다.
    2. i2는 자유 변수입니다.
  2. 각 자유 변수가 바인딩되는 상위 범위 찾기:
    1. 콘솔이 글로벌 범위에 바인딩됨.
    2. i2는 f의 범위에 속합니다.
  3. 함수는 어느 범위에서 참조됩니까? setTimeout의 범위.
    1. 따라서 콘솔은 g에 의해 닫히지 않습니다.
    2. 따라서 i2는 g에 의해 닫힙니다.

따라서 함수 g setTimeout 내에서 참조 될 때 자유 변수 i2 g 의 upvalue)에 대한 클로저입니다.

나쁜 점 : 친구가 클로저를 사용하고 있습니다. 내부 기능은 클로저입니다.

 

사례 2 : 프로그램

for (var i = 0; i < 10; i++) {
    setTimeout((function f(i2) {
        return function g() {
            console.log(i2);
        };
    })(i), 1000);
}

fg 두 가지 기능이 있습니다. 클로저인지 확인해 보겠습니다.

f :

  1. 변수 나열:
    1. i2는 로컬 변수입니다.
    2. g는 로컬 변수입니다.
    3. console은 자유 변수입니다.
  2. 각 자유 변수가 바인딩되는 상위 범위 찾기:
    1. 콘솔이 글로벌 범위에 바인딩됨
  3. 함수는 어느 범위에서 참조됩니까? 글로벌 범위.
    1. 따라서 콘솔은 f로 닫히지 않습니다.

따라서 함수 f 는 클로저가 아닙니다.

g :

  1. 변수 나열:
    1. 콘솔은 자유 변수입니다.
    2. i2는 자유 변수입니다.
  2. 각 자유 변수가 바인딩되는 상위 범위 찾기:
    1. 콘솔이 글로벌 범위에 바인딩됨
    2. i2는 f의 범위에 속합니다.
  3. 함수는 어느 범위에서 참조됩니까? 글로벌 범위.
    1. 따라서 콘솔은 g로 닫히지 않는다.
    2. 따라서 i2는 g로 닫힙니다.

따라서 함수 g setTimeout 내에서 참조 될 때 자유 변수 i2 g 의 upvalue)에 대한 클로저입니다.

좋은 점 : 클로저를 사용하고 있습니다. 내부 기능은 클로저입니다.

그래서 당신과 당신의 친구는 모두 클로저를 사용하고 있습니다. 논쟁 그만해. 나는 폐쇄의 개념과 두 사람 모두를 위해 그것들을 식별하는 방법을 분명히했기를 바랍니다.

편집 : 왜 모든 기능이 폐쇄되는지에 대한 간단한 설명 (크레딧 @Peter) :

먼저 다음 프로그램을 고려해 봅시다 ( 컨트롤입니다 ).

lexicalScope();

function lexicalScope() {
    var message = "This is the control. You should be able to see this message being alerted.";

    regularFunction();

    function regularFunction() {
        alert(eval("message"));
    }
}
  1. 어휘 범위와 정규 함수는 위의 정의에서 제외되지 않습니다.
  2. 프로그램을 실행할 때 regularFunction은 폐쇄가 아니기 때문에(즉, 메시지를 포함한 상위 범위의 모든 변수에 액세스할 수 있음) 메시지가 표시될 것으로 예상한다.
  3. 프로그램을 실행할 때 메시지가 실제로 경고된다는 것을 관찰합니다.

다음으로 다음 프로그램을 고려해 보겠습니다 ( 대안 ).

var closureFunction = lexicalScope();

closureFunction();

function lexicalScope() {
    var message = "This is the alternative. If you see this message being alerted then in means that every function in JavaScript is a closure.";

    return function closureFunction() {
        alert(eval("message"));
    };
}
  1. 위의 정의에서 종결 기능만 종결된다는 것을 알고 있습니다.
  2. 프로그램을 실행할 때 closureFunction은 폐쇄이기 때문에(즉, 함수가 생성될 때 로컬이 아닌 모든 변수에 대한 액세스만 가능) 메시지가 표시되지 않을 것으로 예상합니다(이 답변 참조). 여기에는 메시지가 포함되지 않습니다.
  3. 프로그램을 실행할 때 메시지가 실제로 경고되고 있음을 관찰합니다.

이것에서 우리는 무엇을 추론합니까?

  1. JavaScript 인터프리터는 닫힘을 다른 함수를 처리하는 방식과 다르게 처리하지 않습니다.
  2. 모든 기능은 scope chain을 동반한다. 폐쇄에는 별도의 참조 환경이 없습니다.
  3. 폐쇄는 다른 모든 기능과 같습니다. 우리는 단지 그것들이 속한 범위 밖의 범위에서 참조될 때 폐쇄라고 부른다. 왜냐하면 이것은 흥미로운 경우이기 때문이다.
출처 : https://stackoverflow.com/questions/12930272/javascript-closures-vs-anonymous-functions
728x90
반응형