JavaScript执行模型本质是事件驱动,依赖事件循环处理用户交互、定时器、网络请求等异步事件;addEventListener是绑定事件的标准方式,支持多次绑定、阶段控制与移除;需确保DOM加载完成后再绑定,动态元素推荐事件委托。

JavaScript 的执行模型本质是事件驱动
它不按代码从上到下线性跑完就结束,而是启动后先建立事件循环(event loop),然后等事件发生——比如用户点击、页面加载完成、定时器到期、网络请求返回——再把对应的回调函数推入调用栈执行。这意味着 setTimeout、fetch、addEventListener 这些操作都只是“注册监听”,真正执行时机由事件系统决定,不是 JS 主线程主动控制的。
给元素绑定事件最可靠的方式是 addEventListener
直接写 onclick 属性或 HTML 里加 onclick="..." 看似简单,但有硬伤:只能绑定一个处理函数;无法控制捕获/冒泡阶段;容易被覆盖。而 addEventListener 支持多次调用、可选参数、可移除,是现代标准做法:
const btn = document.getElementById('submit');
btn.addEventListener('click', function(e) {
console.log('按钮被点了');
});
// 同一个事件可以绑定多个 handler
btn.addEventListener('click', () => alert('第二个响应'));
- 第三个参数传
{ once: true }可让 handler 执行一次后自动解绑 - 传
{ capture: true }能在捕获阶段触发(默认是冒泡阶段) - 避免用
onxxx属性赋值,尤其在组件化或多人协作时容易冲突
常见绑定时机错误:DOM 元素还没加载出来
如果脚本在 前执行,document.getElementById 或 querySelector 很可能返回 null,后续调用 addEventListener 就会报错 Cannot read property 'addEventListener' of null。
- 把脚本放到
之前是最简单稳妥的做法 - 或者用
DOMContentLoaded事件确保 DOM 解析完成:document.addEventListener('DOMContentLoaded', () => { const el = document.querySelector('.my-btn'); el.addEventListener('click', handler); }); -
load事件要等所有资源(图片、CSS)加载完才触发,通常没必要等那么久
动态插入的元素需要事件委托
如果按钮是 JS 后续用 innerHTML 或 appendChild 插入的,直接对它调用 addEventListener 没问题;但如果是一批同类元素(比如列表项),且未来还会新增,一个个绑定既低效又难维护。这时应把事件监听器挂到父容器上,靠 e.target 判断实际点击的是谁:
立即学习“Java免费学习笔记(深入)”;
document.getElementById('list').addEventListener('click', function(e) {
if (e.target.classList.contains('item-delete')) {
e.target.closest('li').remove();
}
});
- 委托依赖事件冒泡,所以不能用
capture: true - 注意检查
e.target是否符合预期,避免误触发(比如点到子元素文字而非按钮本身) - 不要在委托回调里频繁调用
querySelectorAll,性能差











