본문 바로가기

Front-end/JavaScript

[JavaScript] 속성과 프로퍼티

브라우저는 웹페이지를 만나면 HTML을 읽어(파싱(parsing)) DOM 객체를 생성한다. 요소 노드(element node)에서 대부분의 표준 HTML 속성(attribute)은 DOM 객체의 프로퍼티(property)가 된다.

그런데 속성-프로퍼티가 항상 일대일로 매핑되지는 않는다!

 

1. DOM프로퍼티

DOM 프로퍼티의 종류는 엄청나게 많지만 이런 내장 프로퍼티만으로 충분하지 않은 경우 자신만의 프로퍼티를 만들 수도 있다.

<<document.body에 새로운 프로퍼티를 만들기>>

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

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

DOM 프로퍼티는 일반 자바스립트 객체처럼 행동하므로 아래와 같은 특징을 보인다.

  • 어떤 값이든 가질 수 있다.
  • 대·소문자를 가린다. elem.nodeType는 동작하지만 elem.NoDeTyPe는 동작하지 않는다.

2. HTML 속성

HTML에서 태그는 복수의 속성을 가질 수 있다. 브라우저는 HTML을 파싱해 DOM 객체를 만들 때 HTML 표준속성을 인식하고, 이 표준 속성을 사용해 DOM프로퍼티를 만든다.

따라서 요소가 id같은 표준 속성으로만 구성되어 있다면, 이에 해당하는 프로퍼티가 자연스레 만들어진다.
하지만 표준이 아닌 속성일 때는 상황이 달라진다.

<body id="test" something="non-standard">
  <script>
    alert(document.body.id); // test
    // 비표준 속성은 프로퍼티로 전환되지 않는다.
    alert(document.body.something); // undefined
  </script>
</body>

한 요소에선 표준인 속성이 다른 요소에선 표준이 아닐 수 있다는 점에도 주의해야 한다. "type"은 <input> 에선 표준이지만 <body>에선 아니다. 

<body id="body" type="...">
  <input id="input" type="text">
  <script>
    alert(input.type); // text
    alert(body.type); // type은 body의 표준 속성이 아니므로 DOM 프로퍼티가 생성되지 않아 undefined가 출력
  </script>
</body>

**표준 속성이 아닌 경우, 이에 매핑하는 DOM프로퍼티가 생성되지 않지만, 비표준 속성으로 접근하는 방법**

  • elem.hasAttribute(name) – 속성 존재 여부 확인
  • elem.getAttribute(name) – 속성값을 가져옴
  • elem.setAttribute(name, value) – 속성값을 변경함
  • elem.removeAttribute(name) – 속성값을 지움

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>

4. DOM프로퍼티 값의 타입

DOM 프로퍼티는 항상 문자열이 아니다. 체크 박스에 사용되는 input.checked 프로퍼티의 경우 불린 값을 가진다.

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

<script>
  alert(input.getAttribute('checked')); // 속성 값: 빈 문자열
  alert(input.checked); // 프로퍼티 값: true
</script>

style 속성의 경우 문자열이지만, style 프로퍼티는 객체이다.

<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>

5. 비표준 속성, dataset

HTML을 작성할 때 우리는 대부분 표준 속성을 사용한다. 하지만 표준이 아닌 속성도 존재한다.

비표준 속성은 사용자가 직접 지정한 데이터를 HTML에서 자바스크립트로 넘기고 싶은 경우나 자바스크립트를 사용해 조작할 HTML 요소를 표시하기 위해 사용할 수 있다.

<!-- 이름(name) 정보를 보여주는 div라고 표시 -->
<div show-info="name"></div>
<!-- 나이(age) 정보를 보여주는 div라고 표시 -->
<div show-info="age"></div>

<script>
  // 표시한 요소를 찾고, 그 자리에 원하는 정보를 보여주는 코드
  let user = {
    name: "Pete",
    age: 25
  };

  for(let div of document.querySelectorAll('[show-info]')) {
    // 원하는 정보를 필드 값에 입력해 줌
    let field = div.getAttribute('show-info');
    div.innerHTML = user[field]; // Pete가 'name'에, 25가 'age'에 삽입됨
  }
</script>

비표준 속성은 요소에 스타일을 적용할 때 사용되기도 한다.

<style>
  /* 스타일이 커스텀 속성 '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>

이렇게 커스텀 속성을 사용하는 게 .order-state-new, .order-state-pending, order-state-canceled같은 클래스를 사용하는 것보다 왜 선호될까?

--> 속성은 클래스보다 다루기 편리하기 때문이다.

// 새 클래스를 추가하거나 지우는 것보다 더 쉽게 상태(state)를 바꿀 수 있다.
div.setAttribute('order-state', 'canceled');

물론 커스텀 속성에도 문제가 발생할 수 있다.

비표준 속성을 사용해 코드를 작성했는데 나중에 그 속성이 표준으로 등록되게 되면 문제가 발생하기 때문!!

이런 충돌을 방지하기 위한 속성인 data-*가 있다.

’data-'로 시작하는 속성 전체는 개발자가 용도에 맞게 사용하도록 별도로 예약된다. dataset 프로퍼티를 사용하면 이 속성에 접근할 수 있다.

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