javascript在使用中需要注意的几点
typeof
typeof运算符返回一个用于识别其运算数类型的字符串。所以:
typeof 98.6返回'number'。但遗憾的是:
typeof null返回'object',而不是null。
parseint
parseint是一个把字符串转换为整数的函数。它在遇到非数字时会停止解析,所以parseint("16")与parseint("16 tons")产生相同的结果。
如果该字符串第1个字符是0,那么该字符串会基于八进制而不是十进制来求值。在八进制中,8和9不是数字,所以parseint("08")和parseint("09")都产生0作为结果。这个错误会导致程序解析日期和时间出现问题。幸运的是,parseint可以接受一个基数作为参数,如此一来parseint("08" ,10)结果为8 。
浮点数
二进制的浮点数不能正确地处理十进制的小数,因此0.1 + 0.2不等于0.3 。这是javascript中最经常被报告的bug,并且它是遵循二进制浮点算术标准ieee 754而有意导致的结果。这个标准对很多应用都是适合的,但它违背了大多数你在中学所学过的关于数字的知识。幸运的是,浮点数中的整数运算是精确的,所以小数表现出来的错误可以通过指定精度来避免。
nan
nan是ieee 754中定义的一个特殊的数量值。它表示的不是一个数字 ,尽管下面的表达式返回的是true:
typeof nan === 'number' //true
该值可能会在试图把非数字形式的字符串转换为数字时产生。例如:
+ '0' //0 + 'oops' nan
如果nan是数学运算中的一个运算数,那么结果就是nan。所以,如果你有一个公式链产生出nan的结果,那肯定要么其中一个输入项是nan,要么在某个地方产生了nan。
你可以对nan进行检测。正如我们之前所见,typeof不能辨识数字和nan,而且nan也不等同于它自己。所以,下面的代码结果令人惊讶:
nan === nan //false nan !== nan //true
javascript提供了一个isnan函数,可以辨识数字与nan:
isnan(nan) //true isnan(0) //false isnan('oops') //true isnan('0') //false
判断一个值是否可用作数字的最佳方法是使用isfinite函数,因为它会筛除掉nan和infinity。遗憾的是,isfinite会试图把它的运算数转换为一个数字,所以,如果值事实上不是一个数字,它就不是一个好的测试。你可以这样定义自己的isnumber函数:
var isnumber = function isnumber(value) { return typeof value === 'number' && isfinite(value); }
伪数组
javascript没有真正的数组。这也不全是坏事。javascript的数组确实非常容易使用。你不必给它们设置维度,而且它们永远不会产生越界错误。但它们的性能比真正的数组可能相当糟糕。
typeof运算符不能辨别数组和对象。要判断一个值是否为数组,你还需要检查它的constructor属性:
if (my_value && typeof my_value === 'object' && my_value.constructor === array) { //my_value是一个数组 }
上面的检测对于在不同帧或窗口创建的数组将会给出false。当数组有可能在其他的帧中被创建时,下面的检测更为可靠:
if (object.prototype.tostring.apply(my_value) === '[object array]'){ //my_value确实是一个数组! }
arguments数组不是一个数组,它只是一个有着length成员属性的对象。上面的检测会分辨出arguments并不是一个数组。
javascript有两组相等运算符:===和!==,以及它们邪恶的孪生兄弟==和!=。===和!==这一组运算符会按照你期望的方式工作。如果两个运算数类型一致且拥有相同的值,那么===返回true,!==返回false。而它们邪恶的孪生兄弟只有在两个运算数类型一致时才会做出正确的判断,如果两个运算数是不同的类型,它们试图去强制转换值的类型。转换的规则复杂且难以记忆。
'' == '0' //false 0 == ''//true 0 == '0' //true false == 'false' //false false == '0' //true false == undefined //false false == null //false null == undefined //true ' \t\r\n ' == 0 //true
==运算符对传递性的缺乏值得我们警惕。始终用===和!==。如果以上所有的比较使用===运算符,结果都是false。
eval
eval函数传递一个字符串给javascript编译器,并且执行其结果。它是一个被滥用得最多的javascript特性。那些对javascript语言一知半解的人们最常用到它。例如,如果你知道点表示法,但不知道下标表示法,就可能会这么写:
eval("myvalue = myobject." + mykey + ";");
而不是这么写:
myvalue = myobject[mykey];
使用eval形式的代码更难以。这种形式使得性能显著降低,因为它需要运行编译器,但也许只是为了执行一个微不足道的赋值语句。
提供的settimeout和setinterval函数,它们能接受字符串参数或函数参数。当传递的是字符串参数时,settimeout和setinterval会像eval那样去处理。同样也应该避免使用字符串参数形式。