共计 7584 个字符,预计需要花费 19 分钟才能阅读完成。
关注前端小讴,浏览更多原创技术文章
错误处理
相干代码 →
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 块中
- 所有浏览器都反对谬误对象的 message 和name属性
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"); // finally
return 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 调用父类构造函数,手动给父类传参,并将返回值赋给子类中的 this
this.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 function function 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 function function reverseSort2(values) {if (values !== null) { // 不可取,values 不为 null 的状况很多 values.sort(); values.reverse();} } // reverseSort2(1); // TypeError: values.sort is not a function function 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 function function 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 循环模仿模块初始化,某一模块加载时产生谬误但不影响后续模块
正文完
发表至: javascript
2024-02-28