Frontend 10
JavaScript 연결, 콘솔, 변수와 자료형: 웹페이지에 생명 불어넣기
HTML과 CSS는 화면에 바로 보이는데 JavaScript는 script 연결, 콘솔 출력, 변수 선언부터 낯설다.
근거 · 교안 p36-p42
1장: JavaScript, 어디서부터 시작해야 할까요? (연결의 미스터리)
솔라는 노트북 화면을 노려보고 있었다. 화면 한쪽에는 몇 줄 안 되는 HTML 코드가, 다른 한쪽에는 텅 빈 흰색의 웹페이지가 떠 있었다. 모니터의 푸른빛이 솔라의 미간에 패인 옅은 그림자를 더 짙게 만들었다.
“분명히… 연결은 했는데.”
솔라의 손가락이 키보드 위에서 망설였다. <body>와 </body> 태그 사이에 <script></script> 한 줄을 넣은 지 10분이 지났다. HTML 태그를 하나 추가하면 없던 글자가 생기고, CSS 색상 코드를 바꾸면 칙칙하던 배경이 화사해졌다. 그런데 자바스크립트는? 아무런 시각적 변화가 없었다. 마치 벽에 대고 말하는 기분이었다.
“언니, 나 이것 좀 봐줘. ‘자바스크립트는 웹페이지에 동작을 추가하는 언어’라며. 근데 아무리 봐도 모르겠어.”
거실에서 책을 읽던 루나가 조용히 다가와 솔라의 어깨너머로 화면을 들여다보았다. 솔라는 답답하다는 듯 마우스 커서를 흔들었다.
“HTML을 고치면 바로 글자나 그림이 보이고, CSS를 바꾸면 모양이 바뀌잖아. 근데 이건… 그냥 아무 일도 안 일어나. 내가 뭘 잘못한 건가?”
솔라가 가리킨 곳에는 텅 빈 <script> 태그가 덩그러니 놓여 있었다. 루나는 잠시 솔라의 코드를 살펴보다가, 텅 빈 웹페이지 쪽으로 시선을 옮겼다.
“솔라, 저 스크립트 태그는 지금 빈 상자 같아.”
“빈 상자?”
“응. 우리가 이사할 때 ‘주방용품’이라고 쓴 상자를 주방에 뒀다고 해서, 그 안에서 저절로 컵이 튀어나오거나 접시가 놓이지는 않잖아. 상자를 그 자리에 두는 건 첫 단계일 뿐이야. 진짜 중요한 건 상자 안에 뭘 담느냐지.”
루나의 말에 솔라는 고개를 갸웃했다. 여전히 알쏭달쏭한 표정이었다. 루나는 솔라의 코드 편집기에서 깜빡이는 커서를 가리켰다.
“그 상자 안에, 아주 간단한 지시를 하나만 넣어보자.”
루나는 솔라가 따라 칠 수 있도록 천천히 불러주었다. alert('Hello, JS!');
솔라는 미심쩍은 얼굴로 그 코드를 <script> 태그 사이에 그대로 타이핑했다. 괄호, 작은따옴표, 세미콜론까지. 여전히 화면에는 아무 변화가 없었다.
“이게 뭐 하는 건데?”
“일단 저장하고, 브라우저에서 새로고침 해봐.”
솔라는 반신반의하며 파일을 저장하고 브라우저 창으로 돌아가 새로고침 아이콘을 클릭했다.
바로 그 순간이었다.
‘띵’ 하는 작은 시스템 소리와 함께, 텅 비어 있던 웹페이지 위로 작은 경고창이 불쑥 튀어나왔다. 그 안에는 솔라가 방금 타이핑한 Hello, JS!라는 문구가 선명하게 적혀 있었다.
“어!”
솔라의 눈이 동그래졌다. 놀라서 자신도 모르게 의자를 뒤로 살짝 뺐다.
“창이… 떴어! 페이지 자체가 바뀐 건 아닌데, 갑자기 컴퓨터가 나한테 말을 걸었어. 이게… 이게 ‘동작’이라는 거야?”
솔라는 확인 버튼을 눌러 경고창을 닫았다. 창이 사라지자 페이지는 다시 아무 일 없었다는 듯 텅 빈 흰색으로 돌아갔다. 하지만 솔라의 머릿속은 더 이상 비어있지 않았다. HTML, CSS와는 완전히 다른 방식으로 무언가 ‘일어났다’는 사실이 강렬하게 남았다. 코드가 화면을 그리는 재료가 아니라, 브라우저를 움직이는 명령어가 될 수 있다는 첫 경험이었다.
루나가 조용히 고개를 끄덕였다.
“맞아. HTML이 건물의 뼈대고 CSS가 페인트나 벽지 같은 인테리어라면, 자바스크립트는 그 건물 안의 엘리베이터나 자동문, 전등 스위치 같은 거야. 평소에는 눈에 잘 띄지 않지만, 분명히 존재하면서 건물이 ‘기능’하도록 만들지. 스크립트 태그는 그 모든 자동화 장치를 설치할 공간을 마련해준 거고.”
솔라는 다시 자신의 코드를 보았다. 이제 <script> 태그는 더 이상 의미 없는 빈칸이 아니었다. 웹페이지의 보이지 않는 신경계를 심을 수 있는, 명확한 목적을 가진 공간으로 보였다. 웹페이지에 생명을 불어넣는 첫 번째 연결점이었다.
잠깐의 흥분이 가라앉자, 솔라는 다시 경고창이 떴던 자리를 바라보며 미간을 찌푸렸다.
“그런데 언니, 이 alert라는 건 너무… 시끄러운 것 같아. 페이지를 열 때마다 불쑥 튀어나와서 꼭 확인 버튼을 눌러야 하잖아. 내가 짠 코드가 잘 작동하는지 확인하고 싶은데, 이렇게 매번 방문객을 놀라게 하지 않고 조용히, 나만 볼 수 있게 ‘응, 나 잘 실행되고 있어’ 하고 신호를 주는 방법은 없을까? 마치… 개발자만 아는 비밀 통로처럼 말이야.”
2장: 보이지 않는 소리, 콘솔로 듣다 (실행 결과 확인)
솔라는 자신의 HTML 파일에서 alert('Hello, JS!'); 라인을 말끔히 지워버렸다. 시끄러운 경고창은 사라졌지만, 동시에 자바스크립트가 살아있다는 유일한 증거도 함께 사라졌다. 파일을 저장하고 웹페이지를 새로고침하자, 화면은 다시 텅 빈 백지로 돌아왔다. 마치 아무 일도 없었다는 듯 고요했다. 그 침묵이 솔라를 더 답답하게 만들었다.
루나는 소파에 앉아 그런 솔라의 뒷모습을 조용히 지켜보고 있었다. 솔라가 키보드 위에서 손가락을 몇 번 더 망설이다가, 결국 의자를 돌려 루나를 바라보았다.
“언니 말대로, 그 시끄러운 경고창은 없앴어. 그런데… 이제 다시 깜깜이야. 코드가 일을 하는지 안 하는지 알 수가 없어. 개발자만 아는 비밀 통로가 있다고 했잖아. 그건 어떻게 열어?”
루나는 책을 덮고 일어나 솔라의 옆으로 다가왔다. 그리고는 지워진 alert 코드의 빈자리를 가리켰다.
“그 통로로 신호를 보내는 새로운 주문이 있어. 한번 따라 쳐볼래?”
루나가 불러준 코드는 console.log('이 메시지는 어디에?'); 였다. alert와 비슷하면서도 console.log라는 이름은 어딘가 더 전문적으로 들렸다. 솔라는 의심 반, 기대 반으로 코드를 입력했다. log라는 단어에서 ‘기록’이라는 의미가 어렴풋이 떠올랐다. 무언가를 기록해준다는 뜻일까?
솔라는 파일을 저장하고, 다시 한번 브라우저를 새로고침했다.
역시나, 웹페이지에는 아무런 변화도 없었다. 경고창도 뜨지 않았고, 새로운 글자나 그림도 나타나지 않았다. 솔라는 실망한 표정으로 루나를 쳐다보았다.
“이것도 똑같잖아. 아무 일도 안 일어나는데? 내 메시지는 대체 어디로 간 거야?”
“사라진 게 아니야. 우리가 아직 못 보고 있을 뿐이지. 솔라, 그 웹페이지 화면에서 키보드의 F12 키를 한번 눌러봐.”
“F12?”
솔라가 무심코 F12 키를 누르자, 갑자기 화면의 절반가량이 낯선 패널로 채워졌다. 수많은 탭과 알 수 없는 단어들, 복잡한 코드 조각들이 어지럽게 널려 있었다. 마치 자동차의 보닛을 난생 처음 열어본 기분이었다.
“우와, 이게 다 뭐야? 뭔가… 엄청 복잡해 보여.”
솔라가 당황해서 중얼거렸다. 루나는 그 복잡한 패널 속에서 ‘Console’이라고 적힌 탭을 손가락으로 가리켰다.
“여기가 바로 우리가 찾던 비밀 통로야. 브라우저의 개발자 도구, 그중에서도 콘솔 창이지.”
솔라는 조심스럽게 콘솔 탭을 클릭했다. 그러자 복잡했던 화면이 조금은 단순해지면서, 그 안에 익숙한 문장이 눈에 들어왔다.
> 이 메시지는 어디에?
솔라의 눈이 다시 한번 커졌다. 자신이 코드에 썼던 바로 그 문장이었다. 웹페이지에는 보이지 않던 메시지가, 이 숨겨진 공간에 조용히 도착해 있었다.
“찾았다! 여기 있었네!”
솔라는 자신도 모르게 탄성을 질렀다. 시끄러운 경고창처럼 사용자를 방해하지도 않고, 오직 코드를 작성한 자신만이 볼 수 있는 비밀스러운 출력. 이것이 바로 솔라가 원했던 ‘조용한 신호’였다.
“그렇구나! console.log는 사용자에게 보여주는 게 아니라, 이 개발자 도구의 콘솔 창에 무언가를 보여주라는 명령이었구나!”
솔라는 신이 나서 다시 코드로 돌아갔다. console.log 안의 문구를 ‘진짜 비밀 통로 발견!’이라고 바꾼 뒤 다시 저장하고 새로고침했다. 콘솔 창에는 이전 메시지 아래에 새로운 메시지가 정확히 찍혔다.
> 진짜 비밀 통로 발견!
루나가 부드럽게 미소 지었다. “이제 이 콘솔은 솔라, 너만의 작업 일지이자 청진기 같은 게 될 거야. 코드의 심장 소리를 듣고, 내부에서 무슨 일이 벌어지는지 들여다볼 수 있는 창이지.”
청진기라는 비유에 솔라는 고개를 끄덕였다. alert가 환자에게 직접 소리치는 거라면, console.log는 의사가 조용히 환자의 상태를 진단하는 도구와 같았다. 웹페이지의 겉모습 너머, 보이지 않는 코드의 실행 과정을 엿볼 수 있는 첫 번째 창을 얻은 것이다. 이제 자바스크립트가 더 이상 막연한 존재가 아니었다. 연결하고, 실행하고, 그 결과를 이 콘솔을 통해 확인할 수 있는 구체적인 대상으로 느껴졌다.
한참 동안 신기하게 콘솔 창을 들여다보던 솔라의 표정에 새로운 궁금증이 떠올랐다.
“좋아, 이제 내가 쓴 코드가 잘 돌아가는지는 확인할 수 있게 됐어. 그런데 언니, 지금은 그냥 내가 쓴 글자를 그대로 보여주는 것뿐이잖아. 웹사이트가 진짜로 ‘동작’하려면… 예를 들어 사용자가 이름을 입력하면 ‘OOO님, 환영합니다!’라고 말해주거나, 버튼을 누른 횟수를 세는 것처럼 뭔가를 기억하고 계산해야 하지 않아? 그런 값들은 어디에, 어떻게 담아두는 거야?“
3장: 동작을 위한 재료 (변수와 자료형)
솔라의 손가락이 키보드 위에서 경쾌하게 움직였다. 이제 개발자 도구의 콘솔 창을 여는 것은 익숙한 일이 되었다. 그녀는 스크립트 태그 안에 새로운 코드를 자신 있게 써 내려갔다.
console.log('방문자를 환영합니다!');
새로고침하자, 콘솔 창에 어김없이 메시지가 나타났다. 하지만 솔라는 만족스럽지 않았다. 그녀는 다음 줄에 무언가 더 해보고 싶었다. ‘솔라 님, 환영합니다!’ 처럼 이름을 넣어서 말이다. 하지만 어떻게? console.log('솔라'); 를 추가하는 건 그냥 두 개의 다른 메시지를 보내는 것일 뿐, 원하는 바가 아니었다. 마치 요리사가 “손님, 식사 나왔습니다”와 “재료는 감자입니다”를 따로 외치는 것과 같았다. ‘감자 요리 나왔습니다’라고 말해야 하는데.
솔라는 잠시 고민하다, 자기가 하고 싶은 말을 콘솔 창에 직접 타이핑해 보았다.
console.log('솔라' + '님, 환영합니다!');
엔터. 그러자 콘솔에 솔라님, 환영합니다! 라고 한 줄로 합쳐진 문장이 나타났다.
“오, 되네?”
작은 성공에 신이 난 솔라는 한 걸음 더 나아갔다. 버튼을 누른 횟수를 세는 상황을 상상하며 다음 코드를 썼다.
console.log('버튼 클릭 횟수: ' + 1);
결과는 버튼 클릭 횟수: 1 이었다. 성공이었다. 하지만 솔라의 미간은 금세 다시 좁아졌다. 횟수를 하나 늘리려면? console.log('버튼 클릭 횟수: ' + 2); 라고 코드를 직접 고쳐야 했다. 이건 ‘세는’ 게 아니라 그냥 매번 다른 숫자를 ‘쓰는’ 것일 뿐이었다. 사용자가 버튼을 누를 때마다 코드를 수정할 수는 없는 노릇이었다. ‘1’이라는 숫자를 어딘가에 붙잡아 두고, 필요할 때마다 1씩 더해야 했다. 하지만 그 ‘어딘가’가 대체 어디인지 알 수 없었다.
“언니, 막혔어.”
솔라가 의자를 돌리자, 루나는 솔라가 무엇과 씨름하고 있었는지 이미 짐작했다는 듯 조용히 미소 지었다.
“콘솔에 메시지를 보내는 건 이제 박사네. 그런데 보내는 메시지가 전부 일회용이라 아쉬운 거지?”
“응. 뭔가를 기억하게 만들고 싶어. 사용자 이름이라든가, 클릭 횟수 같은 거 말이야. 근데 이 값들이 그냥 한번 스쳐 지나가고 사라져 버려. 잡을 수가 없어.”
루나는 솔라의 책상 위에 놓인 작은 메모지 한 장을 집어 들었다.
“솔라, 네가 만약 가게 주인이라면, 단골손님의 이름을 어디에 적어둘 거야?”
“음… 고객 명부에 적어두겠지? 이름 옆에 마지막 방문 날짜나 좋아하는 메뉴 같은 것도 같이.”
“바로 그거야. 자바스크립트한테도 그런 고객 명부가 필요해. 값을 그냥 흘려보내는 게 아니라, 이름표를 붙여서 보관할 장소가 필요한 거지. 그 장소를 우리는 ‘변수(variable)’라고 불러.”
루나는 솔라의 코드 편집기로 시선을 옮겼다. “한번 이름을 보관하는 변수를 만들어볼까? ‘이름’이라는 상자를 하나 마련해달라고 이렇게 쓰는 거야.”
루나는 let userName; 이라는 코드를 보여주었다.
솔라는 코드를 따라 쳤다. let 이라는 낯선 단어는 마치 ‘상자를 하나 준비해줘’라고 말하는 주문처럼 느껴졌다.
“좋아. 이제 userName이라는 이름표가 붙은 빈 상자가 하나 생긴 거야. 이제 그 상자에 네 이름을 넣어보자. 등호(=)를 사용해서.”
솔라는 다음 줄에 userName = '솔라'; 라고 입력했다. 이제 ‘솔라’라는 값이 userName이라는 이름표가 붙은 상자 안에 담기는 모습이 머릿속에 그려졌다.
“그럼… 이 상자 안에 든 걸 확인하려면?”
“이제부턴 상자 이름만 부르면 돼. 콘솔한테 userName을 보여달라고 해봐.”
솔라는 console.log(userName); 이라고 썼다. 이전처럼 따옴표로 감싸지 않고, 그냥 상자 이름만 적었다. 파일을 저장하고 새로고침하자, 콘솔 창에 ‘솔라’라는 두 글자가 선명하게 나타났다.
“됐다! ‘솔라’라고 직접 쓰지 않았는데, 내가 저장해둔 이름이 나왔어!”
솔라의 목소리에 흥분이 실렸다. 이것이 바로 그녀가 원했던 ‘기억’이었다. userName이라는 이름은 이제 단순한 글자가 아니라, 언제든 불러내 쓸 수 있는 값을 담은 소중한 저장소가 되었다.
루나는 고개를 끄덕이며 덧붙였다. “이제 우리는 재료를 보관할 상자를 만들 수 있게 됐어. 그런데 상자마다 담을 수 있는 재료의 종류가 달라. 방금 넣은 ‘솔라’ 같은 글자 덩어리는 **문자열(string)**이라고 불러. 요리의 레시피처럼 항상 따옴표로 감싸주지.”
솔라는 방문 횟수를 떠올렸다. “그럼 숫자는?”
“숫자는 따옴표 없이 그냥 써. 그건 숫자(number) 타입이야. 그래야 덧셈이나 뺄셈 같은 계산을 할 수 있거든.”
솔라는 곧바로 새로운 상자를 만들었다.
let visitCount = 1;
console.log(visitCount);
콘솔에는 숫자 1이 찍혔다. 솔라는 곧바로 실험에 들어갔다.
visitCount = visitCount + 1;
console.log(visitCount);
결과는 2였다. 코드를 직접 바꾸지 않고도, 저장된 값을 불러와 계산한 뒤 다시 저장하는 것이 가능했다. 드디어 ‘세는’ 것이 가능해졌다.
“신기하다. 글자랑 숫자를 다르게 다루는구나. 또 다른 종류의 재료도 있어?”
“응. 아주 중요한 게 하나 더 있어. ‘로그인 했나요?’ 같은 예/아니오 질문에 답하는 재료야. **불리언(boolean)**이라고 부르고, true(참) 아니면 false(거짓) 두 가지 값만 있어.”
솔라는 코드를 추가했다.
let isLoggedIn = true;
console.log(isLoggedIn);
콘솔에는 true라는 단어가 나타났다. 따옴표 없는 true는 문자열 ‘true’가 아니라, ‘켜져 있음’ 또는 ‘사실임’을 의미하는 특별한 신호처럼 보였다.
문득 솔라는 let 말고 다른 키워드도 본 기억이 났다. const였다.
“언니, let 말고 const라는 것도 있던데, 그건 뭐야?”
“좋은 질문이야. visitCount처럼 계속 값이 바뀌어야 하는 건 let으로 만든 상자에 담아. 뚜껑이 있어서 얼마든지 다른 걸로 바꿀 수 있지. 그런데 솔라, 네 생일처럼 절대 바뀌지 않는 값도 있잖아. 그런 건 const로 만들어. 한 번 넣으면 바꿀 수 없도록 봉인해버리는 상자야.”
솔라는 const로 자신의 태어난 해를 저장했다.
const birthYear = 2005;
그러고는 장난스럽게 그 값을 바꾸려고 시도했다.
birthYear = 2006;
저장하고 새로고침하자, 웹페이지는 그대로였지만 콘솔 창에 빨간색 에러 메시지가 나타났다. ‘상수(constant) 변수에 값을 할당하려고 했습니다.’
“아하! const는 정말로 못 바꾸게 막는구나.”
솔라는 에러 메시지를 확인하고 birthYear = 2006; 라인을 지웠다. 에러가 사라졌다. 이제 let과 const는 더 이상 비슷해 보이는 낯선 단어가 아니었다. 앞으로 바뀔 가능성이 있는 값인지, 아니면 절대 불변의 값인지에 따라 골라 쓰는 명확한 용도를 가진 도구였다.
솔라는 자신이 작성한 코드를 처음부터 다시 쭉 훑어보았다.
let userName = '솔라';
let visitCount = 1;
const birthYear = 2005;
let isLoggedIn = true;
이제 이 코드들은 추상적인 명령어의 나열이 아니었다. 웹페이지에 ‘동작’을 불어넣기 위해 차곡차곡 준비해 둔 재료들이었다. 문자열, 숫자, 불리언이라는 각기 다른 성질의 재료들을 let과 const라는 이름표가 붙은 상자에 용도에 맞게 담아둔 것이다.
‘자바스크립트는 웹페이지에 동작을 추가하는 언어다.’
처음에는 막연하게만 느껴졌던 이 문장이 이제 구체적인 그림으로 다가왔다. ‘동작’이란, 바로 이 재료들을 꺼내고, 바꾸고, 조합해서 새로운 결과를 만들어내는 과정이었다. 솔라는 마지막으로 자신의 모든 재료를 조합해 하나의 메시지를 만드는 코드를 작성했다.
console.log(userName + '님, 당신의 ' + visitCount + '번째 방문을 환영합니다!');
콘솔 창에 솔라님, 당신의 2번째 방문을 환영합니다! 라고 뜨는 것을 확인한 솔라의 얼굴에 환한 미소가 번졌다. 드디어 웹페이지의 보이지 않는 심장을 뛰게 할 재료와 그 재료를 담을 그릇을 모두 손에 넣은 것이다.