JavaScript 3주차

Dongkyu·2025년 7월 9일

JavaScript

목록 보기
4/5

브라우저 환경?

window

우리가 사용하고 있는 브라우저는 어떠한 구조를 가지고 있을까?
웹 브라우저의 최상단에는 window라는 루트객체가 존재한다.

  • 이는 자바스크립트 코드의 전역 객체이다.
  • 브라우저를 제어할 수 있는 메서드를 가지고 있다.
  • BOM과 DOM을 담고있는 최상위 객체로 브아루저 창 그자체이다.

때문에 우리는 function, console, alert등의 메소드를 사용할 수 있는 것이다.
window객체는 생략이 가능하며, window.consol로 사용을 해도 아무 문제가 없다.

DOM(문서 객체 모델)

Document Object Model은 웹페이지의 모든 콘텐츠를 객체로 나타내준다.
즉 웹페이지가 로드되면 브라우저가 HTML 문서를 파싱하여 트리 형태의 객체 모델을 생성하게된다. 우리는 이 Document객체를 이용하여 HTML과 CSS에 접근이 가능하다.

  • document객체는 페이지의 기본 '진입점'역할을 한다.
  • document객체를 통해 페이지 내의 모든 것을 수정 수정 및 생성이 가능하다.
// body 스타일 지정
document.body.style.color = "blue";

// HTML 요소 참조
document.querySelector(".content");

// 문서 위치 객체 참조
document.location

BOM(브라우저 객체 모델)

DOM은 브라우저를 통해 컴파일된 HTML과 CSS을 객체로 표현해주는 document를 말한다.
BOM은 브라우저에 대한 정보를 나타내는 객체 모델이다.

  • navigator를 통해 브라우저의 정보를 제공한다.
  • location을 통해 현재 문서의 URL 정보등을 제공한다.

DOM 탐색하기

DOM에서 내가 원하는 요소에 접근하여 수정 및 생성 등이 가능하다. 하지만 이러한 DOM의 조작을 하기 위해서는 DOM객체에 접근하는 것이 필요로하다.

DOM의 최 상단에 위치하는 객체는 document이다. 즉 document를 통해 DOM에 진입하는 것이라고 봐도 무방하다.
document -> documentElement(HTML) -> document.body -> node -> element로 연결되어있다.
DOM구조

  • document node : HTML 문서 전체를 나타내는 노드
  • element node : 모든 HTML 요소는 노드이며, 속성 노드를 가질 수 있는 유일한 노드
  • attribute node : 모든 HTML요소의 속성은 속성 노드이며, 요소 노드에 관한 정보를 가지고 있다.
  • text node : HTML 문서의 모든 텍스트는 텍스트 노드이다. 개행, 공백은 우리 눈에 명시적으로 보이지 않아도 text node로 취급된다. 따라서 각 요소 노드 사이에는 "\n"이라는 텍스트 노드가 존재한다.
  • comment node : HTML 문서의 모든 주석은 주석 노드이다.

노드란 뭘까?

왜 객체지향형 프로그램인 자바스크립트는 이것들을 객체라고 하지 않고 노드라고 표현 한 걸까?

트리 구조에서의 "노드"

  • 컴퓨터에서 사용되는 Tree(트리)는 계층적 구조를 가진 자료를 말한다.
  • Tree에서는 각각의 요소(점)를 노드(Node)라고 부른다.

그래서 트리는 보통 root node에서 시작해 child node로 뻗어나아가는 구조를 가지게 된다.

Node는 배열인가?

자바스크립트에서 DOM을 조작하기 위해 사용되는 데이터들의 집합을 우리는 배열로 묶어 사용한다. 때문에 [Array]에 대한 많은 메소드들을 이해하고 사용 할 줄 알아야 한다.

하지만 여기서 한가지 궁금증이 생긴다. Node는 배열인가?
우리가 documenent.querySelector()로 HTML의 요소를 가져와 변수에 참조했다고 가정을 해보자.
그렇다면 이 변수는 어떠한 타입일까?


위 사진에서 nodeType이 1이라는 값을 반환했다.
1은 Element Node를 뜻한다. 즉 우리는 이 노드를 불러와 사용하고 있는 것이다.

노드 간 이동

같은 부모를 가진 노드를 sibling 노드라고 부른다.

  • nextsibling : 다음 형제에 대한 정보
  • previousSibling : 이전 형제 노드에 대한 정보
  • parentNode : 부모 노드에 대한 정보

위의 프로퍼티는 모든 종류의 노드를 참조한다.

<ul>
  <li class="list-one">1</li>
  <li class="list-two">2</li>
  <li class="list-three">3</li>
</ul>

위의 HTML문에서에 nextsibling을 찾으면 생기는 문제가 있다.

const listOne = document.querySelector(".list-one");  
const nextList = listOne.nextSibling;           
console.log(nextList) // textNode

이때 우리의 예상과는 다르게 textNode가 나오는 것을 볼 수 있다.

왜 그럴까?
nextSibling은 현제 node의 다음 형제node를 찾는다. 이때 찾는 node타입에 상관없이 바로 다음 요소를 찾기 때문에 위 상황에서 줄바꿈을 인식해 textNode가 호출되는 것이다.

요소 탐색

JavaScript에서 요소들을 탐색하는 방법은 다양하다. 하지만 결국 JavaScript는 DOM에 접근하여, 브라우저가 읽은 HTML에 접근을 하는 것이다.

getElement

요소에 id값이 있다면, getElementById를 사용하여 요소를 탐색 할 수 있다.

const divBox = document.getElementById("div-box")

div요소의 id를 사용하여 divBox라는 변수에 참소를 하는 방식이다.

  • 복수의 경우 : getElementsById를 사용한다.
  • document.getElementById를 사용하는 이유는 문서노드에 해당되는 요소만을 찾기 위해서이다.

querySelector

getElementById는 문서노드의 id만을 참조할 수 있었다. 하지만 우리는 요소의 기본 속성인 id외에도 많은 속성을 사용하고 있다. 이러한 요소의 기본 속성들을 모두 참조하여 사용할 수 있는 방법이 querySelector이다.

// class 선택자
const item = document.querySelector(".item")

// class 선택자 + attribute
const userName = document.querySelector('.user[aria-label="sujin"]');

위의 예시처럼 속성과 class선택자 등 요소에 사용되는 모든 데이터를 접근하여 선택 참조가 가능하다.

  • 복수의 형태로 가져올 경우 querySelectorAll()을 사용하면 된다.
    • 복수의 참조를 변수에 저장할 경우 nodeList의 타입으로 저장이 된다.(nodeList는 유사배열의 형태로, 배열이 아니기에 배열처럼 사용하기 위해서는 Array.from()을 사용해 변환시켜야한다.)
  • 가상요소 선택자또한 참조 가능하다.

정적탐색과 동적 탐색

그렇다면 지금까지 학습한 getElementBy와 querySelector의 차이점이 무엇일까?
단지 사용되는 선택자의 차이뿐인 것일까? 결론부터 말하자면 아니다.

두 메소드에는 아주 중요한 차이점이 있다. 바로 정적인 탐색과, 동적인 탐색 방식의 차이이다.

동적 탐색

document.getElementsBy 메소드는 DOM에 생성되는 요소들이 변하는 동시에 참조가 이루어진다. 즉 새로운 요소가 생긴다면, 추가적으로 그 값을 할당하고 저장한다.

<div>div1</div>
let divs = document.getElementsByTagName("div");
console.log(divs.length) // 1

위 상황에서 <div>모두를 변수 divs에 저장한 상황에서, 해로운 <div>를 추가했을 때에 getElementBy메소드는 새로 추가된 값을 인식한다.

<div>div2</div>

새로운 <div> 추가

console.log(divs.length) // 2

다시 divs배열의 길이를 출력해보면 2가 나오는 것을 볼 수 있다.

하지만 querySelectorAll메소드는 이러한 동적 탐색이 불가능하다.
기존에 DOM을 읽었던 상황에 저장된 값들만을 담고 있으며, 추가된 데이터는 저장되지 못한다.

DOM 프로퍼티

브라우저가 웹페이지를 만나면 HTML을 읽어 DOM객체를 생성한다. 이때 elementNode에서 대부분의 표준 HTML 속성은 DOM객체의 프로퍼티가 된다.

document.body.userData = {
  name : "Arika",
  age : 16,
}

alert(document.body.userData.name); // "Arika"

document.body에 새로운 프로퍼티를 만들어보았다.

document.body.sayHelloTag = function() {
  console.log(`Hello, I'm ${this.tagName}`)
}

document.body.sayHelloTag() // Hello, I'm BODY

이처럼 메소드를 추가하는 것 또한 가능하다.

  • 프로퍼티와 메소드로 모든 값을 가질 수 있다.
  • 사용되는 프로퍼티와 메소드의 대소문자를 구분한다.

DOM 프로퍼티와 메소드는 자바스크립트의 객체와 같은 행동을 하므로 위와 같은 특징을 가지고 있다.

HTML 속성(Attribute)

우리는 DOM에 생성된 요소들에 접근하여, 다양한 작업을 하게 된다. 특히 속성값들을 변경하거나, 읽는 등의 작업또한 사용하지 않을 수 없는 기능이다.

  • element.getAttribute(name) : 속성값 읽음
  • element.setAttribute(name, value) : 속성값 변경
  • element.hasAttribute(name) : 속성값 유무 확인
  • element.removeAttribute(name) : 속성값 제거

위의 메소드를 사용하여 속성값에 대한 접근 및 수정이 가능하다.

요소 생성

DOM 노드를 만들때 사용하는 메서드는 두 가지이다.

// 태그 이름을 사용해 새로운 요소 노드를 만듦
const div = document.createElement("div")

// 주어진 텍스트를 사용해 새로운 텍스트 노드를 만듦
const textNode = document.createTextNode("Hello!")

생성 과정

<div>를 생성하고, 값을 추가하고, DOM에 추가하는 과정을 순서대로 나열해보았다.

// 1. <div> 생성
const div = document.createElement("div")

// 2. <div>에 텍스트 추가
div.textContent = "안녕하세요"

// 3. body에 추가
document.body.appendChild(div)

위의 과정을 통해 요소를 생성하고, 내용을 부여하고, 페이지에 추가하는 방법으로 요소를 제어할 수 있다.

노드 삽입 메소드

  • node.append(노드 || 문자열) : 노드나 문자열을 node 끝에 삽입한다.
  • node.prepend(노드 || 문자열) : 노드나 문자열을 node 맨 앞에 삽입한다.
  • node.before(노드 || 문자열) : 노드나 문자열을 node 이전에 삽입한다.
  • node.after(노드 || 문자열) : 노드나 문자열을 node 다음에 삽입한다.
  • node.replaceWith(노드 || 문자열) : node를 새로운 노드나 문자열로 대체한다.

이 메서드들을 사용하면 복수의 노드와 문자열을 한 번에 넣을 수 있다.
또한 삽입 메서드에 문자열을 넘겨 텍스트 노드를 만들 땐 인수로 넘긴 문자열이 'HTML'이 아닌 '문자열' 그 형태로 삽입된다는 점에 주의 해야한다.

insertAdjacentHTML/Text/Element

아주 다재다능한 메소드이다. 이를 사용하면 모든 요소의 추가 이동 수정 등의 기능을 한번에 사용 할 수 있다.

elem.insertAdjacentHTML(where, html)

where에는 다음과 같은 값이 온다.

  • beforbegin : elem바로 앞에 html을 삽입한다.
  • afterbegin : elem의 첫 번째 자식 요소 바로 앞에 html을 삽입한다.
  • beforend : elem의 마지막 자식 요소 바로 다음에 html을 삽입한다.
  • afterend : elem바로 다음에 html을 삽입한다.

html에는 문자열로, 이 HTML은 이스케이프 처리되지 않고 그대로 삽입된다.

<div id = "div"></div>

<script>
  div.insertAdjacentHTML('beforbegin', '<p>안녕하세요</p>')
  div.insertAdjacentHTML('afterend', '<p>안녕히 가세요</p>')
</script>

위처럼 삽입을 했을 경우 hmlt은 이러한 구조를 가지게 된다.

<p>안녕하세요.</p>
<div id="div"></div>
<p>안녕히 가세요.</p>

노드 제거하기

node.remove()를 사용하면 원하는 요소를 제거할 수 있다.

<div id="div">안녕하세요</div>

<script>
	div.remove()
</script>

아주 간단하게 요소를 제거해보았다.
이 외에도 elem.removeChild()라는 메소드도 있으나, 이는 과저의 잔유물이 되었기에 생략을 하겠다.

profile
인생의 모든날을 사랑하고 즐기자

0개의 댓글