【读书笔记】读《编写可维护的JavaScript》 - 编程风格(第一部分)
之前大致翻了一遍这本书,整体感觉很不错,还是不可追求快速,需要细细理解。
这篇随笔主要对本书的第一部分中对自己触动比较大的部分及与平常组织代码最为息息相关的部分做一个记录,加深印象。
主要讲述五点内容——
一、空行
二、null
三、undefined
四、变量声明
五、函数声明
一、空行
/* * 通常来讲,代码看起来应当像一系列可读的段落,而不是一大段揉在一起的连续文本。 * 有时一段代码的语意和另一段代码不相关,这时就应该使用空行将它们分隔,确保语义有关联的代码展现在一起。 */ var len = 2, array = [], flag, i; if (flag) { for (i = 0; i < len; i++) { array[i] = i; if (i % 2 === 0) { console.log(i + 'is an even number.'); } else { console.log(i + 'is an odd number.'); } } } /* * 这段示例代码中所展示的编程规范是在每个流程控制语句之前(比如if和for语句)添加空行。 * 这样做能使你更流畅的阅读这些语句。一般来讲,在下面这些场景中添加空行也是不错的主意。 * 1.在方法之间。 * 2.在方法中的局部变量(local varialbe)和第一条语句之间。 * 3.在多行或单行注释之前。 * 4.在方法内的逻辑片段之间插入空行,提高可读性。 */ // 给这段代码添加几个空行之后 var len = 2, array = [], flag, i; if (flag) { for (i = 0; i < len; i++) { array[i] = i; if (i % 2 === 0) { console.log(i + 'is an even number.'); } } }
总结:利用好空行,能够清晰的去读我们的代码,有助于我们快速去理解代码思路,非常好的代码组织实践。推荐博友们好好用之。
二、null
/* * null是一个特殊值,但我们常常误解它,将它和undefined搞混。 * 在下列场景中应当使用null。 * 1.用来初始化一个变量,这个变量可能赋值为一个对象。 * 2.用来和一个已经初始化的变量比较,这个变量可以是也可以不是一个对象。 * 3.当函数的参数期望是对象时,用作参数传入。 * 4.当函数的返回值是对象时,用作返回值传出。 * 还有下面一些场景中不应当使用null。 * 1.不要使用null来检测是否传入了某个参数。 * 2.不要使用null来检测一个未初始化的变量。 */ // 好的用法 var person = null; // 好的用法 function getPerson() { if (condition) { return new Person('king'); } else { // 当函数的返回值是对象时,用作返回值传出 return null; } } // 不好的写法:用来和未初始化的变量比较 var person; if (person != null) { doSomething(); } // 不好的写法:检测是否传入了参数 function doSomething(arg1, arg2, arg3, arg4) { if (arg4 != null) { doSomethingElse(); } }
总结:如本书所说,“理解null最好的方式是将它当做对象的占位符(placeholder)”,这样我们就可以清晰的与undefined做一个对比。
三、undefined
/* * undefined是一个特殊值,我们常常将它和null搞混。其中一个让人颇感困惑之处在于null == undefined结果是true。 * 然而,这两个值得用途却各不相同。那些没有被初始化的变量都有一个初始值,即undefined,表示这个变量等待被赋值。 */ // 不好的写法 var person; console.log(person === undefined); // true /* * 尽管这段代码能正常工作,但建议避免在代码中使用undefined。这个值常常和返回"undefined"的typeof运算符混淆。 * 事实上,typeof的行为也很让人费解,因为不管是值是undefined的变量还是为声明的变量,typeof的运算结果都是"undefined"。 */ // foo未被声明 var person; console.log(typeof person); // "undefined" console.log(typeof foo); // "undefined" /* * 在这段代码中,person和foo都会导致typeof返回"undefined",哪怕person和foo在其他场景中的行为有天壤之别(在语句中, * 使用foo会报错,而使用person则不会报错)。 * * 通过禁止使用特殊值undefined,可以有效地确保只在一种情况下typeof才会返回"undefined":当变量未声明时。 * 如果你使用了一个可能(或可能不会)赋值为一个对象的变量时,则将其赋值为null。 */ // 好的做法 var person = null; console.log(person === null); // true /* * 将变量初始值赋值为null表明了这个变量的意图,它最终可能赋值为对象。typeof运算符运算null的类型时返回"object",这样就可以和undefined区分开了。 */
总结:我想大部分前端同学都控制不好null与undefined的使用,好好去理解它们,在该用的地方正确用之,无疑能够增加代码的可读性。
四、变量声明
// Crockford的编程规范、SproutCore编程风格指南和Dojo编程风格指南推荐奖局部变量的定义作为函数内的第一条语句。 function doSomethingWithItems(items) { var i, len; var value = 10; var result = value + 10; for (i = 0, len = items.length; i < len; i++) { doSomething(items[i]); } } // Crockford还进一步推荐在函数顶部使用单var语句 function doSomethingWithItems(items) { var i, len, value = 10, result = value + 10; for (i = 0, len = items.length; i < len; i++) { doSomething(items[i]); } } // Dojo编程风格指南规定,只有当变量之间有关联性时,才允许使用单var语句。 /* * 本书作者比较倾向于将所有的var语句合并为一个语句,每个变量的初始化独占。 * 赋值运算符应当对齐。对于那些没有初始值的变量来说,它们应当出现在var语句的尾部。 */ function doSomethingWithItems(items) { var value = 10, result = value + 10, i, len; for (i = 0, len = items.length; i < len; i++) { doSomething(items[i]); } }
总结:本书举例三种变量声明风格,我个人而言,倾向于最后一种,会让代码显得更加简洁、可维护。
五、函数声明
/* * 推荐函数内部的局部函数应当紧接着变量声明之后声明。 */ function doSomethingWithItems(items) { var value = 10, result = value + 10, i, len; function doSomething(item) { // 代码逻辑 } for (i = 0, len = items.length; i < len; i++) { doSomething(items[i]); } }
总结:确保在函数调用之前,声明了该函数即可。但是我个人更喜欢函数表达式的方式去定义函数。
function doSomethingWithItems(items) { var value = 10, result = value + 10, i, len; var doSomething = function(item) { // 代码逻辑 } for (i = 0, len = items.length; i < len; i++) { doSomething(items[i]); } }
本书第一部分的其他内容(如缩进层级、行的长度、命名、注释、相等、严格模式等等),就不在这里罗嗦了。在日常开发过程中,基本上遵循了这些规范。