前言
本文摘自Google JavaScript编码规范指南,截取了其中比较容易理解与遵循的点作为团队的JavaScript编码规范。
JavaScript 语言规范
变量
声明变量必须加上 var
关键字.
当你没有写 var, 变量就会暴露在全局上下文中, 这样很可能会和现有变量冲突. 另外, 如果没有加上, 很难明确该变量的作用域是什么, 变量也很可能像在局部作用域中, 很轻易地泄漏到 Document 或者 Window 中, 所以务必用 var 去声明变量.
常量
常量的形式如: NAMES_LIKE_THIS, 即使用大写字符, 并用下划线分隔. 你也可用 @const 标记来指明它是一个常量. 但请永远不要使用 const 关键词.
关键词 const
, 因为 IE 不能识别, 所以不要使用.
分号
总是使用分号.
如果仅依靠语句间的隐式分隔, 有时会很麻烦. 你自己更能清楚哪里是语句的起止.而且有些情况下, 漏掉分号会很危险.
嵌套函数
可以使用
嵌套函数很有用, 比如,减少重复代码, 隐藏帮助函数, 等. 没什么其他需要注意的地方, 随意使用.
块内函数声明
不要在块内声明一个函数
不要写成:
if (x) { function foo() {} }
虽然很多 JS 引擎都支持块内声明函数, 但它不属于 ECMAScript 规范 (见 ECMA-262, 第13和14条). 各个浏览器糟糕的实现相互不兼容, 有些也与未来 ECMAScript 草案相违背. ECMAScript 只允许在脚本的根语句或函数中声明函数. 如果确实需要在块中定义函数, 建议使用函数表达式来初始化变量:
if (x) { var foo = function() {} }
异常
可以
你在写一个比较复杂的应用时, 不可能完全避免不会发生任何异常. 大胆去用吧.
自定义异常
可以
有时发生异常了, 但返回的错误信息比较奇怪, 也不易读. 虽然可以将含错误信息的引用对象或者可能产生错误的完整对象传递过来, 但这样做都不是很好, 最好还是自定义异常类, 其实这些基本上都是最原始的异常处理技巧. 所以在适当的时候使用自定义异常.
标准特性
总是优于非标准特性.
最大化可移植性和兼容性, 尽量使用标准方法而不是用非标准方法, (比如, 优先用string.charAt(3)
而不用 string[3]
, 通过 DOM 原生函数访问元素, 而不是使用应用封装好的快速接口.
闭包
可以, 但小心使用.
闭包也许是 JS 中最有用的特性了. 有一份比较好的介绍闭包原理的文档.
有一点需要牢记, 闭包保留了一个指向它封闭作用域的指针, 所以, 在给 DOM 元素附加闭包时, 很可能会产生循环引用, 进一步导致内存泄漏.
eval()
只用于解析序列化串 (如: 解析 RPC 响应)
eval()
会让程序执行的比较混乱, 当 eval()
里面包含用户输入的话就更加危险. 可以用其他更佳的, 更清晰, 更安全的方式写你的代码, 所以一般情况下请不要使用 eval(). 当碰到一些需要解析序列化串的情况下(如, 计算 RPC 响应), 使用 eval
很容易实现.
this
仅在对象构造器, 方法, 闭包中使用.
this
的语义很特别. 有时它引用一个全局对象(大多数情况下), 调用者的作用域(使用 eval
时), DOM 树中的节点(添加事件处理函数时), 新创建的对象(使用一个构造器), 或者其他对象(如果函数被 call()
或 apply()
).
使用时很容易出错, 所以只有在下面两个情况时才能使用:
- 在构造器中
- 对象的方法(包括创建的闭包)中
JavaScript 编码风格
命名
通常, 使用 functionNamesLikeThis
, variableNamesLikeThis
, ClassNamesLikeThis
, EnumNamesLikeThis
, methodNamesLikeThis
, 和 SYMBOLIC_CONSTANTS_LIKE_THIS
.
属性和方法
- 文件或类中的 私有 属性, 变量和方法名应该以下划线 "_" 开头.
- 保护 属性, 变量和方法名不需要下划线开头, 和公共变量名一样.
延迟初始化
可以
没必要在每次声明变量时就将其初始化.
明确作用域
任何时候都需要
任何时候都要明确作用域 - 提高可移植性和清晰度. 例如, 不要依赖于作用域链中的 window
对象. 可能在其他应用中, 你函数中的 window
不是指之前的那个窗口对象.
代码格式化
主要依照C++ 格式规范 ( 中文版 ), 针对 JavaScript, 还有下面一些附加说明.
大括号
分号会被隐式插入到代码中, 所以你务必在同一行上插入大括号. 例如:
if (something) { // ... } else { // ... }
数组和对象的初始化
如果初始值不是很长, 就保持写在单行上:
var arr = [1, 2, 3]; // No space after [ or before ]. var obj = {a: 1, b: 2, c: 3}; // No space after { or before }.
初始值占用多行时, 缩进.
// Object initializer. var inset = { top: 10, right: 20, bottom: 15, left: 12 };
比较长的标识符或者数值, 不要为了让代码好看些而手工对齐. 如:
CORRECT_Object.prototype = { a: 0, b: 1, lengthyName: 2 };
不要这样做:
WRONG_Object.prototype = { a : 0, b : 1, lengthyName: 2 };
函数参数
尽量让函数参数在同一行上. 如果一行超过 80 字符, 每个参数独占一行, 并以4个空格缩进, 或者与括号对齐, 以提高可读性. 尽可能不要让每行超过80个字符. 比如下面这样:
// Four-space, wrap at 80. Works with very long function names, survives // renaming without reindenting, low on space. goog.foo.bar.doThingThatIsVeryDifficultToExplain = function( veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) { // ... };
传递匿名函数
如果参数中有匿名函数, 函数体从调用该函数的左边开始缩进2个空格, 而不是从 function 这个关键字开始. 这让匿名函数更加易读 (不要增加很多没必要的缩进让函数体显示在屏幕的右侧).
//bad style var names = items.map(function(item) { return item.name; }); prefix.something.reallyLongFunctionName('whatever', function(a1, a2) { if (a1.equals(a2)) { someOtherLongFunctionName(a1); } else { andNowForSomethingCompletelyDifferent(a2.parrot); } });
更多的缩进
事实上, 除了 初始化数组和对象 , 和传递匿名函数外, 所有被拆开的多行文本要么选择与之前的表达式左对齐, 要么以4个(而不是2个)空格作为一缩进层次.
空行
使用空行来划分一组逻辑上相关联的代码片段.
二元和三元操作符
操作符始终跟随着前行, 这样就不用顾虑分号的隐式插入问题. 如果一行实在放不下, 还是按照上述的缩进风格来换行.
字符串
使用 ' 优于 "
单引号 (') 优于双引号 ("). 当你创建一个包含 HTML 代码的字符串时就知道它的好处了.
注释
暂未约定注释模板,待补充
至少要确保大部分函数都有函数注释,采用JSDoc的格式
/** * Converts text to some completely different text. * @param arg1 An argument that makes this more interesting. * @return Some return value. */ project.MyClass.prototype.someMethod = function(arg1) { // ... };