zoukankan      html  css  js  c++  java
  • Google代码规范

    文件名

    文件名须全部小写,下划线(_)和短横线(-)

    源文件采用 UTF-8 编码。

     

    非空代码块:K&R 风格

    • 左花括号不另起新行

    • 左花括号后紧跟换行

    • 右花括号前需要换行

    • 如果右花括号结束了语句,或者它是函数、类、类中的方法的结束括号,则其后面需要换行。如果后面紧跟的是 elsecatchwhile,或逗号,分号以及右括号,则不需要跟一个换行。

     

    代码块中的编进:+2 个空格

    新开代码块中代码需要加 2 个空格的缩进

    数组字面量:类代码块(block-like)
    const c = [0, 1, 2];
    
    someMethod(foo, [
      0, 1, 2,
    ], bar);
    
    Switch 语句

    一如其他代码块一样,switch 语句中每个条件块也是增加 2 个空格的缩进。 每个 switch 标签后新起一行,加缩进,就像是创建了一个带花括号的代码块一样。每个标签开始时缩进又恢复,相当于只有 switch 标签中的内容是当作代码块来处理的。

    break 关键字后面的空行是可选的。

    switch (animal) {
      case Animal.BANDERSNATCH:
        handleBandersnatch();
        break;
    
      case Animal.JABBERWOCK:
        handleJabberwock();
        break;
    
      default:
        throw new Error('Unknown animal');
    }

    声明语句

    一个声明占一行

    每个声明语句后都跟换行。

    分号是必需的

    语句后需用分号结束。不能依赖于编辑器的自动分号插入功能。

    最大列宽:80

    何处该换行

    换行的的准则是:尽量在优先级高的语法层面(higher syntactic level)进行

    currentEstimate =
        calc(currentEstimate + x * currentEstimate) /
            2.0f;

    语法优先级从高到低依次为:赋值,除法,函数调用,参数,数字常量。

    换行后后续行至少有 4 个空格的缩进

    当发生换行时,第一行后面跟着的其他行至少缩进 4 个空格,除非满足代码块的缩进规则,另说。

    换行后后续跟随多行时,缩进可适当大于 4 个空格。通常,语法中低优先级的后续行以 4 的倍数进行缩进,如果只有两行并且处于同一优先级,则保持一样的缩进即可。

    空格

    垂直方向的空格

    以下场景需要有一个空行:

    1. 类或对象中的方法间 a. 例外的情形:对象中属性间的空行是可选的。如果有的话,一般是用来将属性进行分组。

    2. 方法体中,尽量少地使用空行来进行代码的分隔。函数体开始和结束都不要加空行。 3.类或对象中首个方法前及最后一个方法后的空行,既不提倡也不反对。

    3. 适用此风格中其他条目的规定(e.g.3.4 goog.require statements)。

    连续多个空行不是必需的,但了不鼓励这么做。

    水平方向的空格

    水平方向的空格依位置为定,有三种大的分类:行首(一行的开始),行尾(一行的结束)以及行间(一行中除去行首及行尾的部分)。行首的空格(i.e. 缩进)无处不在。行尾的空格是禁止的。

    除了 Javascript 本身及其他规则的要求,还有字面量,注释,JSDoc 等需要的空格外,单个的 ASCII 类型的空格在以下情形中也是需要的。

    1. 将关键字(譬如 ifforcatch)与括号(()分隔。

    2. 将关键字(elsecatch)与闭合括号(}) 分隔。

    3. 对于左花括号有两种例外: a. 作为函数首个参数的对象之前,数组中首个对象元素 (e.g. foo({a: [{c: d}]}) b. 在模板表达式中,因为模板语法的限制不能加空格(e.g. abc${1 + 2}def)。

    4. 二元,三元操作符的两边

    5. 逗号或分号后。但其前面是不允许有空格的。

    6. 对象字面量中冒号后面。

    7. 双斜线(//)两边。这里可以使用多个空格,但也不是必需的。

    8. JSDoc 注释及其两边 e.g. 简写的类型声明 this.foo = /** @type {number} */ (bar); 或类型转换(cast)function(/** string */ foo) {

    函数参数

    推荐将函数的所有参数放在与函数名同一行的位置。如果这样会导致列宽超限,那参数应该以一种易读的方式进行换行。为了节省空间,尽量超过宽度限制时才进行换行,换行后每个参数一行以提高可读性。换行后缩进为 4 个空格。与括号对齐是可以的,但不推荐。以下是觉的参数换行示例:

    // Arguments start on a new line, indented four spaces. Preferred when the
    // arguments don't fit on the same line with the function name (or the keyword
    // "function") but fit entirely on the second line. Works with very long
    // function names, survives renaming without reindenting, low on space.
    doSomething(
        descriptiveArgumentOne, descriptiveArgumentTwo, descriptiveArgumentThree) {
      //
    }
    
    // If the argument list is longer, wrap at 80. Uses less vertical space,
    // but violates the rectangle rule and is thus not recommended.
    doSomething(veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo,
        tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) {
      //
    }
    
    // Four-space, one argument per line.  Works with long function names,
    // survives renaming, and emphasizes each argument.
    doSomething(
        veryDescriptiveArgumentNumberOne,
        veryDescriptiveArgumentTwo,
        tableModelEventHandlerProxy,
        artichokeDescriptorAdapterIterator) {
      //
    }

    注释

    块状注释

    块状注释与被注释代码保持相同缩进。/* ... */// 都是。对于多行的 /* ... */ 注释,后续注释行以 * 开头且与上一行缩进保持一致。参数的注释紧随参数之后,用于在函数名或参数名无法完全表达其意思的情况。

    注意区分 JSDoc(/** ... */),上面不注释不能写成这样。

     

    本地变量的声明

    使用 constlet

    所有本地变量使用 constlet 来声明。默认使用 const,除非该变量需要重新赋值。杜绝使用 var

    一次声明一个变量

    一次只声明一个本地变量,let a = 1, b = 2; 这样的做法是禁止的。

    需要时才声明,声明后尽快初始化

    本地变量不要全部一次性声明在代码块的开头。声明在该变量每一次需要被使用的地方,以减少其影响范围。

    尽量标明类型

    JSDoc 类型注释可以添加在声明语句上面,或者内联到变量名前面。

    const /** !Array<number> */ data = [];
    
    /** @type {!Array<number>} */
    const data = [];

    数组字面量

    尾部加逗号

    始终在元素后面带上一个结束的逗号。

    属性引号保持一致(字典键的类型一致)

    对象属性分为不包含引号或 Symbols 的 structs 类型和包含引号或运算属性的 dicts 类型。两种类型不要混合使用,应该保持一致。

    标识符类型的命名规则

    包名

    包名使用小写开头的驼峰命名 lowerCamelCase

    类名

    类,接口,record (这是什么?) 以及 typedef names (类型定义符) 使用大写开头的驼峰 UpperCamelCase

    未被导出的类只本地使用,并没有用 @private 标识,所以命名上不需要以下划线结尾。

    类型名称通常为名词或名词短语。比如,RequestImmutableList,或者 VisibilityMode。此外,接口名有时会是一个形容词或形容短语(比如 Readable)。

    方法名

    方法名使用小写开头的驼峰。私有方法需以下划线结尾。

    方法名一般为动词或动词短语。比如 sendMessage 或者 stop_。属性的 Getter 或 Setter 不是必需的,如果有的话,也是小写驼峰命名且需要类似这样 getFoo(对于布尔值使用 isFoohasFoo 形式),setFoo(value)

    注:私有属性或方法以下划线开头才是主流吧

    单元测试代码中的方法名会出现用下划线来分隔组件形式。一种典型的形式是这样的test<MethodUnderTest>_<state>,例如 testPop_emptyStack。对于这种测试代码中的方法,命名上没有统一的要求

    枚举

    枚举使用大写开头的驼峰,和类相似,一般一个单数形式的名词。枚举中的元素写成 CONSTANT_CASE

    常量

    常量写成 CONSTANT_CASE:所有字母使用大写,以下划线分隔单词。私有静态属性可以用内部变量代替,所以不会有使用私有枚举的情况,也就无需将常量以下划线结尾来命名。

    常量的定义

    每个常量都是 @const 标识的静态属性或 模块内部通过 const 声明的变量,但并不是所有 @const 标识的静态属性或 const 声明的变量都是常理。需要常量时,先想清楚该对象是否真的不可变。例如,如果该对象中做生意状态可被改变,显然不适合作为常量。只是想着不去改变它的值是不够的,我们要求它需要从本质上来说应该一成不变。

    非常量字段

    非常量字段(静态或其他)使用小写开头的驼峰,如果是私有的私有的则以下划线结尾。

    一般是名词或名词短语。例如 computedValuesindex_

    参数

    参数使用小写开头的驼峰。即使参数需要一个构造器来初始化时,也是这一规则。

    公有方法的参数名不能只使用一个字母。

    例外:如果三方库需要,参数名可以用 $ 开头。此例外不适用于其他标识符(e.g. 本地变量或属性)。

    本地变量

    本地变量使用小写开头的驼峰,除非是上面介绍过的本地常量。函数中的常量命名仍然使用小写开头的驼峰lowerCamelCase。即使该变量指向的是构造器也使用 lowerCamelCase。

    模板参数/Template parameter names

    模板参数力求简洁,用一个单词,一个字母表示,全部使用大写,例如 TYPETHIS

    驼峰:定义

    有时将一个英文短语转成驼峰有很多形式,例如首字母进行缩略,IPv6 以及 iOS 这种都有出现。为保证代码可控,本规范规定出如下规则。

    1. 将短语移除撇号转成 ASCII 表示。例如 Müller's algorithm 表示成 Muellers algorithm

    2. 将上述结果拆分成单词,以空格或其他不发音符号(中横线)进行分隔。 a. 推荐的做法:如果其中包含一个已经常用的驼峰翻译,直接提取出来(e.g. AdWords 会成为 ad words)。需要注意的是 iOS 本身并不是个驼峰形式,它不属性任何形式,所以它不适用本条规则。

    3. 将所有字母转成小写,然后将以下情况中的首字母大写: a. 每个单词的首字母,这样便得到了大写开头的驼峰 b. 除首个单词的其他所有单词的首字母,这样得到小写开头的驼峰

    4. 将上述结果合并。

    过程中原来名称中的大小写均被忽略。

    示例:

    Prose formCorrectIncorrect
    XML HTTP request XmlHttpRequest XMLHTTPRequest
    new customer ID newCustomerId newCustomerID
    inner stopwatch innerStopwatch innerStopWatch
    supports IPv6 on iOS? supportsIpv6OnIos supportsIPv6OnIOS
    ouTube importer YouTubeImporter YoutubeImporter*

    *这种情况可接受,但不推荐。

    注释:一些英文词汇通过中横线连接的方式是有歧义的,比如 "nonempty" 和 "non-empty" 都是正确写法,所以方法名 checkNonempty checkNonEmpty 都算正确。

    JSDoc

    JSDoc 使用在了所有的类,字段以及方法上。

    通用形式

    JSDoc 基本的形式如下:

    /**
     * Multiple lines of JSDoc text are written here,
     * wrapped normally.
     * @param {number} arg A number to do something to.
     */
    function doSomething(arg) { … }

    或者这种单行的形式:

    /** @const @private {!Foo} A short bit of JSDoc. */
    this.foo_ = foo;

    如果单行形式长到需要折行,则需要切换到多行模式而不是使用单行形式。

    有许多工具会对 JSDoc 文档进行解析以提取出有效的信息对代码进行检查和优化。所以这些注释需要好好写。

    Markdown

    JSDoc 支持 Markdown,所以必要时可包含 HTML。

    工具会自动提取 JSDoc 的内容,其中自己书写的格式会被忽略。比如如果你写成下面这个样子:

    /**
     * Computes weight based on three factors:
     *   items sent
     *   items received
     *   last timestamp
     */

    最终提取出来是这样的:

    Computes weight based on three factors: items sent items received last timestamp

    取而代之,我们应该按 markdown 的语法来格式化:

     

    JSDoc tags

    本规则可使用 JSDoc tags 的一个子集。详细列表见 9.1 JSDoc tag reference。大部分 tags 独占一行。

    错误的示例:

    /**
     * The "param" tag must occupy its own line and may not be combined.
     * @param {number} left @param {number} right
     */
    function add(left, right) { ... }

    简单的 tag 无需额外数据(比如 @private@const@final@export),可以合并到一行。

     
    /**
     * Place more complex annotations (like "implements" and "template")
     * on their own lines.  Multiple simple tags (like "export" and "final")
     * may be combined in one line.
     * @export @final
     * @implements {Iterable<TYPE>}
     * @template TYPE
     */
    class MyClass {
      /**
       * @param {!ObjType} obj Some object.
       * @param {number=} num An optional number.
       */
      constructor(obj, num = 42) {
        /** @private @const {!Array<!ObjType|number>} */
        this.data_ = [obj, num];
      }
    }

    关于合并及合并后的顺序没有明确的规范,代码中保持一致即可。

    详细的类型信息可参见 Annotating JavaScript for the Closure CompilerTypes in the Closure Type System

    换行

    换行之后的 tag 块使用四个空格进行缩进。

    /**
     * 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.
     */
    exports.method = function(foo) {
      return 5;
    };

    @fileoverview 换行时不缩进。

    文件头部注释

    一个文件可以在头部有个总览。包括版权信息,作者以及默认可选的可见信息/visibility level等。文件中包含多个类时,头部这个总览显得很有必要。它可以帮助别人快速了解该文件的内容。如果写了,则应该有一个描述字段简单介绍文件中的内容以及一些依赖,或者其他信息。换行后不缩进。

    示例:

    /**
     * @fileoverview Description of file, its uses and information
     * about its dependencies.
     * @package
     */

    类的注释

    类,接口以及 records 需要有描述,参数,实现的接口以及可见性或其他适当的 tags 注释。类的描述需要告诉读者类的作用及何时使用该类,以及其他一些可以帮助别人正确使用该类的有用信息。构造器上的文本描述可省略。@constructor@extends 不与 class 一起使用,除非该类是用来声明接口 @interface 或者扩展一个泛型类。

    /**
     * A fancier event target that does cool things.
     * @implements {Iterable<string>}
     */
    class MyFancyTarget extends EventTarget {
      /**
       * @param {string} arg1 An argument that makes this more interesting.
       * @param {!Array<number>} arg2 List of numbers to be processed.
       */
      constructor(arg1, arg2) {
        // ...
      }
    };
    
    /**
     * Records are also helpful.
     * @extends {Iterator<TYPE>}
     * @record
     * @template TYPE
     */
    class Listable {
      /** @return {TYPE} The next item in line to be returned. */
      next() {}
    }

    枚举和 typedef 注释

    枚举和 typedef 需要写文档。仅有的枚举和 typedef 其文档的描述不能为空。枚举中单个元素的文档可直接写在元素的前面一行。

    /**
     * A useful type union, which is reused often.
     * @typedef {!Bandersnatch|!BandersnatchType}
     */
    let CoolUnionType;
    
    
    /**
     * Types of bandersnatches.
     * @enum {string}
     */
    const BandersnatchType = {
      /** This kind is really frumious. */
      FRUMIOUS: 'frumious',
      /** The less-frumious kind. */
      MANXOME: 'manxome',
    };

    Typedefs 可方便地用于定义 records 类型,或 unions 的别名,复杂函数,或者 泛型类型。Typedefs 不适合用来定义字段很多的 records,因为其不支持对每个字段进行文档书写,也不适合用于模板或递归引用中。对于大型 records 使用 @record

    方法与函数

    参数和返回类型需要写文档。必要时 this 也需要在文档中说明。方法,参数及返回的描述在方法的其他 JSDoc 中或方法签名中有表述,那么也是可以省略的。方法的描述应使用第三人称。如果方法重载父类中的方法,需要使用 @override 标识。重载方法需要包含所有的参数 @param 以及 @return 如果类型有变的话,如果没变也可省略。

    /** This is a class. */
    class SomeClass extends SomeBaseClass {
      /**
       * Operates on an instance of MyClass and returns something.
       * @param {!MyClass} obj An object that for some reason needs detailed
       *     explanation that spans multiple lines.
       * @param {!OtherClass} obviousOtherClass
       * @return {boolean} Whether something occurred.
       */
      someMethod(obj, obviousOtherClass) { ... }
    
      /** @override */
      overriddenMethod(param) { ... }
    }
    
    /**
     * Demonstrates how top-level functions follow the same rules.  This one
     * makes an array.
     * @param {TYPE} arg
     * @return {!Array<TYPE>}
     * @template TYPE
     */
    function makeArray(arg) { ... }

    匿名函数不需要写 JSDoc,但在自动推荐参数类型有困难时,也可手动指定一下类型。

    promise.then(
        (/** !Array<number|string> */ items) => {
          doSomethingWith(items);
          return /** @type {string} */ (items[0]);
        });

    属性

    属性的类型需要加文档。对于私有属性如果其命名已经很好地提示了其类型,则描述可省略。

    公有的常量与属性是一样的文档写法。当 @const 类型的属性从一个表达式初始化时,是能明显看出其类型的,此时其显式的类型指定可省略。

    小贴士:@const 属性的类型从构造器的参数进行初始化时,其类型是“显然”的,因为参数上面声明了类型,或者从一个函数调用进行初始化,因为函数返回值的类型也是声明了的。对于非常量或者它的值来源不是很明朗的情况下才需要指定其类型。

    /** My class. */
    class MyClass {
      /** @param {string=} someString */
      constructor(someString = 'default string') {
        /** @private @const */
        this.someString_ = someString;
    
        /** @private @const {!OtherType} */
        this.someOtherThing_ = functionThatReturnsAThing();
    
        /**
         * Maximum number of things per pane.
         * @type {number}
         */
        this.someProperty = 4;
      }
    }
    
    /**
     * The number of times we'll try before giving up.
     * @const
     */
    MyClass.RETRY_COUNT = 33;

    警告

    如何处理警告

    解决之前,先明白警告的意思。如果不清楚,可以询问。

    一旦了解之后,可进行如下操作:

    1. 首先,修复或找替代方案。 尝试针对该警告进行修复,或者换种方式实现相同的功能同时规避掉警告。

    2. 或者,检查看是否是一个误报。 如果确认代码没问题,警告是误报,写下相应注释并添加 @suppress标识。

    3. 或者,留下 TODO 注释。 这是最次的做法。这种做法相当于直接忽略警告,直到时机成熟再解决。

    将警告控制在最小范围

    将警告控制在最小合理的作用域范围,通常一个本地变量或很小的方法范围内。然后可以将这个变量或方法单独提取出来。

    示例:

    /** @suppress {uselessCode} Unrecognized 'use asm' declaration */
    function fn() {
      'use asm';
      return 0;
    }

    一个类中大量的 @suppress 也好过编译时报大量的警告。

    已有代码的重新格式化

    更新已有代码时,遵循以下原则:

    1. 没必要更新所有老代码以满足本规范。需要在成本与代码一致性之间找个平衡点。规范不断在演变,花大成本更新老代码需要折衷。然而,如果老文件大部分都被修改了的话,那可以顺便将其全部改为符合现在的规范。

    2. 注意控制改动范围。如果你发现需要投入大量精力去更新代码而影响了当前需求的进展,考虑将这些老代码的更新另起一个分支。

    新增代码:遵循本规范

    全新创建的文件应该全部遵循本规范,某些包中其他类型文件有其他规范的另说。

    向一个不是遵循本规范而写的文件添加新代码时,推荐先重新格式化当前文件

    如果重新格式化完不成,那么新加的代码应该与老代码尽量保持一致,但不要滥用规范。

     

     

  • 相关阅读:
    CSS3 定位| Position研究
    ASP.NET中Partial Class部分类
    如何安全实现“记住我”的功能
    JavaScript后台代码操作HTML TABLE的方法
    强悍的CSS工具组合:Blueprint, Sass, Compass
    CSS的力量:用一个DIV画图
    ASP.NET记录错误日志的方式
    ASP.NET私有构造函数作用
    c#.net实现浏览器端大文件分块上传
    asp.net实现浏览器端大文件分块上传
  • 原文地址:https://www.cnblogs.com/ZSMblog/p/9612451.html
Copyright © 2011-2022 走看看