멀티캠퍼스

[2026.04.07]TIL - 7일차 JavaScript(DOM 응용과 이벤트, 구조분해할당)

buckwheat 2026. 4. 8. 02:36

오늘은 DOM을 직접 조작하는 실습을 중심으로 이미지 넘기기, 태그 추가와 이동, 입력값을 표에 추가하고 삭제하는 기능까지 이어서 정리했다.

 

이와 함께 이벤트 모델의 차이와 구조분해할당, 스프레드 연산자 같은 문법도 같이 확인하면서


화면을 다루는 부분과 JavaScript 문법을 함께 정리할 수 있었다.

1. 이미지 넘기기와  attribute / property 

 

이번 실습에서는 좌우 버튼을 눌러 이미지를 바꾸는 기능과, input과 checkbox를 이용해 attribute와 property 차이를 확인하는 내용을 같이 다뤘다.

 

1) 이미지 넘기기

이미지를 가운데에 두고 왼쪽 오른쪽 버튼 만들기

우선 html <a> 태그와 <img> 태그로 이미지와 왼쪽 화살표, 오른쪽 화살표를 만들어준다.

css에서 vertical-align : middle; 로 이미지와 양 옆의 화살표의 세로 정렬을 맞추고,

text-decoration : none; 으로 <a>태그 기본으로 들어가는 밑줄을 없애준다.

  • window.onload를 사용해 페이지가 다 뜨고 나서 실행하도록 한다. 그렇지 않으면 <a> 태그나 <img> 태그를 찾지 못할 수도 있다.
  • let count = 1.

count 변수에 현재 이미지 번호를 저장한다. 이 변수는 전역변수로써 오른쪽 a 태그, 왼쪽 a 태그 모두 사용할 수 있도록 한다.

  • document.querySelectorAll("a")[1].onclick = function()

<a> 두 개 중 [0]은 왼쪽 버튼이고, [1]은 오른쪽 버튼이다. <a> 태그 중 오른쪽 태그를 선택하여 클릭했을 때 함수가 실행되도록 한다.

  • document.querySelector("img").alt

document.querySelector("img")  - <img> 태그를 선택한다.

.alt - 그 이미지의 alt 값을 읽는다.

즉 결과는 imgAlt = "img01" 이 된다.

  • if(imgAlt == "img03")
  • document.querySelector("img").setAttribute("alt","img01");
  • document.querySelector("img").setAttribute("src","../0_sample/img01.jpeg");

만약 3번째 이미지면 count = 1로 이미지 번호를 바꾼다.

count로 현재 이미지 번호를 관리하고, alt로 현재 이미지 상태를 확인하며, src를 변경해서 실제 화면의 이미지를 바꾸는 방식으로 동작한다. 단순히 count 값만 바꿔서는 화면이 변하지 않기 때문에 반드시 src를 함께 수정해야 이미지가 변경된다.

왼쪽 태그도 오른쪽과 마찬가지로 1번 이미지면 count =3 으로, alt도 img03으로, src도 변경해준다.

그렇지 않은 경우에는 --count로 숫자를 하나 줄여준다. 2번 이미지면 1로, 3번 이미지면 2로 변경한다.

 

let imgAlt2 = img.alt;
console.log(imgAlt2);

 

imgAlt2 변수를 만들어 현재 이미지가 몇 번인지 console.log로 보여준다.

 

3) attribute와 property 차이 확인

 

 

이 코드는 input과 checkbox의 property attribute 차이를 확인하는 코드이다.

 

id = val인 부분 즉, 입력창을 input 태그에 대입한다.

input.id 방식(property : js에서 접근할 수 있는 값)과 input.getAttribute("id") (attribute : html에 적혀있는 값) 방식으로 로그에 보여준다.

value도 마찬가지로 보여준다.

변경 전에는 id = val 이고, value = "입력값"이다.

 

변경 후, id= "v"로 바꿔준다.

id property, attribute 모두 v로 나온다.

 

value"테스트 중"으로 바꾸었는데 여기서 propertyattribute의 차이가 드러난다.

input.value = "테스트 중"으로 바꾸었기 때문에

property : input.value는 "테스트 중"으로 출력된다.

attribute : HTML에 처음 적혀있던 값이므로 "입력값"으로 나온다. 처음 값은 "입력값"이지만 JS가 현재 상태만 바꾼것이기 때문에 두 방식에 결과값 차이가 생기는 것이다.

또한 checkbox의 경우 checked는 현재 상태를 나타내는 boolean 값(true/false)이고, getAttribute("checked")는 HTML에 작성된 "checked" 문자열을 반환하여 두 값의 차이를 확인할 수 있다.

“HTML에 적힌 값” 과 “자바스크립트에서 지금 보고 있는 값” 이 다를 수 있다는 걸 보여주는 예제이다.
property는 현재 상태, attribute는 HTML 초기값을 의미한다.

 


2. 태그 추가와 이동

이번 실습에서는 DOM으로 태그를 새로 만들고, 원하는 위치에 추가하거나,
이미 만들어진 태그를 다른 곳으로 이동시키는 내용을 다뤘다.

 

 

 

1) appendChild()로 마지막에 추가하기

  • let p = document.createElement("p");

p 태그를 생성하고, 그 요소를 p 변수에 저장한다.

 

  • innerText /  textContent

innerText는 화면에 보이는 텍스트 기준이고, 화면 상태 영향을 많이 받는다.
textContent는 태그 안의 텍스트 내용 자체를 기준으로 한다.
이번 실습에서는 새로 만든 태그 안에 글자를 넣기 위해 textContent를 사용했다

 

  • document.getElementById("addele").appendChild(p);

id="addele"인 부모 태그를 선택한 뒤,
새로 만든 p 태그를 그 안의 마지막 자식으로 추가하는 코드이다.

 

2) insertBefore()로 앞에 추가하기

새로 만든 p 태그를 #addele 안에 있는 div 태그 앞에 넣는 코드이다.

addBefore() 함수에서는 마찬가지로 p 태그를 새로 만든 뒤 이번에는 insertBefore()를 사용했다.

fieldset 안에서 div 태그를 먼저 찾고, 그 div 앞에 새로 만든 p 태그를 넣는 방식이다.

 

  • let fieldset = document.getElementById("addele");

id="addele"인 fieldset 태그를 선택해서 fieldset 변수에 저장한다.
즉, 새 태그를 넣을 부모 요소를 먼저 가져오는 부분이다.

 

  • let div = document.querySelector("#addele > div");

#addele 안에 들어 있는 div 태그를 선택해서 div 변수에 저장한다.
여기서는 이 div 태그가 기준점 역할을 한다.

 

  • fieldset.insertBefore(p,div);

fieldset 안에서 div 태그 앞에 p 태그를 삽입하게 된다.

 

appendChild()와 insertBefore() 실행 결과

 

3) 태그 이동과 삭제

<fieldset id="addele">
        <legend>부모태그</legend>
        <div>div태그</div>

 </fieldset>
  •  let ele = document.querySelector("#addele").children[1];

.children[1]  이니까 자식요소 인덱스 중에 2번째인 <div>태그를 뜻한다. div 태그를 ele 변수에 저장한다.

 

  • document.body.appendChild(ele);

ele 태그를 body 태그의 마지막 자식으로 붙인다.
원래 fieldset 안에 있던 div가 빠져서 body 아래로 옮겨진다.

 

moveEle()를 실행하면 fieldset에서 body의 아래로 이동하는 모습을 보여준다.

 

  • let fieldset = document.getElementById("addele");

id="addele"인 fieldset 태그를 찾는다.
그 태그를 fieldset 변수에 저장한다.

  • fieldset.remove();

fieldset 태그 자체를 삭제한다. 즉, id="addele"인 fieldset이 화면에서 사라진다.

 


3. 입력값을 표에 추가하고 삭제하기

form에 입력한 값을 표에 한 줄씩 추가하고, 추가된 행을 개별로 삭제하거나 전체 삭제하는 기능을 만들었다.

직접 입력한 값을 DOM으로 tr, td 태그를 생성해서 넣는 방식이라 지금까지 했던 태그 생성 실습이 실제 기능으로 연결되는 느낌이 있었다.

 

 

 

1) 입력값 가져오기와 유효성 검사

먼저 tableVal() 함수에서 첫 번째 form을 가져온 뒤, 아이디, 비밀번호, 주소, 전화번호 값을 배열로 묶었다.

그리고 for문을 사용해 비어있는 칸은 없는지 검사하였다. 하나라도 비어 있으면 alert를 띄우고 return으로 함수를 끝내서 아래 코드가 실행되지 않도록 막았다.(입력값이 다 들어왔을 때만 표에 추가되도록 만들었다.

 

입력값 검사가 끝나면 createRow(vals) 함수를 호출해서 새로운 tr 태그를 만든다.

 

  • document.getElementById("addtr").append(tr)

<tbody id="addtr"></tbody> 를 가져와 찾아온 tbody안에 tr을 마지막에 붙인다.

즉, 새로 만든 한 줄을 표 맨 아래에 추가하는 코드이다.

 

2) tr, td 태그를 만들어서 표에 추가하기

반복문으로 vals 배열 길이만큼 td 태그를 생성한다.
그리고 textContent에 vals[i] 값을 넣어 각 칸의 내용을 채운다.
이후 tr.appendChild(td);를 사용해 생성한 td를 tr의 자식 요소로 추가한다

.

즉, 배열에 들어 있는 값들이 반복문을 돌면서
표 한 줄의 칸(td)으로 하나씩 들어가는 구조이다.

그다음에는 삭제 버튼을 위한 td를 하나 더 만든다.
버튼도 새로 생성하고, 버튼 안에는 "삭제"라는 글자를 넣는다.

 

버튼 클릭 시에는 this.parentNode.parentNode.remove();를 실행해서 버튼이 들어있는 td의 부모인 tr 태그를 삭제한다.

즉, 한 줄 전체를 삭제한다.

아래 줄은 버튼을 td의 자식 요소로(버튼을 칸 안에 넣는 것이다.) 넣는 코드이다.

tr.appendChild(td);는 버튼이 들어있는 td를 다시 tr에 붙이는 코드이다.

즉, 삭제 버튼이 들어 있는 마지막 칸을 한 줄에 추가하는 과정이다.

그 후, tr을 반환한다.

3) 한 줄만 삭제하기와 표 전체 삭제하기.

  • delRow(ele)

ele = 삭제 버튼
ele.parentElement = 버튼이 들어 있는 td
ele.parentElement.parentElement = 그 td가 들어 있는 tr

즉, 삭제 버튼이 포함된 한 줄 전체를 제거하는 코드이다.

  • delVal()

tbody를 선택하고 그 안에 자식 태그가 남아있는 동안 첫 번째 자식을 계속 삭제하는 방식으로 처리한다.

 

다만 이렇게 tbody 태그 안에 있는 모든 내용을 지울 때엔

tbody.innerHTML = "" ; 이렇게도 모두 삭제할 수 있다.

 


4. 이벤트 모델

이번에는 JavaScript에서 이벤트를 연결하는 방식인
인라인, 고전, 표준 이벤트 모델을 정리했다.

같은 클릭 이벤트라도 어떤 방식으로 연결하느냐에 따라 코드 작성 방식이 달라지고,
이벤트를 나중에 바꾸거나 제거할 수 있는지도 달라진다.

 

1) 인라인

 

HTML 태그 안에 onclick 같은 속성으로 바로 이벤트를 작성하는 방식이다.

가장 간단하게 사용할 수 있다.

 

2) 고전

고전 방식과 표준 방식은 인라인 방식과 달리 페이지가 다 로드되기 전에 실행되는 것을 방지하기 위해

window.onload를 쓴다.

 

3) 표준

마찬가지로 window.onload 이후에 실행된다.

표준 방식은 addEventListener()를 사용하는 방식인데

괄호 안 첫 번째 인자는 이벤트 종류이고,

두 번째 인자는 실행할 함수이다.

 

가장 많이 사용하는 방식이고, 이벤트를 추가하거나 제거하기에도 편하다.

실행할 함수를 밖으로 빼서 함수이름을 넣어도 무관하다.

 

코드를 내려 살펴보면 test4 클릭했을 때 "클릭!!"이라는 alert가 뜨지만 그 이후 test2의 alert가 달라지는걸 확인할 수 있다.

test4의 클릭을 누르면, test2의 클릭이 변경된다.

그리고 removeEventListener()를 사용하면 이벤트를 삭제할 수 있는데

test4를 클릭하게 되면 test2의 alert()를 변경한 것 뿐 아니라 test3의 이벤트도 삭제가 된다.


5. 구조분해할당(Destructuring)과 스프레드 연산자

이번에는 JavaScript에서 값을 더 편하게 꺼내거나 묶을 때 자주 쓰는 구조분해할당과 스프레드 연산자를 정리했다.

둘 다 문법 자체는 짧아 보이는데, 배열이나 객체를 다룰 때 코드를 훨씬 간단하게 만들어주는 문법이라
한 번 익숙해지면 자주 쓰게 될 것 같다.

1) 배열 구조분해할당

배열 구조분해할당은 배열 안에 들어 있는 값을 순서대로 꺼내서 각각 다른 변수에 바로 저장하는 문법이다.

예를 들어 배열의 첫 번째, 두 번째 값을 하나씩 직접 꺼내지 않아도 한 번에 여러 변수에 나눠 담을 수 있다.

또한 배열 길이보다 변수를 더 많이 선언하면 없는 값은 undefined로 들어가고, 기본값을 미리 넣어둘 수도 있다.

즉, 배열 값을 필요한 만큼만 꺼내서 쓰거나 기본값까지 같이 지정할 수 있는 문법이라고 보면 된다.

2) 객체 구조분해할당

객체 구조분해할당은 객체 안에 있는 속성값을 꺼내서 각각 변수에 저장하는 문법이다.

배열은 순서 기준이라면, 객체는 속성 이름 기준으로 값을 꺼낸다는 점이 다르다.

필요하면 변수 이름을 새로 바꿔서 저장할 수도 있고, 없는 값에 대해서는 기본값을 넣을 수도 있다.

함수 매개변수에서도 사용할 수 있어서 객체를 전달받을 때 필요한 값만 바로 꺼내 쓸 수 있다는 점도 편리했다.

3) 스프레드 연산자

스프레드 연산자는 배열이나 객체 안에 들어 있는 값을 펼쳐서 사용하는 문법이다.

배열에서는 기존 배열의 값을 다른 배열 안에 자연스럽게 이어 붙일 수 있고, 객체에서는 기존 객체의 속성을 다른 객체 안으로 복사하듯 넣을 수 있다.

즉, 배열 합치기나 객체 확장처럼 기존 데이터를 바탕으로 새로운 값을 만들 때 유용하게 쓰인다.

4) rest 문법

rest 문법은 여러 값을 하나의 배열로 묶어서 받는 방식이다.

주로 함수 매개변수에서 많이 사용하고, 전달된 인자의 개수가 정해져 있지 않을 때 편하게 처리할 수 있다.

스프레드가 “펼치는” 느낌이라면, rest는 여러 값을 “묶는” 느낌이라고 이해하면 헷갈리지 않았다.

5) 정리

이번 내용은 화면이 바로 바뀌는 실습은 아니었지만,
배열과 객체를 다룰 때 문법을 훨씬 간단하게 만들어주는 부분이라 중요하게 느껴졌다.

특히 구조분해할당은 값을 꺼내는 코드를 줄여주고,
스프레드 연산자는 기존 배열이나 객체를 활용해서 새로운 데이터를 만들 때 편리하다는 점이 인상적이었다.

구조분해할당은 값을 나눠 담는 문법이고,
스프레드와 rest는 값을 펼치거나 묶을 때 사용하는 문법이다.

 


6. 정리 및 느낀점

오늘은 이미지를 넘기거나 태그를 추가하고 이동시키는 것처럼


DOM을 직접 다루는 실습부터, 입력값을 표에 추가하고 삭제하는 기능, 이벤트 모델, 구조분해할당과 스프레드 연산자까지 같이 정리했다.

 

이번에는 단순히 태그를 선택해서 값을 바꾸는 걸 넘어서 태그를 새로 만들고, 옮기고, 지우고, 입력값을 받아서 화면에 반영하는 흐름까지 이어졌다는 점이 더 크게 느껴졌다.

 

특히 입력값을 표에 추가하는 부분은 지금까지 따로 배웠던 태그 생성, appendChild, 삭제 기능이
하나의 예제로 연결된 느낌이라 더 인상적이었다.

 

이벤트 모델도 인라인, 고전, 표준 방식으로 나눠서 보니까 그동안 비슷하게만 보였던 방식들의 차이가 조금 더 정리됐다.

 

마지막에 배운 구조분해할당과 스프레드 연산자는 배열과 객체를 다룰 때 코드를 훨씬 간단하게 만들 수 있다는 점에서
앞으로 자주 쓰게 될 것 같았다.