브라우저: 문서, 이벤트, 인터페이스
1. JavaScript와 브라우저 환경
자바스크립트는 원래 웹 브라우저에서 사용하려고 만들어졌지만, 이후에는 다양한 플랫폼에서도 사용되는 범용 프로그래밍 언어로 진화했습니다. 자바스크립트는 호스트(host)라는 플랫폼에서 동작하며, 호스트는 브라우저, 웹 서버, 모바일 앱, IoT 기기 등 다양한 환경이 될 수 있습니다.
호스트 환경은 자바스크립트에 특정된 객체와 함수를 제공하며, 이러한 객체와 함수는 해당 환경에서 동작하는 기능을 수행합니다. 웹 브라우저에서는 웹 페이지를 제어하기 위한 기능을 제공하고, Node.js에서는 서버 사이드 기능을 제공합니다.
자바스크립트 명세서에서는 호스트 환경을 호스트 환경(host environment)이라고 부르며, 이는 랭귀지 코어(ECMAScript)에 더하여 해당 환경에서 제공하는 객체와 함수를 설명합니다.
웹 브라우저에서 자바스크립트를 사용할 때는 DOM(Document Object Model), BOM(Browser Object Model), Canvas, XMLHttpRequest 등의 객체와 함수를 사용할 수 있습니다. DOM은 HTML 문서의 요소에 접근하고 조작할 수 있는 기능을 제공하며, BOM은 브라우저 창에 대한 제어 및 정보를 제공합니다. Canvas는 그래픽을 그리기 위한 기능을 제공하며, XMLHttpRequest는 서버와 데이터를 주고받을 수 있는 기능을 제공합니다.
Node.js에서는 자바스크립트를 사용하여 서버 사이드 애플리케이션을 작성할 수 있습니다. 이를 위해 Node.js는 파일 시스템, 네트워크, 프로세스 관리 등의 기능을 제공합니다.
1-1. 브라우저 환경
위 그림은 자바 스크립트의 호스트 환경이 브라우저일 경우 사용할 수 있는 기능을 보여줍니다.
[1] Window
window 객체: 자바스크립트에서 전역 객체(Global Object)로 사용되는 객체이며, 브라우저 창을 대변하고 제어하는데 사용됩니다. 즉, window 객체는 브라우저 창에 대한 정보와 제어 기능을 제공하는 객체입니다.
1. 전역 객체 : 자바스크립트 코드의 전역 객체입니다.
2. '브라우저 창(browser window)'을 대변하고, 이를 제어할 수 있는 메서드를 제공합니다.
[2] DOM (Document Object Model)
DOM은 웹 개발에서 매우 중요한 개념 중 하나입니다. 이를 이용해 동적으로 HTML 태그를 추가하거나, 수정, 삭제할 수 있으며, 이를 통해 웹 페이지의 UI를 보다 효과적으로 제어할 수 있습니다. 또한, 사용자의 인터랙션에 따라 동적으로 변경되는 UI를 만들어낼 수도 있습니다.
예를 들어, document.getElementById() 메서드를 이용해 특정 요소에 접근하고, 해당 요소의 속성 값을 변경하거나 이벤트를 처리할 수 있습니다. 또한, document.createElement() 메서드를 이용해 새로운 HTML 요소를 생성하고, 이를 특정 요소의 하위 요소로 추가할 수도 있습니다.
DOM은 웹 페이지의 요소들을 객체로 나타내기 때문에, 이를 이용해 다양한 연산을 수행할 수 있습니다. 예를 들어, 특정 요소의 하위 요소 중에서 특정 조건을 만족하는 요소들만 가져오거나, 요소의 스타일을 변경하는 등의 작업이 가능합니다.
따라서, DOM은 웹 개발에서 필수적인 개념 중 하나이며, 자바스크립트를 이용해 동적인 웹 페이지를 구현하거나 사용자 인터랙션을 처리하는 등 다양한 기능을 구현하는 데 활용됩니다.
위의 예시를 살펴보면, 문서에 명시된 트리에 있는 노드는 모두 객체입니다. 또한 태그는 요소 노드(element node)또는 개별 요소로 트리 구조를 구성합니다.
<html>은 루트 노드가 되고, <head>와 <body>는 `루트 노드의 자식이 됩니다. 그리고 요소 내의 문자는 텍스트(text) 노드가 됩니다. 텍스트 노드에 대해 짧게 알아보면, 문자열만 담을 수 있으며 자식 노드를 가질 수 없고, 트리의 끝에서 잎 노드(leaf node)가 됩니다.
위 그림에서 <title> 태그는 "사슴에 관하여"라는 텍스트 노드를 자식으로 갖습니다.
텍스트 노드에 있는 특수문자들은 아래와 같습니다.
- 새 줄(newline): ↵ (자바스크립트에선 \n로 표시)
- 공백(space): ␣
새 줄과 공백은 글자나 숫자처럼 항상 유효한 문자로 취급됩니다. 따라서 이 두 특수문자는 텍스트 노드가 되고, DOM의 일부가 됩니다. 위 HTML 문서를 보면 <head>와 <title>사이에 새 줄과 약간의 공백이 있는 것을 볼 수 있는데, 이런 특수문자 역시 #text 노드가 됩니다.
텍스트 노드 생성엔 두 가지 예외가 있습니다.
- 역사적인 이유로, <head> 이전의 공백과 새 줄은 무시됩니다.
- HTML 명세서에서 모든 콘텐츠는 body 안쪽에 있어야 한다고 했으므로, </body> 뒤에 무언가를 넣더라도 그 콘텐츠는 자동으로 body 안쪽으로 옮겨집니다. 따라서 </body> 뒤엔 공백이 있을 수 없습니다.
두 예외를 제외하곤 아주 간단합니다. 문서 내에 공백이 있다면 다른 문자와 마찬가지로 텍스트 노드가 됩니다. 그리고 공백을 지우면 텍스트 노드도 사라집니다. 공백이 없는 텍스트 노드만으로 HTML 문서를 구성하려면 HTML을 아래와 같이 만들어야 합니다.
<!DOCTYPE HTML>
<html><head><title>사슴에 관하여</title></head><body>사슴에 관한 진실.</body></html>
기형적인 HTML을 만나면 브라우저는 DOM 생성과정에서 HTML을 자동으로 교정합니다.
예를 들어 가장 최상위 태그는 항상 <html>이어야 하는데 문서에 <html> 태그가 없는 경우, 문서 최상위에 이를 자동으로 넣어주죠. 따라서 DOM에는 <html>에 대응하는 노드가 항상 있습니다. <body>도 같은 방식이 적용됩니다.
만약 HTML 파일에 "안녕하세요."라는 문장 하나만 저장된 상황이라면, 브라우저가 자동으로 이 문장을 <html> 과 <body>로 감싸줍니다
DOM 생성과정에서 브라우저는 문서에 있는 에러 등, 닫는 태그가 없는 에러 등을 자동으로 처리합니다.
닫는 태그가 없는 경우, 태그 짝이 안 맞아도 브라우저는 태그를 읽고, 자동으로 빠진 부분을 채워 넣어 줍니다.
따라서 최종 결과물은 정상적인 DOM이 됩니다.
HTML/XML 문서는 브라우저 안에서 DOM 트리로 표현됩니다.
- 태그는 요소 노드가 되고 트리 구조를 형성합니다.
- 문자는 텍스트 노드가 됩니다.
- 이 외에 HTML 내의 모든 것, 주석까지 DOM을 구성합니다.
2. DOM 탐색
DOM 탐색은 DOM 트리 구조를 따라 DOM 객체를 찾아가는 것입니다. 이를 위해서는 먼저 document 객체를 통해 DOM에 접근해야 합니다.
DOM 탐색에는 여러 가지 메서드와 속성이 있습니다. 가장 일반적으로 사용되는 메서드는 getElementById(), getElementsByTagName(), getElementsByClassName() 등입니다. 이들 메서드는 해당하는 요소의 ID, 태그 이름, 클래스 이름을 이용해 DOM 객체를 찾습니다.
또한, parentNode, childNodes, firstChild, lastChild 등의 속성을 이용하면 DOM 객체의 부모, 자식, 형제 노드를 탐색할 수 있습니다. 이 외에도 nextSibling, previousSibling 등의 속성을 이용해 다음 혹은 이전 형제 노드를 찾을 수 있습니다.
2.1 document 객체
document 객체는 DOM에 접근하기 위한 진입점(entry point)으로, 웹 페이지에 표시되는 문서 전체를 나타냅니다. 즉, HTML 문서를 표현하는 DOM 트리의 루트 역할을 합니다.
document 객체를 이용하면 웹 페이지에서 다양한 조작이 가능합니다. 예를 들어, HTML 요소에 접근하거나 조작하는 메소드와 속성을 사용할 수 있습니다. document 객체의 주요 속성과 메소드는 다음과 같습니다.
- document.documentElement: 문서의 최상위 요소(root element)를 나타내는 요소 노드
- document.body: 문서의 body 요소를 나타내는 요소 노드
- document.title: 문서의 타이틀을 나타내는 문자열
- document.getElementById(id): 지정한 id 속성 값을 가진 요소 노드를 찾아 반환
- document.getElementsByClassName(className): 지정한 class 이름을 가진 모든 요소 노드를 찾아 반환
- document.getElementsByTagName(tagName): 지정한 태그 이름을 가진 모든 요소 노드를 찾아 반환
- document.createElement(tagName): 새로운 요소 노드를 생성
- document.createTextNode(data): 새로운 텍스트 노드를 생성
위와 같은 속성과 메소드를 이용하여 document 객체를 통해 DOM 요소에 접근하고, 조작할 수 있습니다. 이를 통해 동적으로 웹 페이지를 변경하거나, 다양한 이벤트를 처리하는 등의 작업을 수행할 수 있습니다.
노드 간의 관계
- 자식 노드(child node, children) 는 바로 아래의 자식 요소를 나타냅니다. 자식 노드는 부모 노드의 바로 아래에서 중첩 관계를 만듭니다. <head>와 <body>는 <html>요소의 자식 노드입니다.
- 후손 노드(descendants) 는 중첩 관계에 있는 모든 요소를 의미합니다. 자식 노드, 자식 노드의 모든 자식 노드 등이 후손 노드가 됩니다.
노드는 다른 노드와 관계를 맺으며, 이를 통해 DOM을 구성합니다. 자식 노드(child node, children)는 부모 노드의 바로 아래에서 중첩된 요소를 말합니다. 예를 들어, <body>는 <html>요소의 자식 노드이며, <div>와 <ul>은 <body>의 자식 노드입니다.
후손 노드(descendants)는 중첩된 관계에 있는 모든 요소를 포함합니다. 이는 자식 노드, 자식 노드의 자식 노드, 그리고 그 아래의 모든 노드들을 포함합니다. 예를 들어, <body>는 <html>의 후손 노드이며, <div>와 <ul>, 그리고 그들의 하위 요소들도 후손 노드입니다.
2.2 형제와 부모 노드
같은 부모를 가진 노드는 형제(sibling) 노드 라고 부릅니다.
<head>와 <body>는 대표적인 형제 노드입니다.
<html>
<head>...</head><body>...</body>
</html>
- <body>는 <head>의 ‘다음(next)’ 혹은 '우측(right)'에 있는 형제 노드입니다.
- <head>는 <body>의 ‘이전(previous)’ 혹은 '좌측(left)'에 있는 형제 노드입니다
다음 형제 노드에 대한 정보는 nextSibling, 이전 형제 노드에 대한 정보는 previousSibling 프로퍼티에서 찾을 수 있습니다.
위의 내용들을 토대로 각 노드 간에 관계를 통해서 상호 간의 다양한 호출이 가능합니다.
2.3 주요 노드 프로퍼티
DOM 노드에 대해 좀 더 알아봅시다.
DOM 노드 : HTML 문서의 요소(element), 속성(attribute), 텍스트(text), 주석(comment) 등을 구성하는 노드를 의미
DOM 노드는 종류에 따라 각 다른 프로퍼티를 지원하고 모든 DOM 노드는 공통 조상으로 부터 만들어짐 ( 공통 프로퍼티가 존재 )
- <a> : 링크 관련 프로퍼티
- <input> : 입력 관련 프로퍼티
각 노드 클래스는 다음과 같은 특징을 가집니다.
- EventTarget – 루트에 있는 ‘추상(abstract)’ 클래스로, 이 클래스에 대응하는 객체는 실제로 만들어지지 않습니다. EventTarget가 모든 DOM 노드의 베이스에 있기때문에 DOM 노드에서 '이벤트’를 사용할 수 있습니다.
- Node – '추상’ 클래스로, DOM 노드의 베이스 역할을 합니다. getter 역할로 parentNode, nextSibling, childNodes 등의 주요 트리 탐색 기능을 제공합니다. Node 클래스의 객체는 절대 생성되지 않습니다. 하지만 이 클래스를 상속받는 클래스는 여럿 있습니다. 텍스트 노드를 위한 Text 클래스와 요소 노드를 위한 Element 클래스, 주석 노드를 위한 Comment클래스는 Node클래스를 상속받습니다.
- Element – DOM 요소를 위한 베이스 클래스입니다. nextElementSibling, getElementsByTagName, querySelector 같이 요소 전용 탐색을 도와주는 프로퍼티나 메서드가 이를 기반으로 합니다. 브라우저는 HTML뿐만 아니라 XML, SVG도 지원하는데 Element 클래스는 이와 관련된 SVGElement, XMLElement, HTMLElement 클래스의 베이스 역할을 합니다.
- HTMLElement – HTML 요소 노드의 베이스 역할을 하는 클래스입니다. 아래 클래스들은 실제 HTML 요소에 대응하고 HTMLElement를 상속받습니다.
- HTMLInputElement – <input> 요소에 대응하는 클래스
- HTMLBodyElement – <body> 요소에 대응하는 클래스
- HTMLAnchorElement – <a> 요소에 대응하는 클래스
이외에도 다른 클래스가 많은데, 각 태그에 해당하는 클래스는 고유한 프로퍼티와 메서드를 지원하고, 각 노드에서 사용 가능한 프로퍼티와 메서드는 상속을 기반으로 결정됩니다.
즉, DOM 노드는 프로토타입을 기반으로 상속 관계를 갖는 일반 자바스크립트 객체입니다.
각 DOM 노드는 고유한 클래스에 속합니다. 클래스들은 계층 구조를 형성합니다. DOM 노드에서 지원하는 프로퍼티와 메서드는 계층 구조에서 어떤 클래스를 상속받느냐에 따라 결정됩니다.
DOM에서 자주 사용되는 프로퍼티들은 다음과 같습니다.
- nodeType: 요소의 타입을 식별하는 노드 타입 상수 값입니다. 요소 노드 일 경우에는 1을, 텍스트 노드 일 경우에는 3을 반환합니다.
- nodeName/tagName: 요소의 이름을 반환하는 프로퍼티입니다. 요소 노드일 경우 대문자로 변환된 태그 이름을 반환합니다.
- innerHTML: 요소 내부의 HTML 코드 문자열을 읽거나 수정하는 프로퍼티입니다.
- outerHTML: 요소 전체의 HTML 코드 문자열을 읽거나 수정하는 프로퍼티입니다.
- nodeValue/data: 요소가 아닌 노드(텍스트, 주석 등)의 내용을 반환하거나 변경하는 프로퍼티입니다.
- textContent: HTML 태그를 제외한 순수 텍스트 정보만 조회하는 프로퍼티입니다.
- hidden: 요소를 화면에서 숨길 때 사용하는 Boolean 타입의 프로퍼티입니다.
이러한 프로퍼티들을 활용하면, 동적으로 HTML 문서를 조작할 수 있습니다.
3. 속성과 프로퍼티
브라우저는 웹페이지를 만나면 HTML을 읽어(파싱(parsing)) DOM 객체를 생성합니다.
요소 노드(element node)에서 대부분의 표준 HTML 속성(attribute)은 DOM 객체의 프로퍼티(property)가 됩니다.
이 때, 속성-프로퍼티가 항상 일대일로 매핑되지는 않는다.
ex) 태그 <body id="page">가 있을 때, DOM 객체에서 body.id="page"를 사용
3-1. DOM property
DOM 프로퍼티의 종류는 엄청나게 많습니다. 하지만 이런 내장 프로퍼티만으로 충분하지 않은 경우 자신만의 프로퍼티를 만들 수도 있습니다
3-2. HTML 속성
브라우저는 HTML을 파싱해 DOM 객체를 만들 때 HTML 표준 속성을 인식하고, 이 표준 속성을 사용해 DOM 프로퍼티를 만듭니다.
- elem.hasAttribute(name) – 속성 존재 여부 확인
- elem.getAttribute(name) – 속성값을 가져옴
- elem.setAttribute(name, value) – 속성값을 변경함
- elem.removeAttribute(name) – 속성값을 지움
프로퍼티 ( DOM ) | 속성 ( HTML ) | |
타입 | 모든 타입 가능, 각 표준 프로퍼티의 타입은 명세서에 설명되어 있음 | 문자열 |
이름 | 대·소문자 구분 | 대·소문자 구분하지 않음 |
거의 모든 상황에서 속성보다는 프로퍼티를 사용하는 게 더 낫습니다.
3-3. 프로퍼티-속성 동기화
표준 속성이 변하면 대응하는 프로퍼티는 자동으로 갱신됩니다. 몇몇 경우를 제외하고 프로퍼티가 변하면 속성 역시 마찬가지로 갱신됩니다.
<input>
<script>
let input = document.querySelector('input');
// 속성 추가 => 프로퍼티 갱신
input.setAttribute('id', 'id');
alert(input.id); // id (갱신)
// 프로퍼티 변경 => 속성 갱신
input.id = 'newId';
alert(input.getAttribute('id')); // newId (갱신)
</script>
'Tech Stack > HTML&CSS' 카테고리의 다른 글
박스 모델과 요소의 위치와 정렬 (0) | 2023.05.12 |
---|---|
CSS : Selector , Style (0) | 2023.05.12 |
HTML [2] (0) | 2022.02.17 |
HTML (0) | 2022.01.17 |