前言
在Web开发中,我们经常遇到"Attributes"和"Properties"这两个术语,它们虽然在日常对话中经常被互换使用,但实际上代表着两个完全不同的概念。正确理解它们之间的区别对于编写有效、可靠的代码至关重要。本文将帮助大家深入解析Attributes与Properties之间的根本差异。
定义与关联
定义
Attribute
Attribute 可扩展 HTML 或 XML 元素,改变其行为或提供元数据。
Property
JavaScript 属性是一个对象的成员,它将键与值联系起来。JavaScript 对象是一种数据结构,它存储了属性的集合。
官方定义看不懂?记住一点:DOM 中的属性是Attribute,JS对象中的属性是Property。
以 <input type="text"> 为例:
- input 标签里的 type 是 attribute,读取、修改 DOM 中的属性时使用
getAttribute、setAttribute等方法; input.type:这里的input 是HTMLInputElement实例后的一个JS对象,type 是JS对象的 propterty;
那这两者之间有什么关联?
我们在编码过程中,需要查询 html 标签的 attribute 通常的做法是先通过document.getElementById等方法获取标签元素,再通过input.type的形式读取属性值。其内部是attribute反射机制,通过这个机制将 html 的 attribute 与 js 对象的 property 进行关联,使得我们能够通过 js 对象操作 html 标签的 attribute。
以下是一个反射id的例子帮助理解反射过程:
class HTMLInputElement extends HTMLElement {
get id() { return this.getAttribute('id') ?? ''; }
set id(str) {
this.setAttribute('id', String(str));
}
}
Attribute 与 Property 的差异
序列化
var input = document.createElement('input');
input.setAttribute('age', 18);
input.age2 = '19';
input.name = 'age';
//<input age="18" name="age">
通过以上例子可知:
- 当 property 能与关联到标签元素的 attribute 时,通过
input.name='age'的方式设置属性,最终 name 属性会序列化成 html; - 当 property 能与无法关联到标签元素的 attribute 时,通过
input.age2='19'的方式设置属性,age2 属性不会序列化成 html; - 使用setAttribute 设置属性则一定会序列化为 html;
大小写敏感性
attribute 大小写不敏感, property 敏感;
使用getAttribute方法时会将参数自动转为小写。
<div id="test" HeLlO="world"></div>
var div = document.getElementById('test');
console.log(div.getAttributeNames()); // ['id', 'hello']
div.age = 1;
div.Age = 2;
console.log(div.age, div.Age); // 1 2
数据类型类型
attribute 的值主要是 string, property 的值可以是任意类型;
例如以下例子将bool attribute 设置布尔类型true,通过getAttribute获取到的实际是字符串'true'.
var div = document.createElement('div');
div.setAttribute('bool', true);
console.log(div.getAttribute('bool')); // 'true'
命名差异
attribute 与 property 命名存在差异,常见的 attribute 如crossorigin,class,aria-label,对应的 property 名分别为crossOrigin,className,ariaLabel
默认值
html 的部分属性实际是存在默认值的,例如 input 标签的 type 默认为 text;
property 反射内部对于一些属性做了默认值判断,使得通过 input.type 和 getAttribute 方式获取的结果存在差异。
var input = document.createElement('input');
console.log(input.type); // 'text'
console.log(input.getAttribute('type')); // 'foo'
值校验
通过 property 即 input.type 的方式赋值会对值进行校验,而通过 setAttribute的方式赋值则没有校验;
var input = document.createElement('input');
input.type ='foo';
console.log(input.type);
input.setAttribute('type', 'foo');
console.log(input.type, input.getAttribute('type'));
attribute、property 操作结果的差异
property 赋值
var input = document.createElement('input');
input.type = '';
input.value = '';
input.readOnly = true;
input.myname = 'tom';
input.name = 'jim';
console.log(input.type, input.getAttribute('type')); // 'text', ''
console.log(input.value, input.getAttribute('value')); // '', null
console.log(input.readOnly, input.getAttribute('readonly')); // true, ''
console.log(input.myname, input.getAttribute('myname')); // 'tom', null
console.log(input.name, input.getAttribute('name')); // 'jim', null
document.body.appendChild(input); // <input type="" readonly="" name="jim">
以上代码属性均使用 property 的赋值操作,分析代码的输出结果得出以下结论。
property 有2种情况:
-
如果属性存在默认值,例如
type属性,property为默认值,attribute为空字符串; -
如果属性无默认值,
property为空字符串,attribute为null或空字符串;
attribute 也有两种情况:
-
type等特殊属性,property赋值时会直接修改attribute的值,attribute与property一致; -
一般属性,反射无特殊逻辑,
attribute为null; -
如果使用
setAttribute为标签元素自定义属性,property获取的为undefined,attribute为设置的值;
attribute 赋值
var input = document.createElement('input');
input.setAttribute('type', '');
input.setAttribute('value', '');
input.setAttribute('readonly', true);
input.setAttribute('name', 'jim');
input.setAttribute('myname', 'tom');
console.log('type: ', input.type, input.getAttribute('type')); // 'text', ''
console.log('value: ', input.value, input.getAttribute('value')); // '', ''
console.log('readonly: ', input.readOnly, input.getAttribute('readonly')); // true, 'true'
console.log('name: ', input.name, input.getAttribute('name')); // 'jim', 'jim'
console.log('myname: ', input.myname, input.getAttribute('myname')); // undefined, 'tom'
document.body.appendChild(input);
// <input type="" value="" readonly="true" name="jim" myname="tom">
以上代码属性均使用 attribute 的赋值操作,分析代码的输出结果得出以下结论。
attribute 值为设定值的字符串形式;
property 有2种情况:
- 如果属性为标签自带属性,值与设定值一致;
- 如果属性为自定义属性,值为
undefined;
总结
在深入探讨了HTML attribute与DOM property之后,我们可以清晰地看到,尽管它们在某些情况下可以相互映射,但它们在本质上服务于不同的目的,并具有不同的特性。Attribute是定义在HTML标签中的,它们为元素提供了元数据或者改变了元素的行为。而Property则是JavaScript中的对象特性,可以是任何类型的值,并且受JavaScript类型转换规则的约束。
通过对Attribute和Property的比较,我们了解到了它们在序列化、大小写敏感性、数据类型、命名规则以及默认值和值校验方面的差异。这些差异不仅影响着我们如何访问和修改元素的特性,也决定了元素如何在网页上呈现和行为。
最终,理解这些概念的细微差别对于前端开发者来说至关重要。它不仅帮助我们避免潜在的bug和问题,还让我们能够更精确地控制网页元素的表现和交互。随着Web技术的不断进步,对这些基础知识的掌握将成为构建更复杂、更动态网页应用的坚实基石。