目录
JavaScript 异常机制
1. 基本语法:try...catch...finally
2. 抛出异常:throw
3. 错误对象属性
4. 同步代码的异常处理
5. 异步代码的异常处理
5.1 回调函数
5.2 Promise
5.3 全局未捕获的 Promise 错误
6. 全局错误处理
7. 自定义错误与错误处理策略
8. 注意事项
9. 总结
JavaScript 严格模式与非严格模式
一、严格模式的核心特性
1. 启用方式
二、严格模式 vs 非严格模式的关键差异
三、严格模式的优点
四、严格模式的应用场景
1. 避免全局污染
2. 安全的 this 绑定
3. 防止意外覆盖只读属性
五、非严格模式的典型问题
1. 隐式创建全局变量
2. 危险的 eval 作用域
六、总结
JavaScript 异常机制
JavaScript 的异常处理机制允许开发者捕获和处理运行时错误,确保程序在遇到意外情况时能够优雅地降级或恢复。
1. 基本语法:try...catch...finally
-
try
块:包裹可能抛出错误的代码。 -
catch
块:捕获并处理try
块中抛出的异常。 -
finally
块:无论是否发生异常,最终都会执行(常用于清理资源)。
try {// 可能出错的代码throw new Error("出错了!");
} catch (error) {// 处理错误console.error("捕获到错误:", error.message);
} finally {// 清理资源(如关闭文件、释放内存)console.log("无论如何都会执行");
}
2. 抛出异常:throw
-
使用
throw
语句手动抛出错误,可抛出任意类型(但推荐使用Error
对象或其子类)。 -
内置错误类型:
-
Error
:通用错误基类。 -
SyntaxError
:语法错误(如 JSON 解析失败)。 -
TypeError
:类型错误(如调用非函数)。 -
RangeError
:数值超出有效范围(如递归过深)。 -
ReferenceError
:引用未声明变量。 -
URIError
:URI 处理函数使用不当。 -
AggregateError
:多个错误的集合(如Promise.any
全部拒绝)。
-
// 抛出内置错误
throw new TypeError("变量类型错误");// 自定义错误
class NetworkError extends Error {constructor(message) {super(message);this.name = "NetworkError";}
}
throw new NetworkError("网络请求失败");
3. 错误对象属性
-
name
:错误类型(如"Error"
,"TypeError"
)。 -
message
:错误描述信息。 -
stack
(非标准但广泛支持):错误的调用栈跟踪。
try {throw new Error("测试错误");
} catch (error) {console.log(error.name); // "Error"console.log(error.message); // "测试错误"console.log(error.stack); // 堆栈跟踪信息
}
4. 同步代码的异常处理
-
同步错误:在
try
块中直接抛出,由catch
捕获。 -
示例:
function divide(a, b) {if (b === 0) throw new Error("除数不能为零");return a / b; }try {divide(10, 0); } catch (error) {console.error(error.message); // "除数不能为零" }
5. 异步代码的异常处理
5.1 回调函数
-
错误优先回调:Node.js 约定回调函数的第一个参数为错误对象。
const fs = require('fs'); fs.readFile('file.txt', (err, data) => {if (err) {console.error("读取文件失败:", err.message);return;}console.log(data); });
5.2 Promise
-
.catch()
:捕获 Promise 链中的错误。 -
async/await
:结合try...catch
处理异步错误。// Promise.catch() fetch('https://api.example.com/data').then(response => response.json()).catch(error => console.error("请求失败:", error));// async/await + try...catch async function fetchData() {try {const response = await fetch('https://api.example.com/data');const data = await response.json();return data;} catch (error) {console.error("请求失败:", error);} }
5.3 全局未捕获的 Promise 错误
-
浏览器:监听
unhandledrejection
事件。 -
Node.js:监听
unhandledRejection
事件。// 浏览器 window.addEventListener('unhandledrejection', event => {console.error("未处理的 Promise 错误:", event.reason); });// Node.js process.on('unhandledRejection', (reason, promise) => {console.error("未处理的 Promise 错误:", reason); });
6. 全局错误处理
-
浏览器:
window.onerror
或window.addEventListener('error')
。 -
Node.js:
process.on('uncaughtException')
。// 浏览器全局错误捕获 window.onerror = (message, source, lineno, colno, error) => {console.error("全局错误:", message, "发生在", source, "行号:", lineno); };// Node.js 全局错误捕获 process.on('uncaughtException', (error) => {console.error("未捕获的异常:", error);process.exit(1); // 通常建议终止进程 });
7. 自定义错误与错误处理策略
-
自定义错误类:继承
Error
以区分错误类型。 -
条件捕获:在
catch
块中根据错误类型处理。class ValidationError extends Error {constructor(field, message) {super(message);this.name = "ValidationError";this.field = field;} }try {throw new ValidationError("email", "邮箱格式无效"); } catch (error) {if (error instanceof ValidationError) {console.error(`字段 ${error.field} 验证失败: ${error.message}`);} else {console.error("其他错误:", error);} }
8. 注意事项
-
避免过度使用异常:异常适用于意外情况,而非控制流程。
-
资源清理:在
finally
或try...catch
外释放资源(如关闭数据库连接)。 -
错误日志:记录错误信息(如
console.error
、日志服务)。 -
错误传播:在无法处理错误时重新抛出(
throw error
)。 -
性能考量:频繁抛出异常可能影响性能,需谨慎使用。
9. 总结
机制 | 场景 | 工具/语法 | 注意事项 |
---|---|---|---|
同步错误处理 | 函数内直接抛出错误 | try...catch...finally | 处理意外情况,避免流程控制 |
异步错误处理 | Promise、回调函数、async/await | .catch() 、try...catch | 避免未处理的 Promise 拒绝 |
全局错误捕获 | 未被捕获的运行时错误 | window.onerror 、process.on | 记录日志并终止不稳定进程 |
自定义错误 | 区分业务错误类型 | 继承 Error 类 | 提供清晰的错误分类和信息 |
JavaScript 严格模式与非严格模式
JavaScript 的 严格模式(Strict Mode) 是 ES5 引入的一种受限的代码执行环境,旨在消除代码中的静默错误、提高安全性,并为未来版本铺路。
一、严格模式的核心特性
1. 启用方式
-
全局启用:在脚本或函数顶部添加
"use strict";
"use strict"; // 整个脚本进入严格模式
-
函数级启用:在函数体顶部添加
"use strict";
function strictFunc() {"use strict";// 该函数内部为严格模式 }
二、严格模式 vs 非严格模式的关键差异
特性 | 非严格模式 | 严格模式 | 示例与说明 |
---|---|---|---|
未声明变量赋值 | 自动创建全局变量 | 抛出 ReferenceError | x = 10; → 严格模式下报错,防止全局污染 |
删除不可删除的属性 | 静默失败 | 抛出 TypeError | delete Object.prototype; → 严格模式下报错 |
重复的函数参数 | 允许重复参数名 | 抛出 SyntaxError | function(a, a) {} → 严格模式下语法错误 |
八进制字面量 | 允许 0123 表示八进制 | 必须使用 0o123 | const num = 0123; → 严格模式下报错,改用 0o123 |
eval 和 arguments | 可被重新赋值 | 视为关键字,不可赋值 | eval = 10; → 严格模式下报错 |
with 语句 | 允许使用 | 抛出 SyntaxError | with(obj) { ... } → 严格模式下语法错误 |
this 默认绑定 | 全局对象(window ) | undefined | function f() { console.log(this); } f(); → 严格模式输出 undefined |
arguments.callee | 可用 | 抛出 TypeError | function f() { return arguments.callee; } → 严格模式下报错 |
对象字面量重复属性 | 允许重复属性名(后者覆盖前者) | 抛出 SyntaxError | const obj = { a: 1, a: 2 }; → 严格模式下语法错误 |
三、严格模式的优点
-
更早暴露错误:将静默错误转为显式抛出(如未声明变量)。
-
优化代码安全性:防止意外全局变量、限制危险操作(如
eval
)。 -
优化引擎性能:减少歧义代码,便于编译器优化。
-
未来兼容性:避免使用未来可能成为语法的保留字(如
interface
、let
)。
四、严格模式的应用场景
1. 避免全局污染
"use strict";
function init() {count = 10; // ReferenceError: count is not defined
}
init();
2. 安全的 this
绑定
"use strict";
function logThis() {console.log(this); // undefined(非严格模式为 window)
}
logThis();
3. 防止意外覆盖只读属性
"use strict";
const obj = {};
Object.defineProperty(obj, 'readOnly', { value: 42, writable: false });
obj.readOnly = 100; // TypeError: Cannot assign to read only property
五、非严格模式的典型问题
1. 隐式创建全局变量
function leak() {x = 10; // 非严格模式下自动成为 window.x
}
leak();
console.log(window.x); // 10
2. 危险的 eval
作用域
var x = 10;
function test() {eval('var x = 20;'); // 非严格模式下修改局部变量console.log(x); // 20(严格模式下输出 10)
}
test();
eval()
函数会将传入的字符串当做 JavaScript 代码进行执行。
六、总结
决策因素 | 非严格模式 | 严格模式 |
---|---|---|
代码安全性 | 低(隐式错误多) | 高(显式错误提示) |
兼容性 | 兼容旧代码 | 需注意 ES3 特性差异 |
开发体验 | 灵活但易出错 | 规范且易维护 |
未来兼容性 | 可能逐渐淘汰 | 符合现代标准 |
建议:所有新项目默认启用严格模式,旧项目逐步迁移。通过 "use strict";
提升代码质量,减少潜在 Bug。