본문 바로가기

Languages/JavaScript

[JavaScript] 반복문 while, for, for in, for of , for each 총정리, 비교, 차이점 완전정복

728x90

   목차 

1. while (문법, 예시)

2. do...while (문법, 예시)

3. for (문법, 예시)

4. for...in (문법, 특징, 용도, 배열x)

5. fot...of (문법, 특징, 예시, for...in과 차이점)

6. forEach (문법, 특징, 예시, for을 forEach로)

7. 모든 반복문 종류 차이점 알아보기

8. 결론 

 

 

 

자바스크립트에서는 반복문이 정말 많이 쓰이기 때문에 모르면 안되는 개념이다.
그런데 비슷하게 생긴(for, while 등 단어가 들어간) 반복문 종류가 많아서 정말 혼란 그 자체였다.
그래서 이 모든걸 다 총망라해서 종류와 차이점까지 전부 정리를 해야겠다고 결심했다.
MDN, 모던JS인포, 구글링 등등 정말 많은 자료를 보면서 총정리를 해보았다.
무려 이틀 전부를 소요...(매우 지침)

힘들어서 그런가 서론이 길었다...ㅎ
여하튼 이 글을 보면 반복문의 종류, 실행과정, 차이점 등등을 이해하는 데 많은 도움이 될 것이다.



 


 

 

 

 

 

 while 

 

조건문이 참일 때 실행되는 반복문이다. 조건은 문장안이 실행되기 전에 참, 거짓을 판단한다.

 

 

 while 반복문의 문법 

 

while (조건) {
  // 코드 ('반복문 본문(body)'이라 불림)
}

조건이 true이면 '반복문 본문'이 실행된다.

 

 

 while 반복문의 예시 1 

 

let i = 0;
while (i < 3) { // 0, 1, 2가 출력된다.
  alert( i );
  i++;
}

 

< 과정 >

- 변수 i는 값이 0이다.
- i가 0이므로 (i < 3) 조건이 true가 된다.
- 반복문 본문이 실행돼서 alert창에 '0'이 뜬다. 그리고 i가 1로 증가한다. (변수 i에 1이 재할당된다.)
- i가 1이므로 (i < 3) 조건이 true가 된다.
- 반복문 본문이 실행돼서 alert창에 '1'이 뜬다. 그리고 i가 2로 증가한다. (변수 i에 2가 재할당된다.)
-  i가 2이므로 (i < 3) 조건이 true가 된다.
- 반복문 본문이 실행돼서 alert창에 '2'가 뜬다. 그리고 i가 3으로 증가한다. (변수 i에 3이 재할당된다.)
- i가 3이므로 (i < 3) 조건이 false가 되고 반복문이 종료된다.

 

 

 

 while 반복문의 예시 2 

 

* 참고) while (i != 0)을 짧게 줄여 while (i)라고 표현한다.

let i = 3;
while (i) { // i가 0이 되면 조건이 falsy가 되므로 반복문이 멈춘다.
  alert( i );
  i--;
}

 

< 과정 >

- 변수 i는 값이 3이다.
- i가 3이므로 (i !=0) 조건이 true가 된다.
- 반복문 본문이 실행돼서 alert창에 '3'이 뜬다. 그리고 i가 2로 감소한다. (변수 i에 2가 재할당된다.)
- i가 2이므로 (i !=0) 조건이 true가 된다.
- 반복문 본문이 실행돼서 alert창에 '2'이 뜬다. 그리고 i가 1로 감소한다. (변수 i에 1이 재할당된다.)
- i가 1이므로 (i !=0) 조건이 true가 된다.
- 반복문 본문이 실행돼서 alert창에 '1'이 뜬다. 그리고 i가 0으로 증가한다. (변수 i에 0이 재할당된다.)
- i가 0이므로 (i !=0) 조건이 true가 된다.

 

 


 

 

 do...while 

 

테스트 조건이 거짓으로 평가될 때까지 지정된 구문을 실행하는 루프를 만든다.. 단, 구문이 실행된 뒤에 테스트 조건이 평가됨으로 구문은 무조건 한 번은 실행된다.

 

 

 do...while 반복문의 문법   

 

do {
  // 반복문 본문
} while (조건);

 

본문이 먼저 실행되고, 조건을 확인 한 후에 조건이 true인 동안에 본문이 계속 실행된다.
조건이 truthy 인지 아닌지에 상관없이, 본문을 최소한 한 번이라도 실행하고 싶을 때만 사용해야한다.
대다수의 상황에서는 do..while보다 while 반복문이 적합하다.

 

 

 

 do...while 반복문의 예시 

 

let i = 0;
do {
  alert( i );
  i++;
} while (i < 3);

 

< 과정 >

- 변수 i는 값이 0이다.
- 반복문 본문이 실행돼서 alert창에 '0'이 뜬다. 그리고 i가 1로 증가한다. (변수 i에 1이 재할당된다.)
- i가 1이므로 (i < 3) 조건이 true가 된다.
- 반복문 본문이 실행돼서 alert창에 '1'이 뜬다. 그리고 i가 2로 증가한다. (변수 i에 2가 재할당된다.)
- i가 2이므로 (i < 3) 조건이 true가 된다.
- 반복문 본문이 실행돼서 alert창에 '2'가 뜬다. 그리고 i가 3으로 증가한다. (변수 i에 3이 재할당된다.)
- i가 3이므로 (i < 3) 조건이 false가 되고 반복문이 종료된다.

 

 


 

 

 for 

 

괄호로 감싸고 세미콜론으로 구분한 세 개의 선택식과, 반복을 수행할 문(주로 블럭문)으로 이루어져 있다.

 

 

 for 반복문의 문법 

 

for (begin; condition; step) {
  // ... 반복문 본문 (body) ...
}

 

for (let i = 0; i < 3; i++) { // 0, 1, 2가 출력된다.
  alert(i);
}

 

begin i = 0  반복문에 진입할 때 단 한번 실행된다.
condition i < 3 반복마다 해당 조건이 확인된다. false가 되면 반복문을 멈춘다.
body alert(i) condition(조건)이 true일 동안 계속해서 실행된다. 
step i++ 각 반복의 body가 실행된 이후에 실행된다.

 

begin을 실행함
→ (condition이 truthy이면 → body를 실행한 후, step을 실행함)
→ (condition이 truthy이면 → body를 실행한 후, step을 실행함)
→ (condition이 truthy이면 → body를 실행한 후, step을 실행함)
→ ...

 

* 주의) 변수 선언 시 const를 사용하면 값을 변경할 수 없으므로, 에러가 발생하게된다.

 

 

 

 for 반복문의 예시 1 

 

for (let i = 0; i < 3; i++) { // 0, 1, 2가 출력된다.
  alert(i);
}

 

< 과정 >

- 변수 i는 값이 0이다. (begin 실행)
- i가 0이므로 (i < 3) 조건이 true가 된다. (condition이 truthy이면,)
- 반복문 본문이 실행돼서 alert창에 '0'이 뜨고, i가 1로 증가한다. (body를 실행 한 후, step을 실행함)
- i가 1이므로 (i < 3) 조건이 true가 된다.
- 반복문 본문이 실행돼서 alert창에 '1'이 뜬다. 그리고 i가 2로 증가한다. 
-  i가 2이므로 (i < 3) 조건이 true가 된다.
- 반복문 본문이 실행돼서 alert창에 '2'가 뜬다. 그리고 i가 3으로 증가한다. 
- i가 3이므로 (i < 3) 조건이 false가 되고 반복문이 종료된다.

 

 

* 참고) 변수 i를 반복문 안에서 선언 (인라인 변수 선언) 하면, 반복문 안에서만 접근 할 수 있다.

for (let i = 0; i < 3; i++) {
  alert(i); // 0, 1, 2
}

alert(i); // Error: i is not defined  // 반복문 밖에서는 변수에 접근 불가

 

 

인라인 변수 선언 대신, 정의되어있는 변수(외부 변수)를 사용하면, 반복문 밖에서도 접근 가능하다.

let i = 0;

for (i = 0; i < 3; i++) { // 기존에 정의된 변수 사용
  alert(i); // 0, 1, 2
}

alert(i); // 3, 반복문 밖에서 선언한 변수이므로 사용할 수 있음

 

 

 

 for 반복문의 예시 2 

: for문의 구성요소를 생략하기 (주의사항: 세미콜론(;)을 꼭 넣어줘야한다! 안넣으면 에러 뜸)

 

(1) begin (i=0) 생략하기 

let i = 0;  // i를 선언하고 값을 할당함

for (; i < 3; i++) {  // 'begin'이 필요하지 않기 때문에 생략함
  alert( i ); // 0, 1, 2
}

 

 

(2) step (i++) 생략하기 

let i = 0;

for (; i < 3;) {
  alert( i++ );
}

 

 

(3) 전부 다 생략하기 (무한반복문 → 주의사항: 두개의 세미콜론(;;)을 꼭 넣어줘야한다! 하나라도 없으면 에러 뜸 )

for (;;) {
  // 끊임 없이 본문이 실행된다.
}

 

 


 

 

 for...in 

 

상속된 열거 가능한 속성들을 포함하여 객체에서 문자열로 키가 지정된 모든 열거 가능한 속성에 대해 반복한다.

 

 

 for...in 반복문의 문법 

 

for (const variable in object) {
  statement
}

 

let user = {
name: "John",
age: 30,
isAdmin: true
};

for (const key in user) {
// 키
alert( key );  // name, age, isAdmin
// 키에 해당하는 값
alert( user[key] ); // John, 30, true
}

 

variable key 매번 반복마다 다른 속성(name, age, isAdmin)이 변수(key)로 지정된다.
object user 반복작업을 수행할 객체로 열거형 속성을 가지고 있는 객체

 

* 참고) 반복 변수명은 자유롭게 정할 수 있다. 'for (let prop in obj)'같이 key 말고 다른 변수명을 사용해도된다.

 

 

 

 for...in 반복문의 특징 

 

- 객체의 반복을 위해 만들어졌다. (객체에 주로 쓰인다.) 
- 배열의 반복을 위해서는 추천되지않는다. (이유는 하단에 서술)
- length 연산자 사용 불가 
- key를 순회해서 return함  (key값만 가져올 수 있다.)
- value 값은 string이라 연산이 불가능(접근 불가능)
- 객체의 열거 가능한 '속성들'을 순회(반복)한다. (객체의 키와 값에 접근)
- 여기서 열거 가능하다는 것은 enumerable 하다는 것을 말한다.
- Object.getOwnPropertyDescriptor() 함수를 사용하면, 객체의 속성에 대한 모든 설명을 확인할 수 있다.

 

user 객체의 name 속성을 살펴보면 enumerable이 true임을 확인할 수 있다.

 

 

 

 

 for...in 반복문을 사용하는 이유 (용도) 

 

- 객체의 속성을 확인(콘솔이나 다른 방법으로 출력)할 수 있기 때문에 실질적으로 디버깅을 위해 사용될 수 있다.
키: 값 쌍이 선호되는 데이터의 경우(속성이 "key"의 역할을 함) 특정 값을 가진 키가 있는지 확인하려는 경우에 for...in을 사용할 수 있다.
- 참고로 정확한 키 값을 얻어내려면 hasOwnProperty를 써야한다. ( 자세한 내용은 "hasOwnProperty" 게시글 참고 https://dev-ini.tistory.com/54 )

 

 

 

 배열에 for...in이 적합하지 않은 이유 

 

1. 순서를 보장하지 못함 
- for...in에서 반복되는 순서는 구현에 따라 다르기 때문에, 배열의 반복이 일관된 순서로 요소를 방문하지 못할 수도 있다.
- 즉, 특정 순서에 따라 인덱스를 반환하는 것을 보장할 수 없다. 
- 따라서 방문의 순서가 중요한 배열의 반복시에는 숫자 인덱스를 사용할 수 있는 for 반복문, forEach반복문, for...of 반복문을 사용하는 것이 좋다.

 

2. 필요 없는 프로퍼티도 다 순회해버림
- for...in은 정수가 아닌 이름을 가진 속성, 상속된 모든 열거 가능한 속성들을 반환한다.
- 즉, 모든 프로퍼티를 대상으로 순회하기 때문에, 키가 숫자가 아닌 속성도 순회 대상에 포함된다.
- 해당 Object의 요소 뿐만 아니라 prototype chain으로 상속 받은 속성들도 함께 순회한다.
- 특히, 객체 중 '유사 배열 객체'에는 (배열과는 달리) 키가 숫자형이 아닌 프로퍼티와 메서드가 있을 수 있는데, 유사 배열 객체와 for..in을 함께 사용하면 이 모든 것을 대상으로 순회가 이뤄진다. 따라서 ‘필요 없는’ 프로퍼티들이 문제를 일으킬 가능성이 생기게된다.



3. 배열에 사용하면 느려진다.
- for..in 반복문은 배열이 아니라 객체와 함께 사용할 때 최적화되어 있어서 배열에 사용하면 객체에 사용하는 것 대비 10~100배 정도 느리다.

 

객체에 대해 더 알고싶다면, https://dev-ini.tistory.com/39 "객체" 게시글을, 
배열에 대해 더 알고싶다면, https://dev-ini.tistory.com/51 "배열" 게시글을 참고하세요!

 

 


 

 

 for...of 

 

 반복가능한 객체 (Array(배열)MapSetString(문자열)TypedArrayarguments 객체 등을 포함)에 대해서 반복하고, 각 개별 속성값에 대해 실행되는 문이 있는 사용자 정의 반복 후크를 호출하는 루프를 생성한다.


 

 for...of 반복문의 문법 

 

  for (variable of iterable) { 
      statement  // 반복 동작 부분
    }

 

variable 각 반복에 서로 다른 속성값이 variable에 할당된다.
iterable 반복되는 열거가능(enumerable)한 속성이 있는 객체

 

 

 

 for...of 반복문의 특징 

 

- 배열의 반복에 주로 쓰인다.
- Iterable object이지만, prototype chain에 의한 Iterable은 대상에서 제외한다. 
- [Symbol.iterator] 속성을 가지는 collection만 대상으로 한다. 

 

배열을 콘솔에 찍고 성분을 열어보면 [Symbol.iterator] 속성이 있음을 확인할 수 있다.

 

 

 

 

 for...of 반복문의 예시 1 

Array-배열에 대해 반복

let iterable = [10, 20, 30];

for (const value of iterable) {
  console.log(value);
}
// 10
// 20
// 30

 

 

 

 for...of 반복문의 예시 2 

String-문자열에 대해 반복

let iterable = "boo";

for (let value of iterable) {
  console.log(value);
}
// "b"
// "o"
// "o"

 

 

 

 for...of 반복문의 예시 3 

map에 대해 반복

let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);

for (let entry of iterable) {
  console.log(entry);
}
// [a, 1]
// [b, 2]
// [c, 3]

for (let [key, value] of iterable) {
  console.log(value);
}
// 1
// 2
// 3

 

map에 대해 잘 모르신다면 https://dev-ini.tistory.com/55 "map" 게시글을 참고하세요!

 

 

 

 for...of와 for...in의 차이점 

 

  for...in for of
 차이점 - 객체의 모든 열거가능한 속성에 대해 반복

객체(Object)의 key를 순회
- [Symbol.iterator] 속성을 가지는 것들만을 대상으로 한다. 따라서 객체(iterable하지 않은 일반 Object)에 for...of를 사용하면 에러가 발생한다.

 iterable객체의 value를 순회

 

 

 


 

 

 forEach 

 

forEach 메서드는 주어진 함수를 배열 요소 각각에 대해 실행한다.

 

 

 forEach의 문법 

 

arr.forEach(function(item, index, array) {
  // 요소에 무언가를 할 수 있다.
});



// 위를 화살표 함수를 써서 표현하면 아래와 같다. (주로 이렇게 씀)

arr.forEach((item, index, array) => {
  // 요소에 무언가를 할 수 있다.
});

 

["짱구", "철수", "유리"].forEach((item, index, array) => {
 console.log(`${item}는 ${array} 배열 안에 인덱스 ${index}에 있다.`);
});

// 짱구는 짱구,철수,유리 배열 안에 인덱스 0에 있다.
// 철수는 짱구,철수,유리 배열 안에 인덱스 1에 있다.
// 유리는 짱구,철수,유리 배열 안에 인덱스 2에 있다.

 

item 짱구, 철수, 유리 현재 순회중인 요소
index 0, 1, ,2 현재 순회중인 요소의 index
array ["짱구", "철수", "유리"] 배열 객체 

 

 

 

 forEach 반복문의 특징 

 

- 함수를 넘겨서 사용할 때 forEach가 사용된다. (콜백함수, 즉, 인자를 함수로 받음)

- forEach문은 인덱스를 접근할 수 있는 방법이 존재한다.

- 또 다른 차이점은 forEach문 첫 번째 인수인 현재 배열의 요소는 로컬 범위(Local Scope)이다. 

- 외부와 내부에 선언된 값은 저장소가 다르다.

- forEach문 외부에서 선언된 변수의 값은 변경되지 않는다.

 

 

 

 forEach의 예시1 

item, index, array를 인자로 받기

 

 

 

 

 

 forEach의 예시2 

item, index를 인자로 받기

 

 

 

 

 

 forEach의 예시3 

item을 인자로 받기

 

 

 

 

 

 forEach의 예시4 

map에 대해 반복

 

 

 

 

 

 for 반복문을 forEach로 바꾸기 

 

아래는 for 반복문이다.

 

 

 

 

 

위의 for반복문을 forEach로 바꾸면 다음과 같다. 

 

 

 

push 메서드에 대해 모르신다면 https://dev-ini.tistory.com/51 "배열의 메서드" 게시글을 참고하세요!

 

 

 

 

 앞서 말한 모든 반복문 종류의 차이점을 알아보자! 

 

  for for...in forEach for...of
문법 for (begin; condition; step) {
  // ... 반복문 본문 ...
}
for (const variable in object) {
 // ... 반복문 본문 ...
}

arr.forEach((item, index, array) => {
  // 요소를 무언가를 할 수 있다
});
  for (variable of iterable) { 
      // ... 반복문 본문 ...
    }
설명 - ES1 시절부터 있덨던 가장 근본적인 방법


- 초기값부터 시작해서 조건식에 부합하면 멈추지 않고 계속해서 순회한다. (배열의 길이만큼 순회)


- 멈추고 싶다면 'break;'를 사용 가능

- 단순히 배열을 순회하려는 목적에 비해서 많은 작업이 필요함. (추가적인 변수 선언 및, 증가, 길이 계산 등)
→ 따라서 코드의 길이가 길어지는 문제점이 있다.

- 반복 횟수를 명확히 알고 있을 때 주로 사용 

- 인덱스만 접근할 필요가 있을 때 사용 

- forEach랑 for...of가 추가 된 이후로는 잘 사용이 안됨

- 동기 방식이라서 오류가 나면 오류가 난 위치 이후의 작업이 동작하지 않고 멈춰버린다.



- ES1 시절부터 있덨던 가장 근본적인 방법

객체(Object)의 key를 순회 (key값만 가져올 수 있음, value값 접근 불가능)

- 객체의 모든 열거가능한 프로퍼티를 대상으로 순회하기 때문에, key가 "숫자가 아닌 속성"도 순회 대상에 포함된다.

 
- 해당 Object의 요소 뿐만 아니라 prototype chain으로 상속 받은 속성들도 함께 순회한다.


- 배열에는 쓰지말자


- for...in은 for...of보다 처리 속도가 훨씬 느리다.



















- ES6에서 새로 추가된 방법

- 반복문 기능을 지닌 배열 메서드이다. (반복문이 아니다.)

- 즉,  배열(Array)을 순회하는 데 사용되는 Array의 메소드이다.


- Array의 prototype을 상속받은 객체만 사용할 수 있는 함수이다.

- 배열의 각 요소에 대해 콜백(callback)을 실행한다. (즉, 인자를 함수로 받는다.)


- 배열의 요소를 순회하며, 모두 순회하면 실행을 멈춘다. 

- 'break'를 사용이 불가능하다. (사용하고 싶으면 for문 사용)

- 'await'을 루프 내부에 쓸 수 없다. 

- 중간에 루프 탈출하려면 'some'을 사용하면 되긴한데 다른 사람이 이해하기 어려워짐

- for문보다 수행 속도가 빠르다. 

- 비동기 방식이라서 오류가 나도 멈추지 않고 동작한다. 



- ES6에 나온 가장 최신 기능

 iterable객체의 value 순회를 도와주는 반복문이다. 

- 때문에 Array만 반복할 수 있는 forEach와 다르게, 내부에 [Symbol.iterator]를 가진 객체라면 어떤 객체든 모두 순회할 수 있다.

- [Symbol.iterator] 속성을 가지는 것들만을 대상으로 한기 때문에, 객체(iterable하지 않은 일반 Object)에 for...of를 사용하면 에러가 발생한다. (일반 객체에는 for...in 사용)

-  key만 접근하거나, 혹은 key와 value 모두 접근하거나 하는 것이 모두 가능

- 'break', 'continue', 'yield' 사용 가능

- 'await' 사용 가능 



















 

* 참고)  while과 do...while은?

for문은 배열에 많이 사용되지만, while문은 조건에 따라 반복횟수를 결정해야할 때 주로 사용된다. 
무한반복문을 사용하는 경우에는 조건을 "true"라고만 설정하면 된다.
정리하자면, while문은 특정 조건에 만족할 때까지 반복해야하는 경우나 무한루프를 만들 때 쓰인다. 

 

do...while
조건이 truthy 인지 아닌지에 상관없이, 본문을 최소한 한 번이라도 실행하고 싶을 때만 사용해야한다.
대다수의 상황에서는 do..while보다 while 반복문이 적합하다.

 

 

 

 결론 


- while ▶ 조건에 따라 반복횟수를 결정해야할 때 사용

- do...while조건이 truthy 인지 아닌지에 상관없이, 본문을 최소한 한 번이라도 실행하고 싶을 때만 사용

- for ▶ 인덱스에만 접근해야할 때 사용

- for...in ▶ 객체(Object)의 key에만 접근해야할 때 사용

- for...of ▶ 가장 최신 기술 답게 제일 할 수 있는게 많아서 iterable객체 순회 시에 적절히 사용 ([Symbol.iterator]를 가진 객체라면 어떤 객체든 모두 순회할 수 있고, key, value 다 접근 가능하고, 'break', 'continue', 'yield' 'await' 전부 사용 가능)
참고) index와 value를 받을 때는 Array.entries와 같이 사용

- forEach ▶ 배열(Array) 순회할 때 사용 (함수 넘겨서 사용할 때)

- 여담으로 프론트앤드 개발에서는 for...of 보다는 map이나 reduce를 많이 사용해서 해결한다고 한다. (함수형이고 읽기도 쉽다.)

 

- 배열의 경우 for..of문 또는 forEach문을 사용
- 객체의 경우 for..in문 또는 Object.메서드 사용
- 배열을 반복문으로 순회하여 값과 인덱스에 접근해야 하는 경우 for 또는 forEach문을 사용

 

 

반복문 빠져나오기와 다음 반복으로 넘어가기 (break, continue, label)는 https://dev-ini.tistory.com/53 게시글을 참고하세요!

 

 

 

 

 

참고자료


https://ko.javascript.info/while-for

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/while

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/do...while

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/for

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/for...in

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/for...of

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

https://ko.javascript.info/array

https://ko.javascript.info/array-methods

https://ko.javascript.info/object

https://velog.io/@yangareum1818/JS-%EB%B0%98%EB%B3%B5%EB%AC%B8%EC%9D%98-%EC%A2%85%EB%A5%98-%EC%B4%9D-%EC%A0%95%EB%A6%AC

https://yceffort.kr/2021/06/best-solution-for-looping-over-array

728x90