如果你还不熟悉 JavaScript 编写规则的话,谷歌发布了自己的 JS 编写风格指南,罗列出在他们看来最优雅的写法,以求写出的代码简单易读。
这份谷歌的风格指南并不提供硬性的要求,它不会教你如何写 JS,它只会针对如何写出连贯漂亮的 JS 提出风格方面的建议。JS 是很灵活的语言,允许很多编写风格的并存。
谷歌和爱彼邻都有发布自己的 JS 风格指南,在目前同类指南中是最受瞩目的两份。如果你工作中涉及到大量的 JS 编写,我强烈建议你花点时间研究一下这两份指南。
我从谷歌的风格指南中提取了 13 点在我看来最有意思且最有实际意义的建议,罗列如下,仅供参考。
无论是行内争议较大的一些问题,比如,缩进是用制表符还是用空格,如何使用分号,还是比较细枝末节的方面,谷歌 JS 风格指南都给出了自己很明确的回应。毋庸置疑,这份指南大大改变我写 JS 的习惯。
针对每一点,我都会先大致总结一下规则,然后附上指南的原文节选,来辅助对规则细节的理解。如果可能的话,我还会加上符合该条规则的代码范例来阐述,以及不合规的代码反例来加以对比。
缩进用空格,不要用制表符
除了行终止符,ASCII 水平空格字符(0x20)是源文件中出现过的唯一代表空白的字符,说明制表符不能用来缩进。
指南还推荐使用两个(不是四个)空格来完成缩进。
// bad
function foo() {
∙∙∙∙let name;
}
// bad
function bar() {
∙let name;
}
// good
function baz() {
∙∙let name;
}
必须用分号
每个语句都要用分号来结尾,禁止依靠自动分号插入。
我是无法理解为什么有人要质疑分号结尾的必要性,但就像缩进是用制表符还是空格,要不要在语句结尾加上分号也变得越来越有争议性。在这份指南中,谷歌给出了非常明确的回应,即必须使用分号。
// bad
let luke = {}
let leia = {}
[luke, leia].forEach(jedi => jedi.father = 'vader')
// good
let luke = {};
let leia = {};
[luke, leia].forEach((jedi) => {
jedi.father = 'vader';
});
暂时还先别使用 ES6 的模块(modules)
暂时还先别用 ES6 的模块(例如 export
和 import
命令),它们的语义还没完全确定下来。在 ES6 模块语义和用法完全确定下来后,我们会重新考量此条规则。
// 暂时先别这么写:
//------ lib.js ------
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ main.js ------
import { square, diag } from 'lib';
不鼓励(不禁止)水平对齐
虽然水平对齐并没有被禁用,但一般来说,谷歌是不鼓励这种做法的。在代码中如果已经做过水平对齐处理,谷歌也不鼓励保持水平对齐的做法。
在代码中加入多余的空格,以和上下行的同类变量保持对齐的做法就是所说的"水平对齐“。
// bad
{
tiny: 42,
longer: 435,
};
// good
{
tiny: 42,
longer: 435,
};
别再用 var
了
所有的本地变量都应该使用 const
或者 let
来引出声明。除非该变量需要被重新赋值,不然都默认用 const
来声明。禁止再使用 var
。
在 StackOverflow 和其他地方,我还是会看到 var
出现在各种代码范例中,不知道是因为积习太难改,还是因为有人坚持认为 var
还有存在的理由……
// bad
var example = 42;
// good
let example = 42;
箭头函数是首选
箭头函数的句法更简洁,也解决了 this
关键词使用中的一些老大难问题。特别是在写嵌套函数的时候,箭头函数的优势相较传统的 function
表达式更突出,是首选。
我个人更喜欢箭头函数只是因为觉得它更简洁、更美观,碰巧写箭头函数确实能解决一些重要的实际问题。
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
使用模版字符串,而不要将普通字符串叠加
在处理复杂的字符串叠加,尤其是多行字符串的叠加时,模版字符串(使用反引号`来界定)是更优的选择,可以实现跨多行的效果。
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// bad
function sayHi(name) {
return `How are you, ${ name }?`;
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
长字符串不要使用反斜杠来分隔每行
请不要在基本字符串或者模版字符串的每行后用反斜杠(/)表示结尾,虽然 ES5 不会对这样的操作报错,但这样做会让你在排查错误的时候很头疼,因为斜杠后的多余空格会报错,而且很难看出。
爱彼邻(Airbnb)和谷歌在这一点上的推荐做法是有分歧的(详情参见爱彼邻的文档)。
谷歌建议用 +
运算符将多行字符串相连(如下所示),爱彼邻建议什么都不做,让长字符串自由覆盖。
// bad (sorry, this doesn't show up well on mobile)
const longString = 'This is a very long string that \
far exceeds the 80 column limit. It unfortunately \
contains long stretches of spaces due to how the \
continued lines are indented.';
// good
const longString = 'This is a very long string that ' +
'far exceeds the 80 column limit. It does not contain ' +
'long stretches of spaces since the concatenated ' +
'strings are cleaner.';
“for… of”
是写 for
循环的首选方式
在 ES6 体系下,JS 支持三种写 for
循环的方式,但 for
-of
是最优选。
其实我也觉得这条规则有点奇怪,但是我还是选择把它纳入,因为考虑到谷歌会明确规定写 for
循环的最优方式,还是很有看头的。
我个人觉得,for…in
更适合对象的循环,for…of
更适合数组的循环,要视情况而定。
谷歌的建议也不一定和我的想法相悖,但针对这个问题谷歌有明确的表态,让我觉得有必要列出来思考一下。
别使用eval()
除了在代码加载器中,平时不要使用 eval
,也不要使用 Function(...string)
构造函数,这些特性都是有潜在的危险的,而且在 CSP 环境中根本不起作用。
MDN上的 eval()
页 有一个章节的标题就是“避免使用 eval
!"。
// bad
let obj = { a: 20, b: 30 };
let propName = getPropName(); // returns "a" or "b"
eval( 'var result = obj.' + propName );
// good
let obj = { a: 20, b: 30 };
let propName = getPropName(); // returns "a" or "b"
let result = obj[ propName ]; // obj[ "a" ] is the same as obj.a
常量命名应该全大写,并且用下划线分隔单词
常量应该遵循 CONSTANT_CASE
命名规则:全大写,单词用下划线分割。
如果你确定一个变量的值不会发生改变,你应该用常量的命名规则来命名该变量,让你在浏览代码的时候更直观。
如果该常量仅定义并作用在某个函数内,那么这个常量的命名应该遵守 camelCase 规则,而不该全大写。
// bad
const number = 5;
// good
const NUMBER = 5;
每次只声明一个变量
每个声明语句里只包含一个变量,像 let a = 1, b = 2;
这样的写法是不合规、不推荐的。
// bad
let a = 1, b = 2, c = 3;
// good
let a = 1;
let b = 2;
let c = 3;
用单引号,不用双引号
普通字符串文字,用单引号 ('
)而不是双引号("
)来标记字符串的结尾 。
小贴士:如果字符串中含有单引号,用模版字符串来避免单引号转义失效的情况。
// bad
let directive = "No identification of self or mission."
// bad
let saying = 'Say it ain\u0027t so.';
// good
let directive = 'No identification of self or mission.';
// good
let saying = `Say it ain't so`;
写在最后
这 13 点规则并不是所谓的的金规玉律,我在文章开头说过的,这里再强调一下。谷歌是科技巨擘之一,这些推荐处理方法只是他们的一家之言。
虽说如此,这一家之言是很有分量的,谷歌雇用了大量的顶尖工程师,资质深厚的他们写过大量的优质代码,他们的建议值得一看。
如果你想写出符合谷歌源文件级别标准的代码,你可以完全遵循谷歌这套风格指南中的所有规则。如果你对其中的个别规则或者所有规则有异议——很多人都有异议——那你大可不必理会这些建议。
我个人觉得在很多写法问题的建议处理上,爱彼邻的版本会比谷歌更合理一些。但万变不离其宗,无论你个人认为怎么样写才是优雅简洁的,在写代码的时候还是要遵循一定的规则,尽量做到前后风格一致。
原文链接:https://medium.freecodecamp.org/google-publishes-a-javascript-style-guide-here-are-some-key-lessons-1810b8ad050b,作者:Daniel Simmons