报错$ is not defined?排查jquery.js未成功加载的常见原因

作者:小括号时间:2026-10-30 19:13:24浏览:224

详细梳理浏览器报 Uncaught ReferenceError: $ is not defined 错误的核心原因与排查步骤。涵盖脚本加载顺序、路径错误、CDN失效与协议拦截、作用域冲突及模块化打包等常见场景,提供清晰实用的修复方案。

JavaScript 调试 jQuery 前端工程 阅读时长约 8 分钟
在浏览器控制台中看到 Uncaught ReferenceError: $ is not defined,本质是当前 JavaScript 执行环境中找不到名为 $ 的变量或函数。对于依赖 jQuery 的项目,这通常意味着 jquery.js 根本没有成功下载、或者自写业务代码在基础库加载就绪之前便抢先执行了。通过本文梳理的“网络链路 → 加载顺序 → 协议限制 → 作用域冲突”四步排查链条,可以快速定位并根治该问题。
报错$ is not defined?排查jquery.js未成功加载的常见原因
图 0:jQuery 资源加载与浏览器全局作用域挂载机制全貌

一、核心机制:为什么会触发 ReferenceError?

在标准的浏览器环境中,当 jquery.js 脚本被加载并解析时,其源码最外层的立即执行函数会将核心实例挂载到顶层全局对象 window 上,同时建立两个全局属性引用:window.jQuery 以及快捷符号 window.$。

JavaScript 引擎是单线程自上而下解析执行脚本的。当我们在代码中编写诸如 $('#btn') 时,引擎会沿着当前作用域链逐层向上寻找 $ 的声明。若一路查找到 window 顶层仍未命中,引擎就会抛出 Uncaught ReferenceError: $ is not defined 并立刻中断当前脚本的后续执行。

报错$ is not defined?排查jquery.js未成功加载的常见原因
图 1:浏览器主线程脚本解析时序与全局对象注入对比

从图 1 可以看出,引发报错的核心分歧点在于代码执行的瞬间,全局对象中是否存在有效定义。即使后端服务器上确实存有 jquery.js 文件,只要它未能在调用发生前完成注入,报错就会必然发生。

二、原因一:脚本引入顺序颠倒或错误使用了异步加载

初学者和快速重构旧页面时最容易发生的错误是引入位置颠倒。例如在 HTML 结构中,先编写了内联操作代码,后才引入 jQuery 脚本库。

1. 典型的顺序颠倒示例

<!-- 错误示例:依赖代码写在了基础库之前 -->
<script>
  // 此时浏览器尚未解析到下方的 jquery.js,window.$ 仍为 undefined
  $('#submit-btn').on('click', function() {
    console.log('提交表单');
  });
</script>

<!-- 此时才引入 jQuery,调用已经报错中断 -->
<script src="js/jquery-3.7.1.min.js"></script>

2. 异步属性 async 与 defer 的陷阱

现代网页为了优化首屏渲染性能,经常在 <script> 标签上添加 async 或 defer 属性。这两个属性对执行时序有截然不同的影响:

  • async 属性:脚本异步下载,一旦下载完成便立刻执行,完全不保证不同脚本之间的先后执行顺序。如果为 jquery.js 标记了 async,体积较小的业务脚本很可能先于它执行完毕,必然产生 $ is not defined。
  • defer 属性:脚本异步下载,但会严格按照在 HTML 中声明的先后顺序在 DOMContentLoaded 事件触发前执行。如果要使用 defer,必须确保 jquery.js 和后续依赖它的业务代码均添加了 defer,且 jQuery 声明在前。
避坑提醒:绝不要给基础库 jquery.js 单独添加 async 属性。若普通业务脚本不带 async,两者执行顺序将完全无法预测。

三、原因二:文件路径书写错误导致 404 Not Found

当 jQuery 文件存放在本地服务器时,相对路径在不同路由层级下的解析偏离是导致加载失败的高频诱因。

报错$ is not defined?排查jquery.js未成功加载的常见原因
图 2:通过浏览器开发者工具排查 404 与资源状态的四步操作法

1. 相对路径与路由层级的脱节

考虑以下目录结构:页面位于 /views/user/profile.html,而脚本位于 /public/js/jquery.min.js:

<!-- 错误写法:在二级目录下使用相对路径 -->
<script src="js/jquery.min.js"></script>
<!-- 浏览器解析出的实际请求为:/views/user/js/jquery.min.js (404 Not Found) -->

<!-- 正确写法:使用站点根目录绝对路径 -->
<script src="/public/js/jquery.min.js"></script>

2. 文件名大小写敏感问题

在本地 macOS 或 Windows 系统开发时,文件系统默认对大小写不敏感,写成 jQuery.min.js 或 jquery.min.js 均可正常访问;然而线上 Linux 服务器默认严格区分大小写,一旦文件名拼写不完全吻合,线上就会立即返回 404 状态码。

DevTools 验证小技巧:按 F12 打开开发者工具,切换至 Network (网络) 选项卡,按类型筛选 JS,刷新页面检查 jquery 请求的状态码。若是红色 404,直接将鼠标悬停在请求条目上,查看实际拼出的 Request URL 并与服务器物理磁盘路径核对。

四、原因三:CDN 节点不可用与 Mixed Content 协议阻断

采用第三方公共 CDN 引入 jQuery 是常见做法,但在生产环境中需要防范网络不可达与浏览器安全策略限制。

1. 混合内容 (Mixed Content) 拦截

当你的站点已经启用 HTTPS 协议(如 https://example.com),而页面中书写的 jQuery 引用依然为 HTTP 明文协议:

<!-- 在 HTTPS 页面中引入 HTTP 资源 -->
<script src="http://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

现代主流浏览器会出于安全策略直接阻断该请求,在控制台抛出 Mixed Content: The page was loaded over HTTPS, but requested an insecure script。此时该请求甚至不会真正发送出去,直接以失败告终。

2. 推荐的 CDN 容灾降级方案 (Local Fallback)

公共 CDN 可能因偶发网络波动、内网环境隔离或服务商维护而暂时不可用。工业级的前端页面推荐使用本地降级回退模式:

<!-- 优先通过 CDN 载入,确保使用 https 或协议相对路径 -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>

<!-- 容灾检测:若 window.jQuery 不存在,则就地写入本地脚本标签 -->
<script>
  window.jQuery || document.write('<script src="/assets/js/jquery-3.7.1.min.js"><\/script>');
</script>

这段代码先检测全局是否存在 window.jQuery。若 CDN 请求失败未完成挂载,则同步向文档流写入本地备用脚本,确保后续代码执行时基础库依然可用。

五、原因四:多库共存导致命名冲突与 noConflict 调用

在部分复杂的遗留系统或企业级门户中,页面可能同时引入了 Prototype.js、MooTools 等同样占用 $ 作为全局标识符的类库,或者其他开发人员在公共脚本中主动调用了 jQuery.noConflict()。

报错$ is not defined?排查jquery.js未成功加载的常见原因
图 3:全局命名空间中 $ 的占有权转移与安全闭包隔离原理

1. noConflict 释放行为

调用 jQuery.noConflict() 会将 window.$ 的控制权交还给最先定义它的外部库,或者恢复为 undefined,但 window.jQuery 仍完整保留。

排查方法:在控制台中分别输入 typeof jQuery 与 typeof $:

  • 如果 typeof jQuery === 'function',而 typeof $ === 'undefined',即可百分之百断定是别名冲突或被释放。

2. 安全的闭包使用范式

无论外界是否释放了 $,在编写业务代码或组件插件时,均应使用局部作用域来保护别名映射:

// 推荐写法一:在 DOM 准备就绪的回调中直接接收局部参数 $
jQuery(function($) {
  // 此作用域内的 $ 严格指向 jQuery,与全局 window.$ 无关
  $('#nav-menu').addClass('active');
});

// 推荐写法二:自执行匿名函数 (IIFE)
(function($) {
  'use strict';
  function initModule() {
    $('#sidebar').toggle();
  }
  window.myModule = { init: initModule };
})(jQuery);

六、原因五:现代工程化模块打包中的作用域隔离

在基于 Webpack、Vite 或 Rollup 构建的现代前端工程中,即便在 package.json 中安装了 jquery 并在入口文件写了 import $ from 'jquery',页面内直接编写的 <script> 标签或第三方旧插件依然可能报 $ is not defined。

1. 模块作用域与全局挂载的区别

ES Module 规范下,import 进来的变量属于模块私有上下文,默认不会自动挂载到 window 全局作用域。如果页面上混用了从 HTML 直接加载的旧插件(例如旧版轮播图或富文本编辑器),这些插件在全局找不到 window.$ 就会报错。

2. 显式挂载全局变量

若必须兼容依赖全局对象的旧脚本,可在项目入口文件(如 main.js)的顶部显式执行全局挂载:

// 入口文件:main.js
import $ from 'jquery';

// 显式将引用挂载至浏览器顶层对象
window.$ = $;
window.jQuery = $;

如果使用 Webpack 进行打包,也可以在 webpack.config.js 中借助内置的 ProvidePlugin 插件自动注入全局映射:

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  // ... 其他配置
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
      'window.jQuery': 'jquery',
      'window.$': 'jquery'
    })
  ]
};

七、系统化排查决策树与速查清单

遇到 $ is not defined 时,不必盲目调整代码,按照以下逻辑决策树进行系统化排查,可在 2 分钟内准确锁定根因:

报错$ is not defined?排查jquery.js未成功加载的常见原因
图 4:报错 $ is not defined 的完整故障诊断决策树
检查层级 现象特征 核心根因 推荐修复措施
网络层 Network 面板出现 404 / 403 / Failed 文件相对路径写错、大小写不符、CDN 不稳定或 Mixed Content 协议阻断 检查 Request URL,改用以 / 开头的绝对路径;协议统一使用 HTTPS;配置 Fallback 本地兜底。
文档结构层 Network 面板根本没有 jquery.js 请求 HTML 遗漏 <script> 标签,或在 SSR / 模板引擎中被条件注释过滤 审查 Elements DOM 树,在 <head> 或 <body> 底部显式补全引入标签。
执行时序层 请求 200 成功,但业务代码先执行 业务代码位于 jQuery 之前,或为 jQuery 错误添加了 async 属性 确保基础库标签物理位置在前;移除 async 属性;统一规范 defer 顺序。
运行时作用域 typeof jQuery === 'function' 但 $ === 'undefined' 调用了 noConflict() 或被其他三方类库占用了 $ 改用 jQuery(...) 或通过自执行匿名函数 (function($){...})(jQuery) 隔离别名。
工程构建层 构建产物运行正常,但外部插件报错 ES Module 模块隔离未向 window 暴露全局变量 在入口处添加 window.$ = window.jQuery = $; 或配置 Webpack ProvidePlugin。
排查完毕确认: 修复之后,在控制台输入 $.fn.jquery,若能准确打印出版本字符串(例如 "3.7.1"),且控制台无任何新抛出的 ReferenceError,则表明 jQuery 已经成功加载并在当前页面中建立起稳定的运行上下文。
作者最新文章
相关文章
更多