Frontend 11

연산자, 조건문, 함수로 JavaScript 동작 묶기

연산자, if/else, 함수, 화살표 함수가 문법 조각으로만 보이고 실제 동작 단위가 어떻게 만들어지는지 모르겠다.

근거 · 교안 p43-p47

연산자, 조건문, 함수로 JavaScript 동작 묶기 대표 이미지

1장: 연산자: 가장 작은 동작의 묶음, ‘값’을 만들다

1. 연산자: 가장 작은 동작의 묶음, ‘값’을 만들다

솔라는 방금 스쳐 지나간 문장 하나에 발목이 잡혔다. “JavaScript는 연산자, 조건문, 함수를 사용해 동작을 묶는다.” 조건문이나 함수가 코드를 묶는다는 건 어렴풋이 알 것 같았다. 하지만 연산자라니. +, >, && 같은 기호들이 대체 무엇을 ‘묶는다’는 걸까? 솔라의 머릿속에서 연산자는 그저 계산이나 비교를 위한 문법 부호, 구두점 같은 존재였다.

답답한 마음에 솔라는 스케치북과 펜을 들고 거실로 나갔다. 언니 루나는 소파에 앉아 노트북으로 무언가를 들여다보고 있었다.

“언니, 잠깐 뭐 좀 물어봐도 돼?”

루나는 고개를 들어 솔라를 보았다. 솔라의 손에 들린 텅 빈 스케치북을 보고는 말없이 노트북을 덮었다.

“연산자가 ‘동작을 묶는 방법’이라는 게 이해가 안 가. +는 그냥 더하기 기호 아니야? 뭘 묶는다는 건지 모르겠어.”

솔라는 스케치북에 큼직하게 + 기호를 그렸다. 마치 범인을 지목하는 것 같았다.

루나는 잠시 생각하더니, 솔라의 손에서 펜을 가져갔다. 그리고 + 기호 옆에 이렇게 적었다.

5 + 3

“솔라, 이게 뭐야?”

“팔.”

너무 당연한 걸 묻는다는 듯 솔라가 퉁명스럽게 대답했다. 루나는 고개를 끄덕이며 그 옆에 = 8이라고 덧붙였다. 그러고는 그 아래에 새로운 식을 썼다.

10 > 5

“이건?”

이번엔 솔라가 잠시 망설였다. “…참?”

“응, ‘참’.”

루나는 이번에도 = true라고 적었다. 마지막으로 한 줄을 더 썼다.

true && false

“이건 ‘거짓’이지.” 솔라는 이제 언니가 무엇을 하려는지 조금 알 것 같아 먼저 대답했다. 루나는 미소 지으며 똑같이 = false를 적어 넣었다.

스케치북에는 세 개의 식이 나란히 적혀 있었다.

5 + 3 = 8
10 > 5 = true
true && false = false

루나는 펜으로 등호(=)의 왼쪽 편들을 전부 동그랗게 감쌌다. 5 + 3, 10 > 5, true && false.

“솔라 네가 방금 이것들을 보고 8, true, false라는 답을 내놨어. 이 왼쪽의 식들은 그냥 기호 덩어리가 아니야. 사실은 아주 작은 ‘동작’을 하고 있는 거야.”

“동작?”

“응. 5 + 3은 ‘두 숫자를 더해서 새로운 숫자를 내놓아라’라는 동작이야. 그 동작이 실행된 결과가 바로 값 8인 거고. 10 > 5는 ‘왼쪽 숫자가 오른쪽 숫자보다 큰지 비교해서 참/거짓으로 답해라’라는 동작인 거지. 그 결과가 바로 true라는 값이고.”

루나는 덧붙였다. “모든 연산자는 이렇게 입력된 값들을 처리해서, 단 하나의 새로운 값을 내놓는 작은 동작이야. 연산자는 기호가 아니라, 값을 만들어내는 가장 작은 단위의 ‘동작’인 셈이지.”

솔라는 스케치북을 가만히 들여다보았다. 5 + 3이라는 글자가 더 이상 ‘5 더하기 3’으로 보이지 않았다. 마치 두 개의 숫자 구슬을 삼켜 새로운 숫자 ‘8’ 구슬 하나를 뱉어내는 작은 기계처럼 느껴졌다. > 기호도 마찬가지였다. 숫자 두 개를 넣었더니 true라는 이름표가 붙은 구슬을 뱉어내는 비교 기계.

“아…!”

탄성이 터져 나왔다.

“그러니까 +> 같은 연산자들이 그냥 수식을 꾸미는 기호가 아니라… 입력값을 받아서 결과값을 만들어내는, 그 자체가 하나의 완결된 ‘동작’이라는 거구나. 값을 생성하는 동작!”

솔라는 이제야 ‘동작을 묶는다’는 말의 첫 단추를 찾은 기분이었다. 연산자는 그 자체로 ‘값을 생성하는 동작’을 수행하는 가장 작은 단위였다. 코드는 이런 작은 동작들이 모여서 더 큰 흐름을 만들어내는 것이었다.

“맞아. 모든 연산식은 결국 하나의 값으로 변해. 자바스크립트는 5 + 3을 보면 그 자리에 8을 놓아두고, 10 > 5를 보면 true를 놓아두는 식으로 코드를 읽어나가는 거야.”

솔라는 고개를 끄덕였다. 머릿속에 흩어져 있던 문법 조각들이 제자리를 찾는 느낌이었다. 연산자는 더 이상 외워야 할 기호 목록이 아니었다. 값을 만들어내는 작은 엔진, 가장 기본적인 ‘동작 단위’였다.

문득 솔라는 새로운 궁금증이 생겼다. 그녀는 방금 루나가 그려준 스케치북에서 truefalse 값을 손가락으로 가리켰다.

“알겠어. 연산자는 값을 만들어내는 작은 동작이야. 그런데… 이 truefalse 같은 값은 만들어서 어디에 쓰는 거야? 그냥 ‘참이다’, ‘거짓이다’ 하고 끝나면 의미 없잖아. 이 작은 동작으로 만들어진 값을 가지고 어떻게 더 큰 동작을 만들 수 있는 거지?”

2장: 조건문: 동작을 ‘선택적으로 묶어’ 분기하다

루나는 솔라가 가리키던 스케치북의 truefalse를 잠시 바라보더니, 펜을 들어 그 아래에 새로운 그림을 그리기 시작했다. 길게 뻗어 나가던 하나의 선이 두 갈래로 나뉘는, 갈림길이었다. 한쪽 길 위에는 ‘A’라고 적었고, 다른 쪽 길 위에는 ‘B’라고 적었다.

그림을 다 그린 루나는 갈림길이 시작되는 지점을 펜으로 콕 찍었다. 솔라는 언니의 의도를 기다렸다. 이전 장에서 연산자가 값을 만들어내는 작은 ‘동작’이라는 것을 깨달았지만, 그 결과물인 truefalse의 쓸모는 여전히 물음표로 남아 있었다.

“솔라 네가 한 질문이 바로 이 그림이야. ‘truefalse 같은 값은 만들어서 어디에 쓰는가?’ 그 값들은 바로 이 갈림길의 이정표가 돼.”

루나는 솔라의 눈을 보며 말했다.

“어떤 길로 갈지 결정해주는 신호등 같은 거지. true라는 신호가 켜지면 A 길로 가고, false라는 신호가 켜지면 B 길로 가는 거야.”

“갈림길…?”

“응. 코드를 짜다 보면 언제나 하나의 길로만 갈 수는 없어. 어떤 상황에서는 이쪽 동작을, 다른 상황에서는 저쪽 동작을 해야 하거든. 자, 이걸로 한번 생각해 볼까?”

루나는 스케치북의 새 페이지를 넘겨 방금 한 말을 코드로 옮기기 시작했다. 마치 일상의 고민을 코드로 번역하는 것 같았다.

“‘오늘 기온이 20도보다 높으면 반팔을 입고, 그렇지 않으면 긴팔을 입는다.’ 이걸 코드로 표현한다고 해보자.”

루나는 익숙한 단어들로 코드를 구성했다.

let temperature = 15;

if (temperature > 20) {
  // 동작 묶음 A: 반팔 입기
  console.log("반팔 티셔츠를 입는다.");
} else {
  // 동작 묶음 B: 긴팔 입기
  console.log("긴팔 스웨터를 입는다.");
}

솔라는 코드를 뚫어지라 쳐다봤다. ifelse라는 문법은 본 적이 있었다. ‘만약 ~하면, 아니면 ~한다’ 정도로만 알고 있었을 뿐, 이것이 ‘동작을 묶는다’는 개념과 어떻게 연결되는지는 생각해보지 못했다.

루나는 if 옆의 괄호, (temperature > 20) 부분을 손가락으로 가리켰다.

“이 부분, 어제 우리가 봤던 거지? 값을 만들어내는 작은 동작. ‘비교 연산자’야. temperature가 지금 15니까, 이 식은 결국 어떤 값으로 변할까?”

false.” 솔라가 바로 대답했다.

“맞아. 이 자리에 false라는 값이 놓이는 거야. 그리고 자바스크립트는 false라는 이정표를 보고 else 뒤에 있는 길, 즉 B 경로를 선택하는 거지.”

루나의 펜이 else 뒤의 중괄호 {}를 따라 빙 둘렀다. “그리고 이 중괄호 안에 있는 모든 동작을 실행해. 여기서는 ‘긴팔 스웨터를 입는다’는 동작이 되겠지.”

그 순간, 솔라의 머릿속에서 무언가 ‘탁’ 하고 맞아 들어갔다. if/else는 그냥 ‘만약’을 뜻하는 문법이 아니었다. 두 개의 ‘동작 묶음’을 미리 준비해두고, 조건의 결과값에 따라 그중 하나를 ‘선택’하게 만드는 장치였다.

솔라는 ifelse 뒤에 붙은 중괄호 {}를 손가락으로 짚었다.

“그럼 이 괄호들이… 동작을 담는 주머니 같은 거네. temperature > 20가 ‘참’이라는 열쇠를 주면 if 쪽 주머니를 열고, ‘거짓’이라는 열쇠를 주면 else 쪽 주머니를 여는 거고.”

스스로 말하고도 놀란 듯 솔라의 눈이 커졌다.

“아니, 주머니보다 ‘동작 묶음’이라는 말이 더 맞겠다. ‘반팔 입기’ 안에는 사실 ‘옷장에서 반팔 티셔츠를 꺼낸다’, ‘청바지를 입는다’ 같은 여러 동작이 들어갈 수 있으니까. 이 조건문은 어떤 ‘동작 묶음’을 선택해서 실행할지 결정해주는 거구나!”

연산자가 값을 만드는 가장 작은 ‘동작 단위’였다면, 조건문은 그 값을 이용해서 거대한 코드의 흐름을 나누는 첫 번째 갈림길이었다. 어떤 동작들을 한 묶음으로 묶어둘지, 그리고 어떤 조건에서 그 묶음을 실행할지 결정하는 것. 비로소 코드의 흐름을 ‘제어’한다는 말의 의미가 실감 나기 시작했다.

솔라는 고개를 끄덕이며 방금 깨달은 사실을 정리했다. if는 단지 문법 키워드가 아니라, true라는 결과값과 한 쌍이 되어 특정 동작 묶음을 실행시키는 선택의 도구였다.

그러다 솔라는 잠시 생각에 잠겼다. 그녀는 ‘긴팔 입기’라는 묶음을 펜으로 동그라미 쳤다.

“‘긴팔 스웨터를 꺼낸다’, ‘코트를 걸친다’… 이 동작 묶음은 오늘만 쓰는 게 아니잖아. 내일도 춥다면 똑같은 동작을 해야 할 텐데… 그럼 이 코드를 그대로 복사해서 또 써야 하나? 똑같은 동작 묶음인데, 필요할 때마다 계속 적어주는 건 비효율적인 것 같아. 이 동작 묶음을 어딘가에 저장해두고 이름만 불러서 쓸 수는 없을까?”

3장: 함수: 동작들을 ‘이름 붙여’ 재사용하다

솔라의 질문이 채 끝나기도 전에, 루나는 스케치북을 가져가 솔라가 동그라미 쳤던 ‘긴팔 입기’ 코드 묶음을 말없이 세 번 연달아 적었다. 마치 복사해서 붙여넣기라도 한 것처럼. 각 묶음은 서로 다른 날짜의 기온을 확인하는 if 문 안에 들어있었다. 어제도, 오늘도, 내일도 추울 경우를 가정한 코드였다.

스케치북에는 똑같은 동작 묶음이 불필요하게 공간을 차지하며 반복되고 있었다. 솔라가 지적했던 비효율이 눈앞에 그대로 펼쳐졌다. 루나는 아무 말 없이 그 세 덩어리의 코드를 빤히 바라보다가, 페이지를 휙 넘겼다. 이번에는 전혀 다른 예시를 적기 시작했다.

console.log("안녕하세요, 솔라님!");
console.log("안녕하세요, 루나님!");
console.log("안녕하세요, 방문자님!");

“이건 어때? 여기서 반복되는 동작은 뭘까?”

솔라는 즉시 알아차렸다. “‘안녕하세요, OOO님!’ 하고 인사하는 동작. 이름 부분만 계속 바뀌네.”

이전 예시처럼 완전히 똑같지는 않지만, ‘인사한다’는 핵심 동작의 구조가 계속 반복되고 있었다. 만약 인사할 사람이 백 명이라면, 이 코드를 백 줄이나 써야 할 터였다.

루나는 고개를 끄덕이며 말했다. “바로 그럴 때, 우리는 이 ‘동작 묶음’에 이름을 붙여줄 수 있어. 마치 서랍장에 ‘양말’이라고 이름표를 붙여두는 것처럼. 그러면 필요할 때마다 서랍장 전체를 새로 만들 필요 없이, ‘양말 서랍 열어줘’라고 말하기만 하면 되잖아.”

루나는 방금 적었던 세 줄의 코드를 지우고, 새로운 코드 블록을 작성했다.

function greet(name) {
  console.log(`안녕하세요, ${name}님!`);
}

“이게 바로 동작에 이름을 붙여주는 방법이야. function이라는 키워드를 써서 ‘지금부터 동작 묶음을 만들 거야’라고 알려주고, greet라는 이름을 붙여준 거지. 그리고 이 동작이 실행될 때마다 바뀔 수 있는 부분, 즉 재료는 저 괄호 안에 name이라는 이름으로 넣어주면 돼.”

솔라는 function greet(name) { ... } 부분을 유심히 쳐다봤다. 이전 장에서 봤던 if 문의 중괄호 {}와 비슷했지만, 이번에는 functiongreet라는 이름이 붙어 있었다.

루나는 이제 그 아래에 훨씬 간결해진 코드를 적었다.

greet('솔라');
greet('루나');
greet('방문자');

결과는 아까와 똑같이 세 개의 인사말이 출력되겠지만, 코드의 모습은 완전히 달라져 있었다. 반복되던 console.log(...) 구문은 greet라는 이름 안으로 사라지고, 오직 ‘누구에게’ 인사할 것인지만 남아있었다.

“아…!”

솔라의 입에서 나지막한 탄성이 터져 나왔다.

“단순히 코드를 복사하지 않으려고 쓰는 게 아니구나. ‘이름을 매개로 인사를 건넨다’는 일련의 동작 전체를 greet라는 하나의 ‘단어’로 정의해버린 거네. 이제 greet('솔라')라는 코드는 ‘솔라에게 인사하는 동작을 실행해!’라는 명령이 되는 거고.”

솔라는 깨달았다. 함수는 코드를 담는 상자가 아니었다. 특정 목적을 가진 동작의 레시피였고, 그 레시피에 고유한 이름을 붙여주는 행위였다. 이제 greet는 단순한 단어가 아니라, 자바스크립트 세상에서 실존하는 ‘동작 단위’가 된 것이다. 필요할 때마다 그 이름을 부르기만 하면, 약속된 동작이 어김없이 실행되는 재사용 가능한 마법 주문처럼 느껴졌다.

“맞아. 우리는 연산자로 새로운 ‘값’을 만들고, 조건문으로 값에 따라 실행할 ‘동작 묶음’을 선택했어. 그리고 함수는 그 동작 묶음 자체를 어딘가에 저장해두고, 이름표를 붙여서 언제든 다시 불러 쓸 수 있게 해주는 거야. 일종의 ‘동작 저장소’인 셈이지.”

연산자, 조건문, 함수. 흩어져 있던 문법 조각들이 ‘동작을 묶는 방법’이라는 하나의 줄기로 꿰이는 순간이었다. 솔라는 이제 스케치북의 빈 페이지를 자신 있게 마주할 수 있을 것 같았다.

그녀는 펜을 들고 루나에게 말했다. “그럼, 한번 해볼게. 배운 걸 전부 써서.”

솔라의 머릿속에는 새로운 문제가 떠올랐다. ‘방문자의 나이를 확인해서, 성인이면 환영 인사를, 미성년자면 안내 문구를 보여주는 동작’을 만드는 것이었다.

그녀는 잠시 고민하더니, 코드를 설계하기 시작했다.

“먼저, ‘나이를 받아서 성인인지 확인하고 그에 맞는 메시지를 정하는 동작’이 필요해. 이건 여러 번 쓸 수 있으니 checkAge라는 이름의 함수로 묶어야겠다.”

솔라는 스케치북에 함수를 그렸다.

function checkAgeAndGreet(name, age) {
  // 1. 나이를 비교해서 true/false 값을 만드는 '동작' (연산자)
  const isAdult = age >= 19; 

  let message;
  // 2. 그 값에 따라 다른 동작 묶음을 '선택' (조건문)
  if (isAdult) {
    message = `환영합니다, ${name}님!`;
  } else {
    message = `안내 드립니다, ${name}님. 미성년자는 이용할 수 없습니다.`;
  }

  console.log(message);
}

코드를 다 적은 솔라는 스스로 감탄했다. age >= 19 라는 ‘값 생성 동작’이 if 문을 위한 이정표가 되고, if/else는 두 개의 ‘동작 묶음’ 중 하나를 선택했다. 그리고 이 모든 과정은 checkAgeAndGreet라는 이름 아래 하나의 거대한 ‘재사용 가능한 동작 단위’로 묶여 있었다.

솔라는 마지막으로 자기가 만든 함수를 호출하는 코드를 적었다.

checkAgeAndGreet('솔라', 17);
checkAgeAndGreet('루나', 21);

더 이상 연산자, 조건문, 함수는 낯선 문법이 아니었다. 문제를 해결하기 위해 동작을 만들고, 나누고, 저장하는 세 가지의 강력한 도구였다. 솔라는 스케치북에 적힌 자신의 코드를 보며, 비로소 자바스크립트로 무언가를 ‘만들어낼’ 수 있겠다는 자신감을 얻었다.