<p>优先用 getAttribute() 读取 data-* 属性,因其兼容性好、无隐式转换、支持任意命名;dataset 仅适用于全小写连字符命名,且存在诸多限制和陷阱。</p>

用 getAttribute() 逐个读取最稳
dataset 不是普通对象,不能直接遍历;而 getAttribute() 是底层、无转换、兼容性最好的方式。只要你知道属性名(比如 data-user-id、data-api-key),就能 100% 拿到原始字符串值。
常见错误:写 elem.dataset['user-id'] 或 elem.dataset.user-id(语法错误),结果返回 undefined;或者误以为 data-item-2-id 能转成 item2Id——其实浏览器根本不支持数字开头的驼峰转换,dataset.item2Id 一定为 undefined。
- 优先用
elem.getAttribute('data-user-id'),不依赖命名规则,不自动改名,不丢大小写和数字 - 对非法命名(如
data-userId、data_abc、data-URL)也有效,getAttribute照样返回值或null - IE11 及更老环境也能跑,
dataset在 IE 中不可用
批量读取所有 data-* 属性必须绕过 dataset
Object.keys(elem.dataset)、for...in elem.dataset 都不行——dataset 是 DOMStringMap,不是普通对象,这些方法返回空或不可靠结果。真正能拿到全部自定义属性的方式,是扫描元素所有 attribute。
正确做法是过滤 elem.attributes:
立即学习“前端免费学习笔记(深入)”;
const dataAttrs = Array.from(elem.attributes)
.filter(attr => attr.name.startsWith('data-'))
.reduce((acc, attr) => {
acc[attr.name] = attr.value;
return acc;
}, {});这个结果是纯对象,键为完整属性名(如 data-user-id),值为原始字符串,无任何隐式转换。
- 别用
Object.fromEntries(Array.from(elem.dataset)):它只适用于现代 Chrome/Firefox,Safari 16.4 之前不支持,且仍受驼峰转换限制 - 如果需要小驼峰键名,自己写转换逻辑,别依赖
dataset的“自动”行为 - 注意:空属性如
<div data-flag></div>,attr.value是空字符串"",不是null
dataset 只适合简单命名场景,且必须严格守规
dataset 的唯一适用场景是:属性名全小写 + 连字符,不含数字、大写字母、下划线。例如 data-role、data-index、data-api-url。一旦破例,它就静默失效。
你写 elem.dataset.userId 能取到 data-user-id,但写 elem.dataset.apiUrl 却取不到 data-api-url?不对——data-api-url 对应的是 apiUrl,没问题;但 data-API-URL 或 data-apiUrl 就完全不会被解析,getAttribute('data-API-URL') 也会返回 null。
- 命名必须是
data-xxx-yyy形式,xxx 和 yyy 全小写,中间只用连字符 -
dataset是只读映射,赋值如elem.dataset.foo = 'bar'不会更新 DOM,后续getAttribute('data-foo')仍是旧值 - 所有值都是字符串,
data-active="false"→elem.dataset.active === "false",不是布尔false
判断 data 属性是否存在,别用真假值判断
if (elem.dataset.flag) 在 data-flag="false" 时仍为 true(非空字符串恒真);if (!elem.dataset.count) 在 data-count="0" 时也进分支("0" 是真值)。这类判断极易翻车。
正确方式分两层:
- 是否存在该属性:
'flag' in elem.dataset或elem.hasAttribute('data-flag') - 值是否为语义上的 true:
elem.dataset.flag === 'true'(约定写法)或JSON.parse(elem.dataset.config || '{}')(存 JSON 时) - 数值转换务必显式:
+elem.dataset.count或Number(elem.dataset.count),避免字符串拼接
最隐蔽的坑是:属性存在但没赋值(<div data-loaded></div>),getAttribute('data-loaded') 返回 "",elem.dataset.loaded 也是 "",不是 undefined——它确实存在,只是值为空。



















