- 文档
- 教程
- 前端
【免费下载链接】zh.javascript.info
现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。
本文基于《现代 JavaScript 教程》中文仓库 2-ui/1-document/06-dom-attributes-and-properties/article.md 及其配套练习任务编写。当浏览器解析 HTML 生成 DOM 时,标准 HTML 特性会自动变成 DOM 属性,但这两者并非一一对应。读完本文,你将掌握特性与属性的本质区别、完整的特性操作 API、data-*自定义数据的安全传递方式(dataset),并能够独立完成"获取data-widget-name特性值"与"将外部链接染成橙色"两类典型实战任务。
一、两个易混淆的概念:特性(attribute)与属性(property)
在继续之前,先建立最基础的心智模型:
- 特性(attribute)——写在 HTML 标签里的内容,例如
<body id="page">中的id="page"。 - 属性(property)——DOM 对象上的 JavaScript 属性,例如解析后生成的
document.body.id。
当浏览器加载页面时,它会"解析" HTML 并生成 DOM 对象。对于元素节点,大多数标准的 HTML 特性会自动变成 DOM 对象的属性。例如标签<body id="page">会让 DOM 对象拥有body.id = "page"。
但要注意:特性—属性映射并不是一一对应的。本章节接下来的内容全部围绕"它们何时相同、何时不同、如何操作"展开。
二、DOM 属性:本质是常规 JavaScript 对象
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.sayHi = function() { alert(`Hello, I'm ${this.tagName}`); }; document.documentElement.sayHi(); // Hello, I'm HTML document.body.sayHi(); // Hello, I'm BODY由此可以总结出 DOM 属性的两条行为准则:
- 属性可以承载任意类型的值(对象、函数、布尔值等);
- 属性名是大小写敏感的(必须写
elem.nodeType,不能写elem.NoDeTyPe)。
三、HTML 特性:标准与非标准之分
浏览器解析 HTML 文本并创建 DOM 对象时,只会为标准特性创建对应的 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 // 没有对应的 DOM 属性,因为它不是 body 的标准特性 alert(body.type); // undefined </script> </body>那么,既然非标准特性没有对应的 DOM 属性,我们该如何访问它?答案是使用下面这一组特性操作 API。
四、特性操作四大方法 + attributes 集合
所有特性(无论标准与否)都可以通过以下方法访问,这些方法操作的实际是HTML 中的内容:
| 方法 | 作用 |
|---|---|
elem.hasAttribute(name) | 检查特性是否存在 |
elem.getAttribute(name) | 获取该特性的值 |
elem.setAttribute(name, value) | 设置该特性的值 |
elem.removeAttribute(name) | 移除该特性 |
此外,elem.attributes可以读取所有特性:它是内建Attr类对象的集合,每个对象含name和value属性。
读取非标准特性的示例:
<body something="non-standard"> <script> alert(document.body.getAttribute('something')); // non-standard </script> </body>HTML 特性有两个重要特征:
- 特性名大小写不敏感(
id与ID等价); - 特性值永远是字符串类型。
下面是一个综合展示这些特征的扩展示例:
<body> <div id="elem" about="Elephant"></div> <script> alert( elem.getAttribute('About') ); // (1) 'Elephant',首字母大写也能读取 elem.setAttribute('Test', 123); // (2) 写入,值会被转成字符串 "123" alert( elem.outerHTML ); // (3) 新特性在 outerHTML 中可见 for (let attr of elem.attributes) { // (4) attributes 可迭代,列出全部 alert( `${attr.name} = ${attr.value}` ); } </script> </body>四个值得注意的细节:
getAttribute('About')首字母大写照样能读到,因为特性名大小写不敏感;- 任何值赋给特性都会被字符串化,所以写入
123实际存储的是"123"; - 所有特性(包括我们刚设置的)都会出现在
outerHTML中; attributes是可迭代对象,能用for...of遍历,其中包含标准与非标准的所有特性。
五、属性—特性同步(及value例外)
当一个标准特性被改变时,对应的 DOM 属性会自动更新;反过来,属性被赋值时特性也会同步——只有少数特例。看双向同步的演示:
<input> <script> let input = document.querySelector('input'); // 特性 => 属性 input.setAttribute('id', 'id'); alert(input.id); // id(属性被更新了) // 属性 => 特性 input.id = 'newId'; alert(input.getAttribute('id')); // newId(特性被更新了) </script>但input.value是例外:只能从特性同步到属性,反向无效:
<input> <script> let input = document.querySelector('input'); // 特性 => 属性:生效 input.setAttribute('value', 'text'); alert(input.value); // text // 属性 => 特性:不生效! input.value = 'newValue'; alert(input.getAttribute('value')); // text(没有被更新!) </script>这个"单向"特性在实际中很有用:用户交互会不断改变value属性,而 HTML 中的原始值始终保存在特性里——需要恢复"初始值"时,从getAttribute('value')取即可。
六、DOM 属性是多类型的:checked、style 与 href
DOM 属性不总是字符串:
input.checked(checkbox)是布尔型:
<input id="input" type="checkbox" checked> checkbox <script> alert(input.getAttribute('checked')); // 特性值是:空字符串 "" alert(input.checked); // 属性值是:true </script>style特性是字符串,style属性是对象(CSSStyleDeclaration):
<div id="div" style="color:red;font-size:120%">Hello</div> <script> alert(div.getAttribute('style')); // color:red;font-size:120% alert(div.style); // [object CSSStyleDeclaration] alert(div.style.color); // red </script>- 还有一种罕见情况:即使属性是字符串,也与特性内容不同。例如
href属性永远返回完整的 URL,哪怕特性里写的是相对路径或#hash:
<a id="a" href="#hello">link</a> <script> alert(a.getAttribute('href')); // #hello(HTML 中的原始写法) alert(a.href ); // http://site.com/page#hello 形式的完整 URL </script>因此,当我们需要"HTML 中写的原样值"时,必须使用getAttribute——这一结论将直接服务于后面的实战任务。
七、非标准特性与><!-- 标记这个 div 以显示 "name" --> <div show-info="name"></div> <!-- 标记这个 div 以显示 "age" --> <div show-info="age"></div> <script> let user = { name: "Pete", age: 25 }; for(let div of document.querySelectorAll('[show-info]')) { // 在字段中插入相应的信息 let field = div.getAttribute('show-info'); div.innerHTML = user[field]; // 先 "name" 变为 Pete,再 "age" 变为 25 } </script>
自定义特性还可以驱动样式,例如用order-state控制订单状态的颜色:
<style> .order[order-state="new"] { color: green; } .order[order-state="pending"] { color: blue; } .order[order-state="canceled"] { color: red; } </style> <div class="order" order-state="new">A new order.</div> <div class="order" order-state="pending">A pending order.</div> <div class="order" order-state="canceled">A canceled order.</div>比起.order-state-new、.order-state-pending这类样式类,用特性管理状态更简单——只需一行代码切换状态,无需增删类名:
// 比删除旧的、添加新的类要简单得多 div.setAttribute('order-state', 'canceled');不过,随手发明自定义特性有隐患:HTML 标准在持续演进,你今天用的非标准特性可能明天就被标准收编、赋予新含义,从而产生意料之外的影响。为了避免冲突,HTML 规范保留了data-*前缀:
所有以
data-开头的特性均被保留供程序员使用,它们可以通过dataset属性访问。
命名规则很简单:data-about特性对应elem.dataset.about;多词特性如data-order-state以驼峰式访问:elem.dataset.orderState。
<body><style> .order[data-order-state="new"] { color: green; } .order[data-order-state="pending"] { color: blue; } .order[data-order-state="canceled"] { color: red; } </style> <div id="order" class="order"><!DOCTYPE html> <html> <body> <div><!DOCTYPE html> <html> <body> <div>// 找到所有带有><a name="list">the list</a> <ul> <li><a href="http://google.com">http://google.com</a></li> <li><a href="/tutorial">/tutorial.html</a></li> <li><a href="local/path">local/path</a></li> <li><a href="ftp://ftp.com/my.zip">ftp://ftp.com/my.zip</a></li> <li><a href="http://nodejs.org">http://nodejs.org</a></li> <li><a href="http://internal.com/test">http://internal.com/test</a></li> </ul>9.1 方案一:遍历 + getAttribute 过滤(官方推荐)
let links = document.querySelectorAll('a'); for (let link of links) { let href = link.getAttribute('href'); // 注意:必须用 getAttribute! if (!href) continue; // 没有 href 特性,跳过 if (!href.includes('://')) continue; // 没有协议,跳过 if (href.startsWith('http://internal.com')) continue; // 内部链接,跳过 link.style.color = 'orange'; }关键点:这里用的是link.getAttribute('href')而不是link.href——因为link.href永远返回解析后的完整 URL(如http://internal.com/test会保持完整,但相对路径/tutorial会被拼成完整地址),而我们恰恰需要 HTML 中原样书写的值,才能用includes('://')和startsWith(...)做判定。这正是本章第六节结论的直接应用。
9.2 方案二:纯 CSS 选择器(更简洁)
// 查找所有 href 中包含 :// 的链接,但 href 不以 http://internal.com 开头 let selector = 'a[href*="://"]:not([href^="http://internal.com"])'; let links = document.querySelectorAll(selector); links.forEach(link => link.style.color = 'orange');完整可运行版本见 solution.view/index.html。两种方案对比:
- 方案一:逻辑显式、便于逐步调试与增加复杂判断;
- 方案二:一行选择器搞定,利用 CSS 属性选择器
*=(包含)与^=(开头匹配),代码量最少。
十、总结:何时用属性、何时用特性
| 对比项 | 属性(property) | 特性(attribute) |
|---|---|---|
| 类型 | 任意值,标准属性具有规范中描述的类型 | 总是字符串 |
| 名字 | 大小写敏感 | 大小写不敏感 |
| 所在位置 | DOM 对象中 | HTML 文本中 |
特性操作方法一览:
elem.hasAttribute(name)—— 检查特性是否存在;elem.getAttribute(name)—— 获取特性值;elem.setAttribute(name, value)—— 设置特性值;elem.removeAttribute(name)—— 移除特性;elem.attributes—— 所有特性的集合(可迭代)。
日常开发以 DOM 属性为主,仅在以下场景才使用特性:
- 需要非标准特性——若它以
data-开头,请改用dataset读写; - 想读取 HTML 中"原样书写"的值——因为对应 DOM 属性可能已变形,例如
href属性永远返回完整 URL。
本文的全部代码示例、任务与解答均可在仓库 2-ui/1-document/06-dom-attributes-and-properties/ 目录下找到:章节正文见article.md,两道练习的任务与官方解答分别位于1-get-user-attribute/(task.md+solution.md)与2-yellow-links/(task.md、solution.md,含source.view/、solution.view/两个可直接运行的 HTML 页面)。
- 文档
- 教程
- 前端
【免费下载链接】zh.javascript.info
现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。
相关推荐
使用>使用 data 属性与 dataset 读取元素自定义数据:get user attribute 实战详解 本篇文章围绕 javascript.info 教程中
文档/教程前端基于 DOM 特性与属性教程:用 getAttribute 与 dataset 获取>基于 DOM 特性与属性教程:用 getAttribute 与 dataset 获取 data 自定义特性 本文以《现代 JavaScript 教程中文版》中「
文档教程前端从 DOM 读取>从 DOM 读取 data widget name 自定义属性:getAttribute 与 dataset 完整指南 在现代 JavaScript 教程(Mo
文档/教程前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考