《javascript高级程序设计》学习笔记 | 21.2.错误处理

关注[前端小讴],原创技术文章

错误处理

相关代码 →

try/catch 语句

  • ES3 新增了try/catch语句,基本语法与 Java 中的 try/catch 一样
try {// 可能出错的代码const a = 3;a = 4;
} catch (error) {// 出错时执行的代码console.log("An error happened!"); // An error happened!
}
  • try 块中有代码发生错误,代码会立即退出执行并跳到 catch 块中
  • 所有浏览器都支持错误对象的messagename属性
try {const a = 3;a = 4;
} catch (error) {console.log(error);/* TypeError: Assignment to constant variable.at Object.<anonymous> (c:\Users\43577\Desktop\工作\my_project\my_demos\javascript高级程序设计(第四版)\第21章 错误处理与调试\21.2.错误处理.js:13:5)at Module._compile (internal/modules/cjs/loader.js:1085:14)at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)at Module.load (internal/modules/cjs/loader.js:950:32)at Function.Module._load (internal/modules/cjs/loader.js:790:12)at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12)at internal/main/run_main_module.js:17:47*/console.log(error.name); // TypeError(类型错误)console.log(error.message); // Assignment to constant variable.(常量被赋值)
}

finally 子句

  • try/catch 中可选的 finally 子句始终运行,二者均无法阻止finally 块执行
    • try 中代码运行完,会执行 finally 的代码
    • 出错并执行 catch 中代码,仍会执行 finally 的代码
// finally 子句
try {console.log(1); // 1,执行
} catch (error) {console.log(2); // 不执行
} finally {console.log(3); // 3,执行
}try {const a = 3;a = 4;
} catch (error) {console.log(2); // 2,try出错执行catch
} finally {console.log(3); // 3,仍执行
}
  • 代码中包含 finally, try 或 catch 中的 return 会被忽略
console.log((function testFinally() {try {console.log("try"); // try,非return语句不受影响return 1;} catch (error) {return 2;} finally {console.log("finally"); // finallyreturn 3;}})()
); // 3,包含finally语句,try或catch中的return会被忽略

错误类型

  • Error,基类型
  • InternalError,底层引擎异常时,如递归过多导致的栈溢出
  • EvalError,使用 eval()异常时,但浏览器不会总抛出 EvalError
  • RangeError,数值越界时
  • ReferenceError,找不到对象时
  • SyntaxError,给 eval()传入的字符串包含语法错误时
  • TypeError,最常见
    • 变量不是预期类型时
    • 访问不存在的方法时
new Array(-1); // RangeError: Invalid array length
let obj = x; // ReferenceError: x is not defined
eval("1++2"); // SyntaxError: Invalid left-hand side expression in postfix operation
console.log("a" in "abc"); // TypeError: Cannot use 'in' operator to search for 'a' in abc
Function.prototype.toString().call("name"); // TypeError: Function.prototype.toString(...).call is not a function
  • 可以使用instanceof操作符在 catch 块中确定错误类型
try {const a = 3;a = 4;
} catch (error) {if (error instanceof TypeError) {console.log("TypeError!");}
} // TypeError!
try {new Array(-1);
} catch (error) {if (error instanceof RangeError) {console.log("RangeError!");}
} // RangeError!

try/catch 的用法

  • 浏览器认为 try/catch 中发生的错误已被处理,不会再报错
  • try/catch 最好使用在开发者无法控制有可能出现错误上(如不便修改代码的第三方 js 库,最好使用 try/catch 把函数调用包起来)

抛出错误

  • throw 操作符可在任何时候抛出自定义错误

    • throw 操作符必须有值,类型不限
    // throw 12345; // Uncaught 12345,后续代码停止
    // throw "Hello world"; // Uncaught Hello world,后续代码停止
    // throw true; // Uncaught true,后续代码停止
    // throw { name: "JS" }; // Uncaught {name: 'JS'},后续代码停止
    
    • 使用 throw 时代码立即停止,try/catch 语句中捕获了抛出的值时除外
    try {throw 123;
    } catch (error) {console.log(123);
    } // 123
    console.log(5); // 5,throw被try/catch捕获,后续代码照常
    
  • 可通过内置错误类型模拟浏览器错误

// throw new SyntaxError; //  Uncaught SyntaxError
// throw new InternalError; //  Uncaught InternalError
// throw new TypeError; //  Uncaught TypeError
// throw new RangeError; //  Uncaught RangeError
// throw new EvalError; //  Uncaught EvalError
// throw new URIError; //  Uncaught URIError
// throw new RefenceError; //  Uncaught RefenceError
  • 可通过继承 Error创建自定义错误类型,创建时需提供 name 和 message 属性
class CustomError extends Error {constructor(message) {super(message); // super调用父类构造函数,手动给父类传参,并将返回值赋给子类中的thisthis.name = "CustomError";this.message = message;}
}
// throw new CustomError("My message"); // CustomError: My message

何时抛出错误

  • 已知函数无法正确执行时,浏览器会自动抛出错误
  • 复杂的程序很难找到错误原因,适当创建自定义错误可有效提高代码的可维护性
  • 应仔细评估每个函数,尤其可能导致失败的情形
function process(values) {if (!(values instanceof Array)) {throw new Error("process(): Argument must be an Array.");}values.sort(); // 如果values不是数组,则浏览器会报错。因此在此句之前判断参数类型且用自定义错误,可有效提高代码可维护性for (let value of values) {if (value > 100) {return value;}}return -1;
}
// process(1); // Error: process(): Argument must be an Array.
// process(1); // TypeError: values.sort is not a function(如果没有throw代码段的结果)

抛出错误与 try/catch

  • 捕获错误的目的是阻止浏览器以其默认方式响应
  • 抛出错误的目的是提供有关其发生原因的说明
  • 应该在明确接下来做什么时捕获错误

error 事件

  • 没有被 try/catch 捕获的错误会在浏览器 window 对象上触发 error 事件
    • onerror 事件处理程序中,任何浏览器都不传入 event 对象
    • 传入 3 个参数:错误消息、发生错误的 URL、发生错误的行号
    • 任何错误发生都会触发 error 事件,并执行事件的处理程序,浏览器默认行为会生效
    • 可以返回 false 来阻止浏览器默认报告错误的行为
window.onerror = (message, url, line) => {console.log(message);return false; // 阻止浏览器默认报告错误
};
  • 图片中 src 属性的 url 没有返回可识别的图片格式,也会触发 error 事件
const image = new Image();
image.addEventListener("load", (event) => {console.log("Image loaded!");
});
image.addEventListener("error", (event) => {console.log("Image not loaded!");
});
image.src = "a.jpg"; // Image not loaded!

识别错误

类型转换错误

  • 主要原因是使用了会自动改变某个值的数据类型的草错付或语言构造

    • 比较过程中,应使用严格相等严格不等避免错误
    console.log(5 == "5"); // true
    console.log(5 === "5"); // false,数据类型不同
    console.log(1 == true); // true
    console.log(1 === true); // false,数据类型不同
    
    • 在 if、for、while 等流程控制语句中,应坚持使用布尔值作为条件避免错误
    function concat(str1, str2, str3) {let result = str1 + str2;if (str3) {result += str3;}return result;
    }
    console.log(concat("1", "2", "0")); // '120'
    console.log(concat("1", "2")); // '12',str3是undifined,转化为false
    console.log(concat("1", "2", 0)); // '12',str3是数值0,转化为false,与预期不符function concat(str1, str2, str3) {let result = str1 + str2;if (str3 !== undefined) {result += str3;}return result;
    }
    console.log(concat("1", "2", "03")); // '120'
    console.log(concat("1", "2")); // '12',str3 是 undifined,转化为 false
    console.log(concat("1", "2", 0)); // '120',达到预期
    

数据类型错误

  • JS 是松散类型,其变量函数参数不能保证数据类型

    • 原始类型的值,使用typeof检测
    function getQueryString(url) {const pos = url.indexOf("?"); // indexOf是字符串才有的方法if (pos > 1) {console.log(url.substring(pos + 1)); // substring是字符串才有的方法return;}console.log("not has ?");
    }
    // getQueryString(123); // TypeError: url.indexOf is not a functionfunction getQueryString2(url) {if (typeof url === "string") {// 确保不会因为参数是非字符串值而报错const pos = url.indexOf("?");if (pos > 1) {console.log(url.substring(pos + 1));return;}console.log("not has ?");}
    }
    getQueryString2(123); // 不打印
    getQueryString2("123"); // 'not has ?'
    getQueryString2("https://www.baidu.com?keyWord=error"); // 'keyWord=error'
    
    • 对象值,使用instanceof检测
    function reverseSort(values) {if (values) {// 不可取,values为true的情况很多values.sort();values.reverse();}
    }
    // reverseSort(1); // TypeError: values.sort is not a functionfunction reverseSort2(values) {if (values !== null) {// 不可取,values不为null的情况很多values.sort();values.reverse();}
    }
    // reverseSort2(1); // TypeError: values.sort is not a functionfunction reverseSort3(values) {if (typeof values.sort === "function") {// 不可取,假如values有sort()方法但不是数组则会报错values.sort();values.reverse();}
    }
    // reverseSort3({
    //   sort: () => {
    //     console.log("3");
    //   },
    // }); // 先values.sort()打印3,后报错TypeError: values.reverse is not a functionfunction reverseSort4(values) {if (values instanceof Array) {// 可取,确保values是Array的实例values.sort();values.reverse();}
    }
    let val1 = 1;
    let val2 = [1, 2];
    reverseSort4(val1);
    reverseSort4(val2);
    console.log(val1); // 1
    console.log(val2); // [2,1]
    

通信错误

  • 对于 url 的查询字符串,都要通过encodeURIComponent(),以确保编码合适
let url = "https://www.baidu.com?keyWord=https://www.taobao.com"; // url格式不正确
function addQueryStringArg(url, name, value) {if (url.indexOf("?") === -1) {url += "?";} else {url += "&";}url += `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;return url;
}
let url2 = addQueryStringArg("https://www.baidu.com","keyWord","https://www.taobao.com"
);
console.log(url2); // https://www.baidu.com?keyWord=https%3A%2F%2Fwww.taobao.com,与服务器通信的正确url格式

区分重大与非重大错误

  • 非重大错误
    • 不影响用户主要任务
    • 只影响页面中某个部分
    • 可恢复
    • 重复操作可能成功
  • 重大错误
    • 程序无法继续运行
    • 严重影响用户的主要目标
    • 会导致其他错误
  • 程序某个部分的错误,不应该影响其他部分
  • 模块初始化时,可在 for 循环中加入 try/catch 语句,避免某一模块初始化时发生错误影响其他模块
let mods = [{name: "mod1",init: () => {const a = 1;a = 2;console.log("mod1 init");}, // mod1的init方法里有错误},{name: "mod2",init: () => {console.log("mod2 init");},},
];
for (let mod of mods) {// mod.init(); // 不好,只要有一个mod的init方法出错,影响后续try {mod.init(); // 'mod2 init',mod2照常运行} catch (error) {console.log(error); // TypeError: Assignment to constant variable.}
}

总结 & 问点

  • 错误对象中的哪些属性在全部浏览器中都向用户显示?
  • finally 对 try 或 catch 中的非 return 语句和 return 语句分别有什么影响?
  • 请举例说明有哪些常见错误类型及其出现的原因
  • 请写一段代码,在 try/catch 块中,确定错误的类型
  • throw 操作符必须有值嘛?需要什么数据类型的值?如何才能既使用该操作符又不影响后续代码执行?
  • 写一段代码,通过继承 Error 创建一个自定义的错误类型,创建其实例并用 throw 将其抛出
  • 写一段代码,在一个函数里,通过创建自定义错误类型提高其可维护性
  • 常见的类型转换错误有哪些?分别该如何避免呢?
  • 应分别怎样检测,以避免原始值和对象值在函数传参时可能发生的数据类型错误?
  • 写一个方法,处理与服务器通信的 url 的正确格式
  • 写一段代码,用 for 循环模拟模块初始化,某一模块加载时发生错误但不影响后续模块

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/717001.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vsomeip源码剖析--00环境搭建

环境 Win11 WSL2 Ubuntu22.04安装依赖 sudo apt-get install cmake sudo apt-get install libboost-system1.71-dev libboost-thread1.71-dev libboost-log1.71-dev源码编译 获取源码 https://github.com/COVESA/vsomeip.git编译 cd vsomeip mkdir build cd build// 一般…

漫漫数学之旅035

文章目录 经典格言数学习题古今评注名人小传 - 黎勒•笛卡尔 经典格言 完美的数和完美的人是同样罕见的。——黎勒•笛卡尔&#xff08;Ren Descrates&#xff09; 完美的数和完美的人都是极为罕见的。这句话表达了一个哲学观点&#xff0c;即无论是在数学领域还是人类自身&am…

Spring框架相关问题

RabbitMQ相关问题 Spring框架相关问题 一、Spring容器中的Bean是线程安全的吗&#xff1f;二、如何保证Spring容器中的Bean是线程安全的呢&#xff1f;三、什么情况下会触发Spring事务回滚&#xff1f;四、如果事务方法抛出IOException&#xff0c;是否会触发Spring事务回滚&a…

Zookeeper学习2:原理、常用脚本、选举机制、监听器

文章目录 原理选举机制&#xff08;重点&#xff09;情况1&#xff1a;正常启动集群情况2&#xff1a;集群启动完&#xff0c;中途有机器挂了 监听器客户端向服务端写入数据客户端向服务端Leader节点写入客户端向服务端Follower节点写入 Paxos算法&#xff08;每个节点都可以提…

AMDGPU KFD Test 编译使用

ROCT-Thunk-Interface是一个用于在ROCm软件堆栈中提供设备无关性的层。它是ROCm的一部分,允许不同的硬件平台(如AMD GPU和Intel CPU)使用相同的API进行计算。 要安装ROCT-Thunk-Interface,首先需要创建一个新的目录,并进入该目录: mkdir rocm-build cd rocm-build然后,…

ng : 无法将ng项识别为 cmdlet、函数、脚本文件或可运行程序的名称

ng : 无法将“ng”项识别为 cmdlet、函数、脚本文件或可运行程序的名称”&#xff0c;出现这种错误&#xff0c;那说明你angular-cli没有下载所以环境变量里没有相应的东西 1、需要在cmd里输入npm install -g angular/cli 2、之后运行angular命令时还可能出现这种错误 “ng : …

ruoyi 图片等文件资源读取

老是忘&#xff0c;记录一下 ResourcesConfig 文件下 /** 本地文件上传路径 */ registry.addResourceHandler(Constants.RESOURCE_PREFIX "/**").addResourceLocations("file:" RuoYiConfig.getProfile() "/"); /*** 资源映射路径 前缀*/ …

kafka消费者重平衡是什么?怎么避免?

消费者重平衡是指主题下的分区怎么分配给消费者的过程。下面这个图可以看出该过程&#xff1a;原来有2个消费者&#xff0c;3个分区&#xff0c;其中一个消费者肯定就的处理2个分区了。那么当新加入消费者时&#xff0c;则每个消费者就只处理一个分区了。处理这个分区过程的叫协…

详解Nacos注册中心的使用

文章目录 1、安装2、服务注册2.1、引入依赖2.2、配置nacos地址2.3、重启 3、服务分级存储模型3.1、给user-service配置集群3.2、同集群优先的负载均衡 4、权重配置5、环境隔离5.1、创建namespace5.2、配置namespace 6、Nacos与Eureka的区别7、代码免费分享 ​&#x1f343;作者…

首例以“冠状病毒”为主题的勒索病毒,篡改系统MBR

前言概述 2020年勒索病毒攻击仍然是网络安全的最大威胁&#xff0c;在短短三个月的时间里&#xff0c;已经出现了多款新型的勒索病毒&#xff0c;关于2020年勒索病毒攻击新趋势&#xff0c;可以阅读笔者写的上一篇文章&#xff0c;里面有详细的分析&#xff0c;从目前观察到的…

Linux 学习笔记(9)

九、 运行级别 1 、 Linux 系统的运行级别 (runlevel) Linux 系统有 7 个运行级别&#xff0c; Linux 系统任何时候都运行在一个指定的运行级别上&#xff0c;不同的运行级 别所运行的程序和服务不尽相同&#xff0c;所要完成的工作和要达到的目的也不相同 运行级别…

RH850P1X芯片学习笔记-Generic Timer Module -ATOM

文章目录 ARU-connected Timer Output Module (ATOM)OverviewGLOBAL CHANNEL CONTROL BLOCK ATOM Channel architectureATOM Channel modesSOMP-Signal Output Mode PWMSOMP - ARUSOMC-Signal Output Mode CompareSOMC - ARUSOMC – COMPARE COMMANDSOMC – OUTPUT ACTIONATOM …

Python缩进规则

Python的缩进规则是Python语法中非常重要的一部分&#xff0c;也是Python语言独特的特点之一。在Python中&#xff0c;缩进被用来表示代码块的层次结构&#xff0c;而不是像其他语言一样使用大括号或关键词。这种缩进规则使得Python代码更加简洁、易读、易于理解&#xff0c;同…

python模块百科_操作系统接口_os【一】

python模块百科_操作系统接口_os【一】 os --- 多种操作系统接口一、相关模块1.1 os.path 文件路径1.2 fileinput 文件读取1.3 tempfile 临时文件和目录1.4 shutil 高级文件和目录1.5 platform 操作系统底层模块 二、关于函数适用性的说明2.1 与操作系统相同的接口2.2 支持字节…

Git版本管理常用指令

Git常用命令 一、基本指令二、本地仓库管理三、远程仓库管理四、分支管理五、储藏区六、标签管理一、基本指令 查看Git安装版本:git --version 查看log指令的帮助信息:git log --help 配置Git用户名:git config --global user.name “xxxxx” 配置Git邮箱: git config --…

2024年腾讯云新用户优惠券领取入口及使用教程

随着云计算技术的不断发展和普及&#xff0c;越来越多的个人和企业选择使用云服务。腾讯云作为国内领先的云服务提供商&#xff0c;为了吸引新用户&#xff0c;经常推出各种优惠活动&#xff0c;其中就包括新用户专属优惠券&#xff0c;本文将为大家分享腾讯云新用户优惠券的领…

5个好玩神奇还免费的工具网站收藏不后悔-搜嗖工具箱

生命倒计时 http://www.thismuchlonger.com 这是一个相哇塞的网站&#xff0c;可以让我们静下心来好好想想我们来这个世界究竟为了什么&#xff0c;因为当我们作为命运的主宰者。敲打键盘设定好自己一生长度的时候&#xff0c;我们的剩余寿命已经成绝对值&#xff0c;一旦生命…

创建型模式之原型模式

一、概述 1、工作原理&#xff1a;将一个原型对象传给要发动创建的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现创建过程 2、通过克隆方法所创建的对象是全新的对象&#xff0c;它们在内存中拥有新的地址&#xff0c;每一个克隆对象都是独立的 3…

MySQL 中的 varchar 和 char 有什么区别?MySQL中 in 和 exists 区别?

MySQL 中的 varchar 和 char 有什么区别&#xff1f; char 是一个定长字段,假如申请了char(10)的空间,那么无论实际存储多少内容.该字段都占用 10 个字符,而 varchar 是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度1,最后一个字符存储使用了多长的空间. 在检索…

李沐动手学习深度学习——3.6练习

本节直接实现了基于数学定义softmax运算的softmax函数。这可能会导致什么问题&#xff1f;提示&#xff1a;尝试计算exp(50)的大小。 可能存在超过计算机最大64位的存储&#xff0c;导致精度溢出&#xff0c;影响最终计算结果。 本节中的函数cross_entropy是根据交叉熵损失函数…