本文系统梳理了JavaScript开发中常见的7种原生错误类型,包括RangeError、ReferenceError、SyntaxError、TypeError、URIError、EvalError和InternalError。通过具体代码示例,详细解释了每种错误的触发条件、底层机制及排查方法,帮助开发者快速定位并解决代码中的异常问题,提升代码健壮性。
概述
无论是在浏览器控制台还是Node.js终端环境中,错误信息都频繁出现。本文旨在全面梳理JavaScript开发过程中可能遭遇的各类原生错误,帮助开发者建立系统的错误认知。
提示:提供清晰、准确的错误提示是区分高效开发与低效开发的关键。在编写可复用代码时,务必确保实现了清晰且易于理解的错误处理机制。
1. RangeError(范围错误)
当数值超出了JavaScript允许的范围时,系统将抛出此错误。
例如
const l = console.logconst arr = [90,88]
arr.length=90**99
假设我们有一个包含两个元素的数组arr。接下来,尝试将该数组扩展至包含90**99(即2.9512665430652753e+193)个元素。
该数值远超出了数组长度允许增长的最大范围。执行此操作将抛出RangeError:
$ node errors
errors.js:4
arr.length=90**99
^RangeError: Invalid array length
这是因为我们要增加的arr数组大小超出了JavaScript规范所允许的范围。
2. ReferenceError(引用错误)
当对变量或对象的引用失效时,会引发此错误,通常意味着该变量或对象不存在。
例如
const l=console.logconst cat = "cat"
cat
dog
定义一个变量cat并初始化为“cat”。随后分别引用cat变量和dog变量。此时cat变量存在,而dog变量未定义。
访问cat将返回“cat”,而访问dog将引发引用错误,因为在当前环境记录中找不到名为dog的标识符。
$ node errors
errors.js:3
dog
^ReferenceError: dog is not defined
每当创建或定义变量时,变量名会被写入环境记录(Environment Record)。环境记录类似于键值存储结构:
+-------------+
| Key | Value |
---------------
| cat | "cat" |
+-------------+
每次引用变量时,JavaScript引擎会查找程序中已定义的变量。如果在环境记录中找到对应的值,则提取并返回;否则,以变量名为关键字在环境记录中搜索。若调用尚未定义的函数,同样会触发此错误。
此外,当创建未赋值的变量时,变量名作为键写入环境记录,但其值保持为undefined状态。
var catenv record
+-----------------+
| Key | Value |
-------------------
| cat | undefined |
+-----------------+
稍后为该变量赋值时,引擎会在环境记录中搜索该变量,发现其值为undefined后,将执行赋值覆盖操作。
var cat
cat = "cat"env record
+-------------+
| Key | Value |
---------------
| cat | "cat" |
+-------------+
因此,当在环境记录中找不到变量名时,JavaScript引擎将抛出ReferenceError。
+-------------+
| Key | Value |
---------------
| cat | "cat" |
+-------------+cat // "cat", yes, :) it's there
dog // :( what's this? can't find it
注意:已声明但未赋值的变量(值为undefined)不会抛出ReferenceError,因为其键值对已存在于环境记录中。
3. SyntaxError(语法错误)
这是最常见的错误类型。当代码包含JavaScript引擎无法解析的语法时,就会发生此错误。
JavaScript引擎在代码解析阶段捕获该错误。在终端显示结果之前,代码需经历多个处理阶段:
- 标记化
- 解析
- 解释
标记化(Tokenization)将源代码分解为各个独立单元。在此阶段,数字、关键字、字面量、运算符等会被分类并标记。
随后,生成的标记流传递至解析阶段,由解析器处理。此阶段负责从标记流生成抽象语法树(AST),即代码结构的抽象表示。
在标记化和解析这两个阶段,如果代码语法不符合JavaScript规范,将导致阶段失败并抛出SyntaxError。例如:
const l = console.loglet cat h = "cat"
代码中的“h”代表什么?这个多余的“h”破坏了代码结构。
$ node errors
errors.js:3
let cat h = "cat"
^SyntaxError: Unexpected identifier
Node.js明确指出了问题所在:提示“h”是意外标识符,它破坏了cat变量的声明语法。
因此,可以说语法错误发生在代码的解析或编译期间。
4. TypeError(类型错误)
当其他原生错误对象无法准确指示失败原因时,TypeError用于表示操作因数据类型不匹配而失败。
对错误的数据类型执行操作时会发生TypeError,例如:
如果我们尝试对数字调用转换为大写的操作,如下所示:
const num = 123
num.toUpperCase()
这将引发TypeError
$ node errors
errors.js:4
num.toUpperCase()
^TypeError: num.toUpperCase is not a function
因为toUpperCase函数期望接收字符串数据类型。toUpperCase函数设计为通用方法,不严格要求this值为String对象,因此可绑定到其他对象类型作为方法使用。
只有字符串类型才会转换为大写或小写形式。如果在Object、Boolean、Symbol、null或undefined数据类型上调用toUpperCase函数,由于操作的数据类型错误,将得到TypeError。
5. URIError(URI错误)
这表明使用了与其定义不兼容的全局URI处理函数。
JavaScript中的URI(统一资源标识符)相关功能包括:decodeURI、decodeURIComponent等。
如果使用错误的参数调用其中任何一个函数,将获得URIError。
decodeURI("%")
^URIError: URI malformed
encodeURI用于获取URI的未编码版本。由于“%”不是合法的URI编码字符,因此引发了URIError。
当URI编码或解码过程出现异常时,会抛出URIError。
6. EvalError(Eval错误)
此错误类型用于标识与全局eval()函数使用相关的错误。
根据EcmaSpec 2018版规范:
当前规范未实际使用此异常。保留它是为了与规范的先前版本保持兼容。
7. InternalError(内部错误)
该错误在JavaScript引擎内部发生,通常出现在需要处理过多数据且栈空间增长超过关键限制时。
当JavaScript引擎被过多的递归调用或复杂的switch-case结构淹没时,就会发生此类问题。
switch(num) {
case 1:
...
break
case 2:
...
break
case 3:
...
break
case 4:
...
break
case 5:
...
break
case 6:
...
break
case 7:
...
break
... up to 1000 cases
}
以下是一个典型的多层递归示例:
function foo() {
foo()
}
foo()
总结
正如所言,错误是编程过程中的常态。为了有效应对,我们需要了解可能抛出的原生错误类型。本文列举了这些错误类型,并通过示例说明了它们的触发方式。
因此,无论何时在终端或浏览器中遇到错误,你都能轻松定位错误发生的位置和原因,从而编写出更优质、更少缺陷的代码。
以上就是7个你应该知道的JS原生错误类型的详细内容,更多关于JS原生错误类型的资料请关注本站其它相关文章!