A01 认识 JavaScript 与运行环境

2026-10-31 17:291 阅读累计 不足 1 分钟约 11 分钟JavaScript
AI 摘要30 秒读完

厘清JavaScript语言核心与宿主环境的边界,对比浏览器与Node.js的搭建、三种脚本引入方式差异及调试入口。

  • 语言核心与宿主能力分离,document与process等报错应先判断运行环境
  • 新项目默认使用type="module",模块脚本自带延迟执行且有独立作用域
  • 模块脚本必须经http加载,file://协议会被跨源策略拦截
  • defer保证经典脚本在DOM就绪后按文档顺序执行
  • Node.js中import报错需改用.mjs后缀或声明"type":"module"
AI 生成 · 仅供参考

A01 认识 JavaScript 与运行环境

摘要:JavaScript 是在宿主环境中执行的语言,浏览器与 Node.js 提供不同的外部接口,语言本身保持一致。脚本通过 <script> 接入页面,type="module" 会改变加载时机与作用域。本文给出两种运行环境的搭建、三种引入方式的差异与调试入口,为后续所有示例提供统一环境。
关键词:JavaScript,宿主环境,script 标签,模块,控制台

所属:frontend/js / A-入门 | 上一篇:A00-总结 | 下一篇:A02-变量与数据类型

1 引言

同一个函数在浏览器里能操作 DOM,在 Node.js 里能读写文件,语言语法却完全相同。差异来自宿主环境(host environment,为脚本提供全局对象与外部能力的运行时),不来自语言。

本文解决三个问题:脚本在哪里执行、如何接入页面、出错时从哪里看。范围见表 1-1。

项 本文覆盖 本文不覆盖
环境 浏览器控制台、Node.js 命令行 打包器与框架
引入 内联脚本、script 标签、模块脚本 按需加载与分包策略(C05)
调试 控制台日志、断点、报错定位 性能剖析(C03)

2 预备知识

项 要求 核对方式
浏览器 Chrome 130+,开发者工具可打开 F12 后 Console 面板可输入
Node.js 20 及以上 node -v 输出版本号
编辑器 VS Code 或同类,支持 JavaScript 语法高亮 打开 .js 文件有高亮
前置 HTML A03 能写完整 HTML 结构
素材 一个可运行页面 含容器元素即可

3 原理与实现

3.1 语言与宿主的关系

语言核心只提供语法、类型与内置对象;页面、文件、网络由宿主注入,如图 3-1 所示。

flowchart LR
    A["JavaScript 语言核心<br/>语法·类型·Array·Object"] --> B["浏览器宿主<br/>document·window·fetch"]
    A --> C["Node.js 宿主<br/>fs·process·http"]
    B --> D["页面交互"]
    C --> E["服务端与脚本工具"]

图 3-1 语言核心与两类宿主的能力边界

图上可见:Array、Promise 两边都有,document 只有浏览器有,process 只有 Node.js 有。写错宿主是「document is not defined」的唯一原因。

3.2 三种引入方式

<!-- 运行环境:Chrome 130+;三种方式依次验证加载时机 -->
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>引入方式</title>
    <script src="./scripts/inline-defer.js" defer></script>
    <script type="module" src="./scripts/module.js"></script>
  </head>
  <body>
    <h1 id="title">脚本引入</h1>
    <script>
      console.log('[inline]', document.getElementById('title').textContent);
    </script>
  </body>
</html>
// scripts/inline-defer.js;运行环境:Chrome 130+
console.log('[defer]', document.getElementById('title')?.textContent ?? 'DOM 尚未就绪');
// scripts/module.js;运行环境:Chrome 130+;需通过 http 访问,file 协议会被拦截
import { greet } from './greet.js';

console.log('[module]', greet('模块'));
// scripts/greet.js;运行环境:Chrome 130+
export function greet(name) {
  return `hello ${name}`;
}

三种方式的差异见表 3-1。

方式 写法 执行时机 作用域 适用场景
内联脚本 <script>...</script> 解析到该位置立即执行 全局 调试片段,不长期保留
经典外链 <script src> 默认 下载完成后阻塞解析 全局 老项目、无模块环境
经典外链加 defer <script src defer> 文档解析完成后按序执行 全局 需要 DOM 且不需模块
模块脚本 <script type="module"> 解析完成后执行,默认延迟 模块独立 新项目默认选择

三条规则:新项目一律用 type="module";模块脚本无 defer 也延迟执行,不要重复添加;模块脚本必须经 http 加载,直接双击 file:// 会被跨源策略拦截。

3.3 Node.js 运行方式

# 运行环境:Node.js 20 及以上;执行目录为项目根
node scripts/greet.js
// scripts/greet.js 末尾追加,用于命令行验证;Node.js 20+
console.log(greet('Node'));

预期输出:hello Node。若报 Cannot use import statement outside a module,说明文件后缀为 .js 而目录未声明模块类型,将文件名改为 .mjs 或在 package.json 中加 "type": "module"。

4 验证与讨论

  1. 用本地服务器打开页面(npx serve .),确认控制台依次出现 [defer]、[module]、[inline]。
  2. 删除 defer 属性,确认先出现 DOM 尚未就绪,再出现标题文本。
  3. 用 file:// 直接打开页面,确认模块脚本报 CORS 错误而经典脚本正常。
  4. 执行 node scripts/greet.js,确认命令行输出与服务端能力可用。
检查项 预期结果 说明
defer 顺序 按文档顺序执行 defer 保证顺序
模块延迟 无需 defer 也能拿到 DOM 模块默认延迟
模块隔离 模块内 var 不挂到 window 模块有独立作用域
Node 可用 输出 hello Node 宿主差异不影响语言核心

讨论与局限。 模块脚本的加载顺序与执行顺序一致,但多个模块的下载是并行的;文件协议下模块被拦截是规范要求,不是浏览器缺陷。另,本章不涉及热更新与构建产物替换,见 C05。

5 常见问题

现象 原因 处理
Cannot use import statement 经典脚本中写了 import 改用 type="module"
Failed to load module script 以 file:// 打开页面 启动本地服务器
document is not defined 在 Node.js 中操作 DOM 浏览器专用代码放到页面侧
xxx is not defined 变量未声明或拼写不一致 控制台核对名字,启用严格模式
控制台没有任何输出 脚本 404 或语法错误 Network 面板看状态码,Console 看红字

6 结论

序号 结论 依据
1 语言核心与宿主能力分离,报错先分环境 图 3-1
2 新项目默认用模块脚本 表 3-1
3 模块脚本需要 http 环境 4 节步骤 3
4 defer 解决 DOM 就绪与执行顺序 表 3-1

参考文献

[1] MDN Web Docs · JavaScript 第一步,https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/First_steps(访问于 2026-10-31)
[2] ECMAScript Language Specification,ECMA-262,https://tc39.es/ecma262/(访问于 2026-10-31)

返回文章列表

评论 0

0/2000

还没有评论,快来抢沙发吧~