티스토리 뷰

반응형

본문으로 들어가기 전에 변수의 재선언, 재할당, 변수 참조, 그리고 유효범위(Scope)에 대해서는 아래 페이지에서 참고하면 된다.

 

 

var, let, const 차이점과 유효범위 (Scope)

작업을 할 때 무의식적으로 var로만 변수를 선언하다가, let이나 const라는 변수를 보면 의아할 것이다. 도대체 왜 변수를 구분해서 쓸까? 사실 ES6 이전에는 let과 const가 존재하지 않았다. ES6에서 let

fromnowwon.tistory.com

 

 

 

for 문을 사용할 때, 조건식 영역에서 var을 사용할 때와 let을 사용할 때 결괏값이 다르게 나온다. 그 이유에 대해 알아보자.

 

 

 

 

 

 

 

var, let, const 각각의 변수는 영향을 미칠 수 있는 유효범위(Scope)를 가진다. var은 function scope, let은 block scope를 가진다.

function scope인 변수는 함수 안에서 선언되면 함수 밖에서 접근하지 못한다. 하지만 블록 안에서 선언된 변수는 블록 밖에서 참조가 가능하다.

 

 

 

 

1. var, let, const 비교표

  var let const
재선언 O X X
재할당 O O X
변수 참조 O X X
유효범위 (Scope) function scope block scope block scope

 

 

 

block scope인 변수는 블록 안에서 선언되면 블록 밖에서 참조가 불가하다. if 문이나 for 문 등에서 볼 수 있는 대괄호{}가 블록이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 블록 안에서 선언, 블록 밖에서 참조
for (let i = 0; i < 10; i++) {
    let add1 = 1;
}
 
console.log(add1); // Uncaught ReferenceError: add1 is not defined
 
 
 
// 블록 안에서 선언, 블록 밖에서 참조
if (true) {
    let add1 = 1;
}
 
console.log(add1); // Uncaught ReferenceError: add1 is not defined
cs

 

 

 

 

 

2. for 문에서의 변수 참조

for 문과 var 변수 참조

for 문에서 var로 변수를 선언할 경우 for 문 밖(블록 밖)에서도 변수 참조가 가능하다. 그런데 0, 1, 2, 3, 4가 출력되는 게 아니라 5가 출력된다.

 

1
2
3
4
5
for (var i = 0; i < 5; i++) {
    console.log(i); // 0, 1, 2, 3, 4
}
 
console.log(i); // 5 (조건식에 의해 4까지 돌고 4에 ++한 다음 for 문에서 나오기 때문에)
cs

 

 

 

for 문과 let 변수 참조

for 문에서 let으로 변수를 선언할 경우 for문 밖(블록 밖)에서는 변수 참조가 불가하다. 

 

1
2
3
4
5
for (let i = 0; i < 5; i++) {
    console.log(i); // 0, 1, 2, 3, 4
}
 
console.log(i); // i is not defined
cs

 

 

 

 

 

 

3. for 문 안에서 함수를 사용할 때

var을 사용할 경우

var의 함수 스코프의 특징으로 인해 push 함수 내부에서는 외부에 있는 i를 참조하지 못한다. 따라서 for 문이 모두 돌고 전역 변수 5가 출력되면 그 5를 가지고 push 함수가 실행되는 것이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const array = [];
 
for (var i = 0; i < 5; i++) {
    array.push(function(){
        console.log(i);
    });
}
 
console.log(i); // 5
// for문이 먼저 돌고, 완료되면 for문 밖에서 i는 5로 출력된다.
// 이 때 i는 전역변수가 되기 때문에 push 함수에서 접근이 가능해진다.
// push 함수는 5가 출력되기 전에 i를 참조하지 못하며(함수 스코프), for 문이 완료 된 후 5만 출력되는 것이다.
 
 
array[0](); // 5
array[1](); // 5
array[2](); // 5
array[3](); // 5
array[4](); // 5
cs

 

See the Pen for 문에서 var by cw (@fromnowwon) on CodePen.

 

 

let을 사용할 경우

for 문이 반복될 때마다 새로운 i 값으로 모든 내부 블록을 돈다. 즉, 아래와 같은 순서로 for 문이 돈다.

 

i가 0일 때 그 0이 push 함수까지 적용되고, 함수 내부에서 i를 참조하면 0이 반환된다. (값이 수집된다.)
i가 1일 때 그 1이 push 함수까지 적용되고, 함수 내부에서 i를 참조하면 1이 반환된다. (값이 수집된다.)
i가 1일 때 그 2가 push 함수까지 적용되고, 함수 내부에서 i를 참조하면 2가 반환된다. (값이 수집된다.)
...

 

따라서, array 배열 안에 담아둔 각각의 함수 요소 내부에서 i를 참조하면 각각의 값이 다른 것이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const array = [];
 
for (let i = 0; i < 5; i++) {
    array.push(function(){
        console.log(i);
    });
}
 
 
array[0](); // 0
array[1](); // 1
array[2](); // 2
array[3](); // 3
array[4](); // 4
cs

 

for 문에서 let을 사용할 경우 블록 스코프 변수의 성질 때문에, for 문 내부 블록도 반복된다. 그때마다 값이 수집된다.

push라는 함수가 블록{} 안에서 실행되므로, let 변수 값에 접근 가능한 것이다. 따라서 블록마다 다른 변숫값을 출력할 수 있는 것이다.

 

 

See the Pen for 문에서 let by cw (@fromnowwon) on CodePen.

 

 

 

 

4. for 문 안에서 setTimeout() 함수를 사용할 때

var을 사용할 경우

우선 setTImeout 함수의 구문을 살펴보자.

 

setTimeout(콜백 함수, 시간)

 

콜백 함수는 지정한 시간이 되면 그때 실행되는 함수이다.

for 문이 실행될 때, 콜백 함수 외부에 있는 시간 영역 (1000 * (i + 1))이 같이 실행된다.

 

1
2
3
4
5
6
7
for (var i = 0; i < 5; i++) {
    setTimeout(() => {
        console.log(i);
    }, 1000 * (i + 1));
}
 
// ❺ 5
cs

 

i=0, 콜백함수 0 대기 중, 1000초 뒤로 지정됨

i=1, 콜백 함수 1 대기 중, 2000초 뒤로 지정됨

i=2, 콜백 함수 2 대기 중, 3000초 뒤로 지정됨

i=3, 콜백 함수 3 대기 중, 4000초 뒤로 지정됨

i=4, 콜백 함수 4 대기 중, 5000초 뒤로 지정됨

i=5가 되어 반복문 종료

(위 작업이 1초 전에 끝남)

1초 뒤, 콜백 함수 0 실행하며 i를 참조 => 5 출력  

2초 뒤, 콜백함수 1 실행하며 i를 참조 => 5 출력  

3초 뒤, 콜백함수 2 실행하며 i를 참조 => 5 출력  

4초 뒤, 콜백함수 3 실행하며 i를 참조 => 5 출력  

5초 뒤, 콜백함수 4 실행하며 i를 참조 => 5 출력  

 

 

1초부터 5초까지 매 초마다 5가 출력된다.

 

 

 

 

let을 사용할 경우

let을 사용할 경우 반복문이 한 번 돌 때마다 i 변수를 참조하여 모든 내부 블록이 같이 돌면서 값을 수집한다. 그 수집한 값을 지정한 시간에 출력한다. 따라서 아래와 같은 결과가 나온다.

 

1
2
3
4
5
6
7
8
9
10
11
for (let i = 0; i < 5; i++) {
    setTimeout(() => {
        console.log(i);
    }, 1000 * (i + 1));
}
 
// 0
// 1
// 2
// 3
// 4
cs

 

 

 

결론적으로 for 문을 사용할 때 우리가 원하는 값을 얻으려면 블록 스코프인 let을 사용하여야 한다.

 

 

 

 

 

반응형
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31