优先用 querySelector,它更灵活;getElementById 仅 ID 查找且性能敏感时略快;二者均需检查返回值或确保 DOM 加载完成;事件一律用 addEventListener,支持多次绑定、捕获/冒泡控制及 once 选项;动态元素用事件委托;修改内容优先 textContent 防 XSS,innerHTML 需过滤;操作前须确认元素存在、及时清理监听器、避免异步操作已销毁节点。

JavaScript 操作 DOM 和处理事件本身不难,难在选错方法、忽略事件流、或没处理好元素不存在的边界情况。
用 querySelector 还是 getElementById?
优先用 querySelector,它更灵活,支持 CSS 选择器语法;但若只按 ID 查找且性能敏感(比如高频循环中),getElementById 略快且语义明确。
-
querySelector返回第一个匹配项,querySelectorAll返回 NodeList(不是数组,需用[...nodeList]或Array.from()转换才能用map/forEach) -
getElementById参数不带#,而querySelector('#id')必须带 - 如果元素还没加载完就调用,两者都返回
null—— 务必检查返回值,或把脚本放在</body>前,或监听DOMContentLoaded
绑定点击事件时,onclick 属性和 addEventListener 怎么选?
一律用 addEventListener。直接赋值 onclick 会覆盖之前绑定的处理函数,且无法控制捕获/冒泡阶段。
- 一个元素可多次调用
addEventListener('click', handler),所有 handler 都会执行 - 想移除特定监听器?必须传入**同一个函数引用**:
element.addEventListener('click', fn); element.removeEventListener('click', fn); - 需要一次性执行?加
{ once: true }选项,不用手动清理 - 阻止冒泡用
event.stopPropagation(),阻止默认行为用event.preventDefault()
动态添加的元素收不到事件?试试事件委托
直接给未来才存在的元素绑事件是无效的。把监听器挂到父级(比如 document 或某个稳定容器),利用事件冒泡机制捕获子元素触发的事件。
立即学习“Java免费学习笔记(深入)”;
document.addEventListener('click', function (e) {
if (e.target.matches('.dynamic-button')) {
console.log('点中了动态按钮');
}
});
-
e.target是实际被点击的元素,e.currentTarget才是绑定监听器的那个父元素 -
matches()比正则或 classList.contains 更安全,支持完整选择器(如'button[data-action="save"]') - 避免绑定到
document太深的层级,否则可能拦截不该管的事件;尽量靠近目标元素的最近稳定祖先
修改 DOM 内容时,innerHTML 和 textContent 别混用
textContent 只处理纯文本,不解析 HTML,速度快且防 XSS;innerHTML 解析并渲染 HTML 字符串,有注入风险,也更慢。
- 设按钮文字?用
el.textContent = '提交' - 要插入带标签的结构?必须用
innerHTML,但确保内容可信,或先用DOMPurify.sanitize()过滤 - 批量更新多个节点?别反复改
innerHTML,改用DocumentFragment或一次性写入外层容器 - 读取内容时:
textContent获取所有文本(含隐藏元素),innerText只读可见文本(但受 CSS 影响,兼容性略差)
最常被忽略的是:操作前不确认元素是否存在、事件监听器没清理导致内存泄漏、以及在异步回调里直接操作已销毁的 DOM 节点 —— 这些问题不会报错,但会让行为变得不可预测。











