본문으로 건너뛰기

값을 찍어 보며 고치기

자바스크립트 목차반복레슨 24 / 76

목차

결과가 틀렸는데 오류 메시지가 없을 때는, 이름마다 있어야 할 값을 먼저 적고 console.log로 실제 값을 찍어 둘이 처음 갈리는 줄을 찾습니다. 그 줄 하나를 고친 뒤 다시 돌립니다.

자바스크립트는 글자와 수를 섞어도, 칸 밖을 꺼내도, 수로 바꿀 수 없어도 멈추지 않고 틀린 값을 만들어 다음 줄로 갑니다. 오류 메시지가 없으니 어디가 틀렸는지 알려 주지도 않습니다. 코드를 눈으로 다시 읽으면 쓴 사람이 뜻한 대로 읽혀 틀린 줄을 지나치기 쉽습니다. 그래서 실제 값을 찍어 보며 찾는 차례를 배웁니다.

18단계 중 1단계. 1부터 3까지 더해 6을 찍으려는 코드입니다. 예측 칸에 있어야 할 값을 적어 두고, 실제와 견줍니다.

1오류 없이 틀리는 값

앞 단원들에서 본 세 줄입니다. 셋 다 오류 없이 다음 줄로 넘어갑니다.

console.log('3' + 4);
console.log('커피'[2]);
console.log(Number('2잔'));
실행 결과
34
undefined
NaN

글자에 수를 더하면 이어 붙이고(수·글자·불리언과 typeof), 칸 밖을 꺼내면 undefined이고(인덱스와 자르기), 수로 바꿀 수 없으면 NaN입니다(글자를 수로: Number와 NaN). 이런 값은 만들어진 줄이 아니라 한참 뒤 그 값을 쓰는 줄에서야 드러납니다. 컴퓨터는 쓴 대로만 실행하므로(규칙 6), 틀린 값이 어디서 처음 생겼는지는 찍어 봐야 압니다.

2예측과 실제가 처음 갈리는 줄 찾기

1부터 3까지 더해 6을 찍으려 했는데 3이 찍힙니다.

let total = 0;
for (let n = 1; n < 4; n++) {
  total = 0;
  total = total + n;
}
console.log(total);
실행 결과
3

이렇게 찾습니다.

  1. 예측 적기: 이 코드가 해야 할 일대로라면 total은 바퀴가 끝날 때마다 1, 3, 6이어야 합니다.
  2. 찍어 보기: 덩어리 끝(4번 줄 다음)에 console.log('total', total);⁠을 잠깐 넣고 돌립니다.
  3. 처음 갈리는 곳 찾기: 찍힌 값과 예측을 위에서부터 견줍니다.
  4. 한 곳만 고치고 다시 돌리기: 처음 갈린 줄 하나를 고치고, 찍어 본 줄은 지웁니다.

찍는 줄을 넣은 코드입니다. 5번 줄은 바퀴마다 무엇을 찍을까요? 예측대로 1, 3, 6일지 코드를 쓴 대로 따라가 정한 뒤 펼쳐 보세요.

let total = 0;
for (let n = 1; n < 4; n++) {
  total = 0;
  total = total + n;
  console.log('total', total);
}
console.log(total);
실행 결과 보기
실행 결과
total 1
total 2
total 3
3

예상과 다르면 그곳이 배울 곳입니다. 컴퓨터는 뜻한 대로가 아니라 쓴 대로 실행합니다(규칙 6). 첫 바퀴는 예측(1)과 같고, 둘째 바퀴에서 처음 갈립니다(예측 3, 실제 2). 그러니 틀린 곳은 둘째 바퀴 안의 줄입니다.

둘째 바퀴를 줄마다 따라가며 total의 예측과 실제를 나란히 적으면 갈리는 줄이 보입니다.

줄바뀐 이름예측실제
2n22
2조건 n < 4truetrue
3total10
4total32

둘째 바퀴를 시작할 때 total은 1이었는데, 3번 줄이 0에 다시 붙여 앞 바퀴까지 모은 값을 지웠습니다. 처음 갈리는 줄은 3번 줄입니다. 3번 줄 하나만 지우고 다시 돌리면 6이 찍힙니다.

3이름을 붙여 찍고, 거슬러 올라가기

값만 찍으면(console.log(qty);) 여러 줄이 섞일 때 어느 이름의 값인지 모릅니다. console.log('qty', qty);⁠처럼 이름을 글자로 앞에 붙입니다. 주문서의 '라테 2잔'에서 잔 수를 꺼내 값을 셈하려 했는데 NaN원이 찍힙니다. 셈에 쓰는 이름마다 찍어 봤습니다.

const order = '라테 2잔';
const text = order.slice(3);
console.log('text', text);
const qty = Number(text);
console.log('qty', qty);
console.log(`${4500 * qty}원`);
실행 결과
text 2잔
qty NaN
NaN원

NaN이 처음 보이는 것은 qty지만, 그 앞의 text가 이미 예측('2')과 다릅니다. slice(3)은 3번 칸부터 끝까지라 '잔'까지 꺼냈습니다. 처음 갈리는 줄은 2번 줄이고, order.slice(3, 4)로 고치면 9000원이 찍힙니다. 틀린 값이 보이면 그 값을 만든 이름을 하나 앞으로 거슬러 찍어 봅니다. 처음 갈린 이름에서 멈춥니다.

예제

같아 보이는 값 — typeof도 찍기

커피 3잔과 라테 4잔을 더했는데 34가 찍힙니다. console.log는 글자의 따옴표를 찍지 않아 3과 '3'이 같아 보입니다. 이럴 때는 typeof도 함께 찍습니다.

const coffee = '3';
const latte = 4;
console.log(coffee + latte);
console.log('coffee', coffee);
console.log(typeof coffee);
실행 결과
34
coffee 3
string

4번 줄이 찍은 3은 수처럼 보이지만, 5번 줄의 typeof가 string(글자)이라고 알려 줍니다. 그래서 3번 줄의 + 연산자가 이어 붙였습니다. 1번 줄을 const coffee = 3;으로 고치면(바깥에서 받은 글자라면 Number(coffee)로 바꾸면) 7이 찍힙니다.

자주 틀리는 곳

틀린 생각: 오류 메시지가 없으면 코드는 맞다.

오류가 나면 멈추니, 끝까지 돌았다면 맞게 돈 것 같습니다. 그러나 1절의 세 줄처럼 자바스크립트는 틀린 값을 만들고도 멈추지 않습니다.

2절 코드는 오류 없이 3을 찍었지만 해야 할 일은 6이었습니다.

맞는 규칙: 오류가 없다는 것은 끝까지 실행됐다는 뜻일 뿐입니다. 결과를 예측과 견주어 맞는지 따로 봅니다(규칙 6).

틀린 생각: 틀린 값이 찍힌 줄을 고치면 된다.

NaN원이 6번 줄에서 찍혔으니 6번 줄을 고치고 싶어집니다. 그러나 찍힌 줄은 틀린 값을 쓴 곳일 뿐, 만든 곳이 아닙니다.

3절에서 6번 줄의 식은 맞았고, 틀린 값은 2번 줄에서 처음 생겼습니다. 2절의 3은 6번 줄에서 찍혔지만 고칠 곳은 3번 줄이었습니다.

맞는 규칙: 틀린 값이 찍힌 줄에서 거슬러 올라가며 찍어, 예측과 처음 갈리는 줄을 고칩니다.

틀린 생각: 여러 곳을 한꺼번에 고치면 더 빨리 맞는다.

의심 가는 곳이 여럿이면 한 번에 다 바꾸고 싶습니다. 그러면 결과가 맞아도 어느 고침이 맞았는지, 다른 고침이 새 문제를 만들지 않았는지 알 수 없습니다.

2절에서 3번 줄을 지우면서 4번 줄까지 total = total + n + 1;⁠로 바꿨다면 9가 찍혀 여전히 틀리고, 두 고침 가운데 무엇이 맞았는지 알 수 없습니다.

맞는 규칙: 처음 갈리는 줄 하나만 고치고 다시 돌립니다. 다 맞으면 찍어 보려고 넣은 console.log를 지웁니다.

확인 문제

1. 2절의 찍어 본 코드에서 3번 줄 total = 0;을 지웠습니다. 무엇이 찍히는지 줄마다 그대로 쓰세요.

let total = 0;
for (let n = 1; n < 4; n++) {
  total = total + n;
  console.log('total', total);
}
console.log(total);
힌트

바퀴마다 3번 줄이 total에 무엇을 더하는지 추적 표에 적습니다. 4번 줄은 바퀴마다 찍습니다.

정답
실행 결과
total 1
total 3
total 6
6

이제 바퀴마다 찍힌 값이 예측 1, 3, 6과 같고, 마지막 줄도 6입니다. 맞게 고쳤으니 4번 줄은 지웁니다.

흔한 오답은 total 1만 세 번 쓰는 것입니다. 지운 줄이 여전히 합을 되돌린다고 본 것입니다.

2. 값을 찍어 보며 고치는 차례가 섞였습니다. 처음부터 차례로 기호를 늘어놓으세요.

  • ㉠ 처음 갈린 줄 하나만 고치고 다시 돌린다
  • ㉡ 이름마다 있어야 할 값(예측)을 적는다
  • ㉢ 찍어 보려고 넣은 console.log를 지운다
  • ㉣ 이름을 붙여 console.log로 찍는다
  • ㉤ 찍힌 값과 예측을 위에서부터 견준다
힌트

2절의 차례 넷을 떠올립니다. 무엇과 견줄지가 먼저 있어야 견줄 수 있습니다.

정답

㉡ ㉣ ㉤ ㉠ ㉢입니다.

예측(㉡)이 먼저입니다. 찍은 값만 보면 무엇이 틀렸는지 판단할 기준이 없습니다. 찍은 줄 지우기(㉢)는 고친 코드가 맞게 돈 것을 본 뒤입니다.

3. 사흘 걸음 수 3000 · 4000 · 5000의 합 12000을 구하려 했는데 300040005000이 찍힙니다. 3번 줄 다음에 찍는 줄을 넣어 돌렸더니 이렇게 찍혔습니다. 몇 번 줄을 어떻게 고쳐야 할까요?

let total = '';
for (let i = 3; i < 6; i++) {
  total = total + i * 1000;
  console.log('total', total);
}
실행 결과
total 3000
total 30004000
total 300040005000
힌트

둘째 바퀴에서 예측은 7000입니다. 3000에 4000을 더했는데 이어 붙었다면, 그 앞의 total은 어떤 종류의 값이었을지 1번 줄을 봅니다.

정답

1번 줄을 let total = 0;으로 고칩니다. 그러면 3000, 7000, 12000이 찍혀 예측과 같아집니다.

total이 빈 문자열 ''에서 시작해서, 첫 바퀴의 '' + 3000부터 글자 '3000'이 됐습니다. 그 뒤로는 바퀴마다 글자에 수를 이어 붙였습니다. 찍힌 값이 처음 갈리는 것은 둘째 바퀴지만, 틀린 값은 1번 줄에서 시작했습니다.

흔한 오답은 3번 줄에서 Number(total)로 바꿔 더하는 것입니다. 결과는 맞아도 total을 쓰는 곳마다 바꿔야 해서, 틀린 값이 시작된 1번 줄 하나를 고칩니다.

컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요. 2절의 찍어 본 코드(일곱 줄)를 main.js에 저장해 돌립니다. 그다음 찍는 줄(5번 줄)을 닫는 중괄호 밖으로 옮기면 무엇이 찍힐지 먼저 적고, 옮겨 돌려서 맞춰 봅니다. 저장하고 돌리는 법은 내 컴퓨터에서 돌려 보기에 있습니다.

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

자바스크립트 목차로