# js-style-guide **Repository Path**: louis_w/js-style-guide ## Basic Information - **Project Name**: js-style-guide - **Description**: JavaScript编码规范 - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2016-05-09 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 目录 ## JavaScript编码规范 * [适用范围](#适用范围) * [文体](#文体) * [缩进、换行、空白](#缩进-换行-空白) * [标点符号](#标点符号) * [命名规则](#命名规则) * [注释的使用](#注释的使用) * [其他](#其他) ## 附录一《关于编码规范》 * [编码规范的作用](#编码规范的作用) * [编码规范不是“物神”](#编码规范不是“物神”) * [编写编码规范的原则](#编写编码规范的原则) ## 附录二 参考资料 * [Google的JavaScript风格指南(以下简称Google)](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) * [NPM编码风格(以下简称NPM)](https://npmjs.org/doc/coding-style.html) * [Felix的Node.js风格指南(以下简称Node.js)](http://nodeguide.com/style.html) * [惯用(Idiomatic)的JavaScript(以下简称Idiomatic)](https://github.com/rwldrn/idiomatic.js/) * [jQuery JavaScript风格指南(以下简称jQuery)](http://contribute.jquery.org/style-guide/js/) * [Douglas Crockford的JavaScript风格指南(以下简称Crockford),Douglas Crockford是Web开发领域最知名的技术权威之一,ECMA JavaScript 2.0标准化委员会委员](http://javascript.crockford.com/code.html) # JavaScript编码规范 ## 适用范围   本规范适用于Makeblock所有的JavaScript代码(包括但不限于运行在浏览器中的js、运行在服务器端的js),为详细设计,代码编写和代码审核提供参考和依据。 ## 文体   本规范中的建议分为四种: **建议** , **避免** , **要** , **不要** ,表示需要遵循的级别。文档中会以粗体表示。 * **建议**:描述在一般情况下应该遵循的规范,但如果完全理解规范背后的道理,并有很好的理由不遵循它时,也不畏惧打破常规。(例如:强制类型转换时,在类型和变量之间建议加一空格。) * **避免**:与建议相对,一般情况下应该遵循,但有很好的理由时也可以打破。例如:(避免块内部的变量与它外部的变量名相同。) * **要**:描述必须遵循的规范。(例如:异常类要以“Exception”做为后缀;) * **不要**:描述一些几乎绝对绝不应该违反的规范。(例如:每个函数有效代码(不包括注释和空行)长度不要超过50行。) ## 缩进、换行、空白 ### 使用2个空格进行缩进 缩进 **要** 使用2个空格的字符, **不要** 使用混合的tab和空格作为缩进。 ### 使用Unix风格的换行 **要** 使用Unix风格的换行,每行结尾以(\n)结束, **不要** 使用Windows的换行符(\r\n) ### 无拖尾空白 **不要** 在一行后面留空格,在提交之前,你要像每顿饭刷牙一样清理你的JS文件。否则,腐烂的气味会驱走贡献者或同事。 ## 标点符号 ### 使用分号 当一段代码正确结束后 **要** 使用分号, **不要** 滥用纠错机制(省略分号)。 *注解:* 在JavaScript中前置逗号代码风格和省略分号一直存在争论,下同。 ### 使用单引号 只有在JSON文件中才使用双引号。定义和使用字符串时 **要** 使用单引号, **不要** 使用双引号。 *正确的:* ```js var foo = 'bar'; ``` *不正确的:* ```js var foo = "bar"; ``` *注解:* JavaScript中包含双引号的字符串几乎到处都是,这样你就不需要转义了。 ### 在同一行写大括号 遇到大括号时,开始符大括号 **不要** 换行, **要** 与条件或前置语句并列,结束符大括号 **要** 换行。 同样,注意在条件前后都加个空格。 *正确的:* ```js if (true) { console.log('winning'); } ``` *不正确的:* ```js if (true) { console.log('losing'); } ``` ## 命名规则 ### 模块名字 **要** 使用a-z组成的小写词汇,它们也应该是描述性的,词语之间建议使用链接号(-)进行连接。例如: * form-data * gaze * grunt-contrib-clean *正确的:* ```js require('eyes'); require('fastparse'); require('basic-auth-connect'); ``` *不正确的:* ```js require('Eyes'); require('Fastparse'); require('basic-Buth-*connect'); ``` ### 类名 类名 **要** 使用帕斯卡命名方式,以单词首字母大些组成, **不要** 使用a-z,A-Z以外的字符。例如: * Password * AdminUser * UserService *正确的:* ```js var Eyes = require('eyes'); var User = function (){ var eyes = new Eyes(); return { name: 'zhangsan', age: 18 }; }(); var user = new User(); ``` *不正确的:* ```js var eyes = require('eyes'); var user = function (){ var eyes1 = new eyes(); return { name: 'zhangsan', age: 18 }; }(); var user1 = new user(); ``` ### 文件名、变量名、函数名 **要** 使用骆驼命名法,以首单词小写、其他单词首字母大些组成, **不要** 使用a-z,A-Z以外的字符。例如: * lowerCamelCase * userName * userService.js * getUserName *正确的:* ```js var adminUser = db.query('SELECT * FROM users ...'); ``` *不正确的:* ```js var admin_user = db.query('SELECT * FROM users ...'); ``` ### 阵列(数组、集合) 变量名或方法名涉及到数组、集合时 **要** 使用复数进行命名, **不要** 使用List或Array。 *正确的:* ```js var users = ['zhangsan','lisi']; var apps = getApps(); ``` *不正确的:* ```js var userArray = ['zhangsan','lisi']; var appList = getAppList(); ``` ### 常量 常量应该被声明为普通变量或静态类的属性, **要** 全部使用大写字母,词与词之间使用下划线(_)进行连接。例如: * MAX_PARAMETER_COUNT * SYSTEM * SYSTEM_NAME *正确的:* ```js var SECOND = 1 * 1000; function File() { } File.FULL_PERMISSIONS = 0777; ``` *不正确的:* ```js const SECOND = 1 * 1000; function File() { } File.fullPermissions = 0777; ``` ## 注释的使用 ### 使用斜线注释 **要** 使用斜线为单行和多行注释。尝试从更高层次说明你代码的意图。 **不要** 重申琐碎的事情。 *正确的:* ```js // 'ID_SOMETHING=VALUE' -> ['ID_SOMETHING=VALUE', 'SOMETHING', 'VALUE'] var matches = item.match(/ID_([^\n]+)=([^\n]+)/)); // This function has a nasty side effect where a failure to increment a // redis counter used for statistics will cause an exception. This needs // to be fixed in a later iteration. function loadUser(id, cb) { // ... } var isSessionValid = (session.expires < Date.now()); if (isSessionValid) { // ... } ``` *不正确的:* ```js // Execute a regex var matches = item.match(/ID_([^\n]+)=([^\n]+)/)); // Usage: loadUser(5, function() { ... }) function loadUser(id, cb) { // ... } // Check if the session is valid var isSessionValid = (session.expires < Date.now()); // If the session is valid if (isSessionValid) { // ... } ``` ### 不要对代码进行落款式的注释 项目中的每一行代码成果属于整个团队而非个人,我们应该在编码过程中摒弃个人主义观念,至少在团队项目中如此。 如果留下 编码人、编码时间等信息是为了便于日后维护及追溯,可以通过源代码版本控制工具而非在代码中编写额外的修改纪录。 *标注:* 注释的目的仅仅是为了辅助人类理解代码的意图。 ### 删除废弃的代码,而不是注释它们 删除那些曾经存在,或因为重构留下的代码,即便它们或许是对的,但当你决定此处应该使用较新的代码的时候,为了避免代码的混乱及冗余,请不要犹豫,删除它们。 *标注:* 如果已经正确的使用了版本控制工具(例如:git),并不需要担心无法追溯。 ## 其他 ### 每行最多80个字符 每行最多80个字符。屏幕在最近几年越来越大,但是你的脑子没怎么变,你可以使用多余的空间用来分屏。 ### 方法链(调用链) 如果你使用方法链,确保每行只调用一个方法。 同时你要合理使用缩进来表示他们的父对象是一致的。 *正确的:* ```js User .findOne({ name: 'foo' }) .populate('bar') .exec(function(err, user) { return true; }); ``` *不正确的:* ```js User .findOne({ name: 'foo' }) .populate('bar') .exec(function(err, user) { return true; }); User.findOne({ name: 'foo' }) .populate('bar') .exec(function(err, user) { return true; }); User.findOne({ name: 'foo' }).populate('bar') .exec(function(err, user) { return true; }); User.findOne({ name: 'foo' }).populate('bar') .exec(function(err, user) { return true; }); ``` ### 每行声明一个变量 每个var只声明一个变量,它可以更容易地重新排序。但是,并且变量应该在更有意义的地方声明。 *正确的:* ```js var keys = ['foo', 'bar']; var values = [23, 42]; var object = {}; while (keys.length) { var key = keys.pop(); object[key] = values.pop(); } ``` *不正确的:* ```js var keys = ['foo', 'bar'], values = [23, 42], object = {}, key; while (keys.length) { key = keys.pop(); object[key] = values.pop(); } ``` ### Object / Array 声明 使用尾随逗号,把短的声明在一行: *正确的:* ```js var a = ['hello', 'world']; var b = { good: 'code', 'is generally': 'pretty' }; ``` *不正确的:* ```js var a = [ 'hello', 'world' ]; var b = {"good": 'code' , "is generally": 'pretty' }; ``` ### 使用 === 操作符 编写不应该只记事规则,还要学会使用。 *正确的:* ```js var a = 0; if (a !== '') { console.log('winning'); } ``` *不正确的:* ```js var a = 0; if (a == '') { console.log('losing'); } ``` 注解: === 即会判断类型,又会判断结果。 ### 使用多行三元运算符 三元运算符不应该用在一行。分割成多行来代替。 *正确的:* ```js var foo = (a === b) ? 1 : 2; ``` *不正确的:* ```js var foo = (a === b) ? 1 : 2; ``` ### 不要扩展内置对象 不要扩展原生JavaScript对象的原型。以后会后悔的。 *正确的:* ```js var a = []; if (!a.length) { console.log('winning'); } ``` *不正确的:* ```js Array.prototype.empty = function() { return !this.length; } var a = []; if (a.empty()) { console.log('losing'); } ``` 注解:扩展String.prototype是比较常见的,如format, trim。 ### 使用描述性的条件 任何判断条件应该分配给一个描述性命名的变量或函数: *正确的:* ```js var isValidPassword = password.length >= 4 && /^(?=.*\d).{4,}$/.test(password); if (isValidPassword) { console.log('winning'); } ``` *不正确的:* ```js if (password.length >= 4 && /^(?=.*\d).{4,}$/.test(password)) { console.log('losing'); } ``` ### 写小而短的函数 保持你的函数短小精悍,如果函数逻辑复杂可以考虑横向拆分成多个子函数,应当 **避免** 每个函数内代码超出30行。对一个大房间的最后一排的人民群众而言可以轻松读取幻灯片上的代码是比较合适的。别指望他们有的视力保持每个函数>15行代码。 ### 早点从函数返回 为了避免if语句的深层嵌套,总是尽可能早地在函数返回值。 *正确的:* ```js function isPercentage(val) { if (val < 0) { return false; } if (val > 100) { return false; } return true; } ``` *不正确的:* ```js function isPercentage(val) { if (val >= 0) { if (val < 100) { return true; } else { return false; } } else { return false; } } ``` ### 命名您的闭包 随时给你闭包名称。这表明你关心他们,并能产生更好的堆栈跟踪,heap和cpu profiles。 *正确的:* ```js req.on('end', function onEnd() { console.log('winning'); }); ``` *不正确的:* req.on('end', function() { console.log('losing'); }); ### 不要嵌套闭包 使用闭包,但不能嵌套他们。否则,你的代码会变得一团糟。 *正确的:* ```js setTimeout(function() { client.connect(afterConnect); }, 1000); function afterConnect() { console.log('winning'); } ``` *不正确的:* ```js setTimeout(function() { client.connect(function() { console.log('losing'); }); }, 1000); ``` ### 禁止使用: Object.freeze, Object.preventExtensions, Object.seal, with, eval 这些功能很可笑,远离他们。 *注解:* 类似Java/C#中的protected / private / seal / final。 # 附录一《关于编码规范》   作为软件开发者,我们可以开发低等级的软件,但不能开发低质量的软件。所以,如何实施质量保证,是我们关注的主要问题之一,而编码规范则是实施质量保证的第一步。   编码规范已经成为一个老生常谈的问题,几乎每个项目,每家公司都会定义自己的编码规范。但在真正实施时,却在有意或无意地违背编码规范。程序员,不喜欢改变自己的编程习惯。加之,管理者对质量控制不足,导致编码规范往往形同虚设。有些人会认为:遵守编码规范不能给项目带来利益,也不能让客户看到我们为此付出的努力,其完全是团队自发的行为,没有必要做硬性的要求。还有些人有更好的理由:编码规范会破坏创造性和程序质量。我认为,编码规范,在软件构件以及项目管理中,甚至是个人成长方面,都发挥着重要的作用,好的编码规范是提高我们代码质量的最有效的工具之一。 ## 编码规范的作用 * **提高可读性** “任何一个傻瓜都能写出计算机可以理解的代码,唯有写出人类容易理解的代码,才是优先的程序员。”编码规范,帮助我们写出人类容易理解的代码,它为我们提供了最基本的模板,良好的编码风格,使代码具有一定的描述性,可以通过名字来获取一些需要IDE才能得到的提示,如可访问性、继承基类等。 * **统一全局,促进团队协作** 开发软件是一个团队活动,而不是个人的英雄主义。编码规范,要求团队成员遵守这一统一的全局决策,这样成员之间可以轻松地阅读对方的代码,所有成员正以一种清晰而一致的风格进行编码。而且,开发人员也可以集中精力关注他们真正应该关注的问题——自身代码的业务逻辑,与需求的契合度等局部问题。 * **有助于知识传递,加快工作交接** 风格的相似性,能让开发人员更迅速,更容易理解一些陌生的代码,更快速地理解别人的代码。因为,他和你的代码风格是一样的,你没有必要对他的一些个性化风格进行揣测。这样的好处是开发人员可以很快的接手项目组其他成员的工作,快速完成工作交接。 * **减少名字增生,降低维护成本** 在没有规范的情况下,和容易为同一类型的实例起不同的名字。对于以后维护这些代码程序员来说会产生疑惑。 * **强调变量之间的关系,降低缺陷引入的机会** 命名可以表示一定的逻辑关系,是开发人员在使用时保持警惕,从而一定程度上减少缺陷被引人的机会。 * **提高程序员的个人能力** 不可否认,每个程序员都应该养成良好的编码习惯,而编码规范无疑是教材之一。从一个程序员的代码本身能看出很多东西。所以,即便是为了自身发展,作为程序员也没有理由抵制这种规则的存在。你可能没有认识到,我们正默默地得益于编码规范。 ## 编码规范不是“物神” 在高质量的软件中,你可以看到“架构的概念完整性”与“底层实现”之间的关系。“实现”与“架构”必须是清晰一致的,这种内在的、固有的一致性,需要编码规范来维系。如果没有这种统一的约定,那么我们做出的东西可能会充斥着各种不同的风格,显得混乱且难以理解。团队成员之间可能很不理解彼此之间的想法,甚至是相互抨击。各种编码风格上的差异会不断扩大,而代码质量则不断下降。而且,团队成员会花费时间在理解不同编程风格之间的差异,而没有专注于真正应该解决的问题。这样的时间消耗是难以接受的。所以,在每一个高质量代码的背后,一定存在着一份优秀的编码规范。 然而,也必须认识到编码规范不是“物神”。编码规范仅仅是一个全局性质的规范,它只不过是一种编程约定,不能解决更深层次的问题。就像一篇格式漂亮但内容糟糕的论文不能被发表一样,你不能仅靠一个规范来摆脱软件作坊。而且,在编码规范中不宜包含那些冗长的开发技巧。我认为,对于代码是最佳实践应该是代码审查所要解决的,应该避免将编码规范写成一部关于重构的教科书。 ## 编写编码规范的原则 * **求同存异** 不要妄图改变组织的编码习惯,除非有绝对合理的理由,否则还是以民主为主,毕竟你没有权利要求所有人都沿用你的编码习惯。 * **定义编码规范越早越好** 也早使用编码规范,也早享受其带来的好处。 * **将规范分为强制部分和推荐部分** 求同存异的具体实现。将最基本的规范列放在强制部分,所有成员必须遵守;将好的但不重要的习惯列在推荐部分,开发人员可以根据自己习惯选择是否使用。 * **编码规范不要太长** 太长的文档没人看,所有人都一样,除了礼品单和工资单没人愿意看长的东西,所以编码规范必须精炼,最好是只有2~3页,让开发人员可以打印出来随时查看。 * **必须是约定俗成的** 规范必须是行业中约定俗成的,不要有什么个性化发挥。