Attributes and custom properties
本文转自:http://javascript.info/tutorial/attributes-and-custom-properties
Ilya Kantor
- Properties
- Attributes
- Properties and attribytes synchronization
id
href
value
class/className
- The fun with old IEs
- Attributes as DOM nodes
- Summary
A DOM node may have attributes and properties. Sometimes people mess them up, because they are related, but they are really two different things.
Properties
DOM node is an object. So it can store custom properties and methods just like any JavaScript object.
The following example works by assigning an object to myData
property ofdocument.body
:
01 | document.body.myData = { |
04 | alert(document.body.myData.name) |
06 | document.body.sayHi = function () { |
Custom properties and methods are visible only in JavaScript and don’t affect HTML.
Also, custom properties show up in for..in
mixed with native properties:
1 | document.body.custom = 5 |
4 | for ( var key in document.body) { |
Custom DOM properties:
- May have any value.Property names case-sensitive
- Don’t affect HTML
Attributes
DOM nodes provide access to HTML attributes using the following standard methods:
elem.hasAttribute(name)
- checks if the attribute existselem.getAttribute(name)
- gets an attribute valueelem.setAttribute(name, value)
- sets an attributeelem.removeAttribute(name)
- removes an attribute
The attributes are broken in IE<8 and in IE8 compatible rendering mode:
- Only
getAttribute
and setAttribute
methods exist. - They actually modify DOM properties, not attributes.
- Attributes and properties in IE<8 are merged. Sometimes that leads to weird results, but the ways to manage attributes which we discuss here work fine with that.
In contrast with properties, attributes:
- May be only strings.
- Names not case-sensitive, because HTML attributes are not case-sensitive
- They show up in
innerHTML
(unless it’s older IE) - You can list all attributes using an array-like
attributes
property of the element.
For example, let’s see the following HTML:
< div about = "Elephant" class = "smiling" ></ div > |
The example below sets attributes.
02 | < div about = "Elephant" class = "smiling" ></ div > |
05 | var div = document.body.children[0] |
06 | alert( div.getAttribute( 'ABOUT' ) ) |
08 | div.setAttribute( 'Test' , 123) |
09 | alert( document.body.innerHTML ) |
When you run the code above, note the following:
- An
getAttribute('ABOUT')
uses the name in upper case, but that doesn’t matter. - You can try assign a string or other primitive value, which will become a string. Object should be autoconverted, but IE has problems here, so stick to primitives.
- The
innerHTML
contains the new "test"
attribute.
Properties and attribytes synchronization
Every type of DOM nodes has standard properties.
For example, see the 'A'
tag: Interface HTMLAnchorElement.
It has "href"
and "accessKey"
and other specific attributes. Besides, it inherits"id"
and other attributes from HTMLElement.
Standard DOM properties are synchronized with attributes.
id
For example, the browser synchronizes "id"
attribute with id
property:
2 | document.body.setAttribute( 'id' , 'la-la-la' ) |
3 | alert(document.body.id) |
href
The synchronization does not guarantee the same value. Let’s set the"href"
attribute for example:
3 | var a = document.body.children[0] |
6 | alert( 'attribute:' + a.getAttribute( 'href' ) ) |
7 | alert( 'property:' + a.href ) |
That’s because href
, according to W3C specification must be a well-formed link.
There are other attributes, which are synced, but not copied. For example input.checked
:
1 | < input type = "checkbox" checked> |
4 | var input = document.body.children[0] |
7 | alert( input.getAttribute( 'checked' ) ) |
The value of input.checked
property is either true
orfalse
, but the attribute has whatever you put into it.
value
There are also built-in properties which are synced one-way only.
For example, the input.value
is synchronized from the attribute:
02 | < input type = "text" value = "markup" > |
04 | var input = document.body.children[0] |
06 | input.setAttribute( 'value' , 'new' ) |
But the attribute is not synchronized from the property:
02 | < input type = "text" value = "markup" > |
04 | var input = document.body.children[0] |
08 | alert(input.getAttribute( 'value' )) |
The "value"
attribute keeps the original value after the property was updated, for example when a visitor typed in something. The original value can be used to check if theinput
is changed, or to reset it.
class/className
The naming exception: "class"
attribute corresponds to className
property.
Because "class"
is a reserved word in JavaScript, the name of the corresponding property for the"class"
attribute is className
.
3 | document.body.setAttribute( 'class' , 'big red bloom' ) |
5 | alert( document.body.className ) |
Note, the example above doesn’t work in IE<9, because of the weird way attributes and properties are mixed up.
We can live fine with it, just always use className
property to manage classes, not the attribute.
The fun with old IEs
First, IE<9 synchronizes all properties and attributes.:
1 | document.body.setAttribute( 'try-in-ie' , 123) |
3 | alert( document.body[ 'try-in-ie' ] === 123 ) |
Note that the type is also same. The attribute did not become a string, as it should.
Second, in IE<8 (or IE8 in IE7-compat. mode) properties and attributes are same. That leads to funny consequences.
For example, properties names are case-sensitive, and attribute names are not. And if the browser thinks that they are same, then what should be the result of the following code?
5 | alert( document.body.getAttribute( 'ABba' ) ) |
The browser escapes the trap by picking the first value by default. It also provides an optional second IE-only parameter forgetAttribute
, which makes it case-sensitive. See MSDN getAttribute for details.
The "class"
attribute changes class in all browsers except IE<9. Don’t use the attribute. UseclassName
property all the time.
To live well with any IE, use attributes correctly.
Or, in other words, try using properties all the time, until you really need an attribute.
And the only times you really need an attribute are:
- To get a custom HTML attribute, because it is not synced to DOM property.
- To get an “original value” of the standard HTML attribute, like
<INPUT value="...">
.
Attributes as DOM nodes
Attributes are also accessible via elem.attributes
collection.
In attributes
collection, every attribute is represented by a special kind of DOM node. It has name
, value
and other properties.
For example:
1 | < span style = "color:blue" id = "my" >text</ span > |
4 | var span = document.body.children[0] |
5 | alert( span.attributes[ 'style' ].value ) |
6 | alert( span.attributes[ 'id' ].value ) |
By the way, IE<8 and IE8 in compatibility mode go crazy about the "style"
attribute. Guess why.
Attribute DOM nodes are not the part of the document tree, they are accessible from their elements only.
Summary
Both attributes and properties are core features in the DOM model.
The table of differences and relations:
Properties | Attributes |
---|
Any value | String |
Names are case-sensitive | not case-sensitive |
Don’t show up in innerHTML | Visible in innerHTML |
Standard DOM properties and attributes are synchronized, custom are not. |
Attributes are mixed with properties and screwed up in IE<8, IE8 compat. mode. |
If you want to have custom attributes in HTML, remember that data-*
attributes are valid in HTML5. SeeCustom data attributes section of HTML5 standard.
In real life, in 98% of cases DOM properties are used.
You should use attributes in only two cases:
- A custom HTML attribute, because it is not synced to DOM property.
- To access a built-in HTML attribute, which is not synced from the property, and you are sure you need the attribute.
For example, value
in INPUT
.