속성과 프로퍼티를 어떻게 다룰 수 있는지, 두 가지가 언제 일대일로 매핑되는지, 언제는 매핑되지 않는지에 주의하면서 두 개념을 알아보자.
DOM 프로퍼티의 종류는 엄청나게 많다. 하지만 이런 내장 프로퍼티만으로 충분하지 않은 경우 자신만의 프로퍼티를 만들 수도 있다.
// 프로퍼티 만들기
document.body.myData = {
name: 'Caesar',
title: 'Imperator'
};
alert(document.body.myData.title); // Imperator
// 메서드 만들기
document.body.sayTagName = function() {
alert(this.tagName);
};
document.body.sayTagName(); // BODY (sayTagName의 'this'엔 document.body가 저장된다.)
위에서 살펴본 바와 같이 DOM 프로퍼티와 메서드는 일반 자바스크립트 객체처럼 행동하므로 아래와 같은 특징을 보인다.
브라우저는 HTML을 파싱 해 DOM 객체를 만들 때 HTML 표준 속성을 인식하고, 이 표준 속성을 사용해 DOM 프로퍼티를 만든다.
따라서 요소가 id 같은 표준 속성으로만 구성되어 있다면, 이에 해당하는 프로퍼티가 자연스레 만들어진다. 하지만 표준이 아닌 속성일 때는 상황이 달라진다.
<body id="test" something="non-standard">
<script>
alert(document.body.id); // test
// 비표준 속성은 프로퍼티로 전환되지 않습니다.
alert(document.body.something); // undefined
</script>
</body>
이처럼 표준 속성이 아닌 경우, 이에 매핑하는 DOM 프로퍼티가 생성되지 않는다. 그렇다면 비표준 속성은 어떻게 접근할까?
=> 모든 속성은 아래의 메서드를 사용해 접근할 수 있다.
<body something="non-standard">
<script>
alert(document.body.getAttribute('something')); // 비표준 속성에 접근
</script>
</body>
HTML 속성은 아래와 같은 특징을 보인다.
<body>
<div id="elem" about="Elephant"></div>
<script>
alert( elem.getAttribute('About') ); // (1) 'Elephant', 속성 읽기
elem.setAttribute('Test', 123); // (2) 속성 추가하기, <div id="elem" about="Elephant" test="123"></div>
alert( elem.outerHTML ); // (3) 추가된 속성 확인하기, id = elem
for (let attr of elem.attributes) { // (4) 속성 전체 나열하기
alert( `${attr.name} = ${attr.value}` );// about = Elephant, test = 123
}
</script>
</body>
표준 속성이 변하면 대응하는 프로퍼티는 자동으로 갱신된다.
아래 예시에서 속성 id가 수정되면 이에 대응하는 프로퍼티가 갱신되는 것을 볼 수 있다.
<input>
<script>
let input = document.querySelector('input');
// 속성 추가 => 프로퍼티 갱신
input.setAttribute('id', 'id');
alert(input.id); // id (갱신)
// 프로퍼티 변경 => 속성 갱신
input.id = 'newId';
alert(input.getAttribute('id')); // newId (갱신)
</script>
아래의 input.value처럼 동기화가 속성에서 프로퍼티 방향으로만 일어나는 예외상황도 존재한다.
<input>
<script>
let input = document.querySelector('input');
// 속성 추가 => 프로퍼티 갱신
input.setAttribute('value', 'text');
alert(input.value); // text (갱신)
// 프로퍼티를 변경해도 속성이 갱신되지 않음
input.value = 'newValue';
alert(input.getAttribute('value')); // text (갱신 안됨!)
</script>
속성 value를 수정하면 프로퍼티도 수정된다. 하지만 프로퍼티를 수정해도 속성은 수정되지 않는다.
이런 '기능’은 유용하게 사용될 수도 있다. 유저의 어떤 행동 때문에 value가 수정되었는데 수정 전의 ‘원래’ 값으로 복구하고 싶은 경우, 속성에 저장된 값을 가지고 오면 된다.
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>
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>
비표준 속성은 요소에 스타일을 적용할 때 사용되기도 한다.
아래 예시에선 주문 상태(order state)를 나타내는 커스텀 속성 order-state를 사용해 주문 상태에 따라 스타일을 변경한다.
<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>
dl렇게 커스텀 속성을 사용하는 게 .order-state-new, .order-state-pending, order-state-canceled같은 클래스를 사용하는 것보다 왜 선호될까?
=> 이유는 속성은 클래스보다 다루기 편리하다는 점 때문이다. 속성의 상태는 아래와 같이 쉽게 변경할 수 있다.
// 새 클래스를 추가하거나 지우는 것보다 더 쉽게 상태(state)를 바꿀 수 있다.
div.setAttribute('order-state', 'canceled');
물론 커스텀 속성에도 문제가 발생할 수 있다. 비표준 속성을 사용해 코드를 작성했는데 나중에 그 속성이 표준으로 등록되게 되면 문제가 발생함.
그래서 이런 충돌 상황을 방지하기 위한 속성인 data-* 가 있다.
’data-'로 시작하는 속성 전체는 개발자가 용도에 맞게 사용하도록 별도로 예약된다. dataset 프로퍼티를 사용하면 이 속성에 접근할 수 있다.
요소 elem에 이름이 "data-about"인 속성이 있다면 elem.dataset.about을 사용해 그 값을 얻을 수 있음.
<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>
// 읽기
alert(order.dataset.orderState); // new
// 수정하기
order.dataset.orderState = "pending"; // (*)
</script>
data-order-state 같이 여러 단어로 구성된 속성은 카멜 표기법(camel-cased)을 사용해 dataset.orderState으로 변환된다.
data-* 속성은 커스텀 데이터를 안전하고 유효하게 전달해준다.
data- 속성을 사용하면 읽기 뿐만 아니라 수정도 가능하다. 속성이 수정되면 CSS가 해당 뷰를 자동으로 업데이트해준다. 위 예시에서 ()로 표시한 줄에서 색이 파란색으로 바뀌는 것을 볼 수 있다.
참고자료