try-catch
语句 该语句最适合处理那些我们无法控制的错误,在明明白白地知道自己的代码会发生错误时,再使用该语句就不太合适了。
ECMA-262第3版引入了try-catch语句,基本的语法如下所示:
try { // statements } catch(e) { // statements console.log(e); }
即使不使用这个错误对象,也要起个名字,对象中包含的实际信息因浏览器而异,但共同的是一个保存错误消息的
message
属性,ECMA-262还规定了一个保存错误类型的
name
属性
所有浏览器都支持这个属性(Opera 9之前的版本除外)。
try { document.getElementByIfd("fdsa"); } catch(e) { // statements console.log(e.message); //document.getElementByIfd is not a function console.log(e.name); //TypeError }
又如:
try { var x = 1; var y = 0; console.log(z); } catch(e) { // statements console.log(e.message); //z is not defined console.log(e.name); //ReferenceError }
finally
子句 虽然在try-catch块中是可选的,但finally子句一经用,无论如何都会执行,甚至return语句都不会阻止,例如:
function test() { try { return 1; } catch (error) { return 2; } finally { return 3; } }
上述代码返回3,当try中代码正常执行,finally会执行;当try中代码出现错误,catch代码会执行,finally代码也会执行。
每种错误都有对应的错误类型,而当错误发生时,就会抛出相应类型的错误对象,ECMA-262定义了7种错误类型:
* `Error`: 基类型。 * `EvalError`: 使用eval()函数发生异常时抛出。 * `RangeError`: 数值超出相应范围时抛出。 * `ReferenceError`: 找不到对象时抛出。 * `SyntaxError`: 使用eval()函数中的字符串有语法错误时抛出。 * `TypeError`: 在变量中保存意外类型或访问不存在的方法时抛出。 * `URIError`: 使用encodeURI或decodeURI()中URI格式不正确时抛出。
与try-catch相配的还有一个
throw
操作符,用于抛出自定义错误。
抛出错误时,必须给throw操作符指定一个值,这个值的类型没有要求,例如:
throw 123; throw "Hello World!";
在遇到throw操作符时,代码会立即停止执行。
通过使用某种内置错误类型,可以更真实
如:
try { throw new Error("nooo"); } catch (e) { console.log(e.message); //nooo console.log(e.name); //Error }
或:
throw new SyntaxError("wwwwtttttfffff");
也可以创建自定义错误类型:
function CustomError (message) { this.name = "CustomError"; this.message = message; } CustomError.prototype = new Error(); var somebug = new CustomError("wtf"); try { throw somebug } catch(e) { console.log(e.name); //CustomError console.log(e.message); //wtf }
捕获错误的目的在于避免浏览器以默认方式处理它们;而抛出错误的目的在于提供错误发生具体原因的消息。
没有通过try-catch处理的错误都会触发window对象的
error
事件。任何浏览器中,onerror事件处理程序都不会创建event对象,但它可以接受3个参数:错误消息、错误所在的URL和行号。
只要发生错误,无论是不是浏览器生成的,都会触发error事件,并执行这个事件处理程序,如果在事件处理程序中返回false,可以阻止浏览器报告错误的默认行为,例如:
throw new Error("hello there"); window.onerror = function() { console.log(message); //Uncaught Error: hello there return false; }
图像也支持error事件,只要图像的src属性中的URL不能返回可以被识别的图像格式,就会触发error事件。
var x = new Image(); x.onerror = function () { console.log("message"); //message }; x.src = "fds.png";
常见的三种错误类型为:
类型转换错误
数据类型错误
通信错误
类型转换错误常发生在使用某个操作符或者自动转换数据类型的场景
第一种常见错误是使用相等和不等操作符
console.log(1 == "1"); //true console.log(1 == true); //true
改进: 推荐使用全等( === ) 和非全等( !== ) 操作符, 来避免发生因为使用相等和不等操作符时引发的类型转换错误;
console.log(1 === "1"); //false console.log(1 === true); //false
第二种常见错误是在流控制语句中使用非布尔值.
function concat(str1, str2) { if (str2) { return str1 + str2; } else { return str1; } } concat('a', 0); //a" concat('a', 1); //"a1"
该方法的目的是当第二个参数存在的时候返回两个字符串拼接结果;
当第二个参数不存在的时候直接返回第一个参数.可是除了undefined会转换为布尔值false外, 0 也会转换为false, 而1则转换为true.因此调用结果与本意不太一致.
改进:
function concat(str1, str2) { if (typeof str2 == "string") { return str1 + str2; } else { return str1; } } concat('a', 0); //a" concat('a', 1); //"a"
在JavaScript中, 使用变量和函数参数之前是不会自动进行类型检验的.因此需要开发人员自己编写数据类型检测的代码.例如:
function reverseSort(values) { if (values) { //这里的判断不能保证是数组类型 values.sort(); values.reverse(); } console.log(values); } reverseSort("a"); //TypeError
这里如果传入的参数不是数组类型, 就会发生数据类型错误.一般来说, 对于基本类型使用typeof进行类型检验, 对于对象类型使用instanceof进行类型检验.
function reverseSort(values) { if (values instanceof Array) { values.sort(); values.reverse(); } console.log(values); } reverseSort("a"); //a" reverseSort([6, 2, 3, 8, 1, 5]); //[8, 6, 5, 3, 2, 1]
场景一是在将数据发送给服务器之前, 未使用encodeURIComponent() 对数据进行编码.例如:
www.cnblogs.com ? backurl = http : //www.cnblogs.com?a=1
解决方法是使用encodeURIComponent() 对backurl后面的参数进行编码, 结果为:
www.cnblogs.com ? backurl = http % 3 A % 2 F % 2 Fwww.cnblogs.com % 3 Fa % 3 D1
场景二是对于查询字符串, 也要对于查询参数的名和值都进行编码.
如果把前后端的错误信息集中进行汇总记录, 能极大的方便对数据库错误日志的分析.要把JavaScrpt错误记录到服务器需要借助image控件进行, 因为所有浏览器都支持image对象, 而且可以避免跨域限制.
首先新建一个服务端页面用于处理错误数据.这个页面从查询字符串中获取错误数据, 然后将数据写入到错误日志中, 例如该页面为a.ashx.
然后在调用页面中, 创建image对象, 并且为其src属性赋值, 这样就可以将错误信息发送到服务端页面了.
function logError(msg) { var img = new Image(); img.src = 'a.ashx?msg=' + encodeURIComponent(msg); }