회고록 블로그

[공부 필기] 생활코딩 웹브라우저 자바스크립트 강의 필기 (2) 본문

2. 프로그래밍 언어 공부/JavaScript

[공부 필기] 생활코딩 웹브라우저 자바스크립트 강의 필기 (2)

김간장 2021. 5. 24. 23:02

이전 필기 : https://cinnamonc.tistory.com/185

 

[공부 필기] 생활코딩 웹브라우저 자바스크립트 강의 필기 (1)

1. 웹브라우저에서의 자바스크립트 * 프로그래밍의 본질적인 요소인 조건문, 함수 등을 배우고 * 자바스크립트의 고유 요소인 DOM에 대해서 학습함 * [참고] 자바스크립트가 HTML, CSS를 어떻게 제어

cinnamonc.tistory.com


DOM

* 단수와 복수

   - 객체의 프로퍼티를 이용해서 색상, 이미지 변경 등을 하기 위해서는 객체에 대해 이해할 필요가 있음

   - getElementById와 getElementsByTagName

      => getElementById가 리턴한 값(단수의 값)은 "HTMLLIElement"이라는 객체이고,

           (조회한 엘리먼트가 <li>이기 때문에 HTMLLIElement가 됨)

      => getElementsByTagName이 리턴한 값(복수의 값)은 "HTMLCollection"(=유사배열)이라는 객체임

   - DOM을 직접 이용하는 경우는 많지 않고, 라이브러리를 많이 사용하는데, 그 라이브러리 내부에는 위와 같은 내용들이 감춰져있음

 

HTMLElement

* HTMLElement

   - HTMLUListElement, HTMLAnchorElement, HTMLInputElement

       # 공통점: HTML, Element를 가지고 있음

       # 차이점: 태그에 따라 UList, Anchor, Input 등을 가짐

   - 즉, 요소의 태그마다 '객체'가 다르다는 의미임

       # 그리고 그 객체를 이용해서 요소(element)를 제어함 

   - 또한, 객체 마다 포함하고 있는 프로퍼티(property, 속성)도 다르다는 의미임

       # 왜냐하면, li 같은 경우 리스트만 표현하면 되는 객체이므로 그에 맞는 속성을 갖고 있지만

           a 태그 같은 경우 링크 주소도 필요하고(href), 클릭 했을 때 이동을 어떻게 할 것인지(target) 설정하는 등 속성이 다르기 때문 

   - 정리하자면, "HTML Element"이라는 공통적인 특성을 갖고 있으므로 공통적인 프로퍼티를 가지고 있으면서 동시에

     각 태그들의 쓰임, 스펙, 성격 등에 따라서 조금씩 다른 프로퍼티도 가지고 있다는 말.

       # 그리고 이런 사정으로 인해서 태그마다 '객체'가 다름

   - 사실 HTMLAnchorElement, HTMLInputElement 등은 "HTMLElement" 객체를 상속받은 형태임

       # 상속에 대한 개념은 JavaScript 문법 강의 참고

       # 따라서, HTMLElement의 프로퍼티를 그대로 상속받고 Anchor, Input, UList 등 각자의 태그에 따라 맞춤형(?) 프로퍼티도 갖고 있는 것

출처: MDN Web Docs ; 링크: https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement

* DOM Tree

   - https://opentutorials.org/course/1375/6665

 

HTMLElement - 생활코딩

HTMLElement getElement* 메소드를 통해서 원하는 객체를 조회했다면 이 객체들을 대상으로 구체적인 작업을 처리해야 한다. 이를 위해서는 획득한 객체가 무엇인지 알아야 한다. 그래야 적절한 메소

opentutorials.org

   - DOM을 이해하는 것 = DOM프로그래밍, JavaScript를 통해서 웹페이지를 제어하는 것에 대한 핵심 사항

 

HTMLCollection

* HTMLCollection

   - HTML Collection 객체에는 엘리먼트들이 담겨져있고, 유사배열이라고 볼 수 있음

   - 이 객체는 '목록이 실시간으로 갱신된다'는 독특한 특성을 가짐

   - console.group ~ console.groupEnd

      # console.group 에서 console.groupEnd()까지의 사이에 있는 코드들을 그룹핑해서 보여줌

   - 아래 코드를 통해 HTMLCollection 이해하기

      # <li>태그의 엘리먼트(요소)를 lis 라는 변수에 저장함

      # 'before' 그룹 : lis 변수의 값을 모두 출력함

      # 'after' 그룹 : lis 변수의 값에서 두번째 값(lis[1])을 제거하고 출력함

      # 이를 통해 알 수 있는 점은 "HTMLCollection은 객체를 제거하면, 제거된 순간에 바로 반영"을 한다는 점

 

jQuery 객체

* jQuery의 특성

   - jQuery 객체: jQuery 함수가 리턴한 결과를 말함

   - 저번 필기 복습

jQuery
   - 항상 '$'로 시작함

   - '$'를 jQuery 함수라고 함 (함수이기 때문에 리턴값이 있음)
      => jQuery 함수를 통해서 리턴된 값은 "jQuery 객체"
...

   - 즉, 아래 코드에서 $로 시작하는 $('li')는 jQuery 함수이고, li 변수는 jQuery 객체

var li = $('li');
console.log(li);

   - 예제.

      # $('li') : jQuery 함수가 리턴한 객체는 모든 <li> 태그의 엘리먼트들을 리턴한 것임

      # lis.css('text-decoration', 'underline') : lis는 jQuery 객체이며, 이 객체를 이용해서 여러 작업을 할 수 있음

...
<body>
    <ul>
        <li>HTML</li>
        <li>CSS</li>
        <li>JavaScript</li>
    </ul>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"
        integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
    <script src="./script7.js"></script>
</body>
</html>
// script7.js
var lis = $('li');
console.log(lis);
lis.css('text-decoration','underline');

      # lis.css('text'-decoration', 'underline') : 암시적 반복

          => 모든 <li> 태그들에 대해서 text-decoration을 underline으로 적용하였음

          => 보통 명시적으로 반복문을 이용해서 css를 적용하지만 (아래 참고)

                jQuery 라이브러리를 이용하면 반복문을 이용할 필요가 없음

// Vanila JavaScript
var lis = document.getElementsByTagName('li');
for(var i=0; i<lis.length; i++){
    lis[i].style.textDecoration="underline";
}

 

※ jQuery에 대한 학습은 이후 진행하기로 하고, 우선은 순수한 자바스크립트에 대해서 학습하기로 결정함.


Element 객체

* HTML 문서상에 있는 각각의 태그 (=엘리먼트)

* 엘리먼트를 추상화한 객체가 "Element 객체"

* HTMLElement에게는 부모 객체가 있는데, 그 부모 객체가 바로 "Element"

   # 본 글의 가장 위에서 언급한 'HTMLLIElement, HTMLAnchorElement' 등의 부모는? "HTMLElement"

   # 그리고 그 HTMLElement의 프로퍼티 중 가장 대표적인 것이 "style"임 (특정 엘리먼트의 CSS를 제어함)

   # 그 HTMLElement의 부모가? "Element"

* Element 객체는 문서 상에 나타나는 모든 엘리먼트들에 대한 기능을 정의하는 객체임

   # HTMLElement : 모든 태그들(엘리먼트들)에 대한 공통적인/기본적인 기능을 정의함


Q. Element 객체와 HTMLElement 객체는 유사한 기능을 하는데 왜 구분되어 있을까?

- 사실 DOM(Document Object Model)은 꼭 HTML만을 프로그래밍적으로 제어하기 위해서 사용하는 규격/표준이 아님

- 마크업 언어(HTML, XML, SVG, XUL 등)를 프로그래밍적으로 제어하기 위한 규격이 DOM인 것.

- 당연히 이 마크업 언어들도 모두 엘리먼트를 가지고 있음

- 그 모든 엘리먼트들에게 적용할 수 있는 기능이 "Element" 객체에 정의되어 있는 것이고,

- 마크업 언어들 중에서도 HTML이라는 마크업 언어에서 엘리먼트들이 가져야할 기능들을 추가하기 위해 사용하는 것이 "HTMLElement"인 것.


* 따라서 style이라는 프로퍼티는 "Element" 객체의 프로퍼티가 아닌 "HTMLElement" 객체의 프로퍼티임

* 현재 강의에서는 JavaScript로 DOM을 제어하는 것을 배우고 있지만

   PHP(?), Java(?) 등 다른 언어에서도 DOM을 지원하고 있다면 그 언어를 이용해서 DOM을 제어하는 방법을 익힐 수도 있음

   (DOM은 마크업 언어를 프로그래밍적으로 제어하기 위한 표준임)

* Chrome 개발자도구를 이용하면 객체의 상속관계와 프로퍼터를 알 수 있음

    - 아래 예시) <li> 태그는 HTMLLIElement 객체를 통해 제어하며, 해당 객체의 상속관계는 아래와 같음

* Element 객체가 가지고 있는 API

   - Element.classList ; Element.className ; Element.id ; Element.querySelector 등

     식별자, 조회, 속성 API로 나눌 수 있을 것 같음

 

Element 객체 - 식별자 API

* getElementsByTagName, getElementsByClassName 등을 통해 엘리먼트 객체를 조회함

* 각각의 엘리먼트들은 자신을 찾아낼 수 있도록 이름을 갖는데 그것이 tag name, class, id 등임 (=식별자)

* 그리고 이런 이름을 프로그래밍적으로 알아내는 방법을 알아보는 강의임

* 이때 필요한 것이 '식별자 API'인데, 식별자를 가져오고 변경하는 역할을 함

* Element.tagName

   - 예제)

<body>
    <ul>
        <li>HTML</li>
        <li>CSS</li>
        <li id="active" class="important current">JavaScript</li>
    </ul>
    <script>
        console.log(document.getElementById('active').tagName);
    </script>
...

   - id="active"인 태그는 <li>임

   - 이 <li> 태그의 객체는 HTMLLIElement이며, 부모 객체는 HTMLElement임

      HTMLElement의 부모 객체는 Element 객체이며 Element 객체에는 tagName 이라는 프로퍼티가 있음

   - Element의 tagName 프로퍼티를 이용하면 id="active"의 태그명은 li라는 것을 알아낼 수 있음

   - tagName은 읽기 전용이므로 수정은 불가능함

* Element.id

   - 식별자 id는 문서에서 단 하나만 존재함

   - 식별자 id를 찾아내는 예제)

...
<body>
    <ul>
        <li>HTML</li>
        <li>CSS</li>
        <li id="active" class="important current">JavaScript</li>
    </ul>
    <script>
        console.log(document.getElementById('active').id);
        
    </script>
...

// 결과: active 출력

   - 찾아낸 식별자 id를 수정하는 것도 가능함

...
var active = document.getElementById('active');
active.id = 'deactive';
console.log(active.id);
...

// 결과: deactive 출력

* Element.className, Element.classList

* className

   - className은 classList보다 사용하기 꽤나 불편함 (더 진보된 API는 classList임)

   - 식별자 class명 찾는 예제)

    <ul>
        <li>HTML</li>
        <li>CSS</li>
        <li id="active">JavaScript</li>
    </ul>
    <script>
        var active = document.getElementById('active');
        active.className = "important current";
        console.log(active.className);
...

//결과 : important current 출력 

   - id="active"인 엘리먼트에게 class명을 부여해줌 (important current)

   - 만약 class명을 일부만 제거하고, 일부는 그대로 두고 싶다면?

      => 제거하고자 하는 class명을 제외하고 나머지 class명을 전부 입력해주어야 함

   - class명을 추가할 땐, 전체 class명을 입력 후 추가할 class명을 입력해주거나,

     아래와 같이 코드를 작성함

...
var active = document.getElementById('active');
active.className = "important current";
active.className = active.className + " page";
console.log(active.className);
...

   - class명을 추가하거나 삭제할 때 굉장히 불편함

      # 추가할 땐, "중복되는 class명이 있는지 직접 확인 후" 추가를 하여야 하며

      # 삭제할 땐, "삭제할 대상이 아닌 나머지 class명을 입력 후" 대입하여야 함

      # 이를 해결하기 위해서 classList를 사용함

*classList

   - className과 동일한 기능하지만 조금 까다로움

   - classList는 DOMTokenList 객체임

      # class명이 여러개일 때 각각의 class명을 모두 담아놓은 것

      # DOMTokenList는 유사배열이므로, 배열의 형태로 class명을 담고 있음

          => 배열의 요소에 접근하는 것과 같이 active.classList[0], active.classList[1] ...로 접근함

   - 식별자 class명 찾는 예제)

...
	<ul>
        <li>HTML</li>
        <li>CSS</li>
        <li id="active" class="main-list important current page">JavaScript</li>
    </ul>
    <script>
        var active = document.getElementById('active');
        for(var i=0; i<active.classList.length; i++){
            console.log(active.classList[i]);
        }
	</script>
...

   - class명을 추가하고 싶다면? active.classList.add('[추가할 class명]') 으로 추가 가능

     # DOMTokenList라는 객체에는 add라는 메소드가 있기 때문에 이를 사용해서 class명 간단히 추가 가능

   - class명을 제거하고 싶다면? active.classList.remove('[제거할 class명]') 으로 제거 가능

   - e.g.) "emergency"라는 클래스명이 없다면? -> 추가해주고,

    있다면? -> 제거하도록 하는 기능을 구현하고 싶다면? classList.toggle('emergency')를 이용하면 됨

     # 'emergency' 라는 class명이 기존에는 없었는데 toggle 메소드를 이용해서 추가됐다면 => 'true'가 리턴됨

     # 'emergency' 라는 class명이 기존에는 있었는데 toggle 메소드를 이용해서 삭제됐다면 => 'false'가 리턴됨

Element 객체 - 조회 API

*Element 객체의 getElementsBy*

   - 조회 API는 엘리먼트를 조회하는 기능임

   - 지금까지는 document.getElementsBy* 를 사용하였고,  document는 "문서 전체"를 의미하는 객체임

   - 즉, document.getElementsBy* 는 "문서 전체에서 어떤 엘리먼트를 찾을 때/조회할 때" 사용을 함

   - 찾고자 하는 객체가 어떠한 객체의 하위 엘리먼트인 경우,

     객체를 조회하는 범위를 줄여서 조회를 하고 싶다면 Element 객체에 있는 getElementsBy* 를 이용해야함

   - (Element 객체에도 getElementsBy* 메소드가 있음)

   - 엘리먼트 조회 예제)

      # textContent : Node의 프로퍼티. 요소의 텍스트 컨텐츠(아래 예제에서 HTML, CSS, JavaScript 등)를 가져옴

...
	<ul>
        <li class="marked">HTML</li>
        <li>CSS</li>
        <li id="active">JavaScript
            <ol>
                <li class="marked">DOM</li>
                <li class="marked">BOM</li>
                <li>JavaScript Core</li>
            </ol>
        </li>
    </ul>
    <script>
        // 1번. 전체 문서에서 class='marked' 찾기
        console.group('document');
        var marked = document.getElementsByClassName('marked');
        for(var i=0; i<marked.length; i++){
            console.log(marked[i].textContent);
        }
        console.groupEnd();
    </script>

...
<script>
  // 2번. <li id="active">의 하위에서 class='marked' 찾기
  console.group('active');
  var active = document.getElementById('active');
  var marked = active.getElementsByClassName('marked');
  for(var i=0; i<marked.length; i++){
  console.log(marked[i].textContent);
  }
  console.groupEnd();
</script>
...

Element 객체 - 속성 API

* getAtrribute 

   - HTML 태그에는 속성이 있음 (e.g. <a href="#" target="_blank"> 등)

   - 태그 이름만으로 정보를 표현하기 어려울 때, 부가적인 정보를 속성으로 표현함

   - 이 엘리먼트의 속성값을 제어하는 방법을 강의에서 배움

   - 속성 제어 예제)

...
<a href="http://naver.com">NAVER</a>
<a href="http://daum.net" id="target">Daum</a>
<script>
    var t = document.getElementById('target');
    console.log(t.getAttribute('href'));

    console.log(t.id);  // 결과: target 
    console.log(t.getAttribute('id')); // 결과: target (동일)

    t.setAttribute('href', 'http://google.co.kr');
    console.log(t.getAttribute('href')); // 결과: http://google.co.kr

    t.setAttribute('title', 'webpage'); // title 이라는 속성을 추가함
    console.log(t.getAttribute('title')); // 결과: webpage

    t.removeAttribute('title'); // title 이라는 속성을 제거함
    console.log(t.getAttribute('title')); // 결과: null

    console.log(t.hasAttribute('title')); // title이라는 속성이 존재하는지 확인함 (없으면 false, 있으면 true 리턴)
 ...

* 속성과 프로퍼티

   - property 방식과 attribute 방식

      # 두가지 모두 결과는 동일함

      # 좀 더 빠르고 간편한 방식은 property 방식임

...
var t = document.getElementById('target');

t.className = 'important';  // property 방식
t.setAttribute('class', 'important'); // attribute 방식
...

      # 둘은 사용방법에서 조금씩 차이가 있음

          => attribute 방식은 'class', 'rowspan' 등과 같이 HTML의 속성과 동일한 이름으로 사용할 수 있지만

          => property 방식은 'className', 'rowSpan' 등과 같이 이름을 주의해야함

      # 둘의 결과도 조금 다를 수 있음 (아래 예시)

           => 절대경로에서는 차이가 없지만 상대경로에서는 아래와 같은 차이점이 있음

...
<a href="http://naver.com">NAVER</a>
<a href="./demo1.html" id="target">Daum</a> <!-- 상대경로로 되어 있음 -->
<script>
    var t = document.getElementById('target');

    console.log('t.href :', t.href);
    console.log('t.getAttribute :', t.getAttribute('href'));
</script>
...

 

Node 객체

* DOM에서 시조와 같은 역할을 함 (가장 최상위 객체)

* 모든 DOM에 있는 객체는 Node 객체를 상속받음

* Node 객체와 DOM의 객체들 간의 관계 그림 : https://opentutorials.org/course/1375/6698

* Node 객체에는 각각의 객체들 간의 관계성을 부여하는 API가 있음

   - 각각의 엘리먼트들이 어떤 관계를 갖고 있는지를 프로그래밍적으로 알 수 있음

      # 태그 밑에 <li> 태그가 있을 때, <li>는 <ul> 엘리먼트의 '자식 엘리먼트'가 되는데

         이 '자식 엘리먼트'를 가져올 수 있는게 Node.childNodes 프로퍼티임

      # 이 외에도 Node.firstChild, Node.lastChild, Node.previousSibling 등이 있음

   - 노드의 종류도 알 수 있음

      # 어떤 엘리먼트가 텍스트인지 코멘트(주석)인지

   - 어떤 노드가 갖고 있는 값이 무엇인지도 알 수 있음

      # <li>텍스트입니다</li> 이라는 HTML 태그가 있을 때, li의 값(="텍스트입니다")을 알아내려면 Node.nodeValue를 이용

   - 각각의 노드들의 하위에 있는 자식 엘리먼트를 삭제하거나 추가할 수도 있음

      # Node.appendChild(), Node.removeChild()

* 텍스트(text)는 HTML에서 태그 사이에 있는 값을 의미

   - <a> 태그부터 </a> 태그까지는 엘리먼트라고 함

<a herf="#">html텍스트</a>

* body 태그의 firstChild를 찾으면 아래와 같이 "#text"가 출력됨

   - <ul>이 출력되지 않는 이유?

      # <body>태그와 <ul>태그의 사이에 있는 "공백이나 줄바꿈, 문자 등"이 첫번째 자식이기 때문에 (참고그림 2를 확인할 것)

      # 즉, "공백이나 줄바꿈"도 Node이자 객체라는 것을 알 수 있음 (눈에는 보이지 않지만)

      # <body> 태그와 <ul> 태그 사이의 간격을 제거하면 예상한대로 <ul> 엘리먼트가 body의 첫번째 자식으로 출력됨

참고그림1
참고그림2

* 아래와 같이 응용할 수도 있음

   - body 태그의 첫번째 자식 엘리먼트를 찾고 -> 첫번째 자식 엘리먼트의 다음에 있는 형제 엘리먼트를 찾을 때

      # body 태그의 첫번째 자식 엘리먼트 : 텍스트 (줄바꿈과 공백)

      # body 태그의 첫번째 자식 엘리먼트의 인접한 형제 엘리먼트 : <ul>

      # 그 다음 형제 엘리먼트 : 텍스트(줄바꿈과 공백)

* childNodes

   - 아래와 같이 사용함

   - 단, 아래와 같은 상황에서 childNodes에 있는 요소들의 style을 변경한다면 에러가 발생함

      # 중간에 "text"가 존재하기 때문 (text에는 style 프로퍼티가 없음)

childNodes
에러발생

* nodeType, nodeName

   - nodeType : 3 대신에 Node.TEXT_NODE를 사용해도 됨

   - nodeType 숫자 참고 : https://opentutorials.org/course/1375/6700

   - nodeName : "UL", "#text", "SCRIPT" 등이 있음

* 재귀함수 (어려움)

   - 어떠한 함수가 실행될 때 자기 자신을 호출하는 함수

 

 


2021.06.07

이틀 정도 계속 고민해봤는데, 자바스크립트 강의는 우선 여기까지 듣고 중단하기로 했다.

프론트엔드도 좋은 분야이고 쉽게 배우기 어려운 분야이기는 하지만  개인적으로 취향과 맞지 않아서 (ㅠㅠ) 

이번에는 백엔드쪽을 공부해보기로 했다.

(프로그래머의 수많은 분야 중 맞는 분야를 찾기 위한 결정이다)

Comments