特性和属性(Attributes and properties)

114 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

当浏览器加载页面时,它会“读取”(或者称之为:“解析”)HTML 并从中生成 DOM 对象。对于元素节点,大多数标准的 HTML 特性(attributes)会自动变成 DOM 对象的属性(properties)。(译注:attribute 和 property 两词意思相近,为作区分,全文将 attribute 译为“特性”,property 译为“属性”,请读者注意区分。)

例如,如果标签是 <body id="page">,那么 DOM 对象就会有 body.id="page"

但特性—属性映射并不是一一对应的!在本章,我们将带领你一起分清楚这两个概念,了解如何使用它们,了解它们何时相同何时不同。

DOM 属性

我们已经见过了内建 DOM 属性。它们数量庞大。但是从技术上讲,没有人会限制我们,如果我们觉得这些 DOM 还不够,我们可以添加我们自己的。

DOM 节点是常规的 JavaScript 对象。我们可以更改它们。

例如,让我们在 document.body 中创建一个新的属性:

document.body.myData = {
  name: 'Caesar',
  title: 'Imperator'
};

alert(document.body.myData.title); // Imperator

我们也可以像下面这样添加一个方法:

document.body.sayTagName = function() {
  alert(this.tagName);
};

document.body.sayTagName(); // BODY(这个方法中的 "this" 的值是 document.body)

我们还可以修改内建属性的原型,例如修改 Element.prototype 为所有元素添加一个新方法:

Element.prototype.sayHi = function() {
  alert(`Hello, I'm ${this.tagName}`);
};

document.documentElement.sayHi(); // Hello, I'm HTML
document.body.sayHi(); // Hello, I'm BODY

所以,DOM 属性和方法的行为就像常规的 Javascript 对象一样:

  • 它们可以有很多值。
  • 它们是大小写敏感的(要写成 elem.nodeType,而不是 elem.NoDeTyPe)。

HTML 特性

在 HTML 中,标签可能拥有特性(attributes)。当浏览器解析 HTML 文本,并根据标签创建 DOM 对象时,浏览器会辨别 标准的 特性并以此创建 DOM 属性。

所以,当一个元素有 id 或其他 标准的 特性,那么就会生成对应的 DOM 属性。但是非 标准的 特性则不会。

例如:

<body id="test" something="non-standard">
  <script>
    alert(document.body.id); // test
// 非标准的特性没有获得对应的属性
    alert(document.body.something); // undefined
  </script>
</body>

请注意,一个元素的标准的特性对于另一个元素可能是未知的。例如 "type" 是 <input> 的一个标准的特性(HTMLInputElement),但对于 <body>HTMLBodyElement)来说则不是。规范中对相应元素类的标准的属性进行了详细的描述。

这里我们可以看到:

<body id="body" type="...">
  <input id="input" type="text">
  <script>
    alert(input.type); // text
alert(body.type); // undefined:DOM 属性没有被创建,因为它不是一个标准的特性
  </script>
</body>

所以,如果一个特性不是标准的,那么就没有相对应的 DOM 属性。那我们有什么方法来访问这些特性吗?

当然。所有特性都可以通过使用以下方法进行访问:

  • elem.hasAttribute(name) —— 检查特性是否存在。
  • elem.getAttribute(name) —— 获取这个特性值。
  • elem.setAttribute(name, value) —— 设置这个特性值。
  • elem.removeAttribute(name) —— 移除这个特性。

这些方法操作的实际上是 HTML 中的内容。

我们也可以使用 elem.attributes 读取所有特性:属于内建 Attr 类的对象的集合,具有 name 和 value 属性。

下面是一个读取非标准的特性的示例:

<body something="non-standard">
  <script>
alert(document.body.getAttribute('something')); // 非标准的
  </script>
</body>

HTML 特性有以下几个特征:

  • 它们的名字是大小写不敏感的(id 与 ID 相同)。
  • 它们的值总是字符串类型的。

下面是一个使用特性的扩展示例:

<body>
  <div id="elem" about="Elephant"></div>

  <script>
    alert( elem.getAttribute('About') ); // (1) 'Elephant',读取

    elem.setAttribute('Test', 123); // (2) 写入

    alert( elem.outerHTML ); // (3) 查看特性是否在 HTML 中(在)

    for (let attr of elem.attributes) { // (4) 列出所有
      alert( `${attr.name} = ${attr.value}` );
    }
  </script>
</body>

请注意:

  1. getAttribute('About') —— 这里的第一个字母是大写的,但是在 HTML 中,它们都是小写的。但这没有影响:特性的名称是大小写不敏感的。
  2. 我们可以将任何东西赋值给特性,但是这些东西会变成字符串类型的。所以这里我们的值为 "123"
  3. 所有特性,包括我们设置的那个特性,在 outerHTML 中都是可见的。
  4. attributes 集合是可迭代对象,该对象将所有元素的特性(标准和非标准的)作为 name 和 value 属性存储在对象中。