读javascript高级编程14-错误处理与调试

一  错误类型

ECMA规定了常见的7种错误类型:

  • Error: 基类型.其他常见的错误类型都继承自该类型,一般供开发人员抛出自定义错误.
  • EvalError:该类型会在eval()函数使用异常时被抛出.例如:new eval();.实际上在某些版本浏览器下会抛出TypeError,而且本身eval()函数在实际开发中就要谨慎使用,所以抛出EvalError的几率是很小的.
  • RangeError:在数值超出范围时触发.例如:new Array(-1)//RangeError: invalid array length.
  • ReferrerError: 通常在访问不存在的变量时会触发该错误.例如:console.log(a);//ReferenceError: a is not defined
  • SyntaxError:一般把语法错误的JavaScript字符串传给eval()函数时会触发该类型错误.eval("console.log(a)+")
  • TypeError:当执行特定操作时,如果变量类型不符合就会发生类型错误.常见的几种情形是:访问不存在的方法,函数传入参数类型不符合等.
  • URIError:在使用encodeURI()和decodeURI()方法,而URI的格式不正确时会发生该错误.

在跨浏览器编程时,预先检查错误类型是确定处理方式的途径之一,也就是先用try-catch语句捕捉到错误,然后在catch块中使用 instanceof操作符判断错误类型,最后根据不同的错误类型做出相应的处理.

try {
new 1;
}
catch (error) {
if (error instanceof EvalError) {
console.log(‘eval参数错误‘);
}
else if (error instanceof TypeError) {
console.log(‘类型错误‘);
} else {
console.log(error.message);
}
}

二 捕捉错误与抛出错误

1.try-catch语句捕捉错误

try-catch语句是常用的捕捉错误的方式。其中catch会接到一个包含错误信息的对象error,即使不使用该对象,也要给它取个名字,否则会发生语法错误。catch中对象error有个通用的属性message保存具体的错误信息。

try {
  window.a();
} catch (error) {
  alert(error.message);
}

finally子句:对于包含finally子句的情况,无论是执行try分支还是catch分支,最后肯定都会执行finally分支。即使中间有return语句也不能阻止finally子句的执行。

try {
  console.log(1);
} catch (error) {
  console.log(2);
} finally {
  console.log(3);
}

try-catch适合处理那些我们无法控制的错误。

2.抛出错误

throw操作符用来抛出错误,当遇到该操作符时代码会立即停止执行,仅当try-catch语句捕捉到被抛出的值时,代码才会继续执行.通过使用某种内置的错误类型时,可以更真实的模拟浏览器错误.例如:

throw new Error("test throw error");

比较常用的错误类型是Error,RangeError,ReferenceError,TypeError.

利用原型链可以通过继承Error来创建自定义错误类型.例如:

function MyError(message) {
this.name = ‘MyError‘;
this.message = message;
}
MyError.prototype = new Error();
throw new MyError(‘this is my test error;‘);

对于代码量大的程序,根据原生的报错信息往往很难直接定位错误.这时候带有适当信息的自定义错误就能够显神通了,显著提升了代码的可维护性.在开发过程中,尤其要关注的是函数以及容易导致函数执行失败的位置,比如对参数类型的检验等.例如:

function test(value) {
if (!(value instanceof Array)) {
throw new Error(‘test():参数不是数组‘);
}
return value.sort();
}

总之,抛出错误的目的是为了提供错误发生具体原因相关的详细信息;而捕捉错误的目的是避免浏览器以默认方式处理错误.

三 几种常见错误场景

JavaScript是松散类型的,而且在函数传参时不会检验参数类型,因此错误都是发生在代码运行期间的.常见的三种错误类型为:类型转换错误,数据类型错误和通信错误.

1.类型转换错误

类型转换错误常发生在使用某个操作符或者自动转换数据类型的场景.

第一种常见错误是使用相等和不等操作符

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"

2.数据类型错误

在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]

3.通信错误

场景一是在将数据发送给服务器之前,未使用encodeURIComponent()对数据进行编码.例如:

www.cnblogs.com?backurl=http

://www.cnblogs.com?a=1

解决方法是使用encodeURIComponent()对backurl后面的参数进行编码,结果为:

www.cnblogs.com?backurl= http%3A%2F%2Fwww.cnblogs.com%3Fa%3D1

场景二是对于查询字符串,也要对于查询参数的名和值都进行编码.

四  把错误记录到服务器

如果把前后端的错误信息集中进行汇总记录,能极大的方便对数据库错误日志的分析.要把JavaScrpt错误记录到服务器需要借助image控件进行,因为所有浏览器都支持image对象,而且可以避免跨域限制.

首先新建一个服务端页面用于处理错误数据.这个页面从查询字符串中获取错误数据,然后将数据写入到错误日志中,例如该页面为a.ashx.

然后在调用页面中,创建image对象,并且为其src属性赋值,这样就可以将错误信息发送到服务端页面了.

function logError(msg) {
var img = new Image();
img.src = ‘a.ashx?msg=‘ + encodeURIComponent(msg);
}
时间: 2024-10-19 05:24:40

读javascript高级编程14-错误处理与调试的相关文章

读javascript高级编程02-变量作用域

一. 延长作用域链 有些语句可以在作用域前端临时增加一个变量对象,该变量对象在代码执行完成后会被移除. ①with语句延长作用域. function buildUrl(){ var qs="?debug=true"; with(location){ var url=href+qs; } return url; } buildUrl(); //result:http://www.fanxbao.com/?debug=true ②try...catch...中的catch语句块延长作用域链

读javascript高级编程07-引用类型、Object、Array

一.引用类型 ECMAScript是支持面向对象的,可以通过引用类型描述一类对象所具有的属性和方法. 创建对象实例的方法时是用new 操作符加构造函数:var p=new Person(). 二.Object类型 1.创建Object实例两种方式: 使用new操作符跟Object构造函数. var o = new Object(); o.name = 'dami'; o.age = 25; 使用对象字面量表示法,推荐这种方式,代码量小而且看上去有封装的感觉. var o = { name: 'd

读javascript高级编程08-引用类型之Global、Math、String

一.Global 所有在全局作用域定义的属性和方法,都属于Global对象. 1.URI编码: encodeURI():主要用于对整个URI编码.它不会对本身属于URI的特殊字符进行编码. encodeComponentURI():主要用于对URI中的某一部分进行编码,很常用的是对查询字符串参数进行编码.它会对所有非标准字符进行编码. 对应的解码方法是decodeURI()和decodeURIComponent. var uri='http://www.cnblogs.com?a=1 2&b=陈

读javascript高级编程11-事件

一.事件流 事件流指从页面中接收事件的顺序. 1.事件冒泡(常用) IE中采用的事件流是事件冒泡,先从具体的接收元素,然后逐步向上传播到不具体的元素. 2.事件捕获(少用) Netscapte采用事件捕获,先由不具体的元素接收事件,最具体的节点最后才接收到事件. 3.DOM事件流 DOM2级事件包括三个阶段:事件捕获阶段.处于目标阶段和事件冒泡阶段. 二.事件处理程序 事件处理程序就是响应某些事件的函数,如onclick等. 1. DOM0级事件处理程序 每个元素都有自己的事件处理程序属性,如o

读javascript高级编程10-DOM

一.节点关系 元素的childNodes属性来表示其所有子节点,它是一个NodeList对象,会随着DOM结构的变化动态变化. hasChildNodes():是否有子节点. var headlines=document.getElementById("headline_block"); var childs=headlines.childNodes; childs.length;//1 childs[0];//取第一个子节点 childs.item(0);//取第一个子节点 pare

读javascript高级编程03-函数表达式、闭包、私有变量

一.函数声明和函数表达式 定义函数有两种方式:函数声明和函数表达式.它们之间一个重要的区别是函数提升. 1.函数声明会进行函数提升,所以函数调用在函数声明之前也不会报错: test(); function test(){ alert(1); } 2.函数表达式不会进行函数提升,函数调用在函数声明之前的话会报错: test(); // test is not a function var test=function(){ alert(1); } 二.递归函数 递归函数是通过在函数内部调用自身实现的

读javascript高级编程09-BOM

一.window 1.在全局作用域中定义的变量和函数会被归在window对象. var a=1,b=2; function add(a,b){ return a+b; } console.log(window.a);//1 console.log(window.add(a,b));//3 有点区别在于,全局变量不能用delete删除,而直接在window对象定义的属性可以用delete删除. 2.计算窗口位置: var leftpos=typeof window.screenLeft=="num

读javascript高级编程12-HTML5脚本编程

一.跨文档消息传递(XDM) 1.发送消息 postMessage(msg,domain)用于发送跨文档消息.第一个参数是要传递的消息内容,第二个参数表示接收方来自哪个域.第二个参数有助于提高安全性,如果发现域不匹配则不会进行操作. 2.接收消息 接收到消息时,会触发window对象的message事件.传递给onmessage事件处理程序的对象主要包含三个信息: data:对应postMessage()第一个参数传入的内容: origin:发送消息的文档所在域.接收到消息后,检测消息来源是非常

读javascript高级编程05-面向对象之创建对象

1.工厂模式 工厂模式是一种常用的创建对象的模式,可以使用以下函数封装创建对象的细节: function CreatePerson(name,age){ var p=new Object(); p.name=name; p.age=age; p.speak=function(){ console.log("my name is "+p.name); } return p; } var p1=CreatePerson('Wang',15); p1.speak(); var p2=Crea