前言
DOM中的 Attribute 和 Property 是我们经常用到却又不太关注的知识点。在工作和应聘中我也发现很少有人能把这两个概念聊清楚。
常见的误区是:
Atrribute 是 Property的一个子集,与 Property 中的字段存在一一对应关系
Atrribute 变化(setAttribute)会引起 Property 变化,反之则不成立
DOM是一个js对象 (也对也不对)
还有一些表兄弟论,对象实例论,也许说明了一些问题,但是比喻不伦不类,让人云里雾里。
归根结底的一个问题就是是:
是什么以及如何互动?
本文的目的是把误区澄清以及把困惑解答清除。
我们通常把 Attribute 翻译为 特性,Property 翻译为属性。这样翻译的目的无非只是为区分这两个概念指代不同的事物,从语义上去深究这两个词没有意义。
DOM Properties
DOM对前端的熟悉程度来说真的像人的左右手一样,也许是太过于熟悉,有时候对它的认知反而有灯下黑的感觉。
先来看DOM是什么,它是个js object吗? 很多面试者会给个肯定回答,因为这个认知和实践看起来也是相符的。举个例子,当我们想改变一个input的value,我们是这样做的:
// html: <input id="input"></input>
let inputDOM = document.getElementById('#input'); // 获取input的dom
inputDOM.value = 'new value'; // 操作dom
事实上,DOM 被设计成与特定编程语言相独立,使文档的结构化表述可以通过单一,一致的API获得。作为前端,我们会专注于使用JavaScript, 但实际上DOM 也可以使用其他的语言比如Python来实现:
# Python DOM example
import xml.dom.minidom as m
# DOM property of document object;
doc = m.parse("C:\\Projects\\Py\\chap1.xml");
inputDOM = doc.getElementsByID("input");
有了以上 javascript 和 python 的例子,我们再看 DOM 的定义,是不是更好理解一些:
文档对象模型 (DOM) 是HTML和XML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来。
对于web前端来说,我们经常用到的最核心DOM接口比如document,element,都是javascript 对 DOM 接口的实现。在浏览器环境下,document.getElementById返回的的确是一个 js 对象(这个对象也实现了 DOM 所规定的规范与接口)。
比如说上面例子中的inputDOM,它是一个HTMLInputElement,在 DOM 中规范是这样的:
但是从DOM本身的定义来说,它是一个规范,一组接口,与具体编程语言无关。
对于web前端来说,js 对 DOM 接口的实现,展现给开发人员的就是 js 对象 (Node ),操作 DOM 的方式就是通过改变这个 js 对象的属性 (Property) 或调用相应的方法来实现的 。
HTML Attributes
html标签上的属性称之为Attribute,当浏览器解析 html 文档时会根据 html 标签(div, input etc…)的标准属性(id, class, value etc…)来构建 DOM 树。
注意:
1)非标准 attribute 将会被忽略。
2) 标签的 class attribute 对应于 DOM 的 className,因为 class 是 js 的关键字。
3) Element 会有一个 attributes 属性,这个 attributes 数据类型为 NamedNodeMap,是保存标签包括非标准 attribute 在内的所有 attribute 信息。
Element.attributes 属性返回该元素所有属性节点的一个实时集合。该集合是一个 NamedNodeMap 对象,不是一个数组,所以它没有 数组 的方法,其包含的 属性 节点的索引顺序随浏览器不同而不同。更确切地说,attributes 是字符串形式的名/值对,每一对名/值对对应一个属性节点。
尽管被称为 NamedNodeMap,但这个接口不是用来处理节点对象(Node),而是用来处理属性节点对象(Attr)
HTML Attributes 与 DOM Properties互动
HTML Attribute 和 DOM Property 可以有双向互动,可以有单向互动,也可以没有互动
下面举几个栗子:
双向互动: id, style
id :
// html: <input />
let input = document.querySelector('input');
// attribute => property
input.setAttribute('id', 'id');
console.log(input.id); // id (dom property id updated)
// property => attribute
input.id = 'newId';
console.log(input.getAttribute('id')); // newId (html attribute updated)
style:
HTML Attributes 的 style 是 字符串,而DOM Property 中的 style 是对象****CSSStyleDeclaration (CSSOM : CSS Object Model),尽管是双向互动,但是两个 style 的数据类型却不一样
// html: <div id="div" style="color:red;font-size:120%">Hello</div>
let dom = document.querySelector('#div');
dom.setAttribute('style', 'color: blue');
dom.style.color = 'black';
单向互动:attribute -> property,NOT property -> attribute : value
let input = document.querySelector('input');
// attribute => property
input.setAttribute('value', 'text');
console.log(input.value); // text
// NOT property => attribute
input.value = 'newValue';
console.log(input.getAttribute('value')); // text (not updated!)
没有互动: checked
// html: <input id="input" type="checkbox" checked> checkbox
let input = document.querySelector('input');
console.log(input.checked); // true
console.log(input.attributes.checked); // '' (empty string)
{
input.setAttributes('checked', false);
console.log(input.checked); // true
console.log(input.attributes.checked); // false
}
// 或者
{
input.checked = false;
console.log(input.checked); // false
console.log(input.attributes.checked); // '' (empty string)
}
非标准 Attribute 与 dataset
dataset 即为 custom data attribute. 在HTML5中使用data-前缀设置自定义属性来存放一些特殊数据。
custom data attribute 与 dom dataset 之间的互动也是双向的.
Forms a class of attributes, called custom data attributes, that allow proprietary information to be exchanged between the HTML and its DOM representation that may be used by scripts. All such custom data are available via the HTMLElement interface of the element the attribute is set on. The HTMLElement.dataset property gives access to them.
// html: <div id="user" data-id="1234567890" data-date-of-birth>John Doe </div>
var el = document.querySelector('#user');
console.log(el.dataset.id) // '1234567890'
el.dataset.dateOfBirth = '1960-10-03'; // set the DOB.
总结
- Attributes: 指代 html 标签属性
- Properties: 由 js 根据 DOM 规范生成的对象
Properties | Attributes | |
---|---|---|
数据类型 | 根据DOM文档生成的任何数据类型 | string |
字段名称 | 大小写敏感 | 大小写不敏感 |
在大多数情况下, DOM 可以完全满足我们的开发需求。在某些特定场合比如说对于 input,我们通过 dom.value 来修改显示的值,某种情况下,我们想知道 input 的原始值是什么,则可以通过 attributes 来查看。