반복문 3가지 : for 문, while 문, do ... while 문
for 문
for (변수선언문;반복조건식;변수변형식){
반복 조건식이 참인 경우 실행될 문;
}
반복조건식이 참이라면, 코드블록을 실행한 뒤 변수변형식에 따라 선언된 변수를 변형시키는 제어문이다.
users = ['가영','나영','다영','라영','마영']
for (i = 0; i<users.length; i++){
console.log(users[i]);
}
만약 아래와 같이 코드를 작성하면 무한 루프가 된다.
for (;;) {...}
예를 들어 아래와 같은 코드를 실행하면...
for(;;){
console.log("악성코드에 감염된다면 이렇게 되겠죠?");
}
무한 루프를 끊어내기 위해서는 Ctrl+c 키를 눌러서 exit 해주거나 콘솔을 꺼버리자.
while 문
let count = 0
while (count <= 10) {
console.log(count);
count++;
}
for 문과 달리 while 문은 변수선언문이 while 문 밖에 있다는 점, 그리고 명시적으로 변수변형식이 코드 블럭 내부에 존재한다는 점이 차이가 있다.
책에서는 으레 for 문은 반복 횟수가 명확할 때 주로 사용하고, while 문은 반복 횟수가 불명확할 때 주로 사용한다고 설명되어 있지만, 솔직히 잘 와닿지는 않는다.. 나의 경우에는 변수를 꼭 for 안에서만 굴릴 필요가 없거나 굴려서는 안되는 경우에 주로 쓰는 것 같다.
node에 직접 코드를 찍어보면 10이 두 번 연달아 나오는 것을 볼 수 있다. 이는 반복문이 제대로 작동하지 않은 것이 아니다. while 문의 반환값으로 마지막 값이 콘솔에 찍힌 것 뿐이다.
for 문의 콘솔과 비교해본다면, for 문에서는 undefined로 나왔던 부분에 while 문에서는 마지막 값이 출력된 것을 알 수 있다. 이제 while 문 예제와 같은 내용을 for 문으로도 찍어보자.
for (let i = 0; i<=10;i++){
console.log(i);
}
보다시피 while 문에서 '10'이 출력된 자리에 for 문의 경우 undefined가 출력되었다. 이는 반환값의 차이일 뿐이다.
while 문은 조건식이 true로 평가되면 무한루프가 된다.
while(true){
console.log("악성코드 감염!!")
}
while 문을 응용하여, 항상 실행되게 만든 뒤, 특정 조건에서 탈출하도록 만들 수 있다. for 문이 아니라 while 문을 써야할 상황이 온다면 아마 이 경우일 가능성이 꽤 있다.
let count = 0;
while (true) {
console.log(count);
if (count === 10) break;
count++;
}
do ... while 문
for 문, while 문과 다르게 do ... while 문은 코드블럭을 먼저 실행한 후 조건식을 평가한다는 점이 다르다.
let count = 0;
do {
console.log(count);
count++;
} while (count <= 10);
먼저 실행한 뒤 평가하는 로직을 보려면 아래 예제가 더 유용하다.
let count = 11;
do {
console.log(count);
count++;
} while (count <= 10);
count가 이미 11임에도 do ... while 문이었기 때문에 11이 출력된 뒤 종료되었다. (두 번째로 출력된 11은 undefined 대신에 출력된 반환값일 뿐이다)
반복문을 대체할 수 있는 기능 3가지 : forEach 메서드, for ... in 객체, for ... of 이터러블
Array.prototype.forEach
Array.prototype.forEach 메서드는 배열 고차 함수$^{Higher-Order}$ $^{Function}$의 일종으로, 함수형 프로그래밍을 위해 도입된 메서드이다.
고차 함수란, 함수를 인수로 전달받거나 함수를 반환하는 함수를 말한다.
반복문과 조건문의 사용은 로직의 흐름을 이해하기 어렵게 하고, 변수에 의존한 프로그래밍은 오류 발생의 근본적 원인이 될 가능성이 크기 때문에 이를 지양하는 패러다임이 바로 함수형 프로그래밍인데, 고차 함수는 이러한 함수형 프로그래밍에 기반을 두고 있다.
따라서 위에서 살펴본 3가지 반복문 보다는 forEach 메서드를 비롯한 반복문을 대체할 수 있는 기능을 보다 적극적으로 활용하는 것이 권장된다.
for 문을 이용한 제곱수 구하기
const numbers = [1,2,3,4,5]
const squaredNumbers = []
for (let i = 0; i < numbers.length; i++){
squaredNumbers.push(numbers[i]**2);
}
console.log(squaredNumbers);
for 문 대신 forEach를 이용한 제곱수 구하기
const numbers = [1,2,3,4,5]
const squaredNumbers = []
numbers.forEach(number => squaredNumbers.push(number**2));
console.log(squaredNumbers);
forEach의 의미를 알기만 한다면, 훨씬 가독성이 좋아진 것을 볼 수 있다.
사실 for 문의 90% 이상은 어떤 배열의 각 항에 대해 순차적으로 코드블럭을 시행하는 경우이다.
따라서, 이렇게 정형화된 for 문의 쓰임을 고차 함수로서 단순화한 버전이 forEach 메서드인 셈.
그렇기 때문에, forEach 메서드는 중간에 멈출 수 없고, 자신을 호출한 배열의 모든 요소에 대해 반복적으로 콜백 함수를 호출한다. 다시 말하지만, forEach 메서드는 배열의 모든 요소에 코드블럭을 실행하는 정형화된 for 문의 쓰임을 대체하기 위해 탄생한 메서드이기 때문이다.
참고로 forEach 메서드는 콜백 함수를 호출할 때, 3개의 인수를 전달하며, 순서대로 배열의 요소, 요소의 인덱스, 메서드를 호출한 배열(this)이다.
이 포스팅은 for 문을 대체하기 위한 방법을 간략히(?) 소개하는 자리이므로 forEach에 관해서는 이 정도로 정리하고, 더 깊은 내용은 다음에 배열의 고차 함수를 다룰 때 살펴보기로 한다.
for ... in 문
for (변수선언문 in 객체) {...}
객체의 모든 프로퍼티 키에 대해 반복적으로 코드블럭을 실행할 때 사용한다.
즉, 변수선언문에 의해 선언된 변수에는 객체의 프로퍼티 키가 순차적으로 할당된다.
const user = {
name : '가영',
sex : '남성',
age : 20
}
for (const key in user) {
console.log(`${key} : ${user[key]}`);
}
const key에 의해 코드블럭상의 key에는 user 객체의 프로퍼티 키가 순차적으로 할당될 것이다.
따라서, 순차적으로 name, sex, age가 할당될 것이다.
for ... in 문도 깊게 들어가면 할 얘기가 많지만, 이번 포스팅의 성격상 더 이상의 깊은 이야기는 생략한다..
for ... of 문
for (변수선언문 of 이터러블){...}
이터러블은 이터러블 프로토콜을 준수한 객체를 말한다(...) 동어반복이 아니다. 이터러블 프로토콜을 이야기하자면 또 내용이 길어질 것이므로 이번 포스팅에서는 생략한다..
그래도 간단히만 언급하자면, ES6에서는 이터레이션 프로토콜 $^{iteration}$ $^{protocol}$을 도입하였는데, 이는 순회 가능한$^{iterable}$ 자료구조를 만들기 위해 ECMAScript 사양에 정의하여 약속한 규칙이다. 이러한 이터레이션 프로토콜 중 하나가 이터러블 프로토콜이고, 나머지 하나는 이터레이터 프로토콜이다.
어쨌거나 다시 처음으로 돌아가서 이터러블이란 순회 가능한 요건을 충족시킨 객체이라고 이해하면 된다. 즉, 순회가 가능한 객체를 총칭하는 개념이다.
Javascript에서 제공하는 Built-in 이터러블로는 Array, String, Map, Set,TypedArray, arguments, NodeList, HTMLCollection 이 있다. 여기서 우리가 주로 쓸 녀석은 Array, String, Map, Set 이다. 어쨌거나 중요한건 Array도 이터러블이라는 점이다.
이 포스팅의 취지를 잊지 말자. 우리는 지금 반복문을 대체하기 위한 기능을 알아보는 중이다.
for ... of 문은 이터러블의 Symbol.iterator 메서드를 호출하여 이터레이터를 반환받은 뒤, 이 이터레이터의 next 메서드를 호출하여 이터레이터 결과 객체$^{iterator}$ $^{result}$ $^{object}$의 value 프로퍼티 값을 for ... of 문에서 선언된 변수에 할당하고, done 프로퍼티 값이 false 이면 이터레이터의 next 메서드를 재차 호출하는 식으로 반복한다.
이게 무슨 미친 소리지 싶을 수 있지만, 사실 별거 아니다.. 다만 설명하려면 내용이 너무 길어질 듯 하니 생략하겠다(...날로 먹네) 그냥 코드를 직접 보면 대충 어떻게 굴러가는지 감이 올테니, 이 포스팅에서는 어떨때 쓰는지만 알고 넘어가자.
코드를 보기 전에 잊지 말 것. 우리는 반복문을 대체하는 기능을 보는 중이다.
const numbers = [1,2,3,4,5]
const squaredNumbers = []
for (const number of numbers){
squaredNumbers.push(number**2);
}
console.log(squaredNumbers);
자 위로 올라가서 for 문을 이용한 제곱수 구하기와 forEach 메서드를 이용한 제곱수 구하기, 그리고 for ... of 문을 이용한 제곱수 구하기를 비교해보자. 여러분이 보이게는 어떤 코드가 멋지고 가독성 높아 보이는가?
for ... of 문의 설명과정에서 이터러블과 이터레이터가 나오면서 뭔가 복잡하게 보일 순 있지만, 작동방식이 복잡한 것일뿐 읽고 쓰기에는 for ... of 문이 훨씬 간편할 것이다.
여기서 for ... in 문과 for ... of 문의 차이점이 궁금할 수 있다.
눈치가 빠른 분은 이미 알아챘겠지만, for ... in 문에서는 변수로 선언되는 것이 객체의 Key이다. 자바스크립트의 배열 역시도 객체이므로 당연히 for ... in 문을 통해 반복문을 작성할 수 있다. 하지만 변수가 Key라는 점이 핵심이다.
반면 for ... of 문은 변수로 선언되는 것이 이터러블의 Value 이다. 따라서 배열의 경우 아래와 같이 배열의 요소를 참조할때 코드작성법에서 차이가 발생한다.
한 단계만 더 깊게 들어가자면, for ... in 문은 기본적으로 객체에 대하여 사용되는 구문이여서 배열의 프로퍼티까지도 참조한다. 하지만 for ... of 문은 이터러블에만 사용되는 구문이므로, 배열의 요소가 아닌 프로퍼티는 무시하고 넘어간다는 차이가 있다.
'Learning-Log > Computer Science' 카테고리의 다른 글
[Git] 주니어 개발자가 되기 위해 알아야 할 Git의 모든 것 - (1) (0) | 2022.06.13 |
---|---|
[JS/Array] 배열 Method 및 배열 고차 함수 정리 (0) | 2022.06.13 |
[JS/함수] 함수의 유형 (1) - 즉시 실행 함수 (0) | 2022.06.07 |
[JS/함수] 화살표 함수 1분만에 이해하기 : 함수(Function)을 정의하는 4가지 방법 (0) | 2022.06.07 |
[크롬 확장 프로그램] CrxMouse 버그 발견 (0) | 2022.06.03 |