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

若是你想参与讨论,请点击这里

相关文章
相关标签/搜索