programing tip

자바 스크립트 클로저 vs. 익명 함수

itbloger 2020. 10. 4. 10:38
반응형

자바 스크립트 클로저 vs. 익명 함수


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

이 예를 들어 보겠습니다. 카운팅 루프가 있고 콘솔에 카운터 변수를 지연 인쇄하려고합니다. 따라서 카운터 변수의 값을 캡처하기 위해 setTimeout클로저사용 하여 N 배 값 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 루프 본문을 다른 안에 넣음으로써 (익명 함수를에 전달) 클로저사용하지 않는다는 것을 증명했다 . 그의 함수를 a에 저장 하고 루프 이후에 실행하는 경우에도 마찬가지입니다. 또한 10 번 인쇄합니다. 따라서 제 주장은 그가 실제로 값을 캡처 하지 않아 그의 버전 이 클로저가 아니라는 것입니다.setTimeoutsetTimeoutvari

내 시도는 :

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의 upvalue라고합니다.

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

사례 1 : 친구의 프로그램

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

위의 프로그램에서이 두 가지 기능은 다음과 같습니다 fg. 클로저인지 확인해 보겠습니다.

대상 f:

  1. 변수 나열 :
    1. i2A는 로컬 변수.
    2. iA는 무료 변수.
    3. setTimeoutA는 무료 변수.
    4. gA는 로컬 변수.
    5. consoleA는 무료 변수.
  2. 각 자유 변수가 바인딩 된 상위 범위를 찾으십시오.
    1. i되는 바인딩 전역에.
    2. setTimeout되는 바인딩 전역에.
    3. console되는 바인딩 전역에.
  3. 함수가 참조 되는 범위는 무엇입니까? 전역 범위 .
    1. 따라서 의해 닫히지i 않습니다 .f
    2. 따라서 의해 닫히지setTimeout 않습니다 .f
    3. 따라서 의해 닫히지console 않습니다 .f

따라서 기능 f은 클로저가 아닙니다.

대상 g:

  1. 변수 나열 :
    1. consoleA는 무료 변수.
    2. i2A는 무료 변수.
  2. 각 자유 변수가 바인딩 된 상위 범위를 찾으십시오.
    1. console되는 바인딩 전역에.
    2. i2되는 바인딩 의 범위에 f.
  3. 함수가 참조 되는 범위는 무엇입니까? 의 범위setTimeout .
    1. 따라서 의해 닫히지console 않습니다 .g
    2. 그러므로 i2되어 닫혀 의해 g.

따라서 함수는 g자유 변수에 대한 폐쇄입니다 i2(대한 upvalue이다 g) 경우 가있어 참조 내에서가 setTimeout.

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

사례 2 : 프로그램

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

위의 프로그램에서이 두 가지 기능은 다음과 같습니다 fg. 클로저인지 확인해 보겠습니다.

대상 f:

  1. 변수 나열 :
    1. i2A는 로컬 변수.
    2. gA는 로컬 변수.
    3. consoleA는 무료 변수.
  2. 각 자유 변수가 바인딩 된 상위 범위를 찾으십시오.
    1. console되는 바인딩 전역에.
  3. 함수가 참조 되는 범위는 무엇입니까? 전역 범위 .
    1. 따라서 의해 닫히지console 않습니다 .f

따라서 기능 f은 클로저가 아닙니다.

대상 g:

  1. 변수 나열 :
    1. consoleA는 무료 변수.
    2. i2A는 무료 변수.
  2. 각 자유 변수가 바인딩 된 상위 범위를 찾으십시오.
    1. console되는 바인딩 전역에.
    2. i2되는 바인딩 의 범위에 f.
  3. 함수가 참조 되는 범위는 무엇입니까? 의 범위setTimeout .
    1. 따라서 의해 닫히지console 않습니다 .g
    2. 그러므로 i2되어 닫혀 의해 g.

따라서 함수는 g자유 변수에 대한 폐쇄입니다 i2(대한 upvalue이다 g) 경우 가있어 참조 내에서가 setTimeout.

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

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

편집 : 왜 모든 기능이 닫히는 지에 대한 간단한 설명 (크레딧 @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. 우리는 모두 알고 lexicalScoperegularFunction폐쇄하지 않습니다 위의 정의에서 .
  2. 프로그램을 실행할 때는 클로저가 아니기 때문에 경고를받을 것으로 예상 message 합니다 (즉 , 부모 범위에있는 모든 변수에 액세스 할 수 있습니다 -포함 ). regularFunctionmessage
  3. 프로그램을 실행할 때 실제로 경고 가 발생하는 것을 관찰 합니다 message.

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

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. 우리는 단지 위의 정의로부터의closureFunction 클로저 라는 것을 알고 있습니다.
  2. 프로그램을 실행할 때 우리 는 클로저 이기 때문에 경고를받지 않을 것으로 예상합니다 (즉 , 함수가 생성 될 때 모든 비 로컬 변수액세스 할 수 있습니다 ( 이 답변 참조 )-포함되지 않음 ).message closureFunctionmessage
  3. 프로그램을 실행할 때 실제로 경고를받는 것을 관찰 합니다 message.

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

  1. JavaScript 인터프리터는 다른 함수를 처리하는 방식과 다르게 클로저를 처리하지 않습니다.
  2. 모든 기능은 그 와 함께 스코프 체인전달 합니다. 클로저에는 별도의 참조 환경 이 없습니다 .
  3. 클로저는 다른 모든 기능과 같습니다. 이것은 흥미로운 경우 이기 때문에 그들이 속한 범위 밖의 범위에서 참조 될 때 클로저라고 부릅니다 .

closure정의 에 따르면 :

"클로저"는 해당 변수를 바인딩하는 (표현식을 "닫는") 환경 과 함께 자유 변수를 가질 있는 표현식 (일반적으로 함수)입니다 .

당신이 사용하는 closure당신은 함수의 외부에서 정의 된 변수를 사용하는 함수를 정의합니다. (우리는 변수를 자유 변수 라고 부릅니다 ).
그들은 모두 사용합니다 closure(첫 번째 예에서도).


간단히 말해서 자바 스크립트 클로저 로 기능 할 수 액세스를 가변 되는 어휘 - 부모 함수에서 선언을 .

더 자세한 설명을 봅시다. 클로저를 이해하려면 JavaScript가 변수 범위를 지정하는 방법을 이해하는 것이 중요합니다.

범위

JavaScript에서 범위는 함수로 정의됩니다. 모든 함수는 새로운 범위를 정의합니다.

다음 예를 고려하십시오.

function f()
{//begin of scope f
  var foo='hello'; //foo is declared in scope f
  for(var i=0;i<2;i++){//i is declared in scope f
     //the for loop is not a function, therefore we are still in scope f
     var bar = 'Am I accessible?';//bar is declared in scope f
     console.log(foo);
  }
  console.log(i);
  console.log(bar);
}//end of scope f

f 인쇄 호출

hello
hello
2
Am I Accessible?

이제 g다른 함수 내에 정의 된 함수가있는 경우를 고려해 보겠습니다 f.

function f()
{//begin of scope f
  function g()
  {//being of scope g
    /*...*/
  }//end of scope g
  /*...*/
}//end of scope f

우리는 호출 어휘 부모 의를 . 앞서 설명했듯이 이제 2 개의 범위가 있습니다. 범위 와 범위 .fgfg

그러나 하나의 범위가 다른 범위의 "내"이므로 자식 함수의 범위가 부모 함수 범위의 일부입니까? 부모 함수의 범위에 선언 된 변수는 어떻게 되나요? 하위 기능의 범위에서 액세스 할 수 있습니까? 그것이 바로 클로저가 들어가는 곳입니다.

폐쇄

JavaScript에서 함수 g는 범위에 선언 된 모든 변수에 액세스 할 수있을 g뿐만 아니라 부모 함수의 범위에 선언 된 모든 변수에도 액세스 할 수 있습니다 f.

다음을 고려하십시오.

function f()//lexical parent function
{//begin of scope f
  var foo='hello'; //foo declared in scope f
  function g()
  {//being of scope g
    var bar='bla'; //bar declared in scope g
    console.log(foo);
  }//end of scope g
  g();
  console.log(bar);
}//end of scope f

f 인쇄 호출

hello
undefined

라인을 봅시다 console.log(foo);. 이 시점에서 우리는 범위에 g있으며 foo범위에 선언 된 변수에 액세스하려고합니다 f. 그러나 앞서 언급했듯이 어휘 부모 함수에서 선언 된 모든 변수에 액세스 할 수 있습니다. g의 어휘 부모입니다 f. 따라서 hello인쇄됩니다.
이제 라인을 살펴 보겠습니다 console.log(bar);. 이 시점에서 우리는 범위에 f있으며 bar범위에 선언 된 변수에 액세스하려고합니다 g. bar현재 범위에서 선언되지 않았고 함수 g가의 부모가 f아니므 bar로 정의되지 않았습니다.

실제로 우리는 어휘 "대부모"함수의 범위에서 선언 된 변수에 액세스 할 수도 있습니다. 따라서 함수 h내에 정의 된 함수가 있다면g

function f()
{//begin of scope f
  function g()
  {//being of scope g
    function h()
    {//being of scope h
      /*...*/
    }//end of scope h
    /*...*/
  }//end of scope g
  /*...*/
}//end of scope f

다음 h함수의 범위에 선언 된 모든 변수에 액세스 할 수있을 것 h, g등을 f. 이것은 클로저 로 이루어집니다 . JavaScript 클로저에서 우리는 어휘 부모 함수, 어휘 그랜드 부모 함수, 어휘 그랜드 부모 함수 등에 선언 된 모든 변수에 액세스 할 수 있습니다. 이것은 범위 체인 으로 볼 수 있습니다 . scope of current function -> scope of lexical parent function -> scope of lexical grand parent function -> ... 어휘 부모가없는 마지막 부모 함수까지.

창 개체

사실 체인은 마지막 부모 함수에서 멈추지 않습니다. 특별한 범위가 하나 더 있습니다. 전역 범위 . 함수에서 선언되지 않은 모든 변수는 전역 범위에서 선언 된 것으로 간주됩니다. 글로벌 범위에는 두 가지 전문성이 있습니다.

  • 전역 범위에 선언 된 모든 변수는 어디서나 액세스 할 수 있습니다.
  • 전역 범위에서 선언 된 변수는 window개체 의 속성에 해당 합니다.

따라서 foo전역 범위에서 변수를 선언하는 방법에는 정확히 두 가지가 있습니다 . 함수에서 선언하지 않거나 foo창 개체 의 속성 설정하여 .

두 시도 모두 클로저를 사용합니다.

이제 더 자세한 설명을 읽었으므로 두 솔루션 모두 클로저를 사용하는 것이 분명 할 수 있습니다. 하지만 확실하게 증거를 만들어 봅시다.

새로운 프로그래밍 언어를 만들어 보겠습니다. JavaScript-No-Closure. 이름에서 알 수 있듯이 JavaScript-No-Closure는 Closure를 지원하지 않는다는 점을 제외하면 JavaScript와 동일합니다.

다시 말해;

var foo = 'hello';
function f(){console.log(foo)};
f();
//JavaScript-No-Closure prints undefined
//JavaSript prints hello

자, JavaScript-No-Closure를 사용하는 첫 번째 솔루션에서 어떤 일이 발생하는지 살펴 보겠습니다.

for(var i = 0; i < 10; i++) {
  (function(){
    var i2 = i;
    setTimeout(function(){
        console.log(i2); //i2 is undefined in JavaScript-No-Closure 
    }, 1000)
  })();
}

따라서 이것은 undefinedJavaScript-No-Closure에서 10 번 인쇄됩니다 .

따라서 첫 번째 솔루션은 클로저를 사용합니다.

두 번째 솔루션을 살펴 보겠습니다.

for(var i = 0; i < 10; i++) {
  setTimeout((function(i2){
    return function() {
        console.log(i2); //i2 is undefined in JavaScript-No-Closure
    }
  })(i), 1000);
}

따라서 이것은 undefinedJavaScript-No-Closure에서 10 번 인쇄됩니다 .

두 솔루션 모두 클로저를 사용합니다.

편집 :이 3 개의 코드 조각이 전역 범위에 정의되어 있지 않다고 가정합니다. 그렇지 않으면 변수 foo개체에 i바인딩 window되므로 windowJavaScript 및 JavaScript-No-Closure 개체를 통해 액세스 할 수 있습니다 .


나는 아무도 이것을 설명하는 방식에 만족하지 않았습니다.

클로저를 이해하는 열쇠는 클로저없이 JS가 어떤 것인지 이해하는 것입니다.

클로저가 없으면 오류가 발생합니다.

function outerFunc(){
    var outerVar = 'an outerFunc var';
    return function(){
        alert(outerVar);
    }
}

outerFunc()(); //returns inner function and fires it

일단 outerFunc가 JavaScript의 가상 클로저 비활성화 버전에서 반환되면 outerVar에 대한 참조가 가비지 수집되고 내부 func가 참조 할 수 있도록 아무것도 남기지 않습니다.

클로저는 본질적으로 내부 함수가 외부 함수의 변수를 참조 할 때 해당 변수가 존재할 수 있도록하는 특수 규칙입니다. 클로저를 사용하면 참조 된 변수는 외부 함수가 완료된 후에도 유지되거나 요점을 기억하는 데 도움이되는 경우 '닫힌'상태입니다.

클로저를 사용하더라도 로컬을 참조하는 내부 함수가없는 함수에서 로컬 변수의 수명주기는 클로저없는 버전에서와 동일하게 작동합니다. 기능이 완료되면 지역 주민들은 가비지 수집을받습니다.

내부 함수에 외부 변수에 대한 참조가 있으면 참조 된 변수에 대한 가비지 수집에 문턱이 들어가는 것과 같습니다.

클로저를 보는 더 정확한 방법은 내부 함수가 기본적으로 내부 범위를 자체 범위 foudnation으로 사용한다는 것입니다.

그러나 참조 된 컨텍스트는 사실 스냅 샷과는 달리 영구적입니다. 외부 함수의 로컬 변수를 계속 증가시키고 로깅하는 반환 된 내부 함수를 반복적으로 실행하면 더 높은 값을 계속 경고합니다.

function outerFunc(){
    var incrementMe = 0;
    return function(){ incrementMe++; console.log(incrementMe); }
}
var inc = outerFunc();
inc(); //logs 1
inc(); //logs 2

둘 다 클로저를 사용하고 있습니다.

여기 에서 Wikipedia 정의를 사용 하겠습니다.

컴퓨터 과학에서 클로저 (어휘 클로저 또는 함수 클로저)는 참조 환경 (해당 함수의 각 비 지역 변수 (자유 변수라고도 함)에 대한 참조를 저장하는 테이블)과 함께 함수에 대한 참조 또는 함수입니다. . 일반 함수 포인터와 달리 클로저는 함수가 직접적인 어휘 범위 밖에서 호출 된 경우에도 해당 비 지역 변수에 액세스 할 수 있도록합니다.

친구의 시도 i는 값을 취하고 로컬에 저장할 사본을 만들어 로컬이 아닌 변수를 명확하게 사용합니다 i2.

사용자 자신의 시도는 i익명 함수에 인수로 전달됩니다 (호출 사이트에서 범위에 있음). 이것은 지금까지 클로저가 아니지만 해당 함수는 동일한을 참조하는 다른 함수를 반환합니다 i2. 내부 익명 함수 i2는 로컬이 아니기 때문에 클로저를 생성합니다.


당신과 당신의 친구는 모두 클로저를 사용합니다.

클로저는 함수와 그 함수가 생성 된 환경이라는 두 가지를 결합하는 특별한 종류의 객체입니다. 환경은 클로저가 생성 될 때 범위 내에 있던 모든 지역 변수로 구성됩니다.

MDN : https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures

function(){ console.log(i2); }익명 함수의 클로저 내부에 정의 된 친구의 코드 함수에서 function(){ var i2 = i; ...로컬 변수를 읽고 쓸 수 있습니다 i2.

귀하의 코드에서 함수 function(){ console.log(i2); }폐쇄 내부에 정의 된 함수 function(i2){ return ...는 지역 가치를 읽고 쓸 수 있습니다 i2(이 경우 매개 변수로 선언 됨).

두 경우 모두 함수 function(){ console.log(i2); }setTimeout.

또 다른 동등한 (하지만 메모리 사용률이 낮음)은 다음과 같습니다.

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

폐쇄

클로저는 함수가 아니라 표현식이 아닙니다. 함수 범위 외부에서 사용되는 변수의 일종의 '스냅 샷'으로보아야하며 함수 내부에서 사용되어야합니다. 문법적으로 '변수의 종결을 취하라'고 말해야합니다.

다시 말해서, 클로저는 함수가 의존하는 변수의 관련 컨텍스트의 복사본입니다.

한 번 더 (순진한) : 클로저는 매개 변수로 전달되지 않는 변수에 액세스 할 수 있습니다.

이러한 기능적 개념은 사용하는 프로그래밍 언어 / 환경에 따라 크게 달라집니다. JavaScript에서 클로저는 어휘 범위 지정 (대부분의 C 언어에서 해당)에 따라 다릅니다.

따라서 함수를 반환하는 것은 대부분 익명 / 이름없는 함수를 반환하는 것입니다. 함수가 매개 변수로 전달되지 않고 변수에 액세스 할 때 (어휘) 범위 내에서 클로저가 사용됩니다.

따라서 귀하의 예와 관련하여 :

// 1
for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i); // closure, only when loop finishes within 1000 ms,
    }, 1000);           // i = 10 for all functions
}
// 2
for(var i = 0; i < 10; i++) {
    (function(){
        var i2 = i; // closure of i (lexical scope: for-loop)
        setTimeout(function(){
            console.log(i2); // closure of i2 (lexical scope:outer function)
        }, 1000)
    })();
}
// 3
for(var i = 0; i < 10; i++) {
    setTimeout((function(i2){
        return function() {
            console.log(i2); // closure of i2 (outer scope)

        }
    })(i), 1000); // param access i (no closure)
}

모두 클로저를 사용하고 있습니다. 실행 시점을 클로저와 혼동하지 마십시오. 클로저의 '스냅 샷'이 잘못된 순간에 찍히면 값이 예상치 못한 것일 수 있지만 확실히 클로저가 찍 힙니다!


두 가지 방법을 모두 살펴 보겠습니다.

(function(){
    var i2 = i;
    setTimeout(function(){
        console.log(i2);
    }, 1000)
})();

Declares and immediately executes an anonymous function that runs setTimeout() within its own context. The current value of i is preserved by making a copy into i2 first; it works because of the immediate execution.

setTimeout((function(i2){
    return function() {
        console.log(i2);
    }
})(i), 1000);

Declares an execution context for the inner function whereby the current value of i is preserved into i2; this approach also uses immediate execution to preserve the value.

Important

It should be mentioned that the run semantics are NOT the same between both approaches; your inner function gets passed to setTimeout() whereas his inner function calls setTimeout() itself.

Wrapping both codes inside another setTimeout() doesn't prove that only the second approach uses closures, there's just not the same thing to begin with.

Conclusion

Both methods use closures, so it comes down to personal taste; the second approach is easier to "move" around or generalize.


I wrote this a while ago to remind myself of what a closure is and how it works in JS.

A closure is a function that, when called, uses the scope in which it was declared, not the scope in which it was called. In javaScript, all functions behave like this. Variable values in a scope persist as long as there is a function that still points to them. The exception to the rule is 'this', which refers to the object that the function is inside when it is called.

var z = 1;
function x(){
    var z = 2; 
    y(function(){
      alert(z);
    });
}
function y(f){
    var z = 3;
    f();
}
x(); //alerts '2' 

After inspecting closely, looks like both of you are using closure.

In your friends case, i is accessed inside anonymous function 1 and i2 is accessed in anonymous function 2 where the console.log is present.

In your case you are accessing i2 inside anonymous function where console.log is present. Add a debugger; statement before console.log and in chrome developer tools under "Scope variables" it will tell under what scope the variable is.


Consider the following. This creates and recreates a function f that closes on i, but different ones!:

i=100;

f=function(i){return function(){return ++i}}(0);
alert([f,f(),f(),f(),f(),f(),f(),f(),f(),f(),f()].join('\n\n'));

f=function(i){return new Function('return ++i')}(0);        /*  function declarations ~= expressions! */
alert([f,f(),f(),f(),f(),f(),f(),f(),f(),f(),f()].join('\n\n'));

while the following closes on "a" function "itself"
( themselves! the snippet after this uses a single referent f )

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

or to be more explicit:

for(var i = 0; i < 10; i++) {
    console.log(    f = new Function( 'console.log('+i+')' )    );
    setTimeout( f,  1000 );
}

NB. the last definition of f is function(){ console.log(9) } before 0 is printed.

Caveat! The closure concept can be a coercive distraction from the essence of elementary programming:

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

x-refs.:
How do JavaScript closures work?
Javascript Closures Explanation
Does a (JS) Closure Require a Function Inside a Function
How to understand closures in Javascript?
Javascript local and global variable confusion


I would like to share my example and an explanation about closures. I made a python example, and two figures to demonstrate stack states.

def maker(a, b, n):
    margin_top = 2
    padding = 4
    def message(msg):
        print('\n’ * margin_top, a * n, 
            ' ‘ * padding, msg, ' ‘ * padding, b * n)
    return message

f = maker('*', '#', 5)
g = maker('', '♥’, 3)
f('hello')
g(‘good bye!')

The output of this code would be as follows:

*****      hello      #####

      good bye!    ♥♥♥

Here are two figures to show stacks and the closure attached to the function object.

when the function is returned from maker

when the function is called later

함수가 매개 변수 또는 비 지역 변수를 통해 호출 될 때 코드에는 margin_top, padding 및 a, b, n과 같은 지역 변수 바인딩이 필요합니다. 함수 코드가 작동하는지 확인하려면 오래 전에 사라진 메이커 함수의 스택 프레임에 액세스 할 수 있어야합니다.이 프레임은 함수 메시지 객체와 함께 찾을 수있는 클로저에 백업됩니다.

참고 URL : https://stackoverflow.com/questions/12930272/javascript-closures-vs-anonymous-functions

반응형