루프 내부의 JavaScript 클로저 – 간단한 실제 예


2817

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

이것을 출력합니다 :

나의 가치 : 3
나의 가치 : 3
나의 가치 : 3

반면 출력을 원합니다.

내 값 : 0
내 값 : 1
내 값 : 2


이벤트 리스너를 사용하여 함수 실행 지연이 발생하는 경우에도 동일한 문제점이 발생합니다.

var buttons = document.getElementsByTagName("button");
// let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
  // as event listeners
  buttons[i].addEventListener("click", function() {
    // each should log its value.
    console.log("My value: " + i);
  });
}
<button>0</button>
<br />
<button>1</button>
<br />
<button>2</button>

또는 비동기 코드 (예 : 약속 사용) :

// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));

for (var i = 0; i < 3; i++) {
  // Log `i` as soon as each promise resolves.
  wait(i * 100).then(() => console.log(i));
}

편집 : 그것은 또한 명백 for in하고 for of반복됩니다 :

const arr = [1,2,3];
const fns = [];

for(i in arr){
  fns.push(() => console.log(`index: ${i}`));
}

for(v of arr){
  fns.push(() => console.log(`value: ${v}`));
}

for(f of fns){
  f();
}

이 기본 문제에 대한 해결책은 무엇입니까?


55
funcs숫자 인덱스를 사용하는 경우 배열 이 되고 싶지 않습니까? 그냥 머리 위로.
DanMan

23
이것은 실제로 혼란스러운 문제입니다. 이 기사는 이해하는 데 도움됩니다 . 다른 사람들에게도 도움이 될 수 있습니다.
user3199690

4
또 다른 간단하고 설명 된 솔루션 : 1) 중첩 함수 는 "위"범위에 액세스 할 수 있습니다 . 2) 폐쇄 용액 ... "A 폐쇄 상위 함수가 폐쇄 된 후에도, 상위 범위에 대한 액세스를 갖는 함수이다."
Peter Krauss

2
더 나은 Unserstanding의이 링크를 참조하십시오 javascript.info/tutorial/advanced-functions
Saurabh Ahuja

35
에서는 ES6 , 사소한 해결책 변수 선언하는 난을 함께 하자 루프의 본체 범위된다.
Tomas Nikodym

답변:


2147

문제는 i각각의 익명 함수 내의 변수가 함수 외부의 동일한 변수에 바인딩되어 있다는 것입니다.

클래식 솔루션 : 마감

당신이하고 싶은 것은 각 함수 내의 변수를 함수 외부의 변하지 않는 별도의 값에 바인딩하는 것입니다.

var funcs = [];

function createfunc(i) {
  return function() {
    console.log("My value: " + i);
  };
}

for (var i = 0; i < 3; i++) {
  funcs[i] = createfunc(i);
}

for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

함수 작성을 새 함수로 랩핑하여 JavaScript에는 함수 범위 만있는 블록 범위가 없으므로 "i"값이 의도 한대로 유지되도록합니다.


ES5.1 솔루션 : forEach

Array.prototype.forEach함수의 가용성이 비교적 넓기 때문에 (2015 년) 반복되는 상황에서 주로 일련의 값을 .forEach()반복하여 모든 반복에 대해 뚜렷한 폐쇄를 얻을 수있는 깨끗하고 자연스러운 방법을 제공 한다는 점은 주목할 가치가 있습니다. 즉, 값 (DOM 참조, 객체 등)을 포함하는 일종의 배열이 있고 각 요소에 특정한 콜백을 설정하는 데 문제가 있다고 가정하면 다음을 수행 할 수 있습니다.

var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
  // ... code code code for this one element
  someAsynchronousFunction(arrayElement, function() {
    arrayElement.doSomething();
  });
});

.forEach루프 와 함께 사용되는 콜백 함수를 호출 할 때마다 고유 한 클로저가됩니다. 해당 핸들러로 전달 된 매개 변수는 반복의 특정 단계에 고유 한 배열 요소입니다. 비동기 콜백에서 사용되는 경우 반복의 다른 단계에서 설정된 다른 콜백과 충돌하지 않습니다.

jQuery에서 작업 $.each()하는 경우 비슷한 기능을 제공합니다.


ES6 솔루션 : let

ECMAScript 6 (ES6)에는 기반 변수 와 다른 범위의 새로운 키워드 letconst키워드가 도입되었습니다 var. 예를 들어, let인덱스를 기반 으로하는 루프에서 루프를 반복 할 때마다 i루프 범위를 가진 새 변수 가 있으므로 코드가 예상대로 작동합니다. 많은 자료가 있지만 2ality의 블록 범위 게시물 을 훌륭한 정보 출처로 추천합니다.

for (let i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("My value: " + i);
  };
}

그러나 Edge 14 이전의 IE9-IE11 및 Edge let는 위의 오류를 지원 하지만 위와 i같은 오류가 발생 var합니다. Edge 14는 마침내 그것을 올바르게 얻습니다.


7
아닌 function createfunc(i) { return function() { console.log("My value: " + i); }; }이 변수를 사용하기 때문에 여전히 폐쇄 i?
아렉 쿠스

55
불행히도,이 답변은 구식이며 아무도 아래에서 올바른 답변을 Function.bind()볼 수 없습니다 . 지금까지는 확실히 사용하는 것이 좋습니다 . stackoverflow.com/a/19323214/785541을 참조하십시오 .
Wladimir Palant

81
@Wladimir : 귀하의 제안 .bind()이다는 "정답은" 옳지 않다. 그들은 각자 자신의 자리를 가지고 있습니다. 함께 .bind()하면 바인딩없이 인수를 바인딩 할 수 없습니다 this값입니다. 또한 i호출 사이 에서 인수를 변경하지 않고 인수 사본을 얻습니다 . 때로는 필요합니다. 따라서 .bind()구현이 역사적으로 느리다는 것은 말할 것도없고, 상당히 다른 구성 입니다. 간단한 예에서는 물론 작동하지만 클로저는 이해해야 할 중요한 개념이며 이것이 바로 질문입니다.
쿠키 몬스터

8
이러한 반환 함수 해킹 사용을 중지하고 동일한 범위 변수를 재사용하지 않기 때문에 [] .forEach 또는 [] .map을 대신 사용하십시오.
Christian Landgren

32
@ChristianLandgren : 배열을 반복하는 경우에만 유용합니다. 이러한 기술은 "해킹"이 아닙니다. 그들은 필수 지식입니다.

379

시험:

var funcs = [];
    
for (var i = 0; i < 3; i++) {
    funcs[i] = (function(index) {
        return function() {
            console.log("My value: " + index);
        };
    }(i));
}

for (var j = 0; j < 3; j++) {
    funcs[j]();
}

편집 (2014) :

개인적으로 @Aust의 최근 답변은.bind 이러한 종류의 작업을 수행하는 가장 좋은 방법이라고 생각합니다. LO-대시 밑줄의 /도 있습니다 _.partial당신이 필요하거나 건드리고 싶지 않을 때 bindthisArg.


2
에 대한 설명 }(i));?
aswzen

3
@ aswzen 나는 그것이 함수 i의 인수 index로 전달된다고 생각합니다 .
Jet Blue

실제로 로컬 변수 인덱스를 작성 중입니다.
Abhishek Singh

1
함수 표현, 즉 IIFE를 즉시 호출합니다. (i)는 즉시 호출되는 익명 함수 표현식에 대한 인수이며 색인은 i에서 설정됩니다.
계란

348

아직 언급되지 않은 또 다른 방법은 Function.prototype.bind

var funcs = {};
for (var i = 0; i < 3; i++) {
  funcs[i] = function(x) {
    console.log('My value: ' + x);
  }.bind(this, i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}

최신 정보

@squint와 @mekdev에서 지적했듯이 먼저 루프 외부에서 함수를 만든 다음 루프 내에서 결과를 바인딩하면 성능이 향상됩니다.

function log(x) {
  console.log('My value: ' + x);
}

var funcs = [];

for (var i = 0; i < 3; i++) {
  funcs[i] = log.bind(this, i);
}

for (var j = 0; j < 3; j++) {
  funcs[j]();
}


이것은 요즘 나도하는 일입니다. 나는 또한 lo-dash / underscore 's를 좋아합니다_.partial
Bjorn

17
.bind()ECMAScript 6 기능에서는 더 이상 사용되지 않습니다. 게다가 이것은 실제로 반복마다 두 개의 함수를 만듭니다. 먼저 익명을 만든 다음에 의해 생성 된 익명 .bind()입니다. 루프 외부에서 만든 다음 .bind()내부 에서 만드는 것이 더 좋습니다 .

5
@squint @mekdev-둘 다 맞습니다. 내 초기 예제는 어떻게 bind사용 되는지 보여주기 위해 빠르게 작성되었습니다 . 귀하의 제안에 따라 다른 예를 추가했습니다.
Aust

5
두 개의 O (n) 루프에 대한 계산을 낭비하는 대신 (var i = 0; i <3; i ++) {log.call (this, i); }
user2290820

1
.bind ()는 허용 된 답변이 PLUS 바이올린을 제안하는 것을 수행 this합니다.
niry

269

즉시 호출되는 함수 표현식을 사용하여 인덱스 변수를 묶는 가장 간단하고 읽기 쉬운 방법 :

for (var i = 0; i < 3; i++) {

    (function(index) {

        console.log('iterator: ' + index);
        //now you can also loop an ajax call here 
        //without losing track of the iterator value:   $.ajax({});
    
    })(i);

}

이것은 i우리가로 정의한 익명 함수로 반복자 를 보냅니다 index. 이렇게하면 iIIFE 내의 비동기 기능에서 나중에 사용하기 위해 변수 가 저장 되는 클로저가 생성 됩니다.


10
코드 가독성을 높이고 혼동을 피하기 위해 i함수 매개 변수의 이름을로 바꿉니다 index.
Kyle Falconer

5
어떻게 배열 정의하기 위해이 기술을 사용 funcs 원래의 질문에 설명을?
니코

@Nico index대신 원래 질문에 표시된 것과 동일한 방법 입니다 i.
JLRishe

@JLRishevar funcs = {}; for (var i = 0; i < 3; i++) { funcs[i] = (function(index) { return function() {console.log('iterator: ' + index);}; })(i); }; for (var j = 0; j < 3; j++) { funcs[j](); }
니코

1
@Nico OP의 특별한 경우에, 그들은 숫자를 반복하는 것이므로, 이것은 대단한 경우가 .forEach()아니지만, 배열로 시작하는 많은 시간 forEach()은 다음과 같은 좋은 선택입니다.var nums [4, 6, 7]; var funcs = {}; nums.forEach(function (num, i) { funcs[i] = function () { console.log(num); }; });
JLRishe

164

파티에 늦었지만 오늘이 문제를 탐색하고 있었고 많은 답변이 Javascript가 범위를 처리하는 방법을 완전히 다루지 않았 음을 발견했습니다. 이것이 본질적으로 요약됩니다.

많은 다른 사람들이 언급했듯이 문제는 내부 함수가 동일한 i변수를 참조한다는 것 입니다. 그렇다면 매번 반복 할 때마다 새로운 로컬 변수를 만들고 대신 내부 함수 참조를 사용하지 않겠습니까?

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    var ilocal = i; //create a new local variable
    funcs[i] = function() {
        console.log("My value: " + ilocal); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

이전과 마찬가지로 각 내부 함수가에 할당 된 마지막 값을 출력 한 i경우 이제 각 내부 함수는에 할당 된 마지막 값을 출력합니다 ilocal. 그러나 각 반복마다 고유하지 않아야합니다.ilocal 합니까?

그게 문제입니다. 각 반복은 동일한 범위를 공유하므로 첫 번째 이후의 모든 반복은 그냥 덮어 씁니다 ilocal. 에서 MDN :

중요 : JavaScript에는 블록 범위가 없습니다. 블록과 함께 도입 된 변수는 포함 함수 또는 스크립트로 범위가 지정되며 변수 설정의 효과는 블록 자체를 넘어서 유지됩니다. 다시 말해, 블록 명령문은 범위를 도입하지 않습니다. "독립형"블록은 유효한 구문이지만 C 또는 Java에서 이러한 블록과 같은 것으로 생각되면 자신이 생각하는대로하지 않기 때문에 JavaScript에서 독립형 블록을 사용하고 싶지 않습니다.

강조를 위해 반복 :

JavaScript에는 블록 범위가 없습니다. 블록으로 도입 된 변수는 포함 함수 또는 스크립트 범위

ilocal각 반복에서 선언하기 전에 확인하여이를 확인할 수 있습니다 .

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
  console.log(ilocal);
  var ilocal = i;
}

이것이 바로이 버그가 너무 까다로운 이유입니다. 변수를 다시 선언하더라도 Javascript는 오류를 발생시키지 않으며 JSLint는 경고를 발생시키지 않습니다. 또한이를 해결하는 가장 좋은 방법은 클로저를 활용하는 것입니다. 이는 본질적으로 자바 스크립트에서 내부 범위가 외부 범위를 "포함"하기 때문에 내부 함수가 외부 변수에 액세스 할 수 있다는 아이디어입니다.

폐쇄

이는 내부 함수가 외부 변수를 "유지"하고 외부 함수가 리턴 되더라도 계속 유지함을 의미합니다. 이를 활용하기 위해 순전히 래퍼 함수를 ​​생성하고 호출하여 새 범위를 만들고 새 범위에서 선언 ilocal한 다음 사용하는 내부 함수를 반환합니다 ilocal(아래 설명 참조).

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() { //create a new scope using a wrapper function
        var ilocal = i; //capture i into a local var
        return function() { //return the inner function
            console.log("My value: " + ilocal);
        };
    })(); //remember to run the wrapper function
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

랩퍼 함수 내에 내부 함수를 작성하면 내부 함수에만 액세스 할 수있는 "클로저"개인 환경이 제공됩니다. 따라서 래퍼 함수를 ​​호출 할 때마다 자체 별도의 환경으로 새로운 내부 함수를 만들어 ilocal변수가 서로 충돌하고 덮어 쓰지 않도록합니다. 몇 가지 사소한 최적화는 다른 많은 SO 사용자가 제공 한 최종 답변을 제공합니다.

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = wrapper(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}
//creates a separate environment for the inner function
function wrapper(ilocal) {
    return function() { //return the inner function
        console.log("My value: " + ilocal);
    };
}

최신 정보

이제 ES6을 주류로 삼 으면 새로운 let키워드를 사용하여 블록 범위 변수를 만들 수 있습니다.

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (let i = 0; i < 3; i++) { // use "let" to declare "i"
    funcs[i] = function() {
        console.log("My value: " + i); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) { // we can use "var" here without issue
    funcs[j]();
}

지금 얼마나 쉬운 지보세요! 자세한 내용은 내 정보가 기반으로하는 this answer을 참조하십시오 .


IIFE 방법을 어떻게 설명했는지 좋아합니다. 나는 그것을 찾고 있었다. 감사합니다.
CapturedTree

4
이제 letand const키워드를 사용하여 JavaScript에서 블록 범위 지정과 같은 것이 있습니다. 이 답변이 그것을 포함하도록 확장된다면 그것은 전 세계적으로 훨씬 더 유용 할 것입니다.

@TinyGiant 확실히, 나는 몇 가지 정보를 추가 let하고 더 완전한 설명을 연결했다
woojoo666

@ woojoo666 귀하의 답변은 다음과 같이 루프에서 두 개의 대체 URL을 호출하는 데 효과적 일 수 i=0; while(i < 100) { setTimeout(function(){ window.open("https://www.bbc.com","_self") }, 3000); setTimeout(function(){ window.open("https://www.cnn.com","_self") }, 3000); i++ }있습니까? (window.open ()을 getelementbyid ......로 대체 할 수 있습니다.)
natty에 대해

답글이 늦어 죄송합니다. 예제의 코드가 이미 작동하지 않는 것 같습니다. 당신은 사용하지 않는 i당신이 폐쇄 필요가 없습니다, 시간 제한 기능에
woojoo666

151

ES6가 널리 지원됨에 따라이 질문에 대한 최상의 답변이 변경되었습니다. ES6는 이 정확한 상황에 대한 letconst키워드를 제공합니다 . 클로저를 어지럽히 지 let않고 다음과 같이 루프 범위 변수를 설정하는 데 사용할 수 있습니다 .

var funcs = [];

for (let i = 0; i < 3; i++) {          
    funcs[i] = function() {            
      console.log("My value: " + i); 
    };
}

val그런 다음 루프의 특정 회전과 관련된 객체를 가리키고 추가 클로저 표기법없이 올바른 값을 반환합니다. 이것은 분명히이 문제를 단순화시킵니다.

const 비슷하다 let초기 할당 후 변수 이름을 새 참조로 리바운드 할 수 없다는 추가 제한 사항과 합니다.

최신 버전의 브라우저를 대상으로하는 사용자를위한 브라우저 지원이 제공됩니다. const/ let는 현재 최신 Firefox, Safari, Edge 및 Chrome에서 지원됩니다. 또한 Node에서도 지원되며 Babel과 같은 빌드 도구를 활용하여 어디서나 사용할 수 있습니다. 실제 예제를 볼 수 있습니다 : http://jsfiddle.net/ben336/rbU4t/2/

여기 문서 :

그러나 Edge 14 이전의 IE9-IE11 및 Edge let는 위의 오류를 지원 하지만 위와 i같은 오류가 발생 var합니다. Edge 14는 마침내 그것을 올바르게 얻습니다.


불행히도, 'let'은 특히 모바일에서 여전히 완벽하게 지원되지 않습니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
MattC

2
'16 년 6 월 현재, iOS Safari, Opera Mini 및 Safari 9를 제외한 모든 주요 브라우저 버전에서 let 이 지원됩니다. Evergreen 브라우저가이를 지원합니다. Babel은 높은 호환성 모드를 켜지 않고 예상 동작을 유지하기 위해 올바르게 변환합니다.
Dan Pantry

@DanPantry 예, 업데이트 시간 :) const, doc 링크 및 더 나은 호환성 정보를 포함하여 현재 상태를 더 잘 반영하도록 업데이트되었습니다.
Ben McCormick

이것이 우리가 코드를 변환하기 위해 babel을 사용하는 이유가 아니므로 ES6 / 7을 지원하지 않는 브라우저는 무슨 일이 일어나고 있는지 이해할 수 있습니까?
pixel 67

87

그것을 말하는 또 다른 방법은 i함수를 만들 때가 아니라 함수를 실행할 때 함수 의 in이 바인딩되어 있다는 것입니다.

클로저를 만들 때 i 와 같이 변수의 복사본이 아닌 외부 범위에 정의 된 변수에 대한 참조입니다. 실행 시점에 평가됩니다.

다른 답변의 대부분은 값을 변경하지 않는 다른 변수를 만들어서 해결하는 방법을 제공합니다.

명확성을 위해 설명을 추가한다고 생각했습니다. 해결책은 개인적으로 Harto와 함께 할 것입니다 .Harto의 답변에서 여기에 대한 가장 자명 한 방법이기 때문입니다. 게시 된 코드는 모두 작동하지만 새 변수 (Freddy 및 1800)를 선언하거나 이상한 내장 폐쇄 구문 (apphacker)을 선언하는 이유를 설명하기 위해 주석 더미를 작성 해야하는 폐쇄 공장을 선택합니다.


71

이해해야 할 것은 자바 스크립트의 변수 범위는 함수를 기반으로한다는 것입니다. 이것은 블록 범위가있는 c #보다 중요한 차이점이며 변수를 for 내부에 복사하면 효과가 있습니다.

변수에 함수 범위가 있으므로 apphacker의 답변과 같은 함수 반환을 평가하는 함수로 그것을 감싸는 것은 트릭을 수행합니다.

var 대신 let 키워드가있어 블록 범위 규칙을 사용할 수 있습니다. 이 경우 for 내부에 변수를 정의하면 트릭을 수행합니다. 즉, let 키워드는 호환성 때문에 실용적인 솔루션이 아닙니다.

var funcs = {};

for (var i = 0; i < 3; i++) {
  let index = i; //add this
  funcs[i] = function() {
    console.log("My value: " + index); //change to the copy
  };
}

for (var j = 0; j < 3; j++) {
  funcs[j]();
}


@nickf 어떤 브라우저? 내가 말했듯이 호환성 문제가 있는데 IE에서 let이 지원되지 않는다고 생각하는 것처럼 심각한 호환성 문제가 있음을 의미합니다.
eglasius

1
@nickf yes, this reference : developer.mozilla.org/En/New_in_JavaScript_1.7 ... let 정의 섹션을 확인하십시오. 루프 내부에 onclick 예제가 있습니다
eglasius

2
@nickf 흠, 실제로 버전을 명시 적으로 지정해야합니다 : <script type = "application / javascript; version = 1.7"/> ... IE 제한 때문에 실제로 사용하지 않았습니다. 실용적인 :(
eglasius

여기에 다른 버전의 브라우저 지원을 볼 수 있습니다 es.wikipedia.org/wiki/Javascript
eglasius


59

Bjorn (apphacker)과 유사한이 기술에 대한 또 다른 변형이 있습니다.이 값을 사용하면 변수 값을 매개 변수로 전달하지 않고 함수 내부에 변수 값을 지정할 수 있습니다.

var funcs = [];
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() {
        var index = i;
        return function() {
            console.log("My value: " + index);
        }
    })();
}

어떤 기술을 사용하든 index변수는 일종의 정적 변수가되어 내부 함수의 반환 된 복사본에 바인딩됩니다. 즉, 값을 변경해도 통화간에 유지됩니다. 매우 편리 할 수 ​​있습니다.


감사하고 솔루션이 작동합니다. 그러나 왜 이것이 작동하는지 묻고 싶지만 var회선과 회선을 바꾸면 작동 return하지 않습니까? 감사!
midnite

당신이 교체되면 @midnite var하고 return는 내부 함수를 반환하기 전에 다음 변수가 할당되지 않습니다.
Boann

53

이것은 JavaScript에서 클로저를 사용하는 일반적인 실수를 설명합니다.

새로운 환경을 정의하는 함수

치다:

function makeCounter()
{
  var obj = {counter: 0};
  return {
    inc: function(){obj.counter ++;},
    get: function(){return obj.counter;}
  };
}

counter1 = makeCounter();
counter2 = makeCounter();

counter1.inc();

alert(counter1.get()); // returns 1
alert(counter2.get()); // returns 0

매번 makeCounter호출 될 때마다 {counter: 0}새 오브젝트가 작성됩니다. 또한 obj 새 개체를 참조 할 수 있도록 새 복사본 이 만들어집니다. 따라서, counter1counter2 는 서로 독립적이다.

루프 폐쇄

루프에서 클로저를 사용하는 것은 까다 롭습니다.

치다:

var counters = [];

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = {
      inc: function(){obj.counter++;},
      get: function(){return obj.counter;}
    }; 
  }
}

makeCounters(2);

counters[0].inc();

alert(counters[0].get()); // returns 1
alert(counters[1].get()); // returns 1

공지 사항이 counters[0]counters[1]있습니다 하지 독립적. 사실, 그들은 같은에서 작동obj !

obj성능상의 이유로 루프의 모든 반복에서 공유 사본이 하나만 있기 때문입니다 . {counter: 0}반복 할 때마다 새 객체를 생성 하더라도 동일한 사본이obj 이 최신 객체에 대한 참조로 업데이트됩니다.

해결책은 다른 도우미 기능을 사용하는 것입니다.

function makeHelper(obj)
{
  return {
    inc: function(){obj.counter++;},
    get: function(){return obj.counter;}
  }; 
}

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = makeHelper(obj);
  }
}

이것은 함수 인수 변수뿐만 아니라 함수 범위의 로컬 변수도 입력시 새 사본이 할당되기 때문에 작동합니다.


작은 설명 : 루프의 클로저의 첫 번째 예에서 카운터 [0] 및 카운터 [1]은 성능상의 이유로 독립적이지 않습니다. 그 이유는 다음 var obj = {counter: 0};과 같이 코드가 실행되기 전에 평가되기 때문입니다 . MDN var : var 선언은 코드가 실행되기 전에 처리됩니다.
Charidimos

50

가장 간단한 해결책은

사용하는 대신:

var funcs = [];
for(var i =0; i<3; i++){
    funcs[i] = function(){
        alert(i);
    }
}

for(var j =0; j<3; j++){
    funcs[j]();
}

"2"를 3 번 ​​경고합니다. 이는 for 루프에서 생성 된 익명 함수가 동일한 클로저를 공유하며 해당 클로저에서 값이 i동일하기 때문입니다. 공유 폐쇄를 방지하려면 다음을 사용하십시오.

var funcs = [];
for(var new_i =0; new_i<3; new_i++){
    (function(i){
        funcs[i] = function(){
            alert(i);
        }
    })(new_i);
}

for(var j =0; j<3; j++){
    funcs[j]();
}

이에 대한 아이디어는 for 루프의 전체 본문을 IIFE (즉시 호출 함수 표현식)로 캡슐화하고 new_i매개 변수로 전달 하고로 캡처하는 것 i입니다. 익명 함수가 즉시 실행되므로i 되므로 익명 함수 내에 정의 된 각 함수마다 값이 다릅니다.

이 솔루션은이 문제로 고통받는 원래 코드를 최소한으로 변경해야하기 때문에 이러한 문제에 적합합니다. 실제로 이것은 의도적으로 설계된 것이므로 전혀 문제가되지 않습니다!


2
책에서 비슷한 것을 한 번 읽으십시오. 기존 코드를 많이 만질 필요가 없기 때문에 이것을 선호합니다. 자체 호출 함수 패턴을 배운 후에는 왜 그렇게했는지 분명해집니다. 범위.
DanMan

1
@ DanMan 감사합니다. 자체 호출 익명 함수는 자바 스크립트의 블록 수준 변수 범위 부족을 처리하는 매우 좋은 방법입니다.
Kemal Dağ

3
자체 호출 또는 자체 호출은이 기술에 적합한 용어가 아니며 IIFE (즉시 호출 함수 표현식)가 더 정확합니다. 참조 : benalman.com/news/2010/11/…
jherax

31

이 짧은 시도

  • 배열 없음

  • 추가 for 루프 없음


for (var i = 0; i < 3; i++) {
    createfunc(i)();
}

function createfunc(i) {
    return function(){console.log("My value: " + i);};
}

http://jsfiddle.net/7P6EN/


1
솔루션이 올바르게 출력되는 것 같지만 불필요하게 함수를 사용합니다. 왜 출력을 console.log하지 않습니까? 원래 질문은 동일한 클로저를 가진 익명 함수 작성에 관한 것입니다. 문제는 단일 클로저가 있기 때문에 i의 값은 각각에 대해 동일합니다. 나는 당신이 그것을 바랍니다.
Kemal Dağ

30

다음은 사용하는 간단한 솔루션입니다 forEach(IE9로 다시 작동).

var funcs = [];
[0,1,2].forEach(function(i) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
})
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

인쇄물:

My value: 0
My value: 1
My value: 2

27

OP에 의해 표시된 코드의 주요 문제 i는 두 번째 루프까지 읽지 않는다는 것입니다. 시연하기 위해 코드 내부에 오류가 있다고 상상해보십시오.

funcs[i] = function() {            // and store them in funcs
    throw new Error("test");
    console.log("My value: " + i); // each should log its value.
};

오류는 실제로 funcs[someIndex]실행될 때까지 발생하지 않습니다 (). 이 같은 논리를 사용하면 i이 시점까지 의 값 도 수집되지 않습니다. 원래 루프가 완료되면 조건이 실패하고 루프가 종료 되는 값을 i++가져옵니다 . 이 시점에서 is 등 이 사용되고 평가 될 때 마다 3입니다.i3i < 3i3funcs[someIndex]()i

이 문제를 해결하려면 i문제가 발생한대로 평가해야합니다 . 이것은 이미 funcs[i](3 개의 고유 인덱스가있는) 형식으로 발생했습니다 . 이 값을 캡처하는 방법에는 여러 가지가 있습니다. 하나는 이미 여러 방법으로 표시되는 함수에 매개 변수로 전달하는 것입니다.

또 다른 옵션은 변수를 닫을 수있는 함수 객체를 구성하는 것입니다. 그것은 그렇게 달성 될 수 있습니다

jsFiddle Demo

funcs[i] = new function() {   
    var closedVariable = i;
    return function(){
        console.log("My value: " + closedVariable); 
    };
};

23

JavaScript 함수는 선언시 액세스 할 수있는 범위를 "닫고"해당 범위의 변수가 변경 되더라도 해당 범위에 대한 액세스 권한을 유지합니다.

var funcs = []

for (var i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

위의 배열에있는 각 함수는 전역 범위 (전역 적으로 선언 된 범위이기 때문에 전역 범위)를 닫습니다.

나중에 이러한 함수는 i전역 범위에서 가장 최신 값을 기록하여 호출됩니다 . 그것이 폐쇄의 마법과 좌절입니다.

"JavaScript 함수는 선언 된 범위를 닫고 해당 범위 내의 변수 값이 변경 되더라도 해당 범위에 대한 액세스 권한을 유지합니다."

let대신에 var를 사용 하면 for루프가 실행될 때마다 새 범위를 작성하고 각 함수에 대해 분리 된 범위를 작성하여이를 해결할 수 있습니다. 다른 여러 가지 기술은 추가 기능을 사용하여 동일한 작업을 수행합니다.

var funcs = []

for (let i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

( let변수 범위를 블록으로 만듭니다. 블록은 중괄호로 표시되지만 for 루프의 경우 초기화 변수 i는 중괄호로 선언 된 것으로 간주됩니다.)


1
나는이 답을 읽을 때까지이 개념을 이해하려고 애썼다. 그것은 정말로 중요한 요점에 닿습니다 – 그 가치 i는 세계적인 범위로 설정되고 있습니다. 때 for루프가 실행 완료의 글로벌 값 i(예를 들어, 사용하는 기능이 배열에서 호출 될 때마다 따라서 현재 3 인 funcs[j]1,) i이 함수는 글로벌 참조하고 i(3) 변수.
Modermo

13

다양한 솔루션을 읽은 후 해당 솔루션이 작동하는 이유는 스코프 체인 개념에 의존하기 때문입니다 . JavaScript가 실행 중에 변수를 해결하는 방식입니다.

  • 각 함수 정의는 var및로 선언 된 모든 로컬 변수로 구성된 범위를 형성합니다 arguments.
  • 내부 함수가 다른 (외부) 함수 안에 정의되어 있으면 체인을 형성하고 실행 중에 사용됩니다
  • 함수가 실행될 때 런타임은 범위 체인 을 검색하여 변수를 평가합니다 . 체인의 특정 지점에서 변수를 찾을 수 있으면 검색을 중지하고 사용합니다. 그렇지 않으면 전역 범위에 도달 할 때까지 계속됩니다 window.

초기 코드에서 :

funcs = {};
for (var i = 0; i < 3; i++) {         
  funcs[i] = function inner() {        // function inner's scope contains nothing
    console.log("My value: " + i);    
  };
}
console.log(window.i)                  // test value 'i', print 3

funcs실행됩니다, 범위 체인이 될 것입니다 function inner -> global. 변수 i를 찾을 수 없기 때문에 function inner( var인수로 선언 하거나 인수로 전달하지 않음) 값이 i전역 범위 인에서 전역으로 발견 될 때까지 계속 검색 window.i합니다.

외부 함수로 래핑하여 harto 처럼 도우미 함수를 명시 적으로 정의 하거나 Bjorn 처럼 익명 함수를 사용하십시오 .

funcs = {};
function outer(i) {              // function outer's scope contains 'i'
  return function inner() {      // function inner, closure created
   console.log("My value: " + i);
  };
}
for (var i = 0; i < 3; i++) {
  funcs[i] = outer(i);
}
console.log(window.i)          // print 3 still

funcs실행됩니다, 지금은 범위 체인이 될 것입니다 function inner -> function outer. 이 시간 i은 for 루프에서 3 번 실행되는 외부 함수 범위에서 찾을 수 있으며 매번 값이 i올바르게 바인딩됩니다. window.iinner가 실행될 때 의 값을 사용하지 않습니다 .

더 자세한 내용은 여기 에서 찾을 수 있습니다. 여기
에는 루프에서 클로저를 생성 할 때 발생하는 일반적인 실수와 클로저가 필요한 이유 및 성능 고려 사항이 포함됩니다.


우리는이 코드 샘플을 실제로 작성하는 경우는 거의 없지만 기본을 이해하는 좋은 예라고 생각합니다. 우리가 범위를 염두에두고 그것들이 어떻게 연결되어 있는지, Array.prototype.forEach(function callback(el) {})자연적으로 작동 하는 것과 같은 다른 '현대적인'방법이 왜 작동 하는지 더 분명하게 알 수 있습니다 forEach. 콜백에 정의 된 모든 내부 기능은 바로 사용할 수 있도록 el값을
wpding

13

ES6의 새로운 기능으로 블록 레벨 범위가 관리됩니다.

var funcs = [];
for (let i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (let j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

OP 질문의 코드는 let대신에 로 대체됩니다 var.


const동일한 결과를 제공하며 변수 값이 변경되지 않을 때 사용해야합니다. 그러나 constfor 루프의 이니셜 라이저 내부 사용은 Firefox에서 잘못 구현되어 아직 수정되지 않았습니다. 블록 내부에서 선언되는 대신 블록 외부에서 선언되어 변수를 다시 선언하여 오류가 발생합니다. let초기화 프로그램 내부 의 사용은 Firefox에서 올바르게 구현되므로 걱정할 필요가 없습니다.

10

아직 아무도 forEach지역 변수를 사용하지 않는 것이 더 좋습니다. 사실, 나는 for(var i ...)이런 이유로 더 이상 사용하지 않습니다 .

[0,2,3].forEach(function(i){ console.log('My value:', i); });
// My value: 0
// My value: 2
// My value: 3

// forEach맵 대신 사용하도록 편집했습니다 .


3
.forEach()실제로 아무것도 매핑하지 않는 경우 훨씬 더 나은 옵션이며 Daryl은 게시하기 7 개월 전에 제안 했으므로 놀랄 일이 없습니다.
JLRishe

이 질문은 배열을 통해 루프에 대한 아니다
jherax

글쎄, 그는 함수의 배열을 만들고 싶어합니다.이 예제는 전역 변수를 사용하지 않고 그것을하는 방법을 보여줍니다.
Christian Landgren

9

이 질문은 실제로 JavaScript의 역사를 보여줍니다! 이제 화살표 함수로 블록 범위를 피하고 Object 메소드를 사용하여 DOM 노드에서 직접 루프를 처리 할 수 ​​있습니다.

const funcs = [1, 2, 3].map(i => () => console.log(i));
funcs.map(fn => fn())

const buttons = document.getElementsByTagName("button");
Object
  .keys(buttons)
  .map(i => buttons[i].addEventListener('click', () => console.log(i)));
<button>0</button><br>
<button>1</button><br>
<button>2</button>


8

원래 예제가 작동하지 않은 이유는 루프에서 작성한 모든 클로저가 동일한 프레임을 참조했기 때문입니다. 실제로 하나의 i변수 에 하나의 객체에 3 개의 메소드가 있습니다. 그들은 모두 같은 값을 인쇄했습니다.


8

우선,이 코드의 문제점을 이해하십시오.

var funcs = [];
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

여기서 funcs[]배열이 초기화 i되고 증분 될 때 funcs배열이 초기화되고 func배열 의 크기 가 3이됩니다 i = 3,. 이제 funcs[j]()가 호출되면 변수 i는 이미 3으로 증가한 변수를 사용합니다 .

이제이 문제를 해결하기 위해 많은 옵션이 있습니다. 아래는 두 가지입니다.

  1. 우리는 초기화 할 수 있습니다 i와 함께 let또는 새로운 변수 초기화 index와를 let하고에 동일하게 i. 따라서 호출이 이루어지면 index사용되며 범위는 초기화 후에 종료됩니다. 그리고 전화를 위해 index다시 초기화됩니다.

    var funcs = [];
    for (var i = 0; i < 3; i++) {          
        let index = i;
        funcs[i] = function() {            
            console.log("My value: " + index); 
        };
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }
  2. 다른 옵션은 tempFunc실제 함수를 반환하는를 도입 할 수 있습니다 .

    var funcs = [];
    function tempFunc(i){
        return function(){
            console.log("My value: " + i);
        };
    }
    for (var i = 0; i < 3; i++) {  
        funcs[i] = tempFunc(i);                                     
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }

8

클로저 구조를 사용하면 여분의 for 루프가 줄어 듭니다. 단일 for 루프에서 수행 할 수 있습니다.

var funcs = [];
for (var i = 0; i < 3; i++) {     
  (funcs[i] = function() {         
    console.log("My value: " + i); 
  })(i);
}

7

우리는 당신이 선언 할 때 실제로 무슨 일이 확인합니다 varlet 하나 하나.

Case1 : 사용var

<script>
   var funcs = [];
   for (var i = 0; i < 3; i++) {
     funcs[i] = function () {
        debugger;
        console.log("My value: " + i);
     };
   }
   console.log(funcs);
</script>

이제 F12 를 눌러 크롬 콘솔 창 을 열고 페이지를 새로 고 칩니다 . 배열 내에서 3 개의 함수를 모두 소비하면 [[Scopes]].Expand 라는 속성이 표시됩니다 . 배열이라는 하나의 배열 객체가 표시됩니다 "Global". 'i'값이 3 인 객체에 선언 된 속성을 찾을 수 있습니다.

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

결론:

  1. 'var'함수 외부를 사용하여 변수를 선언하면 전역 변수가됩니다 (입력 i하거나 window.i콘솔 창에서 확인할 수 있습니다 .3을 반환합니다).
  2. 선언 한 익명 함수는 함수를 호출하지 않으면 함수 내부의 값을 호출하고 확인하지 않습니다.
  3. 함수를 호출하면 객체 console.log("My value: " + i)에서 값을 가져와 Global결과를 표시합니다.

CASE2 : let 사용

이제 교체 'var'와 함께'let'

<script>
    var funcs = [];
    for (let i = 0; i < 3; i++) {
        funcs[i] = function () {
           debugger;
           console.log("My value: " + i);
        };
    }
    console.log(funcs);
</script>

동일한 작업을 수행하십시오. 범위로 이동하십시오. 이제 두 개체 볼 수 "Block""Global". 이제 Block객체를 확장 하면 거기에 'i'가 정의되어 있으며 이상한 점은 모든 함수에 대해 값 i이 다른 경우 값 이 다르다는 것입니다 (0, 1, 2).

여기에 이미지 설명을 입력하십시오

결론:

'let'함수 외부에서도 루프 내부에서 변수를 선언하면 이 변수는 전역 변수가 아니며 Block동일한 변수에서만 사용할 수 있는 수준 변수가됩니다. 그 이유는 i다른 값을 얻습니다. 함수를 호출 할 때 각 함수에 대해

더 가까이 작동하는 방법에 대한 자세한 내용은 멋진 비디오 자습서를 참조하십시오 https://youtu.be/71AtaJpJHw0


4

query-js (*) 와 같은 데이터 목록에 선언적 모듈을 사용할 수 있습니다 . 이러한 상황에서 나는 개인적으로 선언적 접근 방식이 덜 놀랍습니다.

var funcs = Query.range(0,3).each(function(i){
     return  function() {
        console.log("My value: " + i);
    };
});

그런 다음 두 번째 루프를 사용하여 예상 결과를 얻거나 할 수 있습니다

funcs.iterate(function(f){ f(); });

(*) 나는 query-js의 저자이며 그것을 사용하는 것에 편향되어 있으므로 선언적 접근 방식에 대해서만 상기 라이브러리에 대한 권장 사항으로 내 말을하지 마십시오 :)


1
다운 투표에 대한 설명을 듣고 싶습니다. 이 코드는 당면한 문제를 해결합니다. 코드를 개선 할 수있는 방법을 아는 것이 중요합니다
Rune FS

1
무엇입니까 Query.range(0,3)? 이것은이 질문에 대한 태그의 일부가 아닙니다. 또한 타사 라이브러리를 사용하는 경우 설명서 링크를 제공 할 수 있습니다.
jherax

1
@ jherax는 물론 명백한 개선입니다. 의견 주셔서 감사합니다. 나는 이미 링크가 있다고 맹세했을 수 있습니다. 게시물이 무의미하다는 것을 알았습니다. :) 그것을 유지하는 나의 초기 아이디어는 내 자신의 라이브러리를 사용하려고 시도하지 않고 선언적 아이디어를 더 많이 사용했기 때문이었습니다. 그러나 hinsight에서 나는 링크가 있어야한다는 것에 전적으로 동의한다
Rune FS

4

forEach의사 범위를 만드는 자체 폐쇄 기능이있는 함수를 선호합니다 .

var funcs = [];

new Array(3).fill(0).forEach(function (_, i) { // creating a range
    funcs[i] = function() {            
        // now i is safely incapsulated 
        console.log("My value: " + i);
    };
});

for (var j = 0; j < 3; j++) {
    funcs[j](); // 0, 1, 2
}

그것은 다른 언어의 범위보다 더 추해 보이지만 IMHO는 다른 솔루션보다 덜 괴물입니다.


무엇을 선호합니까? 이것은 다른 답변에 대한 답변 인 의견 인 것 같습니다. 실제 질문은 전혀 다루지 않습니다 (함수를 할당하지 않았기 때문에 나중에 호출 할 수 있기 때문에).
Quentin

언급 된 문제와 정확히 관련이 있습니다 : 클로저 문제없이 안전하게 반복하는 방법
Rax Wunter

이제 받아 들인 대답과 크게 다르지 않습니다.
Quentin

허용되는 답변에서 "일부 배열"을 사용하는 것이 좋지만 대답의 범위를 다루는 것은 불행히도 js에 좋은 해결책이 없기 때문에 완전히 다른 것이므로 내 대답은 해결하려고합니다. 좋은 방법으로 문제
Rax Wunter

@Quentin 나는 마이닝하기 전에 솔루션을 조사하는 것이 좋습니다
Rax Wunter

4

그리고 또 다른 해결책 : 다른 루프를 만드는 대신 thisreturn 함수에 바인딩하십시오 .

var funcs = [];

function createFunc(i) {
  return function() {
    console.log('My value: ' + i); //log value of i.
  }.call(this);
}

for (var i = 1; i <= 5; i++) {  //5 functions
  funcs[i] = createFunc(i);     // call createFunc() i=5 times
}

이것을 바인딩 하면 문제도 해결됩니다.


3

많은 솔루션이 정확 해 보이지만 Currying여기에서는 이러한 상황에 맞는 기능적 프로그래밍 디자인 패턴 이라고 합니다. 브라우저에 따라 바인딩보다 3-10 배 빠릅니다.

var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = curryShowValue(i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();                      // and now let's run each one to see
}

function curryShowValue(i) {
  return function showValue() {
    console.log("My value: " + i);
  }
}

다른 브라우저에서 성능 향상을 확인하십시오 .


@TinyGiant 함수가 반환되는 예제는 여전히 성능에 최적화 된 카레입니다. 모든 JavaScript 블로거와 같이 화살표 기능을 뛰어 넘지 않을 것입니다. 그것들은 시원하고 깨끗해 보이지만 미리 정의 된 함수를 사용하는 대신 함수를 인라인으로 작성합니다. 이것은 더운 곳에서 명백한 함정이 될 수 있습니다. 또 다른 문제는 불필요한 바인딩을 실행하여 랩핑 클로저를 생성하기 때문에 단순히 구문 설탕이 아니라는 것입니다.
Pawel

2
미래 독자들에게 경고 : 이 답변은 Currying 이라는 용어를 부정확하게 적용합니다 . "통화는 여러 인수를 인수로 취하는 일련의 함수로 나누는 함수를 분해 할 때 발생합니다." . 이 코드는 아무 것도 수행하지 않습니다. 여기에서 한 일은 허용 된 답변에서 코드를 가져 와서 주변을 이동하고 스타일을 변경하고 이름을 지정한 다음 카레라고 부르는 것입니다.

3

코드가 작동하지 않는 이유는 다음과 같습니다.

Create variable `funcs` and assign it an empty array;  
Loop from 0 up until it is less than 3 and assign it to variable `i`;
    Push to variable `funcs` next function:  
        // Only push (save), but don't execute
        **Write to console current value of variable `i`;**

// First loop has ended, i = 3;

Loop from 0 up until it is less than 3 and assign it to variable `j`;
    Call `j`-th function from variable `funcs`:  
        **Write to console current value of variable `i`;**  
        // Ask yourself NOW! What is the value of i?

이제 문제는 i함수가 호출 될 때 변수의 값은 무엇 입니까? 첫 번째 루프는의 조건으로 만들어지기 때문에 i < 3조건이 거짓이면 즉시 중지되므로 i = 3.

함수가 생성 될 때 코드가 실행되지 않으면 나중에 저장하기 만한다는 것을 이해해야합니다. 나중에 호출 될 때, 인터프리터는이를 실행하고 "현재 값은 i무엇입니까?"

따라서 목표는 먼저 ifunction 의 값 을 저장 한 후에 만 ​​함수를에 저장하는 것 funcs입니다. 예를 들어 다음과 같이 수행 할 수 있습니다.

var funcs = [];
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function(x) {            // and store them in funcs
        console.log("My value: " + x); // each should log its value.
    }.bind(null, i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

이런 식으로 각 함수는 자체 변수를 x가지며 각 반복 x의 값으로 설정합니다 i.

이것은이 문제를 해결하는 여러 가지 방법 중 하나 일뿐입니다.


3
var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = function(param) {          // and store them in funcs
    console.log("My value: " + param); // each should log its value.
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j](j);                      // and now let's run each one to see with j
}

3

var 대신 let (blocked-scope)을 사용하십시오.

var funcs = [];
for (let i = 0; i < 3; i++) {      
  funcs[i] = function() {          
    console.log("My value: " + i); 
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j]();                      
}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.