Web前端入门第 54 问:JavaScript 3 种书写位置及 script 标签的正确存放位置
JS 的代码并没有强制规定放在 HTML 中的某个位置,如果您有使用过开发者工具查看过网页源码,那么您会看到很多 JS 代码都以 .js 文件的形式存放,并且放在了 HTML 文件最后,也就是
JS 的代码并没有强制规定放在 HTML 中的某个位置,如果您有使用过开发者工具查看过网页源码,那么您会看到很多 JS 代码都以 .js 文件的形式存放,并且放在了 HTML 文件最后,也就是
结束标签之前。
但如果仔细观察,在
标签中,也会找到很多 script 标签引入的 JS 代码。
那么您是否好奇过他们都有哪些区别??
3 种书写位置
与 CSS 一样,JS 的脚本算起来也有三种书写方式,分别为行间 JS 代码、内联脚本、外部脚本。
1、事件处理
直接在 HTML 元素的事件属性中写代码,此方式一般多用于编写 demo 测试程序,正常的项目开发不推荐这种写法。
原因:onclick 中的方法名必须全局声明,导致污染全局变量,并且混合了 HTML 结构和 JS 事件行为代码,不利于项目维护。
点击我
2、内联脚本
console.log('Hello World!')
3、外部脚本
ES6 模块化引入,此方式必须要有一个服务器环境!比如:本地安装一个 nginx。
内联脚本应用场景
内联脚本一般多用于页面初始化、临时代码调试、首屏渲染必需的初始化逻辑等场景,比如三方插件初始化:
new VConsole();
外部脚本应用场景
外部脚本适合复杂、复用性高的场景,是现代 Web 开发的主流选择,使用外部脚本可以降低 HTML 代码的复杂度,有利于项目的维护。
模块化引入方式:
index.js:
import { a } from './utils.js';
import { b } from './common.js';
a();
b();
document.querySelect('#button').addEventListener("click", async () => {
// 按需加载模块
const module = await import("./test-module.js"); // test-module.js 中导出 run 方法
module.run();
console.log('Hello World!');
});
script 标签属性
script 标签除了常见的 type 和 src 外,还有两个控制脚本异步加载的属性,分别为 async 和 defer,区别如下:
1、无 async/defer
HTML 解析 → 遇到
应用场景:脚本完全独立,不依赖其他脚本或 DOM,比如:统计代码、广告代码等。
3、defer
HTML 解析(并行下载脚本) → HTML 解析完成 → 按顺序执行所有 `defer` 脚本
多个 defer 脚本严格按文档顺序执行,无论下载速度。所有 defer 脚本执行完毕后,才会触发 DOMContentLoaded 事件。
应用场景:脚本需要访问完整的 DOM 或依赖其他脚本,比如:页面初始化逻辑。
script 标签位置
首先要明白,存放在 head 中的 script 标签,会阻塞页面加载,如果这个文件超大,那么页面白屏时间就会很长。
如果是内联脚本,放在哪儿其实影响不大,主要看其内容中有没有耗时的操作。
如果您的脚本需要尽早执行,那么建议放在 head 中。比如:vconsole调试工具,尽早加载有利于捕获代码错误。
如果您的脚本需要访问完整的 DOM,那么建议放在 body 的最后,这样可以确保 DOM 已解析完成。
虽然可以使用 defer 控制脚本延迟加载,但某些兼容原因,还是建议 JS 脚本后置兼容旧版本浏览器。
写在最后
JS 代码应该首先考虑放在外部文件中,HTML 结构应该永远保持简洁。
除非您真的有需求,才建议将 JS 代码放在 head 中,否则 JS 代码应该永远放在 结束标签之前。