본문으로 건너뛰기

for...of로 배열 돌기

자바스크립트 목차배열레슨 35 / 76

목차

for...of 문은 배열이나 문자열에서 값을 앞에서부터 하나씩 꺼내, 바퀴마다 그 값에 이름을 붙이고 덩어리를 실행합니다. split은 글을 잘라 배열을 만들고, join은 배열의 값을 이어 글 하나를 만듭니다.

for의 세 칸으로 주문을 하나씩 찍으려면 자리 번호 i를 0부터 세고, 바퀴마다 orders[i]로 칸을 꺼내야 합니다. 조건을 i <= n으로 잘못 쓰면 칸 밖의 undefined까지 꺼냅니다. for...of는 번호 없이 칸의 값을 차례로 꺼내 줍니다. 이 레슨에서는 for...of가 값을 꺼내는 차례를 따라가고, split·join으로 글과 배열 사이를 오갑니다.

8단계 중 1단계. 배열 orders를 for...of로 도는 코드입니다. 바퀴마다 item이 무엇에 붙는지 따라갑니다.

1for...of로 값을 하나씩 꺼낸다

그림의 코드입니다. for 다음 괄호 안에 const item of orders를 씁니다.

const orders = ['커피', '라테'];
for (const item of orders) {
  console.log(item);
}
실행 결과
커피
라테

2번 줄은 바퀴마다 orders의 다음 칸 값을 꺼내 그 값에 이름 item을 붙이고, 덩어리(3번 줄)를 실행합니다.

바퀴item이 붙는 값3번 줄이 찍는 것
첫째'커피'커피
둘째'라테'라테

둘째 바퀴 뒤에는 꺼낼 칸이 남지 않아 반복이 끝납니다. 칸 수를 세는 조건이 없으니 < 연산자와 <= 연산자를 헷갈릴 일도 없습니다.

for...of는 바퀴마다 이름 item을 새로 만들어 그 바퀴의 값에 붙입니다. 한 바퀴 안에서 다시 붙이지 않으니 const로 만들 수 있습니다. for의 i는 바꾸기 칸 i++가 다시 붙여서 let이어야 했습니다. item도 i처럼 그 반복의 중괄호 안에서만 삽니다(규칙 4).

2문자열은 돌고, 수는 못 돈다

for...of는 문자열에서도 글자를 하나씩 꺼냅니다.

for (const ch of '라테') {
  console.log(ch);
}
실행 결과
라
테

그렇다면 수 3을 주면 세 번 돌까요? 무엇이 찍힐지 정한 뒤 펼쳐 보세요.

const n = 3;
for (const i of n) {
  console.log(i);
}
실행 결과 보기
실행 결과
main.js:2for (const i of n) {                ^ TypeError: n is not iterable    at main.js:2:17

예상과 다르면 그곳이 배울 곳입니다. n is not iterable은 'n은 하나씩 꺼낼 수 있는 값이 아니다'라는 뜻입니다. 수 3에는 꺼낼 칸이 없어서, 한 바퀴도 돌지 못하고 2번 줄에서 멈춥니다. 세 번 돌려면 for (let i = 0; i < 3; i++)⁠처럼 셉니다.

for...of는 배열·문자열처럼 값을 차례로 내주는 것만 돕니다. 이런 값을 자료에 따라 반복 가능한(iterable) 값이라고 부릅니다.

3split과 join으로 글과 배열을 오간다

주문이 '커피,라테,쿠키'처럼 쉼표로 이은 글 하나로 올 때가 있습니다. 문자열 메서드 split은 인자로 준 글자에서 글을 잘라, 조각마다 칸 하나인 배열을 돌려줍니다.

const text = '커피,라테,쿠키';
const orders = text.split(',');
console.log(orders);
console.log(orders.length);
실행 결과
[ '커피', '라테', '쿠키' ]
3

찍힌 결과에 대괄호와 따옴표가 보이니 글이 아니라 배열입니다. 조각이 셋이라 length는 3이고, for...of로 돌 수 있습니다. 원래 글 text는 그대로입니다.

거꾸로 배열 메서드 join은 칸의 값을 인자로 준 글(구분자, separator)로 이어 문자열 하나를 돌려줍니다.

const orders = ['커피', '라테'];
console.log(orders.join(', '));
console.log(orders.join(''));
console.log(orders.join());
실행 결과
커피, 라테
커피라테
커피,라테

빈 문자열 ''을 주면 사이에 아무것도 없이 잇고, 인자를 주지 않으면 쉼표로 잇습니다. 결과에 대괄호와 따옴표가 없으니 배열이 아니라 글입니다.

예제

손님 이름 글로 차례 부르기

쉼표로 이어 온 손님 이름 글을 잘라 한 사람씩 부르고, 끝에 이름을 다시 한 줄로 이어 찍습니다.

const text = '민지,철수,영희';
const names = text.split(',');
for (const name of names) {
  console.log(`${name} 손님`);
}
console.log(names.join(', '));
실행 결과
민지 손님
철수 손님
영희 손님
민지, 철수, 영희

과목 끝의 할 일 앱에서도 할 일 배열을 for...of로 하나씩 꺼내, 화면 목록에 한 줄씩 그립니다.

자주 틀리는 곳

틀린 생각: for...in도 배열의 값을 하나씩 꺼낸다.

in은 '안에서'라는 뜻이라 배열 안의 값을 꺼낼 것 같고, 파이썬의 for x in 리스트도 값을 꺼냅니다. 그러나 자바스크립트의 for...in은 자리 번호를 글자로 꺼냅니다.

const nums = [10, 20];
for (const x in nums) {
  console.log(x + 1);
}
실행 결과
01
11

x는 10, 20이 아니라 자리 번호 '0', '1'에 붙습니다. 글자라서 x + 1은 더하기가 아니라 잇기가 됩니다.

맞는 규칙: 배열의 값은 for...of로 꺼냅니다. for...in은 자리 번호를 글자로 꺼내며, 8단원 객체에서 다시 봅니다.

틀린 생각: split은 쉼표를 빼고 조각을 이은 글을 돌려준다.

찍으면 조각이 나란히 보여, 글 하나가 돌아온 것처럼 읽기 쉽습니다. 그러나 3절에서 찍힌 결과에는 대괄호와 따옴표가 있었고 length는 조각 수 3이었습니다.

맞는 규칙: split은 조각마다 칸 하나인 배열을 돌려줍니다. 조각을 다시 글 하나로 이을 때는 join을 씁니다.

틀린 생각: 구분자에서 join을 부르고 배열을 인자로 준다.

파이썬에서는 ', '.join(orders)처럼 구분자에서 join을 부릅니다. 자바스크립트에서 같은 꼴로 쓰면 멈춥니다.

const orders = ['커피', '라테'];
console.log(', '.join(orders));
실행 결과
main.js:2console.log(', '.join(orders));                 ^ TypeError: ", ".join is not a function    at main.js:2:18

문자열에는 join 메서드가 없어서 is not a function이 납니다.

맞는 규칙: join은 배열의 메서드라 orders.join(', ')처럼 배열에서 부르고, 구분자는 인자로 줍니다.

틀린 생각: 도는 중에 그 배열에서 값을 빼도 남은 값을 모두 돈다.

줄 선 손님을 부를 때마다 맨 앞 손님을 shift로 빼면, 둘을 모두 부르고 줄이 빌 것 같습니다.

const line = ['민지', '철수'];
for (const name of line) {
  console.log(`${name} 손님`);
  line.shift();
}
console.log(line);
실행 결과
민지 손님
[ '철수' ]

for...of는 배열의 칸을 0번, 1번 차례로 꺼냅니다. 첫 바퀴에 '민지'를 빼면 '철수'가 0번 자리로 당겨집니다. 다음 바퀴는 1번 칸을 꺼내려는데 칸이 하나뿐이라 반복이 끝납니다. '철수'는 불리지 못하고 줄에 남습니다.

맞는 규칙: 도는 배열에서 값을 빼면 뒤 칸이 당겨져 다음 값을 건너뜁니다. 돌면서 바꿀 배열은 사본을 돕니다. 2번 줄에서 line 대신 사본 [...line]을 돌면 두 손님을 모두 부르고 []이 찍힙니다(배열 바꾸기와 복사).

확인 문제

1. 가격마다 500원을 더해 찍습니다. 무엇이 찍히는지 마지막 줄까지 그대로 쓰세요.

const prices = [4500, 3000];
for (const p of prices) {
  console.log(p + 500);
}
힌트

바퀴마다 p가 붙는 값을 먼저 적습니다. 자리 번호가 아니라 칸의 값입니다.

정답
실행 결과
5000
3500

p는 바퀴마다 4500, 3000에 차례로 붙고, 3번 줄이 그 값에 500을 더해 찍습니다.

흔한 오답은 500, 501입니다. p가 자리 번호 0, 1을 꺼낸다고 본 것입니다(번호를 꺼낸다는 생각). 번호를 꺼내는 것은 for...in이고, 그때도 번호는 글자라 0500처럼 이어 붙습니다.

2. 무엇이 찍히는지 두 줄을 쓰세요.

const text = '커피/라테/쿠키';
const orders = text.split('/');
console.log(orders.length);
console.log(orders.join(' '));
힌트

split('/')가 돌려준 배열에 칸이 몇 개인지 셉니다. join은 글 하나를 돌려줍니다.

정답
실행 결과
3
커피 라테 쿠키

split('/')는 조각 셋의 배열을 돌려주니 length는 3입니다. join(' ')은 칸 값 사이에 빈칸 하나를 넣어 이은 글을 돌려줍니다.

흔한 오답은 첫 줄에 8을 쓰는 것입니다. split이 글을 돌려준다고 보고 글 '커피/라테/쿠키'의 글자 수를 센 것입니다. 둘째 줄에 [ '커피', '라테', '쿠키' ]를 썼다면 join도 배열을 돌려준다고 본 것입니다.

3. 과일 이름에서 '나'가 몇 번 나오는지 셉니다. 4번 줄이 참일 때만 count에 1을 더합니다. 마지막 줄에 찍히는 값을 고르세요.

const word = '바나나';
let count = 0;
for (const ch of word) {
  if (ch === '나') {
    count = count + 1;
  }
}
console.log(count);
  • ① 2
  • ② 0
  • ③ 3
힌트

문자열을 도는 for...of에서 바퀴마다 ch가 붙는 값을 차례로 적습니다.

정답
실행 결과
2

①입니다. ch는 '바', '나', '나'에 차례로 붙고, 둘째와 셋째 바퀴에서 조건이 참이라 count가 2가 됩니다.

  • ② 문자열을 값 하나로 보고 ch가 '바나나' 전체에 한 번 붙는다고 봤습니다. for...of는 문자열에서 글자를 하나씩 꺼냅니다.
  • ③ 조건을 보지 않고 바퀴 수를 셌습니다. 첫 바퀴의 '바'는 ch === '나'가 거짓이라 더하지 않습니다.

컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요. 1절 그림 코드를 main.js에 저장해 돌린 뒤, 2번 줄의 of를 in으로 바꿉니다. 무엇이 찍힐지 먼저 적고, 바꿔 돌려서 맞춰 봅니다. 저장하고 돌리는 법은 내 컴퓨터에서 돌려 보기에 있습니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

자바스크립트 목차로