系列
JavaScript教程
常见错误、调试和错误处理
在写代码的时候,不可避免地会遇到一些错误,不论初学者还是经验丰富的专家皆如此。尤其是代码行数增长到几百行以后,代码出错的几率就显著增加了,发现这些错误或缺陷的难度也会响应地增加。
本文讨论了一些JavaScript代码中常见的一些错误,了解了这些错误之后,就可以在编码的时候特别留意它们,减少此类错误发生的次数;另外,也介绍了一下调试代码的工具,学习如何使用这些工具单步调试代码,在代码运行时查看变量的内容,从而找出难以发现的错误。
使用未经定义的变量
JavaScript对定义变量的要求非常宽松,因此即使没有使用var
、let
或const
等关键字,也可以隐式地创建一个新的全局变量。比如:
a = 10;
console.log(a);
上面代码运行结果不错,但这样来写就不行
a += 10;
console.log(a);
错误发生后,错误信息“ReferenceError: a is not defined” 明确地指出了“a”没有被定义,因此改正起来就比较容易。
如果严格遵守用变量声明关键字来定义变量,尤其是要尽量使用let
或const来
显式地定义变量,那么在写代码的时候,就很容易避免这类错误。
不区分大小写
JavaScript代码和很多其他编程语言一样,都是对大小写敏感的,因此,编码的时候要特别留意不要弄错大小写。
请找出下面代码中的错误:
let myName = "Tom";
If (myName === "tom") {
console.log(myName.toUppercase());
}
代码运行出错,对吧?
第一个错:Unexpected token: punc ({),这个错误信息很让人迷糊,不同的JavaScript引擎,报的错可能还不一样。我们知道是第三行代码有错,但是错误信息中完全看不出来。其实,关键的一点是“token”,通常来说,这是因为一些关键词不能被识别,我们仔细看一下,原来是if
关键词的第一个字母被大写了,代码编辑器也不能高亮语法了。改正错误,继续运行:
let myName = "Tom";
if (myName === "tom") {
console.log(myName.toUppercase());
}
第二个错,代码没错,却没有任何输出。这里不是一个语法错误,而是一个逻辑错误,Tom不等于tom,因此判断条件不成立,因此代码不会按照期望的方式区执行。错误原因发现了,改正错误,继续运行:
let myName = "Tom";
if (myName === "Tom") {
console.log(myName.toUppercase());
}
第三个错出现了:TypeError: myName.toUppercase is not a function。错误里面说,“is not a function",不是个函数,那是属性吗?写个测试代码看看:
let myName = "Tom";
console.log(myName.toUppercase);
输出是undefined,那就是说myName不存在这个属性或方法,查查文档,才发现,原来把toUpperCase()写成了toUppercase()了。修正完错误,代码就可以正常运行了:
let myName = "Tom";
if (myName === "Tom") {
console.log(myName.toUpperCase());
}
从上面代码可以看出,大小写不注意的话,即使几行代码,就出现了好几个不同类型的错误,的确挺恼人的,这也说明我们写代码的的时候的确需要非常留意大小写的问题。
不匹配的括号
随便开发工具更加强大和智能化,通常在写代码的时候,IDE就会自动补全括号。但是,有些情况下,还是容易出现漏了大括号}
或园括号)
而没有发觉的情况。
通常情况下,代码排版太乱的时候,很容易出现这样的问题:
const areEqual = (x, y) => {
if(x<=y)
{if(x===y)
{
return true;
}
return false;
}
const result = areEqual(1,2);
console.log(result);
代码报错:Unexpected token: eof (undefined),到底是什么原因呢?看起来好难找啊!
这时候不管难不难找,把这样的有问题的代码发给别人帮忙找问题,通常别人是一阵烦的——连基本的代码排版都做不好,还写什么代码啊!
怎么办,先把代码排版好,再看看把:
const areEqual = (x, y) => {
if (x <= y) {
if (x === y) {
return true;
}
return false;
}
const result = areEqual(1, 2);
console.log(result);
啊,原来是第8行少了个大括号}
,很容易,你来改一下上面的代码?
把赋值和相等弄混
不光在JavaScript中,包括很多其他的编程语言,初学者都容易把赋值操作和相等比较操作弄混。
let a = 1;
if (a = 2) {
console.log("a是2");
} else {
console.log("a不是2");
}
初看,程序的打印结果应该是“a不是2”,但实际结果却是“a是2”。问题原因,就出在把赋值运算符误用做相等比较运算符了,赋值操作的逻辑判断总是true
。
上面例子比较简单,容易找到原因,但是由于这种错误不是语法错误而是逻辑错误,在较长的代码中,这个错误就没那么容易发现了。所以,当程序的逻辑出现错误,应该检查一下这种错误,或者通过单步调试代码,才能找到原因。
分不清方法和属性
在JavaScript中,对象的方法,本质上也是对象的一个属性,只不过是一个函数类型的属性。因此,常见到这种代码:
// 假定我们在代码某个地方有这样一个对象,但我们或不容易找到这个代码
const dog = {
name: "Teddy",
printName: function() {
console.log(this.name);
}
};
if (dog.printName) { // 简单判断属性存在且不空
dog.printName(); // 调用对象的方法
}
第9行是用来简单判断printName
方法是否存在,所以只判断属性,这时候就不应该在属性名后加()
。如果加了圆括号的话,就变成方法调用了。
一般规则是:在执行函数时,应该在函数名的后面加上圆括号;把一个函数传递给另一个函数或属性时,不应该使用圆括号。