본문 바로가기
JavaScript

JavaScript] HTML attributes and DOM properties

by Fastlane 2022. 11. 8.
728x90
반응형

출처 : https://javascript.info/dom-attributes-and-properties

브라우저가 page를 로딩할때, HTML을 읽고 DOM objects를 생성한다. 대부분의 표준 HTML attributes는 자동으로 DOM objects의 properties가 된다. 

 

예를들어 태그가 <body id="page">일때, DOM object는 body.id="page"를 갖는다. 

 

하지만, attribute-property가 1:1 매핑되는 것은 아니다. 둘이 언제 같고 다른지 살펴보자. 

DOM properties

이미 많은 내장 DOM properties를 살펴보았다. 하지만 기술적으로 그 수가 제한되지 않았으며, 임의로 추가가 가능하다. DOM nodes는 일반 JavaScript Objects이므로, 수정이 가능하다. 

document.body.myData = {
  name: 'Caesar',
  title: 'Imperator'
};

alert(document.body.myData.title); // Imperator

 함수도 추가할 수 있다. 

document.body.sayTagName = function() {
  alert(this.tagName);
};

document.body.sayTagName(); // BODY (the value of "this" in the method is document.body)

Element-prototype과 같은 built-in prototypes또한 수정이 가능하고, 모든 elements에 새로운 함수 추가가 가능하다. 

Element.prototype.sayHi = function() {
  alert(`Hello, I'm ${this.tagName}`);
};

document.documentElement.sayHi(); // Hello, I'm HTML
document.body.sayHi(); // Hello, I'm BODY

어떤 값도 가질 수 있으며, case-sensitive하다. 

HTML attributes

browser가 HTML tags를 파싱해서 DOM objects를 만들 때, id 나 표준 attributes는 해당하는 property를 생성하지만, non-standard는 생성하지 않는다. 

<body id="test" something="non-standard">
  <script>
    alert(document.body.id); // test
    // non-standard attribute does not yield a property
    alert(document.body.something); // undefined
  </script>
</body>

또한 특정 element에는 표준 attribute이지만, 다른 element에서는 아닐 수 있다. 예를들어 type은 <input>(HTMLInputElement)에서는 표준이지만, <body>(HTMLBodyElement)에서는 아니다. 

<body id="body" type="...">
  <input id="input" type="text">
  <script>
    console.log(document.body.firstElementChild.type); // text
    console.log(document.body.type); // undefined: DOM property not created, because it's non-standard
  </script>
</body>

만약에 attribute가 비표준이라면, DOM-property가 없다. 이러한 attribute에 접근할 수 있는 함수들이 있다. 

  • elem.hasAttribute(name) - 존재 체크
  • elem.getAttribute(name) - value가져오기
  • elem.setAttribute(name, value) - value 설정
  • elem.removeAttribute(name) - attribute삭제

elem.attributes를 통해서 모든 attributes를 확인할 수도 있다. 

  <body id="body" something="non-standard">
    <script>
	console.log(document.body.getAttribute('something')); // non-standard
	console.log(document.body.attributes); // text
   </script>

HTML attributes는 아래 특징이 있다. 

  • name은 case-insensitive하다. (id와 ID는 동일)
  • value는 항상 string이다. 
<body>
  <div id="elem" about="Elephant"></div>

  <script>
    console.log( elem.getAttribute('About') ); // (1) 'Elephant', reading

    elem.setAttribute('Test', 123); // (2), writing

    console.log( elem.outerHTML ); // (3), see if the attribute is in HTML (yes)

    for (let attr of elem.attributes) { // (4) list all
      console.log( `${attr.name} = ${attr.value}` );
    }
  </script>
</body>

  1. getAttribute('About') - 첫글자가 대문자이지만, case-insensitive하므로, attribute를 가져올 수 있다. 
  2. attribute를 추가할 수 있으며 값은 string이 된다. 
  3. outerHTML로 모든 attributes를 확인할 수 있다. 
  4. attributes collection은 iterable하고, element의 모든 attributes를 갖고 있다. 

Property-attribute synchronization

표준 attribute가 바뀌면, 해당되는 property도 자동 업데이트된다. 

<input>

<script>
  let input = document.querySelector('input');

  // attribute => property
  input.setAttribute('id', 'id');
  alert(input.id); // id (updated)

  // property => attribute
  input.id = 'newId';
  alert(input.getAttribute('id')); // newId (updated)
</script>

하지만 예외사항이 있다. attribute value는 property를 업데이트할 수 있지만, property 변경은 attribute에 영향을 줄 수 없다. 

<input>

<script>
  let input = document.querySelector('input');

  // attribute => property
  input.setAttribute('value', 'text');
  alert(input.value); // text

  // NOT property => attribute
  input.value = 'newValue';
  alert(input.getAttribute('value')); // text (not updated!)
</script>

사용자의 action이 value를 수정해도, 초기값이 attribute에 있으므로 값을 초기값으로 되돌릴 수 있다. 

DOM properties are typed

DOM properties는 항상 string은 아니다. 

<input id="input" type="checkbox" checked> checkbox

<script>
  alert(input.getAttribute('checked')); // the attribute value is: empty string
  alert(input.checked); // the property value is: true
</script>
<div id="div" style="color:red;font-size:120%">Hello</div>

<script>
  // string
  alert(div.getAttribute('style')); // color:red;font-size:120%

  // object
  alert(div.style); // [object CSSStyleDeclaration]
  alert(div.style.color); // red
</script>

DOM property가 string이라 하더라도 attribute와는 값이 다를 수 있다. 

<a id="a" href="#hello">link</a>
<script>
  // attribute
  alert(a.getAttribute('href')); // #hello

  // property
  alert(a.href ); // full URL in the form http://site.com/page#hello
</script>

Non-standard attributes, dataset

HTML을 작성할 때, 우리는 많은 표준 attributes를 사용한다. 하지만 비표준, custom한 것은 어떨까?

 

때때로 비표준 attributes는 HTML에서 JavaScript로 custom data를 전달하는데 사용되거나, JavaScript를 위해 HTML element를 표시하는데 사용된다. 

 

<!-- mark the div to show "name" here -->
<div show-info="name"></div>
<!-- and age here -->
<div show-info="age"></div>

<script>
  // the code finds an element with the mark and shows what's requested
  let user = {
    name: "Pete",
    age: 25
  };

  for(let div of document.querySelectorAll('[show-info]')) {
    // insert the corresponding info into the field
    let field = div.getAttribute('show-info');
    div.innerHTML = user[field]; // first Pete into "name", then 25 into "age"
  }
</script>

또는 style지정하기 위해서도 사용할 수 있다. 

<style>
  /* styles rely on the custom attribute "order-state" */
  .order[order-state="new"] {
    color: green;
  }

  .order[order-state="pending"] {
    color: blue;
  }

  .order[order-state="canceled"] {
    color: red;
  }
</style>

<div class="order" order-state="new">
  A new order.
</div>

<div class="order" order-state="pending">
  A pending order.
</div>

<div class="order" order-state="canceled">
  A canceled order.
</div>

왜 attribute를 사용하는 것이, class(.order-state-new, .order-state-pending, .order-state-canceled)를 사용하는 것보다 선호되는가? 왜냐하면 attribute가 더 관리에 용이하다. 

// a bit simpler than removing old/adding a new class
div.setAttribute('order-state', 'canceled');

하지만 custom attribute를 사용하는데 발생할 수 있는 문제점이 있다. 특정 목적으로 non-standard attribute를 사용하였는데 차후 standard로 소개될 수 있다. 

 

그런 충돌을 피하기 위해 data-* attributes가 존재한다. 

 

'data-'로 시작하는 모든 attributes는 개발자의 사용을 위해 예약되며, dataset property에서 유효하다. 

<body data-about="Elephants">
<script>
  alert(document.body.dataset.about); // Elephants
</script>

'data-order-state'처럼 여러단어로 된 attribute는 'dataset.orderState'와 같은 camel-cased가 된다. 

<style>
  .order[data-order-state="new"] {
    color: green;
  }

  .order[data-order-state="pending"] {
    color: blue;
  }

  .order[data-order-state="canceled"] {
    color: red;
  }
</style>

<div id="order" class="order" data-order-state="new">
  A new order.
</div>

<script>
  // read
  alert(order.dataset.orderState); // new

  // modify
  order.dataset.orderState = "pending"; // (*)
</script>

'data-*'를 사용하는 것은 유효하고, custom data를 전달하기에 안전한 방법이다. data-attributes는 읽기 뿐만 아니라, 수정도 가능하다. 

Summary

  • Attributes - HTML에서 작성함
  • Properties - DOM objects에 있음

비교해보자 

  Properties Attributes
Type any value, standard properties는 spec에 type이 명시되어 있다.  string
Name case-sensitive case-insensitive

 

대부분의 상황에서 DOM properties를 사용하는 것이 선호된다. DOM properties가 상황에 맞지 않는 경우, attributes를 사용할 수 있다. 

728x90
반응형

'JavaScript' 카테고리의 다른 글

JavaScript] Document Styles and classes  (1) 2022.11.14
JavaScript] document 수정  (0) 2022.11.11
JavaScript] DOM Node properties  (0) 2022.11.04
JavaScript] Searching: getElement*, querySelector*  (0) 2022.11.04
JavaScript] DOM Navigation  (0) 2022.11.03

댓글