《编写可维护的 JavaScript》编程风格 - 第 1 章 基本的格式化

  • 时间:
  • 来源:互联网
  • 文章标签:

编程风格 - 第 1 章 基本的格式化

《编写可维护的 JavaScript》—— Nicholas C. Zakas

编程风格指南的核心是基本的格式化规则(formatting rule)。
这些规则直接决定了如何编写高水准的代码。与写字时所用的方格纸类似。

1. 缩进层级

两种缩进方式:

  • 制表符(tab character)

    • 好处

      • 一个制表符一个缩进层级,一对一的关系
      • 文本编辑器可以配置制表符的展现长度
    • 坏处

      • 系统对制表符的解释不一致,有的长有的短
  • 空格:每个缩进层级由多个空格字符组成,2 或 4 或 8 空格代表一个层级

    • 好处:所有的系统和编辑器中,文件的展现格式不会有差异
    • 坏处:需要配置编辑器的 Tab 键插入的空格数量

缩进风格参考:

  • jQuery Core Style Guide: 制表符
  • Douglas Crockford’s Code Conventions for the JavaScript Programming Language: 4 个空格
  • SproutCore Style Guide: 2 个空格
  • Google JavaScript Guide: 2 个空格
  • Dojo Style Guide: 制表符

推荐:

  • 使用 4 个空格作为一个缩进,很多编辑器默认的缩进设置为 4 个空格
  • 使用 2 个空格,代码的视觉展现并不是最优的

注意:

  • 选择制表符还是空格做缩进只是个人的偏好,但是绝对不要混用

2. 语句结尾

JavaScript 的语句要么独占一行,要么以分号结尾。

有赖于分析器的自动分号插入机制(Automatic Semicolon Insertion,ASI),JavaScript 代码省略分号也是可以正常工作的。

但当某个场景我们任务不需要插入分号而 ASI 认为需要插入时,常常会产生错误。

3. 行的长度

如果一行代码太长,编辑窗口出现了横向滚动条,会让开发人员感觉很别扭。

很多语言的编程规范都提到了一行代码最长不应该超过 80 个字符。
这个数值来源于很久之前文本编辑器的单行最多字符限制,即编辑器中单行最多只能显示 80 个字符,
超过 80 个字符的行要么折行,要么被隐藏起来。

4. 换行

当一行长度达到了单行最大字符数限制时,就需要手动将一行拆成两行。

通常在运算符后换行,下一行会增加两个层级的缩进,比如:(两个空格为一个缩进层次)

// 1. 在运算符后换行;2. 第二行额外加两个缩进
callAFunction(document, element, window, 'some string value', true, 123,
    navigator);

if (isLeapYear && isFebruary && day === 29 &&
    noPlans) {

  waitAnotherFourYears();
}

// 上下行对齐以保证可读性
var result = something + anotherThing + yetAntherThing +
             antherSomethingElse;

为什么要在运算符后换行?
因为 ASI 机制有时会在行结束的位置插入分号,
总是将运算符置于行尾,ASI 就不会自作主张地插入分号,也就避免了错误了发生。

5. 空行

在编程规范中,空行是常常被忽略的一个方面。

通常来讲,代码看起来应当是一系列可读的段落,而不是一大段揉在一起的连续文本。

有时一段代码的语义和另一段代码不相关,这时就应该使用空行将它们分隔,确保语义有关联的代码展现在一起。

// 在每个流程控制语句之前添加空格
if (wl && wl.length) {
  
  for (i = 0, l = wl.length; i < l; i++) {
    p = wl[i];
    type = Y.Lang.type(r[p]);

    if (s.hasOwnProperty(p)) {

      if (merge && type === 'object') {
        Y.mix(r[p], s[p]);
      } else if (ov || !(p in r)) {
        r[p] = s[p];
      }
    }
  }
}

一般来讲,在下面的场景中添加空行也是不错的注意:

  • 在注释(单行或多行)之前
  • 在方法之间
  • 在方法中的变量声明和第一条语句之间
  • 在方法内的逻辑片段之间

6. 命名

“计算机科学只存在两个难题:缓存失效和命名。” —— Phil Karlton。

只要写代码,都会涉及到变量和函数,因此变量和函数命名对增强代码可读性至关重要。

JavaScript 语言的核心 ECMAScript,遵循了驼峰式(Camel Case)命名法。

  • Camel Case(小驼峰式):首字符小写,后续每个单词首字母都大写。
  • Pascal Case(大驼峰式):首字符大写,后续每个单词首字母都大写。

比如:

var thisIsMyName;
var anotherVariable;
var aVeryLongVariableName;

匈牙利命名法

在名字之前添加类型标识符前缀,比如 sName(字符串类型)、iCount(整形类型)、oPerson(对象类型)。

这种风格在 2000 年左右还比较流行,现在主流的编程规范都不推荐这种命名法。

7. 变量和函数

变量名应当遵循小驼峰式命名,且前缀为名词以区分函数(函数以动词为前缀)。比如:

// 好的写法
var count = 10;
var myName = 'Nicholas';
var found = true;

// 不好的写法:变量看起来像函数
var getCount = 10;
var isFound = true;

// 好的写法
function getName() {
  return myName;
}

// 不好的写法: 函数看起来像变量
function theName() {
  return myName;
}

通常来讲,命名长度应该尽可能短,并抓住要点。

尽量在变量中体现出值的数据类型,
如,count、length、size 表明数据类型是数字,name、title、message 表明数据类型是字符串。
单个字符命名的变量(i、j、k)通常在循环中使用。
使用这些能够体现数据类型的命名,可以让你的代码容易被别人和自己读懂。

避免使用没有意义的命名,如 foo、bar、tmp。

对于函数或方法命名来说,第一个单词应该是动词,这里有常用的动词约定:

  • can: 返回一个布尔值
  • has: 返回一个布尔值
  • is: 返回一个布尔值
  • get: 返回一个非布尔值
  • set: 返回一个非布尔值

使用这些约定可以使代码可读性更好,如:

if (isEnabled()) {
  setName('Nicholas');
}

if (getName() === 'Nicholas') {
  doSomething();
}

8. 常量

在 ES6 之前,JavaScript 中并没有真正的常量的概念,然而这并不能阻止开发者将变量用作常量。

为了区分普通的变量(其值可变)和常量(初始化后其值不可变),一种通用的命名约定诞生了。

这个约定源于 C 语言,使用大写字母和下划线来命名,下划线用于分隔单词,比如

var MAX_COUNT = 10;

if (count < MAX_COUNT) {
  doSomething();
}

使用这种不同的约定来定义普通的变量和常量,使两者非常易于区分。
上面的代码中,一眼就能看出 count 是变量,MAX_COUNT 是常量。
这个约定为代码(underlying code)增加了另外一层语义。

9. 构造函数

在 JavaScript 中,构造函数只不过是通过 new 运算符来调用的函数,用以创建对象。

语言本身已经包含了很多内置构造函数,比如 ObjectRegExp;开发者也可以创建自己的构造函数来生成新类型。

构造函数的命名遵循大驼峰(Pascal Case)命名法,将构造函数从变量和普通函数中区分开来。

构造函数的命名也常常是名词,因为它们是用来创建某个类型的实例的,如下

function Person(name) {
  this.name = name;
}

Person.prototype.sayName = function() {
  alert(this.name);
};

var me = new Person('吴钦飞');

以大驼峰命名的函数如果是名词的话,前面一定有 new 运算符,遵循这条约定可以帮我们快速定位问题,如下:

var me = Person('吴钦飞');
var you = getPerson('哇哈哈');

根据命名约定,一眼就能看出第一行出问题了。

10. 直接量

JavaScript 中包含了一些类型的原始值:字符串、数字、布尔值、null、undefined。同样也包含对象直接量、数组直接量。

这其中,只有布尔值是自解释的(self-explanatory)的,其他的类型的值则需要思考一下如何才能更准确地表达出来。

11. 字符串

在 JavaScript 中,字符串可以用双引号括起来,也可以用单引号括起来,比如:

var name = "Nicholas says, \"Hi.\"";

var name = 'Nicholas says, "Hi."';

字符串界定符(string delimiter)使用双引号还是单引号在功能上并无区别,你的代码应当从头到尾只保持一种风格。

多行字符串,如下:

// 不好的写法
var longString = "Here's the story, of a man \
named Brady.";

尽管从技术上讲这种写法是非法的 JavaScript 语法,但的确能在代码中创建多行字符串。
通常不推荐使用这种写法,因为它是一种奇技淫巧而非语言特性。

多行字符串的一种替代写法是使用字符串连接符(+)将字符串分成多份。

var longString = "Here's the story, of a man " +
                 "named Brady.";

12. 数字

在 JavaScript 中的数字类型只有一种,因为所有的数字形式(整数和浮点数)都存储为相同的数据类型。
但有一些写法有问题:

// 整数
var count = 10;

// 小数
var price = 10.0;
var price = 10.00;

// 不推荐的写法:没有小数部分
var price = 10.;

// 不推荐的写法:没有整数部分
var price = .1;

// 不推荐的写法:八进制写法已经被废弃了
var num = 010;

// 十六进制写法
var num = 0xA2;

// 科学计数法
var num = 1e23;

前两种错误的写法(省略了整数部分或小数部分),很难搞清楚省略的部分是不小心丢掉了还是刻意为之。
因此为了避免歧义,请不要省略小数点之前或之后的数字。

数字直接量 010 不是表示 10,而是八进制中的 8。
大多数开发者对八进制格式并不熟悉,也很少用到,所有最好的做法就是在代码中禁止八进制直接量。

13. null

理解 null 最好的方式就是将它当做对象的占位符(placeholder)。

null 是一个特殊值,但我们常常误解它,将它和 undefined 搞混,在下列场景中应当是 null

  • 初始化一个对象类型的变量
  • 当函数的参数期望是对象时
  • 当函数的返回值期望是对象时

14. undefined

undefined 是一个特殊值,容易与 null 搞混,因为 null == undefined; //=> true

未被初始的变量的变量都有一个初始值,即 undefined ,表示这个变量等待被赋值。

建议避免在代码中使用 undefined
因为 typeof 的操作数无论是值为 undefined 的变量还是未声明的变量,其结果都是 "undefined"

var person;
console.log(typeof person); //=> "undefined"

// foo 未声明
console.log(typeof foo);    //=> "undefined"

通过禁止使用特殊值 undefined ,可以确保只在变量未声明的情况下 typeof 才会返回 "undefined"

15. 对象直接量

创建对象推荐使用对象直接量,在直接量中写出所有属性。
不推荐先通过 Object 构造函数插件实例后,再添加属性。

// 不好的写法
var book = new Object();
book.title = 'Maintainable JavaScript';
book.author = 'Nicholas C. Zakas';

// 好的写法
var book = {
  title: 'Maintainable JavaScript',
  author: 'Nicholas C. Zakas',
};

16. 数组直接量

推荐使用数组直接量定义数组;不推荐使用 Array 构造函数来创建数组。

// 不好的写法
var colors = new Array('red', 'green', 'blue');
var numbers = new Array(1, 2, 3, 4);

// 好的写法
var colors = ['red', 'green', 'blue'];
var numbers = [1, 2, 3, 4];

本文链接http://www.taodudu.cc/news/show-2483351.html