《JAVASCRIPT高级程序设计》错误处理与调试

一、错误处理

  错误处理在程序设计中的重要性是毋庸置疑的,任何有影响力的web应用程序都需要一套完善的错误处理机制。良好的错误机制可以让用户得到提醒,知道发生了什么事。

1、try-catch语句

  try-catch语句是javascript处理异常的一种标准方式,它的结构如下:

    try{
// 把所有可能出现错误的代码放在try语句中

    }catch(err){
// 把用于处理错误的块放在catch语句中
// catch块会接受到一个保存错误信息的对象
// 该对象的message属性是唯一一个能够保证所有浏览器都支持的属性
        alert(err.message);

    }finally{
// finally子句无论如何都会执行

    }

2、错误类型

  javascript有7种错误类型,其中,Error是基类型,其他错误都继承自该类型。

  • Error
  • EvalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError
// eval()会计算字符串中的值,并执行其中的js代码
// 正确使用
eval("2+3");

// ECMA-262规定,如果没有把eval()当做函数调用,就会发生错误;但实践中,浏览器不一定会在应该抛出错误的时候就抛出EvalError
new eval();
eval = fool

// RangeError类型的错误会在数值超过相应范围时触发
var item1 = new Array(-20);
var item2 = new Array(Number.MAX_VALUE);

// 在找不到对象的情况下,会发生ReferenceError
var obj=x;

// 把语法错误的字符串给eval()时,会导致SyntaxError
eval("1++2");

// 在变量中保存意外的类型,或访问不存在的方法时,都会抛出TypeError错误
var o = new 10;
alert("name" in true);

3、抛出错误

  使用throw语句,可以抛出上述的错误,也可以抛出自定义的错误;在遇到throw操作符时,代码会立刻停止执行。

// 抛出常规错误
throw new SyntaxError("I don‘t like your syntax");
throw new TypeError("What type of variable do you take me for?");
throw new RangeError("Sorry, you just don‘t have the range");
throw new EvalError("That‘t doesn‘t evaluate.");
throw new URIError("Uri, is that you?");
throw new ReferenceError("You didn‘t cite your references properly.");

// 抛出自定义错误
function CustomError(message){
    this.name = "CustomError";
    this.message = message;
}

CustomError.prototype = new Error();
throw new CustomError("My message");

4、常见的错误类型

  一般来说,需要关注三种类型的错误:

  • 类型转换错误
  • 数据类型错误
  • 通信错误

a)类型转换错误

  为避免类型转换错误,建议使用全等操作符:

alert(5=="5");//true
alert(5==="5");//false

  流控制语句也很容易出错。像if之类的语句,在确定下一步操作之前,会自动把任何值转化成布尔值:

function concat(str1, str2, str3){
    var result = str1 + str2;
    if(str3){ //当str3是大于0的数字,不是string类型时,也会执行
        resutl += str3;
    }
    return result;

}

// 正确的写法
function concat(str1, str2, str3){
    var result = str1 + str2;
    if(typeof str3=="string"){
        resutl += str3;
    }
    return result;

}

b)数据类型错误

  在将变量传递个函数时,对变量进行类型进行检测,可以避免类型错误:

    // 不安全的函数,任何非字符串都会导致错误
    function getQueryString(url) {
        var pos = url.indexOf("?");
        if (pos > -1) {
            return url.substring(pos + 1);
        }
        return "";
    }

// 安全的函数
    function getQueryString(url) {
        if (typeof url == "string") {//通过检查类型确保安全
            var pos = url.indexOf("?");
            if (pos > -1) {
                return url.substring(pos + 1);
            }
            return "";
        }
    }

  在确切知道应该传入什么类型的情况下,应该使用instanceof Array来检测类型:

/ 不安全的函数,任何非数组类型都会导致错误
function reverseSort(values){
    if(values){
        values.sort();
        valuse.reverse();
    }
}

// 不安全的函数,任何非数组类型都会导致错误
function reverseSort(values){
    if(values != null){
        values.sort();
        valuse.reverse();
    }
}

// 不安全的函数,不能只针对某个特性进行检测
function reverseSort(values){
    if(typeof values.sort == "function"){
        values.sort();
        valuse.reverse();
    }
}

// 安全,非数组将被忽略
function reverseSort(values){
    if(values instanceof Array){
        values.sort();
        valuse.reverse();
    }
}

c)数据通信错误

  常见的数据通信错误是把数据发给服务器之前,没有使用encodeURIComponent()对数据进行编码,可以定义一个处理查询字符串的函数:

function addQueryStringArg(url, name ,value){
    if(url.indexOf("?") == -1){
        url += "?";
    }else{
        url += "&";
    }
    url += encodeURIComponent(name) + "=" +encodeURIComponent(value);
    return url;
}

var url = "http://www.baidu.com";
var newUrl = addQueryStringArg(url, "redir", "http://wwww.someotherdomain.com?a=b&b=c");
alert(newUrl);

5、非致命错误与致命错误:

非致命错误:不影响用户的主要任务/只影响页面的一部分/可以恢复/重复相同操作可以消除错误

  这类错误没有必要对用户给出提示---可以直接把页面中受影响的区域替换掉。

致命错误:应用程序根本无法运行/错误明显影响到了用户的主要操作/会导致其他连带错误

  这类错误应该立即给用户发送消息,告诉他们无法继续进行手头上的事情了。

二、调试技术

1、可以使用console对象向javascript控制台写入消息来调试

function sum(num1, num2){
    console.log("Enter sum(), arguements are " + num1 + ", " +num2 );

    console.log("Before calculation");
    var result = num1 + num2;
    console.log("After calculaation");

    console.log("Exiting sum()");
    return result;
}

2、将消息记录在当前页面

  在页面开辟一小块信息,用于显示错误信息

<html>
<head>
    <meta charset = "utf-8">
</head>
<body>
<script>
function log(message){
    var console = document.getElementById("debugInfo");
    if(console == null){
        console = document.createElement("div");
        console.id = "debugInfo";
        console.style.background = "#dedede";
        console.style.border = "1px solid silver";
        console.style.padding = "5px";
        console.style.width = "400px";
        console.style.position = "absolute";
        console.style.right = "0px";
        console.style.top = "0px";
        document.body.appendChild(console);
    }
    console.innerHTML += "<p>" + message + "</p>";
}
log("test……");
</script>
</body>
</html>

3、直接抛出错误

  如果错误消息很具体,基本可以把它当做错误来源的依据,那么可以直接抛出错误:

    function divide(num1, num2){
        if(typeof num1 != "number" || typeof num2 != "number"){
            throw new Error("devide (): both arguments must be number.");
        }
        return num1 / num2;
    }

  也可以自定义一个assert语句,抛出错误:

//assert接受两个参数,一个是求值结果应该为true的条件,一个是条件为false时需要抛出的错误
    function assert(condition , message){
        if(!condition){
            throw new Error(message);
        }
    }
    function divide(num1, num2){
        assert(typeof num1 == "number" && typeof num2 == "number", "devide (): both arguments must be number.");
        return num1 / num2;
}

三、常见的IE的错误

  IE是最难调试JAVASCRIPT错误的浏览器,以下介绍一些错误:

1、操作中止

  对于IE8之前的版本,在修改尚未加载完的页面时,会发生操作中止错误:

<!doctype html>
<html>
<head>
    <title>Operation Aborted Example</title>
</head>
<body>
<p> The following code should cause an Operation Aborted error in IE Versions prior to 8.</p>
<div>
    <script type="text/javascript">
        document.body.appendChild(document.createElement("div"));
    </script>
</div>
</body>
</html>

  解决办法可以是不适用appendChild(),而使用insertBefore():

<!doctype html>
<html>
<head>
    <title>Operation Aborted Example</title>
</head>
<body>
<p> The following code should cause an Operation Aborted error in IE Versions prior to 8.</p>
<div>
    <script type="text/javascript">
        document.body.insertBefore(document.createElement("div"),document.body.firstChild);
    </script>
</div>
</body>
</html>

  也可以把script元素移除来,直接作为<body>的子元素:

<!doctype html>
<html>
<head>
    <title>Operation Aborted Example</title>
</head>
<body>
<p> The following code should cause an Operation Aborted error in IE Versions prior to 8.</p>
<div>
</div>
   <script type="text/javascript">
        document.body.appendChild(document.createElement("div"));
    </script>
</body>
</html>

2、无效字符

  无效字符是Javascript中没有定义的字符,例如直接从word中赋值文本到编辑器里,然后又在IE中运行,则可能会遇到无效字符的错误。

3、未找到成员

  以下函数在单击事件后,window.event对象会被保存;当单击事件执行完毕后,event对象就会被销毁,因而setTimeout中使用的对象就不存在了;因此会出现未找到成员的错误:

    document.onclick = function(){
        var event = window.event;
        setTimeout(function(){
            event.returnValue =  false;  //未找到成员函数
        },1000);
    }

4、未知运行时错误

  当使用innerHTML或者outerHTML以下列方式操作时会发生错误:1)把块级元素插入到行内元素;2)访问表格的任意部分的任意属性

5、语法错误

6、系统无法找到指定资源

  当URL的长度超过IE对URL的最长不能超过2083个字符的限制时,就会发生这个错误:

function createLongUrl(url){
    var s = "?";
    for(var i = 0, len = 2500; i < len; i++ ){
        s += "a";
    }
    return url + s;
}
var x = new XMLHttpRequest();
x.open("get", createLongUrl("http://www.baidu.com/"), true);
x.send(null); 
时间: 2024-08-06 19:49:29

《JAVASCRIPT高级程序设计》错误处理与调试的相关文章

JavaScript高级程序设计学习笔记--错误处理与调试

try-catch语句 只要代码中包含finally子句,则无论try或catch语句块中包含什么代码--甚至return语句,都不会阻止finally子句的执行,来看下面这个函数: function testFinally(){ try{ return 2; }catch(error){ return 1; }finally{ return 0; } } 调用这个函数会返回0(PS:但我实际执行的时候会先返回0,再返回2) 抛出错误 与try-catch语句相配的还有一个throw操作符,用于

《javascript高级程序设计》 touch事件的一个小错误

最近一段时候都在拜读尼古拉斯大神的<javascript高级程序设计>,真的是一本好书,通俗易懂,条理比<javascript权威指南>好理解一些,当然<javascript权威指南>有权威指南的优点,不闲话了,入正题. 看技术书我通常都喜欢把书上的代码敲一遍,虽然很花时间,但只有动手敲的时候,脑中才有各种乱七八糟的想法蹦出来,为什么不能按照自己想的写,为什么书上的代码更好更优雅,还有没有别的办法去解决眼前的问题,想的多了,理解就很深,当然最重要的就是记得牢了.即使很浅

JavaScript高级程序设计学习笔记--基本概念

1.语句 ECMAScript中的语句以一个分号结尾:如果省略分号,则由解析器确定语句的结尾,如下例所示: var sum=a+b //即使没有分号也是有效的语句--推荐 var diff=a-b; //有效的语句--推荐 虽然语句结尾的分号不是必需的,但我们建议任何时候都不要省略它.两个原因:1.加上分号可以避免很多错误 2.加上分号也会在某些情况下增进代码的性能,因为这样解析器就不必再花时间 推测应该在哪里插入分号了. 2.变量 var message="hi"; 像这样初始化变量

《Javascript高级程序设计》阅读记录(四):第五章 下

这个系列,我会把阅读<Javascript高级程序设计>之后,感觉讲的比较深入,而且实际使用价值较大的内容记录下来,并且注释上我的一些想法.做这个一方面是提升了我的阅读效果以及方便我以后阅读 另一个目的是,Javascript高级程序设计这本书内容很多也很厚,希望其他没有时间的人可以通过看这系列摘录,就可以大体学到书里面的核心内容. 绿色背景的内容是我认为比较值得注意的原著内容. 黄色背景的内容是我认为非常重要的原著内容. 我的理解会用蓝色的字体标示出来. 这章的内容较多,而且比较重要,分两篇

《JavaScript 高级程序设计》

因为曾经在高中买来<C Primer Plus>和大学买来的<Clean Code>(挑战自己买的英文版的结果就啃了一点)给我一种经典的书都特别厚的一本就够读大半年的感觉.加上刚上大学图便宜买的有关做网站的旧书(应该是 Table 布局和 Dreamweaver 比较火的时代的书,这些书倒是很薄)让我一度认为做网页不就是 table 然后 tr.td 什么的套呗,高大上点不就是 div+CSS 嘛有什么大不了,给我设计好什么网页不都 ok 能做出来么?这种感觉.然后看网络课程,在网

JavaScript高级程序设计(第3版) 中文pdf扫描版 89M 高清下载

<JavaScript高级程序设计(第3版)>是JavaScript超级畅销书的最新版.ECMAScript5和HTML5在标准之争中双双胜出,使大量专有实现和客户端扩展正式进入规范,同时也为JavaScript增添了很多适应未来发展的新特性. <JavaScript高级程序设计>这一版除增加5章全新内容外,其他章节也有较大幅度的增补和修订,新内容篇幅约占三分之一. 全书从JavaScript语言实现的各个组成部分——语言核心.DOM.BOM.事件模型讲起,深入浅出地探讨了面向对象

《Javascript高级程序设计》阅读记录(二):第四章

这个系列之前文字地址:http://www.cnblogs.com/qixinbo/p/6984374.html 这个系列,我会把阅读<Javascript高级程序设计>之后,感觉讲的比较深入,而且实际使用价值较大的内容记录下来,并且注释上我的一些想法.做这个一方面是提升了我的阅读效果以及方便我以后阅读 另一个目的是,Javascript高级程序设计这本书内容很多也很厚,希望其他没有时间的人可以通过看这系列摘录,就可以大体学到书里面的核心内容. 绿色背景的内容是我认为比较值得注意的原著内容.

JavaScript高级程序设计(第三版)学习笔记20、21、23章

第20章,JSON JSON(JavaScript Object Notation,JavaScript对象表示法),是JavaScript的一个严格的子集. JSON可表示一下三种类型值: 简单值:字符串,数值,布尔值,null,不支持js特殊值:undefined 对象:一组无序的键值对 数组:一组有序的值的列表 不支持变量,函数或对象实例 注:JSON的字符串必须使用双引号,这是与JavaScript字符串最大的区别 对象 { "name":"Nicholas"

JavaScript高级程序设计31.pdf

其它方面的变化 DOM的其他部分在"DOM2级核心"中也发生了一些变化,这些变化与XML命名空间无关,而是确保API的可靠性及完整性 DocumentType类型的变化 DocumentType类型新增了3个属性:publicId.systemId和internalSubset 其中前两个属性表示的是文档类型声明中的两个信息段,这两个信息段在DOM1级中没有办法访问到 alert(document.doctype.publicId); //文档类型声明PUBLIC后的字符串 alert

JavaScript高级程序设计29.pdf

insertAdjacentHTML方法 插入标记最后一个新增的方式是insertAdjacentHTML()方法,它接收两个参数:插入位置和要插入的HTML文本,第一个参数必须是下列值之一: "beforebegin",在当前元素之前插入一个相邻的同辈元素: "afterbegin",在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素: "beforeend",在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子