詳解 HTML attribute 和 DOM property

在大多數的文章中,attribute 通常被翻譯爲「特性」,property 被譯爲「屬性」。html

結論

把結論寫在最前面,若是你全都懂,後面就不用看了。java

HTML attribute DOM property
值永遠是字符串或 null 值能夠是任意合法 js 類型
大小寫不敏感 大小寫敏感
不存在時返回 null 不存在時返回 undefined
對於 href, 返回 html 設置的值 對於 href 返回解析後的完整 url
更新 value, 屬性也更新 更新 value, 特性不更新

概述

當咱們書寫 HTML 代碼的時候,咱們爲 HTML <abbr title="Element">元素</abbr>設置<abbr title="attribute">特性</abbr> ,例如:git

<input id="name" value="justjavac" />

咱們寫了一個 input 標籤,並給他定義了 2 個<abbr title="attribute">特性</abbr> (idvalue)。當瀏覽器解析這段代碼的時候,會把 html 源碼解析爲 DOM 對象,確切的說是解析爲 HTMLInputElement 對象。HTMLInputElement 的繼承關係是:github

HTMLInputElement
  ↓
HTMLElement
  ↓
Element
  ↓
Node
  ↓
EventTarget
  ↓
Object

經過查看文檔會發現,HTMLInputElement 的原型上定義了不少<abbr title="property">屬性</abbr>和方法,例如 form, name, type, alt, checked, src, value 等等,還有從 HTMLElement 繼承來的 id, title, clientTop 等等。瀏覽器

若是仔細找找,就不難發現其中就有咱們爲 input 標籤訂義的<abbr title="attribute">特性</abbr>:idvalue當瀏覽器解析網頁時,將 HTML <abbr title="attribute">特性</abbr>映射爲了 DOM <abbr title="property">屬性</abbr>dom

Element 類還有一個 attributes 屬性,裏面包含了全部的特性。url

可是,HTML attribute 和 DOM property 並不老是一對一的關係prototype

1. DOM 屬性

當瀏覽器解析完 HTML 後,生成的 DOM 是一個繼承自 Object 的常規 JavaScript 對象,所以咱們能夠像操做任何 JS 對象那樣來操做 DOM 對象。翻譯

const el = document.getElementById('name')
el.foo = 'bar'
el.user = { name: 'jjc', age: '18'}

也能夠爲其添加方法。若是你想給每一個 html 元素都添加屬性或方法,甚至能夠直接修改 Element.prototype,不過咱們不推薦這麼作。code

2. HTML 特性

和 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

3. 特性和屬性的同步

當標準的特性更新時,對應的屬性也會更新;反之亦然。

可是 input.value 的同步是單向的,只是 attribute --> property。當修改特性時,屬性也會更新;可是修改屬性後,特性卻仍是原值。

el.setAttribute('value', 'jjc');  // 修改特性
el.value === 'jjc'                // 屬性也更新了  

el.value = 'newValue';            // 修改屬性 
el.getAttribute('value')) === 'jjc' // 特性沒有更新

4. 非標準特性

非標準 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'

自定義特性 VS 非規範特性

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

若是你想參與討論,請點擊這裏

相關文章
相關標籤/搜索