for (var i = 0; i < 5; ++i) {
setTimeout(
function () {
console.log('variable-' + i);
}, 100
);
};
음 for문 내 비동기 함수가 실행되고 익명함수를 콜백 받고...
0~ 4가 출력되지 않을까 생각했다...
일단 답은 틀렸다. 사실 나는 이 코드를 보고 그냥 for문 돌리는거니까 0~4가 출력되겠지 안일하게 생각했었는데 어떻게 코드가 흘러가는지 알아보자.
for (var i = 0; i < 5; ++i) {
setTimeout(
function () {
console.log('variable-' + i);
}, 100
);
};
// 결과: variable-5
// variable-5
// variable-5
// variable-5
// variable-5
실행순서
- 전역 컨텍스트가 생성되면서 전역변수
i = 0
으로 선언과 동시에 초기화가 된다.for
문이 실행되고 실행될때마다 for문 컨텍스트가 생성된다.- 반복문 내부의
settimeout
함수가 실행된다.settimeout
함수는비동기적
으로 실행되어 브라우저 내부의 멀티스레드인WebAPIs
에 의해 처리가 된다.for문
이 실행된다. 5번settimeout
함수 내부에서 사용된 익명함수는클로저
로써 상위 스코프에 접근이 가능하다.- 즉
for문
에서 정의된i
변수에 접근이 가능하다.- 이후
settimeout
실행컨텍스트가 생성되는데 이미 for문은 종료되어있다.for
문이 종료되었을때i
변수의 값은 5가 된다.i = 5
;- 이와같은 방법으로 5번 실행되고
variable-5
가 5번 한번에 출력된다.var
의 경우에는 반복문이 실행될때마다i
변수의 값이 변경되지만
for (let i = 0; i < 5; ++i) {
setTimeout(
function () {
console.log('variable-' + i);
}, 100
);
};
// 결과: variable-0
// variable-1
// variable-2
// variable-3
// variable-4
var
를let
으로 변경하면let
의 경우에는 반복문이 실행될때마다 새로운 스코프를 생성하기 때문에i
의 값이 독립적으로 유지되고 0~4까지의 값이 출력된다.
var
와 let
의 차이점에 대해
var
는 함수 스코프의 적용을 받는다.let
은 블록 스코프의 적용을 받는다.let
의 경우에는 for
문 스코프의 적용을 받는다.for
문이 실행될 때마다 새로운 변수 i=0
, i=1
, i=2
... 각각의 스코프에 적용을 받이 때문에 다른 값을 출력한다.let
사용 외에 다른 해결방법은 없는가?
위의 1번 내용과 같이 var
는 함수 스코프의 적용을 받는다고 했다.
for
문을 함수로 감싸면 어떨까?
function forLoop() {
for (var i = 0; i < 5; ++i) {
setTimeout(
function () {
console.log('variable-' + i);
}, 100
);
};
}
forLoop(); // 결과: variable-5
// variable-5
// variable-5
// variable-5
// variable-5
아 상관없다. 어짜피 for
문 내에서만 사용하니까.
그러면 for
문 내에 settimeout
함수를 콜백함수로 적용시켜보자.
for (var i = 0; i < 5; ++i) {
const forLoop = function(j) {
setTimeout(function () {
console.log('variable-' + j);
}, 100);
}
forLoop(i);
}
console.log(i);
// 결과: 5
// variable-0
// variable-1
// variable-2
// variable-3
// variable-4
값이 0~4로 변경되었다!
변수값을 고정시키기 위해 j
를 끌어다가 사용했다.
전역변수 i
의 값은 5다.
let
과 const
를 쓰자.