浅析JavaScript的7种异常类型及如何快速排查
无论是浏览器控制台还是Node.js
的服务端,我们会在各种地方看到JavaScript
异常,异常处理是编写程序必备的基础能力,在学习异常处理之前,了解 JavaScript
中的几种异常类型是非常有必要的。
1、Error
Error
是最基本的错误类型,其他的错误类型都继承自该类型。
Error
对象主要有两个重要属性 message
和 name
分别表示错误信息和错误名称。
程序运行过程中抛出的异常一般都有具体的类型,
Error
类型一般都是开发人员自己抛出的异常。
try {
throw new Error('ConardLi抛出的异常');
} catch (error) {
console.log(error);
}
2、SyntaxError - 语法错误
语法错误也称为解析错误。语法错误在任何编程语言中都是最常见的错误类型,表示不符合编程语言的语法规范。
JavaScript
是一门解释性语言,执行一段代码时需要经历 词法分析 -> 语法分析 -> 语法树
就可以开始解释执行了:
词法分析是将字符流(char stream
)转换为记号流(token stream
)、语法分析阶段会将记号流(token stream
)生成抽象语法树(AST
)。
在这两个阶段,如果 Javascript
引擎发现了预期之外/无法抓换的 token
,或者 token
顺序和预期不一致时,就会抛出 SyntaxError
。
因此 SyntaxError
应该和其他类型的异常区分开,此类异常发生在 JavaScript
解析/编译时,此类异常一旦发生,导致整个js文件都无法执行,而其他异常发生在代码运行时,这一类的错误会导致在错误出现的那一行之后的代码无法执行,但在那一行之前的代码不会受到影响。
SyntaxError
类型的错误通常是语法错误,遇到这中错误时建议通过你所用的 IDE 排查,比如 VSCode 能够直接跳出这类型的错误提示。
如下图,VSCode 用红色波浪线提示 family
对象有错误,当出现错误时会建议不要只检查当前行,错误可能会存在于上下文中(有可能跨多行的错误),这个例子中仔细检查可以发现在'小明'
后面少了一个逗号。
1)Uncaught SyntaxError: Unexpected identifier
var person = {
name: '小明'
family: {
name: '小明家'
}
}
语法解析错误,因为在对象结构中缺少一个逗号,除了通过在 VSCode 中查看外,也可以直接通过 Chrome Console 切换到 Source 页面查看错误行,并检查此行的上下文中是否存在语法错误
2)Uncaught SyntaxError: Unexpected end of input
function fn() {
console.log('这是一个函数');
console.log(fn);
语法解析错误:未预期的结束,这个例子中缺少结尾的大括号 }
,在编写代码时尽可能的维持正确的锁紧,将代码排列整齐之后更容易找到错误。
3)Uncaught SyntaxError: Unexpected token '}'
if (name)
console.log('立即执行函数')
};
语法解析错误:未预期的符号 }
,代码结尾多了一个 }
符号导致环境运行错误,这个错误的排查方法与上面相同,尽可能将代码排整齐并维持首尾符号的一致。
4)Uncaught SyntaxError: Identifier 'a' has already been declared
let a;
let a;
语法解析错误:识别符号(在这里指的是变量)已经被声明,应该避免重复生命同一个变量,在 ES6 都禁止用 let、const 对变量进行重复声明,直接排除即可。
3、TypeError - 类型错误
运行时最常见的异常,表示变量或参数不是预期类型,比如 new
关键字后面必须为构造函数、()
前必须为函数。
TypeError
是类型上的错误,同样 IDE 也不会预先提示有错误,必须在执行时才会看到,这类型的错误通常是以下几种:
- 试图获取 undefined、null 的属性
- 尝试调用非函式变量或表达式(例如:
'text'()
)
排查重点:在获取变量前先确认其当前的数据类型及结构
1)Uncaught TypeError: Cannot read property 'a' of undefined
var a;
console.log(a.a);
说明:在这个变量的值中无法找到其特定的属性,例如在 undefined、null 的值上是找不到其它属性的。
2)Uncaught TypeError: console.log(...) is not a function
console.log('a')
(function() {
console.log('立即执行函数')
})()
说明:这代码看起来是立即执行函数的错误,但是却出现了 console.log(...) is not a function
。这个错误主要是因为缺少了分号。当遇到这类错误时只要在两者之间补上分号即可。
4、ReferenceError - 引用错误
引用一个不存在的变量时发生的错误,每当我们创建或定义一个变量时,变量名称都会写入一个变量存储中心中。
这个变量存储中心就像键值存储一样,每当我们引用变量时,它都去存储中找到 Key
并提取并返回 Value
,如果我们要找的变量不在存储中,就会抛出 ReferenceError
。
比如下面这个未定义的错误:
请注意,如果我们调用的是一个已经存在的变量的一个不存在的属性,则不会抛出 ReferenceError
,因为变量本身已经在存储中了,调用它不存在的属性只会是未赋值状态,也就是 undefined
:
ReferenceError
这类错误通常是指找不到引用,当出现这类错误时在 IDE 中不一定会提示现错误(除非安装了 Linter),所以在代码的运行阶段才会看到这类错误。
排查重点:
- 通过 Chrome 的提示改正
- 在 JavaScript 开发环境中安装 ESLint
1)ReferenceError: a is not defined
引用错误:由于变量 a 未定义,所以在使用这个变量时会出现未定义的提示,只要先定义好这个变量即可。
还有另一种很常见的情况,当引用外部包时出现 “包名 + is not defined
”,这种情况通常是外部资源没有被正确载入,应该确保该资源被正确的引入。
下面的例子就是因为 jQuery 没有正确导入而导致的。
Uncaught ReferenceError: $ is not defined
5、RangeError - 边界错误
表示超出有效范围时发生的异常,主要的有以下几种情况:
- 数组长度为负数或超长
- 数字类型的方法参数超出预定义范围
- 函数堆栈调用超过最大值
这是创建了超过长度上限的数组或执行了无法退出的递归函数所造成的错误,遇到这类问题需要重新检查代码的逻辑,是否消耗了过多的资源(内存或CPU资源)。
排查重点:需要重新检查逻辑,如果有必要可先删除部分代码,先找出错误的片段后再进行除错。
1)Uncaught RangeError: Maximum call stack size exceeded
(function a() {
a();
})();
说明:在函数调用时会产生一个函数调用栈,如果在递归的过程中超过上限则会产生错误。
这类错误也很常见,却不容易找到出错的原因,其主要原因是在递归时超过了环境的限制(使用框架时也很常见),如果遇到这错误建议改写当前调用函数的方式。
6、URIError - URL 错误
在调用 URI
相关的方法中 URL
无效时抛出的异常,主要包括 encodeURI、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()
几个函数:
7、自定义异常
另外,为了满足各种各样的业务需求,除了 JavaScript
已经给定的异常类型,我们还可以自定义一些异常类型,比如我们要根据不同的异常类型给用户不同的错误提示:
class UnAuthError extends Error { }
class ParamError extends Error { }
function controller() {
throw new UnAuthError();
}
try {
controller();
} catch (error) {
if (error instanceof UnAuthError) {
return '无权限';
}
if (error instanceof ParamError) {
return '参数错误';
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2017-11-23 ES6里关于函数的拓展(三)
2017-11-23 ES6里关于函数的拓展(二)