一起来啃《JavaScript语言精粹》---毒瘤(Awful Parts)与糟粕(Bad Parts)

一、毒瘤(Awful Parts)

在毒瘤部分我会展示JavaScript的一些难以避免的问题特性。我们必须知道这些问题并准备好应对的措施。

(一)全局变量(Global Variables)

在JavaScript所有的糟糕特性之中,最为糟糕的一个就是它对全局变量的依赖。如果某些全局变量的名称碰巧和子程序中的变量名相同,那么它们将会相互冲突,可能导致程序无法运行,而且通常难以调试。
  共有3种方式定义全局变量:

  • 1、在任何函数之外放置一个var语句:
    var foo = value;
  • 2、直接给全局对象添加一个属性。全局对象是所有全局变量的容器。在Web浏览器里,全局对象名为window:
    window.foo = value;
  • 3、直接使用未经声明的变量,这被称为隐式的全局变量,这种方式本来是为了方便,有意让变量在使用前无需声明。遗憾的是,不声明变量成为了一个非常普遍的错误,使其成为了全局变量:
    foo = value;

(二)作用域(Scope)

在所有类似C语言风格的语言里,一个代码块会创造一个作用域。代码块中声明的变量在其外部是不可见的。JavaScript采用了这样的块语法,却没有提供块级作用域,只有函数作用域:代码块中声明的变量在包含此代码块的函数的任何位置都是可见的。


Paste_Image.png

 在大多数语言中,一般来说,声明变量的最好地方是在第一次用到它的地方。但这种做法在JavaScript里反而是一个坏习惯,因为它没有块级作用域。更好的方式是在每个函数的开头部分声明所有变量。

(三)自动插入分号(Semicolon Insertion)

JavaScript有一个自动修复机制,它试图通过自动插入分号来修正有缺损的程序。但是这很有可能会掩盖更严重的错误。有时它会不合时宜地插入分号。比如在return语句中自动插入分号导致的后果。如果一个return语句返回一个值,这个值表达式的开始部分必须和return位于同一行:
return
{status: true};
  这看起来是要返回一个包含status成员元素的对象。遗憾的是,自动插入分号让它变成了返回undefined。我们应该这样避免,把{放在上一行的尾部:
return {status: true};

(四)typeof

typeof运算符返回一个用于识别其运算数类型的字符串。所以:


Paste_Image.png

遗憾的是:


Paste_Image.png

返回的是‘object’,而不是‘null’。这简直太糟糕了。其实,有更简单也更好的检测null的方式:
Paste_Image.png

一个更大的问题是检测对象的值。typeof不能辨别出null与对象:


Paste_Image.png

但我们可以像下面这样做,因为null值为假,而所有对象值为真:
if(xxx && typeof xxx === 'object') {
//xxx是一个对象或数组!
}
Paste_Image.png

(五)+

+运算符可以用于加法运算或字符串连接。如果其中一个运算数是一个空字符串,它会把另一个运算数转换成字符串并返回。如果两个运算数都是数字,它返回两者之和。否则,它把两个运算数都转换为字符串并连接起来。这个复杂的行为是bug的常见来源。因此,<b>如果你打算用+去做加法运算,请确保两个运算数都是整数。</b>


Paste_Image.png

(六)浮点数

二进制的浮点数不能正确地处理十进制的小数,因此0.1+0.2不能与0.3。


Paste_Image.png

这是JavaScript中最经常被报告的bug,并且它是遵循二进制浮点数算术标准而有意导致的结果。幸运的是,浮点数中的整数运算是精确的,所以小数表现出来的错误可以通过指定精度来避免。

(七)NaN

Not a Number,它表示的不是一个数字,尽管下面的表达式返回的是true:


Paste_Image.png

该值可能会在试图把非数字形式的字符串转换为数字时产生。例如:


Paste_Image.png

值得注意的是,NaN本身也不等于本身:
Paste_Image.png

JavaScript提供了一个isNaN函数,可以辨别数字与NaN:


Paste_Image.png

判断一个值是否可用做数字的最佳方法是使用isFinite函数,因为它会筛除掉NaN和Infinity。遗憾的是,isFinite会试图把它的运算数转换为一个数字,所以,如果值事实上不是一个数字,它就不是一个好的测试。我们可以这样定义自己的isNumber函数:
var isNumber = function isNumber(value) {
return typeof value === 'number' && isFinite(value);
}

二、糟粕

在糟粕部分,我会展示JavaScript一些有问题的特性,但我们很容易就能避免它们。

(一)==

JavaScript有两组相等运算符:===和!==,以及它们邪恶的孪生兄弟==和!=。===和!==这一组运算符会按照你期望的方式工作。如果两个运算数类型一致且拥有相同的值,那么===返回true,!==返回false。而==和!=只有在两个运算数类型一致时才会做出正确的判断,如果两个运算数是不同类型,它们试图去强制转换值得类型。


Paste_Image.png

因此,建议永远不要使用那对邪恶的孪生兄弟。请始终使用===和!==。如果以上所有的比较使用===运算符,结果都是false。

(二)continue语句

continue语句跳到循环的顶部。一段代码通过重构移除continue语句之后,性能会得到改善。

(三)位运算符

JavaScript有着与Java相同的一套位运算符&,|,~,>>,>>>,<<。
在大多数语言中,这些位运算符接近于硬件处理,所以非常快。但是JavaScript的执行环境一般接触不到硬件,所以非常慢。而且代码的可读性和可维护性很差,建议不要使用。

(四)函数声明VS函数表达式

JavaScript既有函数声明,同时也有函数表达式。一个函数声明就是其值为一个函数的var语句的速记形式。
下面的语句:
function foo() {}
意思相当于:
var foo = function foo() {};
我们最好用函数表达式,因为它能明确表示foo是一个包含一个函数值的变量。要用好这门语言,理解函数就是数值很重要。
函数声明在解析时会发生被提升的情况。这意味着不管function被放置在哪里,它会被移动到被定义时所在作用域的顶层。这放宽了函数必须先声明后使用的要求,这通常会导致混乱。在if语句中使用function语句也是被禁止的,因为各个浏览器在解析时的处理各不相同。

(五)类型的包装对象

JavaScript有一套类型的包装对象。例如:


Paste_Image.png

这样返回一个对象,该对象有一个valueOf方法会返回被包装的值。这其实完全没有必要,并且有时还令人困惑。不要使用 new Boolean,new Number,new String。
此外也请避免使用new Object以及new Array。可使用 {} 和 [] 来代替。

(六)void

在很多语言中,void是一种类型,表示没有值。而在JavaScript里,void是一个运算符,它接受一个运算数并返回undefined。这没有什么用,而且令人非常困惑。应避免使用它。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容