script标签放<body>底部最稳妥,因DOM已解析完成可直接操作;放<head>会因DOM未就绪导致getElementById报null错误;async/defer是<head>中唯一安全方案,但defer仅对外部脚本生效。

script 标签放 <body> 底部最稳妥,尤其当你操作 DOM 时。
script 放 <head> 会报 document.getElementById(...) is null
浏览器解析 HTML 是从上到下顺序进行的。如果 script 在 <head> 里直接调用 document.getElementById 或绑定事件,此时 DOM 还没开始解析,目标元素根本不存在。
- 常见错误现象:控制台报错
Cannot read property 'innerHTML' of null或undefined - 即使脚本很小,也不代表它能“等 DOM 出来再执行”
- 除非你主动加
DOMContentLoaded监听或用defer,否则不会自动延迟
script 放 <body> 末尾(</body> 前)能直接操作 DOM
这是最常用、最省心的位置,尤其适合初学者和业务逻辑脚本:
- 页面 HTML 已全部解析完成,
document.getElementById、querySelector都能立刻拿到元素 - 不阻塞页面渲染,用户能更快看到内容
- 无需额外包装或监听事件,写完就能用
<body>
<div id="app">Hello</div>
<script>
// ✅ 安全:DOM 已就绪
document.getElementById("app").textContent = "Updated";
</script>
</body>
async 和 defer 是 <head> 里唯一安全用法
如果你必须把 script 放在 <head>(比如第三方统计、Polyfill),就得靠属性控制执行时机:
立即学习“前端免费学习笔记(深入)”;
-
async:下载不阻塞,但执行时机不可控,适合无依赖的独立脚本(如 GA、百度统计) -
defer:下载不阻塞,执行在 DOM 解析完成后、DOMContentLoaded前,且按顺序执行,适合模块化业务脚本
<head> <script defer src="main.js"></script> <script async src="analytics.js"></script> </head>
注意:defer 只对外部脚本生效,内联脚本加了也无效。
真正容易被忽略的是:哪怕你把 script 放在 </body> 后面(即 </body> 和 </html> 之间),HTML 解析器也会自动把它“纠正”进 <body> 内部——这看似没区别,但不符合规范,审查工具可能警告,团队协作时也容易引发歧义。



















