diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..bb6748c Binary files /dev/null and b/.DS_Store differ diff --git a/google-html-css-styleguide/background.rst b/google-html-css-styleguide/background.rst new file mode 100644 index 0000000..fcc222e --- /dev/null +++ b/google-html-css-styleguide/background.rst @@ -0,0 +1,5 @@ +背景 +================================ + +本文档定义了HTML/CSS的排版以及风格的规则。旨在促进合作编程、提高代码质量并且支持基本的架构。它适用于原生的HTML和CSS文件,包括GSS文件。只要保证代码的整体质量,就可以很容易地使用工具进行混淆、压缩和合并。 + diff --git a/google-html-css-styleguide/css_formatting_rules.rst b/google-html-css-styleguide/css_formatting_rules.rst new file mode 100644 index 0000000..c817f3c --- /dev/null +++ b/google-html-css-styleguide/css_formatting_rules.rst @@ -0,0 +1,176 @@ +CSS格式化规则 +=============== + +声明顺序 +--------- + +按字母顺序排列声明。 + +css文件书写按字母顺序排列的方式,容易记忆和维护,以达到一致的代码。 + +在排序时忽略浏览器特定的前缀。但是,特定CSS属性的多个浏览器前缀应按字母顺序排列(如-moz书写在-webkit前面)。 + +.. code-block:: css + + background: fuchsia; + border: 1px solid; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + color: black; + text-align: center; + text-indent: 2em; + +块内容的缩进 +-------------- + +缩进块内容。 + +将包括嵌套及声明的 `块内容 `_ 进行缩进,以体现层次并提高可读性。 + +.. code-block:: css + + @media screen, projection { + + html { + background: #fff; + color: #444; + } + + } + +声明结束 +---------- + +每个属性后使用分号结束。 + +以分号结束每个属性,提高一致性和可扩展性。 + +.. code-block:: css + + /* 不推荐 */ + .test { + display: block; + height: 100px + } + + /* 推荐 */ + .test { + display: block; + height: 100px; + } + +CSS属性名结束 +--------------- + +属性名称的冒号后有一个空格。 + +为保证一致性,在属性名与属性值之间添加一个空格(但是属性名和冒号间没有空格)。 + +.. code-block:: css + + /* 不推荐 */ + h3 { + font-weight:bold; + } + + /* 推荐 */ + h3 { + font-weight: bold; + } + +声明块间隔 +-------------- + +在选择器和后面的声明块之间使用一个空格。 + +最后一个选择器与表示 `声名块 `_ 开始的左大花括号在同行,中间有一个字符空格。 + +表示开始的左大花括号和选择器在同行。 + +.. code-block:: css + + /* 不推荐:缺少空间 */ + #video{ + margin-top: 1em; + } + + + /* 不推荐:不必要的换行符 */ + #video + { + margin-top: 1em; + } + + /* 推荐 */ + #video { + margin-top: 1em; + } + + +选择器及声明分离 +------------------- + +每个选择器和声明独立成行。 + +总是让每个选择器和声明单独成行。 + +.. code-block:: css + + /* 不推荐 */ + a:focus, a:active { + position: relative; top: 1px; + } + + /* 推荐 */ + h1, + h2, + h3 { + font-weight: normal; + line-height: 1.2; + } + + +CSS代码块分离 +----------------- + +使用新空行分离规则。 + +始终把一个空行(两个换行符)放在代码块规则之间。 + +.. code-block:: css + + html { + background: #fff; + } + + + body { + margin: auto; + width: 50%; + } + +CSS引号 +---------- + +属性选择器和属性值中使用单引号。 + +在属性选择器及属性值中使用单引号('')而不是双引号("")。在 ``url()`` 中不要使用引号。 + +特例:如果你确实需要定义 ``@charset`` ,由于 `不允许使用单引号 `_ ,故请使用双引号。 + +.. code-block:: css + + /* 不推荐 */ + @import url("//www.google.com/css/maia.css"); + + html { + font-family: "open sans", arial, sans-serif; + } + + /* 推荐 */ + @import url(//www.google.com/css/maia.css); + + html { + font-family: 'open sans', arial, sans-serif; + } diff --git a/google-html-css-styleguide/css_meta_rules.rst b/google-html-css-styleguide/css_meta_rules.rst new file mode 100644 index 0000000..677301f --- /dev/null +++ b/google-html-css-styleguide/css_meta_rules.rst @@ -0,0 +1,23 @@ +CSS元规则 +=========== + +分段规则 +---------- + +组的分段由一段注释完成(可选)。 + +尽可能地用注释来将css分段,段与段之间采用新行。 + +.. code-block:: css + + /* Header */ + + #adw-header {} + + /* Footer */ + + #adw-footer {} + + /* Gallery */ + + .adw-gallery {} diff --git a/google-html-css-styleguide/css_style_rules.rst b/google-html-css-styleguide/css_style_rules.rst new file mode 100644 index 0000000..ce4d275 --- /dev/null +++ b/google-html-css-styleguide/css_style_rules.rst @@ -0,0 +1,190 @@ +css样式规则 +================== + +CSS有效性 +---------- + +尽可能使用有效的CSS。 + +使用有效的CSS代码,除非在处理css验证器bug或者是专有的语法时。 + +使用诸如 `W3C CSS validator `_ 等工具验证测试。 + +使用有效的CSS代码是一个可衡量CSS代码质量的指标,可帮你找出不起作用可被删除的CSS代码,从而确保CSS的合理使用。 + +id与class的命名 +----------------- + +使用有意义的或者通用的id和class名称 + +用能反映出元素目的或者通用的id、class名称,代替那些很表象的、难懂的名称。 + +如果名称需要是易懂的,或不容易被修改,应该首选特定的或者能反映出元素目的的名称。 + +通用的名称适用于非特殊元素或与兄弟元素无区别的元素。他们常被称为“辅助元素”。 + +使用功能性或者通用的名称,可减少不必要的文档或者模板变化。 + +.. code-block:: css + + /* 不推荐:无意义 */ + #yee-1901 {} + + + /* 不推荐:表象 */ + .button-green {} + .clear {} + + /* 推荐:具体的 */ + #gallery {} + #login {} + .video {} + + /* 推荐:通用的 */ + .aux {} + .alt {} + +id与class的命名规范 +----------------------- + +ID和class命名要尽可能简短,但必要的话就别怕长。 + +尽可能简洁地传达id或者class名称的含义。 + +使用简洁的id或者class名称有助于提高可读性和代码效率。 + +.. code-block:: css + + /* 不推荐 */ + #navigation {} + .atr {} + + /* 推荐 */ + #nav {} + .author {} + +选择器的类型 +-------------- + +应当避免在id和class前添加类型选择器。 + +除了必要情况下(例如辅助的类),不要将元素与id或class名称结合做为选择器。 + +避免不必要的祖先选择器也是出于 `性能原因 `_ 的考虑。 + +.. code-block:: css + + /* 不推荐 */ + ul#example {} + div.error {} + + /* 推荐 */ + #example {} + .error {} + +简写属性 +------------ + +尽可能使用简写的属性书写方式。 + +CSS提供了多种属性 `简写 `_ 的方式(如 ``font`` ),即使只显式设置一个值,也应该尽可能地使用。 + +使用简写属性有助于提高代码效率及可读性。 + +.. code-block:: css + + /* 不推荐 */ + border-top-style: none; + font-family: palatino, georgia, serif; + font-size: 100%; + line-height: 1.6; + padding-bottom: 2em; + padding-left: 1em; + padding-right: 1em; + padding-top: 0; + + /* 推荐 */ + border-top: 0; + font: 100%/1.6 palatino, georgia, serif; + padding: 0 1em 2em; + + +0与单位 +---------- + +省略“0”后的单位。 + +除非必需,否则0后不要加单位。 + +.. code-block:: css + + margin: 0; + padding: 0; + +前导0 +----------- + +省略前导“0”值。 + +在-1至1之间的值无需保留整数位的0。 + +.. code-block:: css + + font-size: .8em; + + +十六进制表示法 +---------------- + +在可能的情况下使用3个字符的十六进制表示法。 + +对于可用3字符十六进制表示的颜色值,按此规则书写更短、更简洁。 + +.. code-block:: css + + /* 不推荐 */ + color: #eebbcc; + + /* 推荐 */ + color: #ebc; + + +前缀选择器 +------------ + +加特定应用前缀(可选) + +大型项目中以及嵌入在其它项目或外部网站上的代码需要给id和class添加前缀(命名空间)。使用短的、独特的标识符,并在其后跟一个破折号。 +使用命名空间有助于防止命名冲突,可以让维护变得简单,例如在搜索和替换操作时。 + +.. code-block:: css + + .adw-help {} /* AdWords */ + #maia-note {} /* Maia */ + + +id与class名称分隔符 +--------------------- + +用连字符分隔ID和类名中的单词。 + +选择器中的词语和缩写中不要使用除了连字符以外的任何字符(包括空字符),以提高可理解性和可读性。 + +.. code-block:: css + + /* 不推荐: 单词未分开 */ + .demoimage {} + + /* 不推荐:使用下划线而不是连字符 */ + .error_status {} + + /* 推荐 */ + #video-id {} + .ads-sample {} + +Hacks +------------ + +请先尝试其他的方法,避免用户代理检测以及CSS的“hacks”。 + +进行用户代理检测或使用特殊的CSS选择器及hacks看起来是处理样式差异的捷径。但为了实现和保持高效性以及代码的可维护性,这两种方案应该放到最后考虑。换句话说,用户代理检测和使用hacks会增大项目推进的阻力,所以从项目的长远利益考虑应尽力避免。一旦允许并无顾忌地使用用户代理检测和hacks便很容易滥用,最终一发而不可收。 diff --git a/google-html-css-styleguide/general_formatting_rules.rst b/google-html-css-styleguide/general_formatting_rules.rst new file mode 100644 index 0000000..7599cb7 --- /dev/null +++ b/google-html-css-styleguide/general_formatting_rules.rst @@ -0,0 +1,60 @@ +总体排版规则 +============== + +缩进 +--------- + +每次缩进使用两个空格。 + +不使用TAB键或者混合使用TAB键和空格进行缩进。 + +.. code-block:: html + +
    +
  • Fantastic +
  • Great +
+ +.. code-block:: css + + .example { + color: blue; + } + +大小写 +---------- + +只使用小写字母。 + +所有的代码都使用小写字母:适用于HTML元素、属性、属性值(除了text/CDATA)、CSS选择器、属性名以及属性值(字符串除外)。 + +.. code-block:: html + + + Home + + + Google + +.. code-block:: css + + /* 不推荐 */ + color: #E5E5E5; + + /* 推荐 */ + color: #e5e5e5; + +尾部的空格 +------------ + +删除尾部的空格。 + +尾部的空格是多余的,不删除则形成无意义的文件差异。 + +.. code-block:: html + + +

What?_ + + +

Yes please. diff --git a/google-html-css-styleguide/general_meta_rules.rst b/google-html-css-styleguide/general_meta_rules.rst new file mode 100644 index 0000000..c7373c2 --- /dev/null +++ b/google-html-css-styleguide/general_meta_rules.rst @@ -0,0 +1,44 @@ +整体的元数据规则 +=================== + +编码 +--------- + +使用UTF-8无BOM编码。 + +让你的编辑器使用无字节顺序标记的UTF-8编码。 + +在HTML模板和文档中使用 ```` 指定编码。不需要为样式表指定编码,它默认是UTF-8。 + +(想了解更多关于应该何时并如何指定编码,请查看 `Handling character encodings in HTML and CSS `_) + +注释 +-------- + +在需要时尽可能去解释你的代码。 + +用注释去解释你的代码,包括它的应用范围、用途、此方案的选择理由等。 + +(这一条是可选的,没必要为每个文件写上详细的注释,会增重HTML/CSS的代码,主要取决于项目的复杂度。) + +处理内容 +---------- + +用TODO标记待办事宜和处理内容。 + +只用TODO来标记待办事宜,不要使用其他格式,例如@@。 + +在括号里添加联系方式(姓名或邮箱),格式为TODO(联系方式)。 + +在冒号后面添加处理内容,格式为TODO:处理内容。 + +.. code-block:: html + + {# TODO(john.doe): 重新处理水平居中 #} +

Test
+ + +
    +
  • Apples
  • +
  • Oranges
  • +
diff --git a/google-html-css-styleguide/general_style_rules.rst b/google-html-css-styleguide/general_style_rules.rst new file mode 100644 index 0000000..9e919d1 --- /dev/null +++ b/google-html-css-styleguide/general_style_rules.rst @@ -0,0 +1,31 @@ +整体样式规则 +================ + +协议 +--------------- + +嵌入式资源省略协议头。 + +省略图片、媒体文件、样式表以及脚本的URL协议头部分(http:、https:),不使用这两个协议的文件则不省略。 +省略协议头,即让URL变成相对地址,可以避免协议混合及小文件重复下载。 + +.. code-block:: html + + + + + + + +.. code-block:: css + + /* 不推荐 */ + .example { + background: url(http://www.google.com/images/example); + } + + /* 推荐 */ + .example { + background: url(//www.google.com/images/example); + } + diff --git a/google-html-css-styleguide/html_formatting_rules.rst b/google-html-css-styleguide/html_formatting_rules.rst new file mode 100644 index 0000000..3563363 --- /dev/null +++ b/google-html-css-styleguide/html_formatting_rules.rst @@ -0,0 +1,51 @@ +HTML格式规则 +============== + +常规格式化 +------------ + +对每个块、列表、表格元素都另起一行,每个子元素都缩进。 + +每个块元素、列表元素或表格元素另起一行,而不必考虑元素的样式(因CSS可以改变元素的 ``display`` 属性)。 + +同样的,如果他们是块、列表或者表格元素的子元素,则将之缩进。 + +(如果你遇到列表项之间有空白的问题,可以把所有 ``li`` 元素放到一行。Linter鼓励抛出警告而不是错误。) + +.. code-block:: html + +
+

Space, the final frontier.

+
+ +
    +
  • Moe +
  • Larry +
  • Curly +
+ + + + + + +
Income + Taxes +
$ 5.00 + $ 4.50 +
+ +HTML引号 +----------- + +当引用属性值时,使用双引号。 + +使用双引号而不是单引号来包裹属性值。 + +.. code-block:: html + + + Sign in + + + Sign in diff --git a/google-html-css-styleguide/html_style_rules.rst b/google-html-css-styleguide/html_style_rules.rst new file mode 100644 index 0000000..bb4d78e --- /dev/null +++ b/google-html-css-styleguide/html_style_rules.rst @@ -0,0 +1,174 @@ +HTML样式规则 +============== + +文档类型 +--------- + +使用HTML5。 + +HTML5(HTML语法)是所有HTML文档的首选: ```` 。 + +(推荐使用HTML,即text/html。不要使用XHTML。XHTML,即 `application/xhtml+xml `_,缺乏浏览器和基础结构的支持,并且优化的空间比HTML小。) +虽然HTML闭合标签没有问题,但是不要自闭合空标签。即写 ``
`` 而不是 ``
`` 。 + + +HTML合法性 +------------ + +在可能的情况下使用合法的HTML。 + +使用合法的HTML代码,除非由于文件大小导致的不可达到的性能目标而不能使用。 + +利用已用工具对合法性进行测试,例如 `W3C HTML validator `_。 + +使用合法的HTML是一个可度量的基准质量属性,该属性有助于了解技术需求和约束,从而确保合理的HTML使用。 + +.. code-block:: html + + + Test +
This is only a test. + + + + + Test +
This is only a test.
+ +语义化 +-------- + +根据HTML的目的使用它。 + +根据元素(有时被错误的叫做“标签”)被创造的用途使用他们。比如,对标题使用标题元素,对段落使用 ``p`` 元素,对锚点使用 ``a`` 元素等。 + +语义化的使用HTML对于可访问性、复用性和代码的高效性等因素非常重要。 + +.. code-block:: html + + +
All recommendations
+ + + All recommendations + +多媒体降级 +------------ + +为多媒体提供替代内容。 + +对于图片、视频、通过 ``canvas`` 实现的动画等多媒体来说,确保提供可访问的替代内容。对于图片,可提供有意义的替代文本( ``alt`` );对于视频和音频,如有条件可提供对白和字幕。 + +提供替代内容对辅助功能很重要:没有 ``alt`` ,一位盲人用户很难知道一张图片的内容,其他用户可能不能了解视频和音频的内容。 +(对于 ``alt`` 属性会引起冗余的图片和你不打算添加CSS的纯粹装饰性的图片,不用添加替代文本,写成 ``alt=""`` 即可。) + +.. code-block:: html + + + + + + Spreadsheet screenshot. + +关注点分离 +----------- + +将结构、表现、行为分离。 + +严格保持结构(标识),表现(样式),行为(脚本)分离,尽量使三者之间的相互影响最小。 + +就是说,确保文档和模板只包含HTML,并且HTML只用来表现结构。把任何表现性的东西都移到样式表,任何行为性的东西都移到脚本中。 + +此外,尽可能少的从文档和模板中引用样式表和脚本来减少三者的相互影响。 + +结构、表现、行为分离对维护非常重要。更改HTML文档和模板总是比更新样式表和脚本成本更高。 + +.. code-block:: html + + + + HTML sucks + + + +

HTML sucks

+

I’ve read about this on a few sites but now I’m sure: + HTML is stupid!!1 +

I can’t believe there’s no way to control the styling of + my website without doing everything all over again!
+ + + + My first CSS-only redesign + +

My first CSS-only redesign

+

I’ve read about this on a few sites but today I’m actually + doing it: separating concerns and avoiding anything in the HTML of + my website that is presentational. +

It’s awesome! + +实体引用 +----------- + +不要使用实体引用。 + +假设文件、编辑器和团队之间使用相同的编码(UTF-8),则没有必要使用例如 ``—`` 、 ``”`` 或 ``☺`` 这样的实体引用。 + +唯一的例外适用于HTML中具有特殊意义的字符(比如<和&),和控制或者隐藏的字符(比如不换行空格)。 + +.. code-block:: html + + + The currency symbol for the Euro is “&eur;”. + + + The currency symbol for the Euro is "€". + +可选的标签 +------------ + +省略可选的标签(可选)。 + +为了优化文件大小和可扫描,考虑省略可选标签。 `HTML5规范 `_ 定义了哪些标签可以被省略。 + +(这种方法可能要求一段宽限期去建立一个更加广泛的准则,因为它和Web开发人员通常所了解的有着显著不同。考虑到一致性和简单性,最好省略所有可选标签。) + +.. code-block:: html + + + + + + Spending money, spending bytes + + +

Sic.

+ + + + + + Saving money, saving bytes +

Qed. + +type属性 +--------- + +为样式表和脚本省略 ``type`` 属性。 + +引用样式表(除非不是使用CSS)和脚本(除非不是使用JavaScript)不要使用type属性。 + +HTML5将 `text/css `_ 和 `text/javascript `_ 设置为默认值,在这种情况下指定type属性并不必要。甚至同样兼容老版本的浏览器。 + +.. code-block:: html + + + + + + + + + + + diff --git a/google-html-css-styleguide/parting_words.rst b/google-html-css-styleguide/parting_words.rst new file mode 100644 index 0000000..b7bcbd1 --- /dev/null +++ b/google-html-css-styleguide/parting_words.rst @@ -0,0 +1,8 @@ +赠言 +======== + +请与周围保持一致。 + +如果你正在编辑代码,花几分钟时间看看上下文代码的格式,确定他们的编码风格。如果在上下文代码中,算术运算符前后有空格,或注释前后添加了“#”,你也应该这样做。 + +编写这个风格指导的目标是让人们可以专注于“我们在讨论什么”而不是“我们该怎么描述”。我们提供了一些通用的编码规范,大家就可以基于这些规范而继续,但特定情况下的规范也同样重要。如果你在一个文件中添加的代码看上去跟其他代码明显不同,你就把阅读此文件的人的节奏打乱了。避免这种情况出现。 diff --git a/google-javascript-styleguide/background.rst b/google-javascript-styleguide/background.rst new file mode 100644 index 0000000..4f3e7c1 --- /dev/null +++ b/google-javascript-styleguide/background.rst @@ -0,0 +1,4 @@ +背景 +============== + +在Google的开源项目中,JavaScript是最主要的客户端脚本语言。本指南是使用JavaScript时建议和不建议做法的清单。 diff --git a/google-javascript-styleguide/javascript_language_rules.rst b/google-javascript-styleguide/javascript_language_rules.rst new file mode 100644 index 0000000..92675fd --- /dev/null +++ b/google-javascript-styleguide/javascript_language_rules.rst @@ -0,0 +1,538 @@ +Javascript语言规则 +========== + +var关键字 +---------------- + +总是用 ``var`` 关键字定义变量。 + +描述 +~~~~~~ + +如果不显式使用 ``var`` 关键字定义变量,变量会进入到全局上下文中,可能会和已有的变量发生冲突。另外,如果不使用var声明,很难说变量存在的作用域是哪个(可能在局部作用域里,也可能在document或者window上)。所以,要一直使用 ``var`` 关键字定义变量。 + +常量 +---------------- + +* 使用字母全部大写(如 ``NAMES_LIKE_THIS`` )的方式命名 + +* 可以使用 ``@const`` 来标记一个常量 *指针* (指向变量或属性,自身不可变) + +* 由于IE的兼容问题,不要使用 `const关键字 `_ + +描述 +~~~~~~ + +常量值 +######## + +如果一个值是恒定的,它命名中的字母要全部大写(如 ``CONSTANT_VALUE_CASE`` )。字母全部大写意味着这个值不可以被改写。 + +原始类型( ``number`` 、 ``string`` 、 ``boolean`` )是常量值。 + +对象的表现会更主观一些,当它们没有暴露出变化的时候,应该认为它们是常量。但是这个不是由编译器决定的。 + +常量指针(变量和属性) +######################## + +用 ``@const`` 注释的变量和属性意味着它是不能更改的。使用const关键字可以保证在编译的时候保持一致。使用 `const `_ 效果相同,但是由于IE的兼容问题,我们不使用const关键字。 + +另外,不应该修改用 ``@const`` 注释的方法。 + +例子 +######## + +注意, ``@const`` 不一定是常量值,但命名类似 ``CONSTANT_VALUE_CASE`` 的 *一定* 是常量指针。 + +:: + + /** + * 以毫秒为单位的超时时长 + * @type {number} + */ + goog.example.TIMEOUT_IN_MILLISECONDS = 60; + +1分钟60秒永远也不会改变,这是个常量。全部大写的命名意味其为常量值,所以它不能被重写。 +开源的编译器允许这个符号被重写,这是因为 *没有* ``@const`` 标记。 + +:: + + /** + * Map of URL to response string. + * @const + */ + MyClass.fetchedUrlCache_ = new goog.structs.Map(); + +在这个例子中,指针没有变过,但是值却是可以变化的,所以这里用了驼峰式的命名,而不是全部大写的命名。 + +分号 +--------- + +一定要使用分号。 + +依靠语句间隐式的分割,可能会造成细微的调试的问题,千万不要这样做。 + +很多时候不写分号是很危险的: + +:: + + // 1. + MyClass.prototype.myMethod = function() { + return 42; + } // 这里没有分号. + + (function() { + // 一些局部作用域中的初始化代码 + })(); + + var x = { + 'i': 1, + 'j': 2 + } //没有分号. + + // 2. 试着在IE和firefox下做一样的事情. + //没人会这样写代码,别管他. + [normalVersion, ffVersion][isIE](); + + var THINGS_TO_EAT = [apples, oysters, sprayOnCheese] //这里没有分号 + + // 3. 条件语句 + -1 == resultOfOperation() || die(); + +发生了什么? +~~~~~~~~~~~~~ + +1. js错误。返回42的函数运行了,因为后面有一对括号,而且传入的参数是一个方法,然后返回的42被调用,导致出错了。 + +2. 你可能会得到一个“no sush property in undefined”的错误,因为在执行的时候,解释器将会尝试执行 ``x[normalVersion, ffVersion][isIE]()`` 这个方法。 + +3. ``die`` 这个方法只有在 ``resultOfOperation()`` 是 ``NaN`` 的时候执行,并且 ``THINGS_TO_EAT`` 将会被赋值为 ``die()`` 的结果。 + +为什么? +~~~~~~~~~~~~ + +js语句要求以分号结尾,除非能够正确地推断分号的位置。在这个例子当中,函数声明、对象和数组字面量被写在了一个语句当中。右括号(")"、"}"、"]")不足以证明这条语句已经结束了,如果下一个字符是运算符或者"("、"{"、"[",js将不会结束语句。 + +这个错误让人震惊,所以一定要确保用分号结束语句。 + +澄清:分号和函数 +~~~~~~~~~~~~~~ + +函数表达式后面要分号结束,但是函数声明就不需要。例如: + +:: + + var foo = function() { + return true; + }; // 这里要分号 + + function foo() { + return true; + } // 这里不用分号 + +嵌套函数 +----------------- + +可以使用。 + +嵌套函数非常有用,比如在创建持续任务或者隐藏工具方法的时候。可以放心的使用。 + +块内函数声明 +--------------------------- + +不要使用块内函数声明。 + +不要这样做: + +:: + + if (x) { + function foo() {} + } + +虽然大多数脚本引擎支持功能区块内声明,但ECMAScript并未认可(见 `ECMA-262 `_ ,第13条和第14)。若与他人的及EcmaScript所建议的不一致,即可视为不好的实现方式。ECMAScript只允许函数声明语句列表, 在根语句列表脚本或者函数。相反,使用一个变量初始化函数表达式在块内定义一个函数块: + +:: + + if (x) { + var foo = function() {} + } + +异常 +------- + +可以抛出异常。 + +如果你做一些比较复杂的项目你基本上无法避免异常,比如使用一个应用程序开发框架。可以大胆试一试。 + +自定义异常 +---------- + +可以自定义异常。 + +如果没有自定义异常,返回的错误信息来自一个有返回值的函数是难处理的,是不雅的。坏的解决方案包括传递引用的类型来保存错误信息或总是返回有一个潜在的错误成员的对象。这些基本上为原始的异常处理hack。在适当的时候使用自定义的异常。 + +标准功能 +---------- + +总是优先于非标准功能。 + +为了最大的可移植性和兼容性,总是使用标准功能而不是非标准功能(例如,采用 `string.charAt(3)` 而非 `string[3]` ,用DOM的功能访问元素而不是使用特定于一个具体应用的简写)。 + +原始类型的包装对象 +------------------ + +没有理由使用原始类型的包装对象,更何况他们是危险的: + +:: + + var x = new Boolean(false); + if (x) { + alert('hi'); //显示“hi”。 + } + +不要这样做! + +然而类型转换是可以的。 + +:: + + var x = Boolean(0); + if (x) { + alert('hi'); //永远都不显示。 + } + typeof Boolean(0) == 'boolean'; + typeof new Boolean(0) == 'object'; + +这是非常有用的进行数字、字符串和布尔值转换的方式。 + +多重的原型继承 +------------------- + +不可取。 + +多重原型继承是Javascript实现继承的方式。如果你有一个以用户定义的class B作为原型的用户自定义class D,则得到多重原型继承。这样的继承出现容易但难以正确创造! + +出于这个原因,最好是使用 `Closure库 `_ 中的 ``goog.inherits()`` 或类似的东西。 + +:: + + function D() { + goog.base(this) + } + goog.inherits( D, B ); + + D.prototype.method =function() { + ... + }; + +方法和属性定义 +------------------------- + +``/**构造函数*/ function SomeConstructor() { this.someProperty = 1; } Foo.prototype.someMethod = function() { ... };`` + +虽然有多种使用“new”关键词来创建对象方法和属性的途径,首选的创建方法的途径是: + +:: + + Foo.prototype.bar = function() { + /* ... */ + }; + +其他特性的首选创建方式是在构造函数中初始化字段: + +:: + + /** @constructor */ + function Foo() { + this.bar = value; + } + +为什么? +~~~~~~~~~~ + +当前的JavaScript引擎优化基于一个对象的“形状”, `给对象添加一个属性(包括覆盖原型设置的值)改变了形式,会降低性能 `_ 。 + +删除 +---------- + +请使用 ``this.foo = null`` 。 + +:: + + o.prototype.dispose = function() { + this.property_ = null; + }; + +而不是: + +:: + + Foo.prototype.dispose = function() { + delete his.property_; + }; + +在现代的JavaScript引擎中,改变一个对象属性的数量比重新分配值慢得多。应该避免删除关键字,除非有必要从一个对象的迭代的关键字列表删除一个属性,或改变 ``if (key in obj)`` 结果。 + +闭包 +------------- + +可以使用,但是要小心。 + +创建闭包可能是JS最有用的和经常被忽视的功能。在 `这里 `_ 很好地描述说明了闭包的工作。 + +要记住的一件事情,一个闭包的指针指向包含它的范围。因此,附加一个闭包的DOM元素,可以创建一个循环引用,所以,内存会泄漏。例如,下面的代码: + +:: + + function foo(element, a, b) { + element.onclick = function() { /* 使用 a 和 b */ }; + } + +闭包能保持元素a和b的引用即使它从未使用。因为元素还保持对闭包的一个引用,我们有一个循环引用,不会被垃圾收集清理。在这些情况下,代码的结构可以如下: + +:: + + function foo(element, a, b) { + element.onclick = bar(a, b); + } + + function bar(a, b) { + return function() { /* 使用 a 和 b */ } + } + +eval()函数 +------------------------ + +只用于反序列化(如评估RPC响应)。 + +若用于 ``eval()`` 的字符串含有用户输入,则 ``eval()`` 会造成混乱的语义,使用它有风险。通常有一个更好 +更清晰、更安全的方式来编写你的代码,所以一般是不会允许其使用的。然而,eval相对比非eval使反序列化更容易,因此它的使用是可以接受的(例如评估RPC响应)。 + +反序列化是将一系列字节存到内存中的数据结构转化过程。例如,你可能会写的对象是: + +:: + + users = [ + { + name: 'Eric', + id: 37824, + email: 'jellyvore@myway.com' + }, + { + name: 'xtof', + id: 31337, + email: 'b4d455h4x0r@google.com' + }, + ... + ]; + +将这些数据读入内存跟得出文件的字符串表示形式一样容易。 + +同样, ``eval()`` 函数可以简化解码RPC的返回值。例如,您可以使用 ``XMLHttpRequest`` 生成RPC,在响应时服务器返回JavaScript: + +:: + + var userOnline = false; + var user = 'nusrat'; + var xmlhttp = new XMLHttpRequest(); + xmlhttp.open('GET', 'http://chat.google.com/isUserOnline?user=' + user, false); + xmlhttp.send(''); + // 服务器返回: + // userOnline = true; + if (xmlhttp.status == 200) { + eval(xmlhttp.responseText); + } + // userOnline 现在为 true + +with() {} +---------------------- + +不建议使用。 + +使用 ``with`` 会影响程序的语义。因为 ``with`` 的目标对象可能会含有和局部变量冲突的属性,使你程序的语义发生很大的变化。例如,这是做什么用? + +:: + + with (foo) { + var x = 3; + return x; + } + +答案:什么都有可能。局部变量 ``x`` 可能会被 ``foo`` 的一个属性覆盖,它甚至可能有setter方法,在此情况下将其赋值为3可能会执行很多其他代码。不要使用 ``with`` 。 + +this +------------------- + +只在构造函数对象、方法,和创建闭包的时候使用。 + +``this`` 的语义可能会非常诡异。有时它指向全局对象(很多时候)、调用者的作用域链(在 ``eval`` 里)、DOM树的一个节点(当使用HTML属性来做为事件句柄时)、新创建的对象(在一个构造函数中)、或者其他的对象(如果函数被 ``call()`` 或 ``apply()`` 方式调用)。 + +正因为 ``this`` 很容易被弄错,故将其使用限制在以下必须的地方: + +* 在构造函数中 + +* 在对象的方法中(包括闭包的创建) + +for-in 循环 +------------------ + +只使用在对象、映射、哈希的键值迭代中。 + +``for-in`` 循环经常被不正确的用在元素数组的循环中。由于并不是从 ``0`` 到 ``length-1`` 进行循环,而是遍历对象中和它原型链上的所有的键,所以很容易出错。这里有一些失败的例子: + +:: + + function printArray(arr) { + for (var key in arr) { + print(arr[key]); + } + } + + printArray([0,1,2,3]); //这样可以 + + var a = new Array(10); + printArray(a); //这样不行 + + a = document.getElementsByTagName('*'); + printArray(a); //这样不行 + + a = [0,1,2,3]; + a.buhu = 'wine'; + printArray(a); //这样不行 + + a = new Array; + a[3] = 3; + printArray(a); //这样不行 + +在数组循环时常用的一般方式: + +:: + + function printArray(arr) { + var l = arr.length; + for (var i = 0; i < l; i++) { + print(arr[i]); + } + } + +关联数组 +----------------------- + +不要将映射,哈希,关联数组当作一般数组来使用。 + +不允许使用关联数组……确切的说在数组,你不可以使用非数字的索引。如果你需要一个映射或者哈希,在这种情况下你应该使用对象来代替数组,因为在功能上你真正需要的是对象的特性而不是数组的。 + +数组仅仅是用来拓展对象的(像在JS中你曾经使用过的 ``Date`` 、 ``RegExp`` 和 ``String`` 对象一样的)。 + +多行的字符串字面量 +------------------------------------ + +不要使用。 + +不要这样做: + +:: + + var myString = 'A rather long string of English text, an error message \ + actually that just keeps going and going -- an error \ + message to make the Energizer bunny blush (right through \ + those Schwarzenegger shades)! Where was I? Oh yes, \ + you\'ve got an error and all the extraneous whitespace is \ + just gravy. Have a nice day.'; + +在编译时每一行头部的空白符不会被安全地去除掉;斜线后的空格也会导致棘手的问题;虽然大部分脚本引擎都会支持,但是它不是ECMAScript规范的一部分。 + +使用字符串连接来代替: + +:: + + var myString = 'A rather long string of English text, an error message ' + + 'actually that just keeps going and going -- an error ' + + 'message to make the Energizer bunny blush (right through ' + + 'those Schwarzenegger shades)! Where was I? Oh yes, ' + + 'you\'ve got an error and all the extraneous whitespace is ' + + 'just gravy. Have a nice day.'; + +数组和对象字面量 +---------------------------------- + +建议使用。 + +使用数组和对象字面量来代替数组和对象构造函数。 + +数组构造函数容易在参数上出错。 + +:: + + // 长度为3 + var a1 = new Array(x1, x2, x3); + + // 长度为 2 + var a2 = new Array(x1, x2); + + // If x1 is a number and it is a natural number the length will be x1. + // If x1 is a number but not a natural number this will throw an exception. + // Otherwise the array will have one element with x1 as its value. + var a3 = new Array(x1); + + // 长度为0 + var a4 = new Array(); + +由此,如果有人将代码从2个参数变成了一个参数,那么这个数组就会有一个错误的长度。 + +为了避免这种怪异的情况,永远使用可读性更好的数组字面量。 + +:: + + var a = [x1, x2, x3]; + var a2 = [x1, x2]; + var a3 = [x1]; + var a4 = []; + +对象构造函数虽然没有相同的问题,但是对于可读性和一致性,还是应该使用对象字面量。 + +:: + + var o = new Object(); + + var o2 = new Object(); + o2.a = 0; + o2.b = 1; + o2.c = 2; + o2['strange key'] = 3; + +应该写成: + +:: + + var o = {}; + + var o2 = { + a: 0, + b: 1, + c: 2, + 'strange key': 3 + }; + +修改内置对象原型 +-------------------------------- + +不建议。 + +强烈禁止修改如 ``Object.prototype`` 和 ``Array.prototype`` 等对象的原型。修改其他内置原型如 ``Function.prototype`` 危险性较小,但在生产环境中还是会引发一些难以调试的问题,也应当避免。 + +Internet Explorer中的条件注释 +---------------------------------------------------------- + +不要使用。 + +不要这样做: + +:: + + var f = function () { + /*@cc_on if (@_jscript) { return 2* @*/ 3; /*@ } @*/ + }; + +条件注释会在运行时改变JavaScript语法树,阻碍自动化工具。 diff --git a/google-javascript-styleguide/javascript_style_rules.rst b/google-javascript-styleguide/javascript_style_rules.rst new file mode 100644 index 0000000..16bb359 --- /dev/null +++ b/google-javascript-styleguide/javascript_style_rules.rst @@ -0,0 +1,2065 @@ +Javascript格式规则 +================== + +命名 +-------------- + +通常来说,使用 ``functionNamesLikeThis`` , ``variableNamesLikeThis`` , ``ClassNamesLikeThis`` , ``EnumNamesLikeThis`` , ``methodNamesLikeThis`` , ``CONSTANT_VALUES_LIKE_THIS`` , ``foo.namespaceNamesLikeThis.bar`` 和 ``ilenameslikethis.js`` 这种格式的命名方式。 + +属性和方法 +~~~~~~~~~~~~~~ + +* *私有* 属性和方法应该以下划线开头命名。 + +* *保护* 属性和方法应该以无下划线开头命名(像公共属性和方法一样)。 + +了解更多关于私有成员和保护成员的信息,请阅读 `可见性 `_ 部分。 + +方法和函数参数 +~~~~~~~~~~~~~~~~~ + +可选函数参数以 ``opt_`` 开头。 + +参数数目可变的函数应该具有以 ``var_args`` 命名的最后一个参数。你可能不会在代码里引用 ``var_args`` ;使用 ``arguments`` 对象。 + +可选参数和数目可变的参数也可以在注释 ``@param`` 中指定。尽管这两种惯例都被编译器接受,但更加推荐两者一起使用。 + +getter和setter +~~~~~~~~~~~~~~~~~ + +EcmaScript 5 不鼓励使用属性的getter和setter。然而,如果使用它们,那么getter就不要改变属性的可见状态。 + +:: + + /** + *错误--不要这样做. + */ + var foo = { get next() { return this.nextId++; } }; + }; + +存取函数 +~~~~~~~~ + +属性的getter和setter方法不是必需的。然而,如果使用它们,那么读取方法必须以 ``getFoo()`` 命名,并且写入方法必须以 ``setFoo(value)`` 命名。(对于布尔型的读取方法,也可以使用 ``isFoo()`` ,并且这样往往听起来更自然。) + +命名空间 +~~~~~~~~ + +JavaScript没有原生的对封装和命名空间的支持。 + +全局命名冲突难以调试,并且当两个项目尝试整合的时候可能引起棘手的问题。为了能共享共用的JavaScript代码,我们采用一些约定来避免冲突。 + +为全局代码使用命名空间 +######################### + +在全局范围内 *总是* 使用唯一的项目或库相关的伪命名空间进行前缀标识。如果你正在进行“Project Sloth”项目,一个合理的伪命名空间为 ``sloth.*`` 。 + +:: + + var sloth = {}; + + sloth.sleep = function() { + ... + }; + +很多JavaScript库,包括 `the Closure Library `_ 和 `Dojo toolkit `_ 给你高级功能来声明命名空间。保持你的命名空间声明一致。 + +:: + + goog.provide('sloth'); + + sloth.sleep = function() { + ... + }; + +尊重命名空间所有权 +##################### + +当选择一个子命名空间的时候,确保父命名空间知道你在做什么。如果你开始了一个为sloths创建hats的项目,确保Sloth这一组命名空间知道你在使用 ``sloth.hats`` 。 + +外部代码和内部代码使用不同的命名空间 +######################################## + +“外部代码”指的是来自你的代码库外并独立编译的代码。内部名称和外部名称应该严格区分开。如果你正在使用一个能调用 ``foo.hats.*`` 中的东西的外部库,你的内部代码不应该定义 ``foo.hats.*`` 中的所有符号,因为如果其他团队定义新符号就会把它打破。 + +:: + + foo.require('foo.hats'); + /** + *错误--不要这样做。 + * @constructor + * @extends {foo.hats.RoundHat} + */ + foo.hats.BowlerHat = function() { + }; + +如果你在外部命名空间中需要定义新的API,那么你应该明确地导出且仅导出公共的API函数。为了一致性和编译器更好的优化你的内部代码,你的内部代码应该使用内部API的内部名称调用它们。 + +:: + + foo.provide('googleyhats.BowlerHat'); + + foo.require('foo.hats'); + /** + * @constructor + * @extends {foo.hats.RoundHat} + */ + googleyhats.BowlerHat = function() { + ... + }; + goog.exportSymbol('foo.hats.BowlerHat', googleyhats.BowlerHat); + +为长类型的名称提供别名提高可读性 +################################### + +如果对完全合格的类型使用本地别名可以提高可读性,那么就这样做。本地别名的名称应该符合类型的最后一部分。 + +:: + + /** + * @constructor + */ + some.long.namespace.MyClass = function() { + }; + + /** + * @param {some.long.namespace.MyClass} a + */ + some.long.namespace.MyClass.staticHelper = function(a) { + ... + }; + + myapp.main = function() { + var MyClass = some.long.namespace.MyClass; + var staticHelper = some.long.namespace.MyClass.staticHelper; + staticHelper(new MyClass()); + }; + +不要为命名空间起本地别名。命名空间应该只能使用 `goog.scope `_ 命名别名。 + +:: + + myapp.main = function() { + var namespace = some.long.namespace; + namespace.MyClass.staticHelper(new namespace.MyClass()); + }; + +避免访问一个别名类型的属性,除非它是一个枚举。 + +:: + + /** @enum {string} */ + some.long.namespace.Fruit = { + APPLE: 'a', + BANANA: 'b' + }; + + myapp.main = function() { + var Fruit = some.long.namespace.Fruit; + switch (fruit) { + case Fruit.APPLE: + ... + case Fruit.BANANA: + ... + } + }; + +:: + + myapp.main = function() { + var MyClass = some.long.namespace.MyClass; + MyClass.staticHelper(null); + }; + +永远不要在全局环境中创建别名。只在函数体内使用它们。 + +文件名 +~~~~~~~~~ + +为了避免在大小写敏感的平台上引起混淆,文件名应该小写。文件名应该以 ``.js`` 结尾,并且应该不包含除了 ``-`` 或 ``_`` (相比较 ``_`` 更推荐 ``-`` )以外的其它标点。 + +自定义 toString() 方法 +------------------------ + +必须确保无误,并且无其他副作用。 + +你可以通过自定义 ``toString()`` 方法来控制对象如何字符串化他们自己。这没问题,但是你必须确保你的方法执行无误,并且无其他副作用。如果你的方法没有达到这个要求,就会很容易产生严重的问题。比如,如果 ``toString()`` 方法调用一个方法产生一个断言,断言可能要输出对象的名称,就又需要调用 ``toString()`` 方法。 + +延时初始化 +-------------- + +可以使用。 + +并不总在变量声明的地方就进行变量初始化,所以延时初始化是可行的。 + +明确作用域 +-------------- + +时常。 + +经常使用明确的作用域加强可移植性和清晰度。例如,在作用域链中不要依赖 ``window`` 。你可能想在其他应用中使用你的函数,这时此 ``window`` 就非彼 ``window`` 了。 + +代码格式 +---------- + +我们原则上遵循 `C++格式规范 `_ ,并且进行以下额外的说明。 + +大括号 +~~~~~~~~ + +由于隐含分号的插入,无论大括号括起来的是什么,总是在同一行上开始你的大括号。例如: + +:: + + if (something) { + // ... + } else { + // … + } + +数组和对象初始化表达式 +~~~~~~~~~~~~~~~~~~~~~~~~~ + +当单行数组和对象初始化表达式可以在一行写开时,写成单行是允许的。 + +:: + + var arr = [1, 2, 3]; //之后无空格[或之前] + var obj = {a: 1, b: 2, c: 3}; //之后无空格[或之前] + +多行数组和对象初始化表达式缩进两个空格,括号的处理就像块一样单独成行。 + +:: + + //对象初始化表达式 + var inset = { + top: 10, + right: 20, + bottom: 15, + left: 12 + }; + + //数组初始化表达式 + this.rows_ = [ + '"Slartibartfast" ', + '"Zaphod Beeblebrox" ', + '"Ford Prefect" ', + '"Arthur Dent" ', + '"Marvin the Paranoid Android" ', + 'the.mice@magrathea.com' + ]; + + //在方法调用中使用 + goog.dom.createDom(goog.dom.TagName.DIV, { + id: 'foo', + className: 'some-css-class', + style: 'display:none' + }, 'Hello, world!'); + +长标识符或值在对齐的初始化列表中存在问题,所以初始化值不必对齐。例如: + +:: + + CORRECT_Object.prototype = { + a: 0, + b: 1, + lengthyName: 2 + }; + +不要像这样: + +:: + + WRONG_Object.prototype = { + a : 0, + b : 1, + lengthyName: 2 + }; + +函数参数 +~~~~~~~~~ + +如果可能,应该在同一行上列出所有函数参数。如果这样做将超出每行80个字符的限制,参数必须以一种可读性较好的方式进行换行。为了节省空间,在每一行你可以尽可能的接近80个字符,或者把每一个参数单独放在一行以提高可读性。缩进可能是四个空格,或者和括号对齐。下面是最常见的参数换行形式: + +:: + + // 四个空格,每行包括80个字符。适用于非常长的函数名, + // 重命名不需要重新缩进,占用空间小。 + goog.foo.bar.doThingThatIsVeryDifficultToExplain = function( + veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) { + // ... + }; + + //四个空格,每行一个参数。适用于长函数名, + // 允许重命名,并且强调每一个参数。 + goog.foo.bar.doThingThatIsVeryDifficultToExplain = function( + veryDescriptiveArgumentNumberOne, + veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, + artichokeDescriptorAdapterIterator) { + // ... + }; + + // 缩进和括号对齐,每行80字符。 看上去是分组的参数, + // 占用空间小。 + function foo(veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) { + // ... + } + + // 和括号对齐,每行一个参数。看上去是分组的并且 + // 强调每个单独的参数。 + function bar(veryDescriptiveArgumentNumberOne, + veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, + artichokeDescriptorAdapterIterator) { + // ... + } + +当函数调用本身缩进,你可以自由地开始相对于原始声明的开头或者相对于当前函数调用的开头,进行4个空格的缩进。以下都是可接受的缩进风格。 + +:: + + if (veryLongFunctionNameA( + veryLongArgumentName) || + veryLongFunctionNameB( + veryLongArgumentName)) { + veryLongFunctionNameC(veryLongFunctionNameD( + veryLongFunctioNameE( + veryLongFunctionNameF))); + } + +匿名函数传递 +~~~~~~~~~~~~~~ + +当在一个函数的参数列表中声明一个匿名函数时,函数体应该与声明的左边缘缩进两个空格,或者与function关键字的左边缘缩进两个空格。这是为了匿名函数体更加可读(即不被挤在屏幕的右侧)。 + +:: + + prefix.something.reallyLongFunctionName('whatever', function(a1, a2) { + if (a1.equals(a2)) { + someOtherLongFunctionName(a1); + } else { + andNowForSomethingCompletelyDifferent(a2.parrot); + } + }); + + var names = prefix.something.myExcellentMapFunction( + verboselyNamedCollectionOfItems, + function(item) { + return item.name; + }); + +使用goog.scope命名别名 +~~~~~~~~~~~~~~~~~~~~~~~ + +`goog.scope `_ 可用于在使用 `the Closure Library `_ 的工程中缩短命名空间的符号引用。 + +每个文件只能添加一个 ``goog.scope`` 调用。始终将它放在全局范围内。 + +开放的 ``goog.scope(function() {`` 调用必须在之前有一个空行,并且紧跟 ``goog.provide`` 声明、 ``goog.require`` 声明或者顶层的注释。调用必须在文件的最后一行闭合。在scope声明闭合处追加 ``// goog.scope`` 。注释与分号间隔两个空格。 + +和C++命名空间相似,不要在 ``goog.scope`` 声明下面缩进。相反,从第0列开始。 + +只取不会重新分配给另一个对象(例如大多数的构造函数、枚举和命名空间)的别名。不要这样做: + +:: + + goog.scope(function() { + var Button = goog.ui.Button; + + Button = function() { ... }; + ... + +别名必须和全局中的命名的最后一个属性相同。 + +:: + + goog.provide('my.module'); + + goog.require('goog.dom'); + goog.require('goog.ui.Button'); + + goog.scope(function() { + var Button = goog.ui.Button; + var dom = goog.dom; + + // Alias new types after the constructor declaration. + my.module.SomeType = function() { ... }; + var SomeType = my.module.SomeType; + + // Declare methods on the prototype as usual: + SomeType.prototype.findButton = function() { + // Button as aliased above. + this.button = new Button(dom.getElement('my-button')); + }; + ... + }); // goog.scope + +更多的缩进 +~~~~~~~~~~~~ + +事实上,除了 `初始化数组和对象 `_ 和传递匿名函数外,所有被拆开的多行文本应与之前的表达式左对齐,或者以4个(而不是2个)空格作为一缩进层次。 + +:: + + someWonderfulHtml = '' + + getEvenMoreHtml(someReallyInterestingValues, moreValues, + evenMoreParams, 'a duck', true, 72, + slightlyMoreMonkeys(0xfff)) + + ''; + + thisIsAVeryLongVariableName = + hereIsAnEvenLongerOtherFunctionNameThatWillNotFitOnPrevLine(); + + thisIsAVeryLongVariableName = 'expressionPartOne' + someMethodThatIsLong() + + thisIsAnEvenLongerOtherFunctionNameThatCannotBeIndentedMore(); + + someValue = this.foo( + shortArg, + 'Some really long string arg - this is a pretty common case, actually.', + shorty2, + this.bar()); + + if (searchableCollection(allYourStuff).contains(theStuffYouWant) && + !ambientNotification.isActive() && (client.isAmbientSupported() || + client.alwaysTryAmbientAnyways())) { + ambientNotification.activate(); + } + +空行 +~~~~~~ + +使用新的空行来划分一组逻辑上相关联的代码片段。例如: + +:: + + doSomethingTo(x); + doSomethingElseTo(x); + andThen(x); + + nowDoSomethingWith(y); + + andNowWith(z); + +二元和三元操作符 +~~~~~~~~~~~~~~~~~~~ + +操作符始终跟随着前行, 这样你就不用顾虑分号的隐式插入问题。否则换行符和缩进还是遵循其他谷歌规范指南。 + +:: + + var x = a ? b : c; // All on one line if it will fit. + + // Indentation +4 is OK. + var y = a ? + longButSimpleOperandB : longButSimpleOperandC; + + // Indenting to the line position of the first operand is also OK. + var z = a ? + moreComplicatedB : + moreComplicatedC; + +点号也应如此处理。 + +:: + + var x = foo.bar(). + doSomething(). + doSomethingElse(); + +括号 +---------- + +只用在有需要的地方。 + +通常只在语法或者语义需要的地方有节制地使用。 + +绝对不要对一元运算符如 ``delete`` 、 ``typeof`` 和 ``void`` 使用括号或者在关键词如 ``return`` 、 ``throw`` 和其他的( ``case`` 、 ``in`` 或者 ``new`` )之后使用括号。 + +字符串 +-------- + +使用 ``'`` 代替 ``"`` 。 + +使用单引号( ``'`` )代替双引号( ``"`` )来保证一致性。当我们创建包含有HTML的字符串时这样做很有帮助。 + +:: + + var msg = 'This is some HTML'; + +可见性(私有和保护类型字段) +----------------------------- + +鼓励使用 ``@private`` 和 ``@protected`` JSDoc注释。 + +我们建议使用JSDoc注释 ``@private`` 和 ``@protected`` 来标识出类、函数和属性的可见程度。 + +设置 ``--jscomp_warning=visibility`` 可令编译器对可见性的违规进行编译器警告。可见 `封闭的编译器警告 `_ 。 + +加了 ``@private`` 标记的全局变量和函数只能被同一文件中的代码所访问。 + +被标记为 ``@private`` 的构造函数只能被同一文件中的代码或者它们的静态和实例成员实例化。 ``@private`` 标记的构造函数可以被相同文件内它们的公共静态属性和 ``instanceof`` 运算符访问。 + +全局变量、函数和构造函数不能注释 ``@protected`` 。 + +:: + + // 文件1 + // AA_PrivateClass_ 和 AA_init_ 是全局的并且在同一个文件中所以能被访问 + + /** + * @private + * @constructor + */ + AA_PrivateClass_ = function() { + }; + + /** @private */ + function AA_init_() { + return new AA_PrivateClass_(); + } + + AA_init_(); + +标记 ``@private`` 的属性可以被同一文件中的所有的代码访问,如果属性属于一个类,那么所有自身含有属性的类的静态方法和实例方法也可访问。它们不能被不同文件下的子类访问或者重写。 + +标记 ``@protected`` 的属性可以被同一文件中的所有的代码访问,任何含有属性的子类的静态方法和实例方法也可访问。 + +注意这些语义和C++、JAVA中private 和 protected的不同,其许可同一文件中的所有代码访问的权限,而不是仅仅局限于同一类或者同一类层次。此外,不像C++中,子类不可重写私有属性。 + +:: + + // File 1. + + /** @constructor */ + AA_PublicClass = function() { + /** @private */ + this.privateProp_ = 2; + + /** @protected */ + this.protectedProp = 4; + }; + + /** @private */ + AA_PublicClass.staticPrivateProp_ = 1; + + /** @protected */ + AA_PublicClass.staticProtectedProp = 31; + + /** @private */ + AA_PublicClass.prototype.privateMethod_ = function() {}; + + /** @protected */ + AA_PublicClass.prototype.protectedMethod = function() {}; + + // File 2. + + /** + * @return {number} The number of ducks we've arranged in a row. + */ + AA_PublicClass.prototype.method = function() { + // Legal accesses of these two properties. + return this.privateProp_ + AA_PublicClass.staticPrivateProp_; + }; + + // File 3. + + /** + * @constructor + * @extends {AA_PublicClass} + */ + AA_SubClass = function() { + // Legal access of a protected static property. + AA_PublicClass.staticProtectedProp = this.method(); + }; + goog.inherits(AA_SubClass, AA_PublicClass); + + /** + * @return {number} The number of ducks we've arranged in a row. + */ + AA_SubClass.prototype.method = function() { + // Legal access of a protected instance property. + return this.protectedProp; + }; + +注意在Javascript中,一个类(如 ``AA_PrivateClass_`` )和其构造函数类型是没有区别的。没办法确定一种类型是public而它的构造函数是private。(因为构造函数很容易重命名从而躲避隐私检查)。 + +JavaScript类型 +----------------- + +鼓励和强制执行的编译器。 + +JSDoc记录类型时,要尽可能具体和准确。我们支持的类型是基于 `EcmaScript 4规范 `_ 。 + +JavaScript类型语言 +~~~~~~~~~~~~~~~~~~~ + +ES4提案包含指定JavaScript类型的语言。我们使用JsDoc这种语言表达函数参数和返回值的类型。 + +随着ES4提议的发展,这种语言已经改变了。编译器仍然支持旧的语法类型,但这些语法已经被弃用了。 + +.. list-table:: + :widths: 8 30 50 8 + :header-rows: 1 + + * - 语法名称 + - 语法 + - 描述 + - 弃用语法 + * - 原始类型 + - 在JavaScript中有5种原始类型: ``{null}`` , ``{undefined}`` , ``{boolean}`` , ``{number}`` ,和 ``{string}`` + - 类型的名称。 + - + * - 实例类型 + - ``{Object}`` + 实例对象或空。 + + ``{Function}`` + 一个实例函数或空。 + + ``{EventTarget}`` + 构造函数实现的EventTarget接口,或者为null的一个实例。 + - 一个实例构造函数或接口函数。构造函数是 ``@constructor`` JSDoc标记定义的函数 。接口函数是 ``@interface`` JSDoc标记定义的函数。 + + 默认情况下,实例类型将接受空。这是唯一的类型语法,使得类型为空。此表中的其他类型的语法不会接受空。 + - + * - 枚举类型 + - ``{goog.events.EventType}`` 字面量初始化对象的属性之一 ``goog.events.EventType`` 。 + - 一个枚举必须被初始化为一个字面量对象,或作为另一个枚举的别名,加注 ``@enum`` JSDoc标记。这个属性是枚举实例。 `下面 `_ 是枚举语法的定义。 + + 请注意,这是我们的类型系统中为数不多的ES4规范以外的事情之一。 + - + * - 应用类型 + - ``{Array.}`` 字符串数组。 + + ``{Object.}`` 一个对象,其中键是字符串,值是数字。 + - 参数化类型,该类型应用一组参数类型。这个想法是类似于Java泛型。 + - + * - 联合类型 + - ``{(number|boolean)}`` 一个数字或布尔值。 + - 表明一个值可能有A型或B型。 + + 括号在顶层表达式可以省略,但在子表达式不能省略,以避免歧义。 + + ``{number|boolean}`` + + ``{function(): (number|boolean)}`` + - ``{(number,boolean)}`` , + ``{(number||boolean)}`` + * - 可为空的类型 + - ``{?number}`` + + 一个数字或空。 + - 空类型与任意其他类型组合的简称。这仅仅是语法糖(syntactic sugar)。 + - ``{number?}`` + * - 非空类型 + - ``{!Object}`` + + 一个对象,值非空。 + - 从非空类型中过滤掉null。最常用于实例类型,默认可为空。 + - ``{Object!}`` + * - 记录类型 + - ``{{myNum: number, myObject}}`` + + 给定成员类型的匿名类型。 + - 表示该值有指定的类型的成员。在这种情况下, ``myNum`` 是 ``number`` 类型而 ``myObject`` 可为任何类型。 + + 注意花括号是语法类型的一部分。例如,表示一个数组对象有一个 ``length`` 属性,你可以写 ``Array.<{length}>`` 。 + - + * - 函数类型 + - ``{function(string, boolean)}`` + + 一个函数接受两个参数(一个字符串和一个布尔值),并拥有一个未知的返回值。 + - 指定一个函数。 + - + * - 函数返回类型 + - ``{function(): number}`` + + 一个函数没有参数并返回一个数字。 + - 指定函数的返回类型。 + - + * - 函数 ``this`` 类型 + - ``{function(this:goog.ui.Menu, string)}`` + + 一个需要一个参数(字符串)的函数,执行上下文是 ``goog.ui.Menu`` + - 指定函数类型的上下文类型。 + - + * - 函数 ``new`` 类型 + - ``{function(new:goog.ui.Menu, string)}`` + + 一个构造函数接受一个参数(一个字符串),并在使用“new”关键字时创建一个 ``goog.ui.Menu`` 新实例。 + - 指定构造函数所构造的类型。 + - + * - 可变参数 + - ``{function(string, ...[number]): number}`` + + 一个函数,它接受一个参数(一个字符串),然后一个可变数目的参数,必须是数字。 + - 指定函数的变量参数。 + - + * - 可变参数( ``@param`` 注释) + - ``@param {...number} var_args`` + + 带注释函数的可变数目参数。 + - 指定带注释函数接受一个可变数目的参数。 + - + * - 函数 `可选参数 `_ + - ``{function(?string=, number=)}`` + + 一个函数,它接受一个可选的、可以为空的字符串和一个可选的数字作为参数。“=”只用于函数类型声明。 + - 指定函数的可选参数。 + - + * - 函数 `可选参数 `_ ( ``@param`` 注释) + - ``@param {number=} opt_argument`` + + ``number`` 类型的可选参数。 + - 指定带注释函数接受一个可选的参数。 + - + * - 所有类型 + - ``{*}`` + - 表明该变量可以接受任何类型。 + - + * - 未知类型 + - ``{?}`` + - 表明该变量可以接受任何类型,编译器不应该检查其类型。 + - + +JavaScript中的类型 +~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 30 50 + :header-rows: 1 + + * - 类型举例 + - 取值举例 + - 描述 + * - number + - :: + + 1 + 1.0 + -5 + 1e5 + Math.PI + - + * - Number + - :: + + new Number(true) + - `Number对象 `_ + * - string + - :: + + 'Hello' + "World" + String(42) + - 字符串 + * - String + - :: + + new String('Hello') + new String(42) + - `String对象 `_ + * - boolean + - :: + + true + false + Boolean(0) + - Boolean值 + * - Boolean + - :: + + new Boolean(true) + - `Boolean对象 `_ + * - RegExp + - :: + + new RegExp('hello') + /world/g + - + * - Date + - :: + + new Date + new Date() + - + * - null + - :: + + null + - + * - undefined + - :: + + undefined + - + * - void + - :: + + function f() { + return; + } + - 没有返回值 + * - Array + - :: + + ['foo', 0.3, null] + [] + - 无类型数组 + * - Array. + - :: + + [11, 22, 33] + - 数字数组 + * - Array.> + - :: + + [['one', 'two', 'three'], ['foo', 'bar']] + - 以字符串为元素的数组,作为另一个数组的元素 + * - Object + - :: + + {} + {foo: 'abc', bar: 123, baz: null} + - + * - Object. + - :: + + {'foo': 'bar'} + - 值为字符串的对象 + * - Object. + - :: + + var obj = {}; + obj[1] = 'bar'; + - 键为整数,值为字符串的对象。 + 注意,js当中键总是会隐式转换为字符串。所以 ``obj['1'] == obj[1]`` 。键在for…in…循环中,总是字符串类型。但在对象中索引时编译器会验证键的类型。 + * - Function + - :: + + function(x, y) { + return x * y; + } + - `Function对象 `_ + * - function(number, number): number + - :: + + function(x, y) { + return x * y; + } + - 函数值 + * - 类 + - :: + + /** @constructor */ + function SomeClass() {} + + new SomeClass(); + - + * - 接口 + - :: + + /** @interface */ + function SomeInterface() {} + + SomeInterface.prototype.draw = function() {}; + - + * - project.MyClass + - :: + + /** @constructor */ + project.MyClass = function () {} + + new project.MyClass() + - + * - project.MyEnum + - :: + + /** @enum {string} */ + project.MyEnum = { + /** The color blue. */ + BLUE: '#0000dd', + /** The color red. */ + RED: '#dd0000' + }; + - 枚举 + + JSDoc中枚举的值都是可选的. + * - Element + - :: + + document.createElement('div') + - DOM元素 + * - Node + - :: + + document.body.firstChild + - DOM节点 + * - HTMLInputElement + - :: + + htmlDocument.getElementsByTagName('input')[0] + - 指明类型的DOM元素 + +类型转换 +~~~~~~~~~~ + +在类型检测不准确的情况下,有可能需要添加类型的注释,并且把类型转换的表达式写在括号里,括号是必须的。如: + +:: + + /** @type {number} */ (x) + +可为空与可选的参数和属性 +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +因为Javascript是一个弱类型的语言,明白函数参数、类属性的可选、可为空和未定义之间的细微差别是非常重要的。 + +对象类型和引用类型默认可为空。如以下表达式: + +:: + + /** + * 传入值初始化的类 + * @param {Object} value某个值 + * @constructor + */ + function MyClass(value) { + /** + * Some value. + * @type {Object} + * @private + */ + this.myValue_ = value; + } + +告诉编译器 ``myValue_`` 属性为一对象或null。如果 ``myValue_`` 永远都不会为null, 就应该如下声明: + +:: + + /** + * 传入非null值初始化的类 + * @param {!Object} value某个值 + * @constructor + */ + function MyClass(value) { + /** + * Some value. + * @type {!Object} + * @private + */ + this.myValue_ = value; + } + +这样,如果编译器可以识别出 ``MyClass`` 初始化传入值为null,就会发出一个警告。 + +函数的可选参数在运行时可能会是undefined,所以如果他们是类的属性,那么必须声明: + +:: + + /** + * 传入可选值初始化的类 + * @param {Object=} opt_value某个值(可选) + * @constructor + */ + function MyClass(opt_value) { + /** + * Some value. + * @type {Object|undefined} + * @private + */ + this.myValue_ = opt_value; + } + +这告诉编译器 ``myValue_`` 可能是一个对象,或 ``null`` ,或 ``undefined`` 。 + +注意: 可选参数 ``opt_value`` 被声明成 ``{Object=}`` ,而不是 ``{Object|undefined}`` 。这是因为可选参数可能是undefined。虽然直接写undefined也并无害处,但鉴于可阅读性还是写成上述的样子。 + +最后,属性的可为空和可选并不矛盾,下面的四种声明各不相同: + +:: + + /** + * 接受四个参数,两个可为空,两个可选 + * @param {!Object} nonNull 必不为null + * @param {Object} mayBeNull 可为null + * @param {!Object=} opt_nonNull 可选但必不为null + * @param {Object=} opt_mayBeNull 可选可为null + */ + function strangeButTrue(nonNull, mayBeNull, opt_nonNull, opt_mayBeNull) { + // ... + }; + +类型定义 +~~~~~~~~~~ + +有时类型可以变得复杂。一个函数,它接受一个元素的内容可能看起来像: + +:: + + /** + * @param {string} tagName + * @param {(string|Element|Text|Array.|Array.)} contents + * @return {!Element} + */ + goog.createElement = function(tagName, contents) { + ... + }; + +你可以定义带 ``@typedef`` 标记的常用类型表达式。例如: + +:: + + /** @typedef {(string|Element|Text|Array.|Array.)} */ + goog.ElementContent; + + /** + * @param {string} tagName + * @param {goog.ElementContent} contents + * @return {!Element} + */ + goog.createElement = function(tagName, contents) { + ... + }; + +模板类型 +~~~~~~~~~~ + +编译器对模板类型提供有限支持。它只能从字面上通过 ``this`` 参数的类型和 ``this`` 参数是否丢失推断匿名函数的 ``this`` 类型。 + +:: + + /** + * @param {function(this:T, ...)} fn + * @param {T} thisObj + * @param {...*} var_args + * @template T + */ + goog.bind = function(fn, thisObj, var_args) { + ... + }; + //可能出现属性丢失警告 + goog.bind(function() { this.someProperty; }, new SomeClass()); + //出现this未定义警告 + goog.bind(function() { this.someProperty; }); + +注释 +---------- + +使用JSDoc。 + +我们使用 `c++的注释风格 `_ 。 +所有的文件、类、方法和属性都应该用合适的 `JSDoc `_ 的 `标签 `_ 和 `类型 `_ 注释。除了直观的方法名称和参数名称外,方法的描述、方法的参数以及方法的返回值也要包含进去。 + +行内注释应该使用 ``//`` 的形式。 + +为了避免出现语句片段,要使用正确的大写单词开头,并使用正确的标点符号作为结束。 + +注释语法 +~~~~~~~~~~ + +JSDoc的语法基于 `JavaDoc `_ ,许多编译工具从JSDoc注释中获取信息从而进行代码验证和优化,所以这些注释必须符合语法规则。 + +:: + + /** + * A JSDoc comment should begin with a slash and 2 asterisks. + * Inline tags should be enclosed in braces like {@code this}. + * @desc Block tags should always start on their own line. + */ + +JSDoc 缩进 +~~~~~~~~~~~~~ + +如果你不得不进行换行,那么你应该像在代码里那样,使用四个空格进行缩进。 + +:: + + /** + * Illustrates line wrapping for long param/return descriptions. + * @param {string} foo This is a param with a description too long to fit in + * one line. + * @return {number} This returns something that has a description too long to + * fit in one line. + */ + project.MyClass.prototype.method = function(foo) { + return 5; + }; + +不必在 ``@fileoverview`` 标记中使用缩进。 + +虽然不建议,但依然可以对描述文字进行排版。 + +:: + + /** + * This is NOT the preferred indentation method. + * @param {string} foo This is a param with a description too long to fit in + * one line. + * @return {number} This returns something that has a description too long to + * fit in one line. + */ + project.MyClass.prototype.method = function(foo) { + return 5; + }; + +JSDoc中的HTML +~~~~~~~~~~~~~~~~ + +像JavaDoc一样, JSDoc 支持很多的HTML标签,像 ```` , ``

`` , ```` , ```` , ``