在大多數的文章中,attribute 通常被翻譯爲「特性」,property 被譯爲「屬性」。html
把結論寫在最前面,若是你全都懂,後面就不用看了。java
HTML attribute | DOM property |
---|---|
值永遠是字符串或 null |
值能夠是任意合法 js 類型 |
大小寫不敏感 | 大小寫敏感 |
不存在時返回 null |
不存在時返回 undefined |
對於 href , 返回 html 設置的值 |
對於 href 返回解析後的完整 url |
更新 value , 屬性也更新 |
更新 value , 特性不更新 |
當咱們書寫 HTML 代碼的時候,咱們爲 HTML 元素設置特性 ,例如:git
<input id="name" value="justjavac" />
複製代碼
咱們寫了一個 input
標籤,並給他定義了 2 個特性 (id
和 value
)。當瀏覽器解析這段代碼的時候,會把 html 源碼解析爲 DOM 對象,確切的說是解析爲 HTMLInputElement
對象。HTMLInputElement
的繼承關係是:github
HTMLInputElement
↓
HTMLElement
↓
Element
↓
Node
↓
EventTarget
↓
Object
複製代碼
經過查看文檔會發現,HTMLInputElement
的原型上定義了不少屬性和方法,例如 form
, name
, type
, alt
, checked
, src
, value
等等,還有從 HTMLElement
繼承來的 id
, title
, clientTop
等等。瀏覽器
若是仔細找找,就不難發現其中就有咱們爲 input
標籤訂義的特性:id
和 value
。當瀏覽器解析網頁時,將 HTML 特性映射爲了 DOM 屬性。bash
而 Element
類還有一個 attributes
屬性,裏面包含了全部的特性。dom
可是,HTML attribute 和 DOM property 並不老是一對一的關係。ui
當瀏覽器解析完 HTML 後,生成的 DOM 是一個繼承自 Object 的常規 JavaScript 對象,所以咱們能夠像操做任何 JS 對象那樣來操做 DOM 對象。url
const el = document.getElementById('name')
el.foo = 'bar'
el.user = { name: 'jjc', age: '18'}
複製代碼
也能夠爲其添加方法。若是你想給每一個 html 元素都添加屬性或方法,甚至能夠直接修改 Element.prototype
,不過咱們不推薦這麼作。spa
和 DOM 屬性相似,除了那些規範裏定義的標準特性外,HTML 也能夠添加非標準的屬性,例如:
<input id="name" value="justjavac" foo="bar" />
複製代碼
當 HTML 特性映射爲 DOM 屬性時,只映射標準屬性,訪問非標準屬性將獲得 undefined
。
const el = document.getElementById('name')
el.foo === undefined
複製代碼
好在 DOM 對象也提供了操做特性的 API:
Element.hasAttribute(name)
– 判斷某個特性是否存在elem.getAttribute(name
) – 獲取指定特性的值elem.setAttribute(name, value)
– 設置指定特性的值elem.removeAttribute(name)
– 移除指定特性以上 API 定義在 Element
上。
根據 HTML 規範,標籤以及特性名是不區分大小寫的,所以如下代碼是同樣的:
el.getAttribute('id')
el.getAttribute('ID')
el.getAttribute('iD')
複製代碼
而且,特性永遠都是字符串或 null
。若是咱們爲特性設置非字符串的值,則引擎會將此值轉換爲字符串。屬性是具備類型的:
el.getAttribute('checked') === '' // 特性是字符串
el.checked === false // 屬性是 boolean 類型的值
el.getAttribute('style') === 'color:blue' // 特性是字符串
typeof el.style === 'object' // 屬性是 CSSStyleDeclaration 對象
複製代碼
即便都是字符串,屬性和特性也可能不一樣,有一個例外就是 href
:
el.getAttribute('href') === '#tag' // 特性原樣返回 html 設置的值
el.href === 'http://jjc.fun#tag' // 屬性返回解析後的完整 uri
複製代碼
當標準的特性更新時,對應的屬性也會更新;反之亦然。
可是 input.value
的同步是單向的,只是 attribute --> property
。當修改特性時,屬性也會更新;可是修改屬性後,特性卻仍是原值。
el.setAttribute('value', 'jjc'); // 修改特性
el.value === 'jjc' // 屬性也更新了
el.value = 'newValue'; // 修改屬性
el.getAttribute('value')) === 'jjc' // 特性沒有更新
複製代碼
非標準 HTML 特性並不會自動映射爲 DOM 屬性。當咱們使用 data-
開頭的特性時,會映射到 DOM 的 dataset 屬性。中劃線格式會變成駝峯格式:
el.setAttribute('data-my-name', 'jjc');
el.dataset.myName === 'jjc'
el.setAttribute('data-my-AGE', 18);
el.dataset.myAge === '18'
複製代碼
HTML 容許咱們自定義標籤,也能夠擴展標籤的特性,可是咱們推薦使用已經進入 HTML5 規範的自定義特性 data-*
。好比咱們想爲div
標籤增長一個 age
特性,咱們能夠有 2 種選擇:
<div age="18">justjavac</div>
<div data-age="18">justjavac</div>
複製代碼
雖然第一種代碼更短,可是卻有一個潛在的風險。由於 HTML 規範是一直髮展變化的,也許在將來的某個版本中,age
被添加進了標準特性裏面,這將會引發潛在的 bug。
閱讀原文:HTML attribute 和 DOM property
討論地址:#15
若是你想參與討論,請點擊這裏