什么是 <script> 标签?

<script> 标签是HTML中用来嵌入或引用JavaScript代码的容器。简单来说,它就是让网页”动起来”的关键元素!

没有脚本,网页就像一本静态的画册;添加脚本后,网页就变成了一个可以交互的应用程序。

<!– 最简单的脚本示例 –>
<script>
  alert(‘你好,世界!’); // 页面加载时会弹出对话框
</script>

注意: 默认情况下,浏览器会将 <script> 标签中的内容当作JavaScript代码来执行。虽然也可以指定其他脚本语言,但现在几乎100%都是使用JavaScript。

脚本放在哪里?

1. 在 <head> 中

脚本放在 <head> 区域会在页面内容显示之前加载和执行。

<!DOCTYPE html>
<html>
<head>
  <title>页面标题</title>
  <script>
    console.log(‘head中的脚本执行了’);
  </script>
</head>
<body>
  <!– 页面内容 –>
</body>
</html>

缺点: 如果脚本很大或者网络慢,会导致用户长时间看到空白页面。

2. 在 <body> 底部

将脚本放在 <body> 结束标签之前是最常用的方法。

<body>
  <!– 页面内容先加载 –>
  <h1>欢迎来到我的网站</h1>

  <script>
    console.log(‘body底部的脚本执行了’);
  </script>
</body>

优点: 页面内容会先显示出来,用户不会看到空白页。脚本执行时用户已经能看到内容了。

内部脚本 vs 外部脚本

内部脚本

直接把JavaScript代码写在HTML文件中:

<script>
  function sayHello() {
    alert(‘你好!’);
  }
</script>

适合场景: 小型脚本、一次性代码、快速测试

外部脚本

将JavaScript代码保存在单独的.js文件中,然后在HTML中引用:

<!– HTML文件 –>
<script src=”scripts/main.js”></script>

// scripts/main.js文件
function sayHello() {
  alert(‘你好!’);
}

优点:

  • 代码分离,结构更清晰
  • 浏览器会缓存.js文件,提高加载速度
  • 多个页面可以共享同一个脚本文件
  • 更容易维护和更新

经验法则: 当脚本超过10行或者需要在多个页面使用时,就应该使用外部脚本。

重要属性详解

src 属性

用于指定外部脚本文件的URL:

<script src=”https://code.jquery.com/jquery-3.6.0.min.js”></script>

当使用src属性时,<script>标签内的代码会被忽略。

async 属性

告诉浏览器”不用等这个脚本,你继续加载页面,脚本下载完就马上执行”:

<script src=”demo.js” async></script>

特点:

  • 下载不阻塞HTML解析
  • 执行时会暂停HTML解析
  • 多个async脚本执行顺序不确定

defer 属性

告诉浏览器”先别执行这个脚本,等页面完全加载完再执行”:

<script src=”demo.js” defer></script>

特点:

  • 下载不阻塞HTML解析
  • 在DOMContentLoaded事件之前执行
  • 多个defer脚本按顺序执行

type 属性

指定脚本类型,现代浏览器中默认是”text/javascript”:

<!– 标准JavaScript –>
<script type=”text/javascript”></script>

<!– 模块化JavaScript –>
<script type=”module”></script>
属性 加载时阻塞HTML解析 执行时阻塞HTML解析 执行顺序 适用场景
无属性 顺序执行 小型脚本、依赖DOM的初始化
async 下载完成顺序 独立脚本(如分析代码)
defer 文档顺序 需要操作DOM的脚本

脚本加载策略

理解脚本加载对网页性能至关重要:

默认行为: 当浏览器遇到<script>标签时,会停止解析HTML,下载并执行脚本,完成后才继续解析HTML。

现代最佳实践

对于关键脚本(需要在页面加载初期运行的):

<script src=”essential.js” defer></script>

对于非关键脚本(如分析、广告等):

<script src=”analytics.js” async></script>

动态加载脚本

可以使用JavaScript在需要时创建并添加脚本:

<button onclick=”loadScript()”>加载脚本</button>

<script>
  function loadScript() {
    let script = document.createElement(‘script’);
    script.src = ‘dynamic.js’;
    document.head.appendChild(script);
  }
</script>

模块化脚本

ES6引入了模块化概念,使用 type=”module” 属性:

<!– 模块化脚本 –>
<script type=”module”>
  import { hello } from ‘./module.js’;
  hello();
</script>

模块化优点:

  • 避免全局变量污染
  • 代码组织更清晰
  • 按需加载
  • 依赖关系明确

注意: 模块化脚本默认具有defer特性,即会在文档解析完成后执行。

处理旧浏览器

虽然现代浏览器都支持JavaScript,但有些用户可能禁用了JS或使用非常旧的浏览器:

<noscript> 标签

当浏览器不支持或禁用了JavaScript时,显示替代内容:

<script>
  document.write(“您已启用JavaScript”);
</script>
<noscript>
  <div style=”background:#ffdddd;padding:20px;”>
    您的浏览器不支持JavaScript或已禁用!
    部分功能可能无法使用。
  </div>
</noscript>

渐进增强原则: 首先确保基本功能在不支持JS时也能工作,然后使用JS增强体验。

最佳实践总结

  • ✅ 将脚本放在 <body> 底部或使用 defer
  • ✅ 尽量使用外部脚本文件
  • ✅ 非关键脚本使用 async
  • ✅ 大型项目使用模块化开发
  • ✅ 考虑旧浏览器用户,提供 <noscript> 提示
  • ❌ 避免使用 document.write()
  • ❌ 避免在脚本中直接写大量HTML
  • ❌ 不要过度依赖全局变量

性能提示: 压缩和合并脚本文件,使用CDN加速,设置缓存策略,延迟加载非必要脚本。

常见问题解答

Q: 一个HTML页面可以包含多个<script>标签吗?

A: 是的,可以包含多个。它们会按照在HTML中出现的顺序依次执行(除非使用async属性)。

Q: 为什么有时脚本不起作用?

A: 常见原因:语法错误、路径错误、在DOM元素加载前就尝试操作它、浏览器缓存问题。

Q: 如何调试脚本问题?

A: 使用浏览器开发者工具(按F12打开):

  • Console(控制台)查看错误信息
  • Sources(源代码)设置断点调试
  • Network(网络)查看脚本是否加载

Q: 什么是CDN?为什么要用它?

A: CDN(内容分发网络)是分布在全球的服务器网络。使用CDN加载常用库(如jQuery)可以加速加载,因为这些文件可能已在用户本地缓存过。