ECMAScriptJAVASCRIPT开发规范

JAVASCRIPT开发规范

同、JavaScript 语言专业

  • JavaScript 是一样栽客户端脚本语言, Google 的浩大开源工程被还产生使它. 这卖指南列有了编制 JavaScript 时需遵守的规则.
  • Alipay 前端 JavaScript 以头规范也仍,局部有修改

            注:http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml

1. 变量 

  • 声称变量必须抬高 var 关键字.
  • Decision: 当你没有写 var , 变量就会暴露在全局上下文中, 这样大可能会见暨现有变量冲突. 另外, 如果没有长, 很为难显该变量的作用域是什么, 变量也大可能像于有图域中, 很轻易地泄漏到 Document 或者 Window 中, 所以务必用 var 去声明变量.

2. 常量

  • 常量的款式要:
    NAMES_LIKE_THIS , 即使用非常写字符, 并用生扛线分割隔. 你吧可用 @const 标记来指明它是一个常量. 但求永远不要用 const 关键词.
  • Decision:
    (1) 对于着力类型的常量, 只需要转换命名.
    /**
    * The number of seconds in a minute.
    * @type {number}
    */
    goog.example.SECONDS_IN_A_MINUTE = 60;
    (2) 对于不基本型, 使用 @const 标记.
    /**
    * The number of seconds in each of the given units.
    * @type {Object.<number>}
    * @const
    */
    goog.example.SECONDS_TABLE = {
    minute: 60,
    hour: 60 * 60,
    day: 60 * 60 * 24
    }
    当即标志告诉编译器它是常量.
     
    至于要词 const , 因为 IE 不可知识别, 所以不要使用.

3. 分号

  • 接连利用剪切号.
  • 如果光因语句间的隐式分隔,
    有时会大麻烦. 你协调再会理解哪里是报句子的从止.
  • 再就是有些情况下, 漏掉分号会坏危险:
    // 1.
    MyClass.prototype.myMethod = function() {
    return 42;
    } // No semicolon here.
     
    (function() {
    // Some initialization code wrapped in a function to create a scope
    for locals.
    })();
     
    var x = {
    ‘i’: 1,
    ‘j’: 2
    } // No semicolon here.
     
    // 2. Trying to do one thing on Internet Explorer and another on
    Firefox.
    // I know you’d never write code like this, but throw me a bone.
    [normalVersion, ffVersion][isIE]();
     
     
    var THINGS_TO_EAT = [apples, oysters, sprayOnCheese] // No
    semicolon here.
     
    // 3. conditional execution a la bash
    -1 == resultOfOperation() || die();
     
     
    立刻段代码会时有发生数什么稀奇事也?

  • 回报 JavaScript 错误 – 例子1齐之语句会解释成, 一个函数带一躲名函数作为参数而吃调用, 返回42后, 又同样糟给”调用”, 这虽招致了错误.

  • 事例2着, 你充分可能会见在运作时撞 ‘no such property in undefined’
    错误, 原因是代码试图这样 x[ffVersion][isIE]() 执行.
  • 当 resultOfOperation() 返回非 NaN 时, 就见面调用 die , 其结果吧会予以给 THINGS_TO_EAT .

为什么?

  • JavaScript 的晓句以分行作为了符, 除非可以死纯粹测算某结位置才见面看略分号. 上面的几单例证产出错误, 均是在谈中声称了函数/对象/数组直接量, 但 闭括号(‘}’或’]’)并不足以表示该语句之结束. 在 JavaScript 中, 只有当语句后的产一个符号是后缀或括号运算符时, 才见面觉得该语句的结束.
  • 脱分号有时见面面世大意外的结果,
    所以确保语句以分公司结束.

4. 嵌套函数

  • 得以
  • 嵌套函数很有因此, 比如,减少重复代码, 隐藏帮助函数, 等. 没什么其他需要留意的地方, 随意使用.

5. 片内函数声明

  • 并非在片内声明一个函数,不要写成:
        if (x) {
            function foo() {}
        }
  • 尽管如此多 JS 引擎都支持块内声明函数, 但它不属 ECMAScript 规范 (见
    ECMA-262,
    第13及14漫漫). 各个浏览器糟糕之落实互动不般配, 有把吗同前程 ECMAScript 草案相违背. ECMAScript 只同意在剧本的根语句或函数中声明函数. 如果真需要以片被定义函数, 建议以函数表达式来初始化变量:
        if (x) {
        var foo = function() {}
        }

6. 异常

  • 可以
  • 而在描写一个比较复杂的以时,
    不可能完全避免不见面起其他异常. 大胆去用吧.

7. 于定义格外

  • 可以
  • 偶尔有很了, 但返回的错误信息比较奇怪, 也不错读. 虽然好用含有错误信息的援对象或可能发生错误的整对象传递过来, 但这样做且不是非常好, 最好或由定义格外类, 其实这些多还是极其原始之挺处理技巧. 所以在恰当的时利用从定义异常.

8. 标准特性

  • 老是优于非标准特性.
  • 最大化可移植性和兼容性, 尽量利用正式措施而非是用不标准方法, (比如, 优先用 string.charAt(3) 而休用 string[3] , 通过 DOM 原生函数访问元素, 而非是应用以封装好之迅猛接口.

9. 包裹基本类型

  • 不要
  • 靡任何理由去包基本型,
    另外还存在一些高风险: var x = new
    Boolean(false);
    if (x) {
    alert(‘hi’); // Shows ‘hi’.
    }
  • 只有明确用于类型转换, 其他情形请千万不要这样做!

var x = Boolean(0);
if (x) {
alert(‘hi’); // This will never be alerted.
}
typeof Boolean(0) == ‘boolean’;
typeof new Boolean(0) == ‘object’;

  • 偶尔用作 number , string
    或 boolean 时, 类型的转换会非常实用.

10. 层层原型结构

  • 无是首选
  • 铺天盖地原型结构是指 JavaScript
    中之连续关系. 当您自定义一个D类, 且把B类作为该原型, 那么这就赢得了一个文山会海原型结构. 这些原型结构会转移得进一步复杂!
  • 采取 Arale 中之 inherits 或外类似的用于后续的函数, 会是双重好的选项择. function MyClass() {
        doSomeThing()
    }
    arale.inherits(MyClass, Parent);
     
    MyClass.prototype.method = function() {
        …
    };

11. 方式定义 Foo.prototype.bar = function() { …
};

产生众多办法可给构造器添加方法要成员,
我们重新倾向于采用如下的形式: Foo.prototype.bar = function()
{
/* … */
};

12. 闭包

  • 好, 但小心使用.
  • 闭包也许是 JS 中极其有效之风味了. 有平等卖比好的牵线闭包原理的文档.
  • 发出几许需要记住, 闭包保留了一个对准她封闭作用域的指针, 所以, 在吃 DOM 元素附加闭包时, 很可能会见生循环引用, 进一步导致内存泄漏. 比如下面的代码: function foo(element, a, b)
    {
        element.onclick = function() { /* uses a and b */ };
    }
  • 此地, 即使没有使 element , 闭包吗保留了 element , a 和 b 的援, . 由于 element 也保留了针对性闭包的援, 这就算发生了巡回引用, 这就是非克让 GC 回收. 这种气象下, 可将代码重构为:
     
    function foo(element, a, b) {
        element.onclick = bar(a, b);
    }
     
    function bar(a, b) {
        return function() { /* uses a and b */ }
    }

13. eval()

  • 独自用于解析序列化串 (如: 解析 RPC 响应)
  • eval() 会于程序执行的比乱, 当 eval() 里面包含用户输入的口舌虽更是危险. 可以就此另外更优质的, 更清晰, 更安全之主意写你的代码, 所以一般景象下请不要采用 eval(). 当遇到一些需分析序列化串的景象下(如, 计算 RPC 响应), 使用 eval 很爱实现.
  • 解析序列化串是指将字节流转换成为外存中的数据结构.
    比如, 你或会见拿一个目标输出成文件形式: users = [
    {
        name: ‘Eric’,
        id: 37824,
        email: ‘jellyvore@myway.com’
    },
    {
        name: ‘xtof’,
        id: 31337,
        email: ‘b4d455h4x0r@google.com’
    },
        …
    ];
  • 充分简单地调用 eval 后, 把代表成文件之多少读取回内存中.
  • 看似的, eval() 对 RPC 响应值进行解码. 例如, 你于利用 XMLHttpRequest 发出一个 RPC 请求后, 通过 eval () 将服务端的应文件转成 JavaScript 对象:
     
    var userOnline = false;
    var user = ‘nusrat’;
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open(‘GET’, ‘http://chat.google.com/isUserOnline?user=’ +
    user, false);
    xmlhttp.send(”);
    // Server returns:
    // userOnline = true;
    if (xmlhttp.status == 200) {
        eval(xmlhttp.responseText);
    }
    // userOnline is now true.

14. with() {}

  • 永不使
  • 运 with 让您的代码在语义上更换得不清晰. 因为 with 的目标, 可能会见与片变量产生冲突, 从而改变而程序原本的之所以义. 下面的代码是干嘛的? with (foo) {
        var x = 3;
        return x;
    }
  • 答案: 任何事. 局部变量 x 可能让 foo 的习性覆盖, 当它定义一个 setter 时, 在赋值 3 后会实施很多其它代码. 所以不要使 with 语句.

15. this

  • 特以靶构造器, 方法, 闭包吃使用.
  • this 的语义很特别. 有时它们引用一个大局对象(大多数景下), 调用者的作用域(使用 eval 时), DOM 树中的节点(添加事件处理函数时), 新创的目标(使用一个构造器), 或者其他对象(如果函数被 call() 或 apply() ).
  • 采用时那个轻错, 所以只有在下面两单情况常常才会使:

 在构造器中

 对象的道(包括创造的闭包)中

16. for-in 循环

  • 只用于 object/map/hash 的遍历
  • 针对 Array 用 for-in 循环有时见面生出错. 因为它们并无是于 0 到 length – 1 拓展遍历, 而是所有出现于对象及其原型链的键值. 下面就是是有的失败的应用案例: function printArray(arr) {
        for (var key in arr) {
            print(arr[key]);
        }
    }
     
    printArray([0,1,2,3]); // This works.
     
    var a = new Array(10);
    printArray(a); // This is wrong.
     
    a = document.getElementsByTagName(‘*’);
    printArray(a); // This is wrong.
     
    a = [0,1,2,3];
    a.buhu = ‘wine’;
    printArray(a); // This is wrong again.
     
    a = new Array;
    a[3] = 3;
    printArray(a); // This is wrong again.
  • 假设遍历数组通常用最为常见的 for
    循环.
    function printArray(arr) {
        var l = arr.length;
        for (var i = 0; i < l; i++) {
            print(arr[i]);
        }
    }

17. 提到数组

  • 世代不要使 Array 作为 map/hash/associative 数组.
  • 数组中无同意利用非整型作为索引值,
    所以也就是未允用关联数组. 而代她用 Object 来表示 map/hash 对象. Array 仅仅是扩张自 Object (类似于其它 JS 中的目标, 就如 Date , RegExp 和 String )一 样来使用.

18. 大多实行字符串

  • 不用使用
  • 甭这么描绘长字符串: 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 的标准规范.

19. Array 和 Object 字面量

  • 使用
  • 使 Array 和 Object 语法, 而非应用 Array 和 Object 构造器.
  • 下 Array 构造器很易为传参不适于导致错误.
     
    // Length is 3.
    var a1 = new Array(x1, x2, x3);
     
    // Length is 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);
     
    // Length is 0.
    var a4 = new Array();
  • 假定传入一个参数而非是2单参数, 数组的长十分有或就是无是若愿意之数值了. 为了避免这些歧义,我们应以重复易于读之直接量来声明.
     
    var a = [x1, x2, x3];
    var a2 = [x1, x2];
    var a3 = [x1];
    var a4 = [];
  • 尽管 Object 构造器没有上述类似之题材, 但鉴于可读性和一致性考虑, 最好或于字面上再也清楚地指明.
    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
    };

20. 窜内置对象的原型

  • 不要
  • 绝对不要改动内置对象, 如 Object.prototype 和 Array.prototype 的原型. 而改内置对象, 如 Function.prototype 的原型, 虽然少危险把, 但仍会促成调试时的新奇现象. 所以也只要避免修改该原型.

21. IE产卵的标准注释

  • 决不采用
  • 绝不这样子写:
     
        var f = function () {
            /@cc_on if (@_jscript) { return 2* @/ 3; /@ }
    @
    /
        };
     
     
            条件注释妨碍自动化工具的行, 因为在运行时, 它们会变动 JavaScript 语法树.

第二、JavaScript 编码风格

1. 命名

    通常, 使用 functionNamesLikeThis ,
variableNamesLikeThis , ClassNamesLikeThis , EnumNamesLikeThis ,
methodNamesLikeThis , 和
SYMBOLIC_CONSTANTS_LIKE_THIS .

A. 属性和艺术

  • 文本要相近吃的 私有 属性, 变量和方法名当以下划线 “_” 开头.
  • 保护 属性, 变量和章程名不需要下划线开头, 和集体变量叫一样.

    更多关于 私有 和 保护 的信息见, visibility.

B.方法以及函数参数

    可选参数为 opt_ 开头.

  • 函数的参数个数不固定时, 应该长最后一个参数 var_args 也参数的单数. 你吧足以不安装 var_args 而代表使用 arguments .
  • 可选和可变参数应该在 @param
    标记中证明清楚. 虽然当时片只规定对编译器没有其余影响, 但还是要尽量遵守

C. Getters 和 Setters

   Getters 和 setters 并无是必备的. 但万一使用其了, 就伸手用 getters 命名成 getFoo() 形式, 将 setters 命名成 setFoo(value) 形式. (对于布尔路的 getters, 使用 isFoo() 也可.)

D. 命名空间

  • JavaScript 不支持担保以及命名空间.
  • 非便于发觉及调试全局命名的冲,
    多个系统融为一体时还可能因命名冲突造成大要紧的问题. 为了提高 JavaScript 代码复用率, 我们本下面的预定以避免冲突.
  • 呢全局代码应用命名空间
  • 以大局作用域上, 使用一个唯一的, 与工程/库相关的名作前缀标识. 比如, 你的工程是 “Project Sloth”, 那么命名空间前缀可取为 sloth.* .
     
    var sloth = {};
    sloth.sleep = function() {

    };
  • 许多 JavaScript 库, 包括 the Closure
    Library and Dojo
    toolkit 为公提供了声明你协调的命名空间的函数.
    比如:
     
    goog.provide(‘sloth’);
     
    sloth.sleep = function() {

    };
  • 妇孺皆知命名空间所有权

 当选择了一个子命名空间, 请确保父命名空间的领导人员了解乃以就此谁子命名空间, 比如说, 你吗工程 ‘sloths’ 创建一个 ‘hats’ 子命名空间, 那包 Sloth 团队人口知情乃当使用 sloth.hats .

 外部代码和里面代码应用 不同之命名空间

 “外部代码” 是指自于公代码体系之表面, 可以独立编译. 内外部命名该严格保持独立. 如果您采取了标库, 他的有所目标还在 foo.hats.* 下, 那么您协调的代码不可知当 foo.hats.* 下命名, 因为非常有或其他团伙也于里面命名.
 
foo.require(‘foo.hats’);
 
/**
* WRONG — Do NOT do this.
* @constructor
* @extend {foo.hats.RoundHat}
*/
foo.hats.BowlerHat = function() {
};
 

 如果你要以外表命名空间受到定义新的 API,
那么你当一直导出一卖外部库, 然后在马上卖代码中修改. 在您的里边代码中, 应该通过他们的里名字来调用内 API , 这样保持一致性可让编译器更好的优化你的代码.
 
foo.provide(‘googleyhats.BowlerHat’);
 
foo.require(‘foo.hats’);
 
/**
* @constructor
* @extend {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());
};
 
 

 不要对命名空间创建别名.
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);
};
 

 不要在全局范围外创建别名, 而仅以函数块作用域中以.

E. 文件名

    文件称当以小写字符, 以避免在微系统平台达成不识别大小写的命名方式. 文件称因 .js 结 尾, 不要含除 – 和 _ 外的标点(使用 – 优于 _ ).

F. JS 钩子

    JS 钩子一律使用 “J-” 前缀,如:#J-ui-repeater

2. 自定义 toString() 方法

  • 有道是总是成功调用且不要抛异常.
  • 不过自定义 toString() 方法, 但确保您的兑现方式满足:
  • 连天成功

  • 未曾其余负面影响. 如果非饱这简单独规范, 那么可能会见造成惨重的问题, 比如, 如果 toString() 调用了含有 assert 的函数, assert 输出导致破产的目标, 这在 toString() 也会见给调用.

3. 延初始化

  • 可以
  • 尚未必要在每次声明变量时虽用那初始化.

4. 明明作用域

  • 其他时候还需
  • 别时刻都要肯定意图域 –
    提高可移植性和清晰度. 例如, 不要借助让意域链中之 window 对象. 可能在其他使用被, 你函数中之 window 不是靠之前的良窗口对象.

5. 代码格式化

    主要以C++ 格式规范 (中文版),
针对 JavaScript, 还有下面有叠加说明.

A. 大括号

 
    分号会受隐式插入到代码中, 所以你要以和一行上插入大括号. 例如:
if (something) {
// …
} else {
// …
}

B. 数组和对象的初始化

  • 如新开始值不是生丰富, 就保持写于单行上:
    var arr = [1, 2, 3]; // No space after [ or before ].
    var obj = {a: 1, b: 2, c: 3}; // No space after { or before }.
  • 初始值占用多尽时, 缩进2个缺损格.
    // Object initializer.
    var inset = {
    top: 10,
    right: 20,
    bottom: 15,
    left: 12 };
     
    // Array initializer.
    this.rows_ = [
    ‘”Slartibartfast” <fjordmaster@magrathea.com>’,
    ‘”Zaphod Beeblebrox” <theprez@universe.gov>’,
    ‘”Ford Prefect” <ford@theguide.com>’,
    ‘”Arthur Dent” <has.no.tea@gmail.com>’,
    ‘”Marvin the Paranoid Android” <marv@googlemail.com>’,
    ‘the.mice@magrathea.com’ ];
     
    // Used in a method call.
    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
    };

C. 函数参数

  • 尽可能吃函数参数在跟一行上.
    如果一行超过 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)
    {
    // …
    };
     
    // Four-space, one argument per line. Works with long function
    names,
    // survives renaming, and emphasizes each argument.
    goog.foo.bar.doThingThatIsVeryDifficultToExplain = function(
        veryDescriptiveArgumentNumberOne,
        veryDescriptiveArgumentTwo,
        tableModelEventHandlerProxy,
        artichokeDescriptorAdapterIterator) {
    // …
    };
     
    // Parenthesis-aligned indentation, wrap at 80. Visually groups
    arguments,
    // low on space.
    function foo(veryDescriptiveArgumentNumberOne,
    veryDescriptiveArgumentTwo,
        tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator)
    {
    // …
    }
     
    // Parenthesis-aligned, one argument per line. Visually groups and
    // emphasizes each individual argument.
    function bar(veryDescriptiveArgumentNumberOne,
        veryDescriptiveArgumentTwo,
        tableModelEventHandlerProxy,
        artichokeDescriptorAdapterIterator) {
    // …
    }

D. 传递匿名函数

    如果参数中发出影名函数, 函数体从调用该函数的左边开始缩进2独空格, 而不是从 function 这个重中之重字开始. 这给匿名函数更加容易读 (不要增加多从未必要之缩进让函数体显示在屏幕的右边). 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);
}
});

E. 更多之缩进

实在, 除了 初始化数组和对象 , 和传递匿名函数外, 所有被拆毁的多行文本要么捎与事先的表达式左对旅, 要么为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();
}

F. 空行

运空行来分一组逻辑上互动关联的代码片段.
doSomethingTo(x);
doSomethingElseTo(x);
andThen(x);
 
nowDoSomethingWith(y);
 
andNowWith(z);

G. 其次第一以及三元操作符

操作符始终与随着提高, 这样便甭操心分号的隐式插入问题. 如果一行实在放不产, 还是按照上述的缩进风格来转换行. 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;

6. 括号

  • 单单以得的下以
  • 不要滥用括号, 只于必要的时候使用它.
  • 对于同样初次操作符(如 delete , typeof 和 void ), 或是在一些关键词(如 return , throw , case , new
    )之后, 不要使用括号.

7. 字符串

  • 使用 ‘ 优于 “
  • 单引号 (‘) 优于复引号 (“). 当你创造一个暗含 HTML 代码的字符串时虽知晓它们的补了.
  • var msg = ‘This is some HTML’;

8. 可见性 (私有域和保护域)

  • 引进应用 JSDoc 中的少独记: @private 和 @protected
  • JSDoc 的个别单记号 @private 和 @protected 用来指明类, 函数, 属性的可见性域.
  • 标志为 @private 的全局变量和函数, 表示她只能在手上文件被访问.
  • 标记为 @private 的构造器, 表示该类只能以当前文件或者其静态/普通成员中实例化; 私有构造器的公物静态属性在脚下文件的别样地方都只是看, 通过 instanceof 操作符也可.
  • 永不要啊 全局变量, 函数, 构造器加 @protected 标记. // File 1.
    // AA_PrivateClass_ and AA_init_ are accessible because they are
    global
    // and in the same file.
     
    /**
    * @private
    * @constructor
    */
    AA_PrivateClass_ = function() {
    };
     
    /** @private */
    function AA_init_() {
        return new AA_PrivateClass_();
    }
     
    AA_init_();
     
  • 标记为 @private 的属性, 在眼前文件被不过看它; 如果是类属性私有, “拥有”该属性的切近的装有静态/普通成员也可是看, 但它们不可知被不同文件被之子类访问还是覆盖.
  • 号为 @protected 的性质, 在眼前文件中而看它, 如果是类属性保护, 那么”拥有”该属性之类似及其子类中的备静态/普通成员为不过访问.
  • 注意: 这跟 C+,
    Java 中的私和保障不同, 它们是于眼前文件被, 检查是不是享有访问私有/保护属性之权能, 有权力即可访问, 而不是只能在和一个好像还是接近层次上. 而 C+ 中的民用属性不克给子类覆盖. (C++/Java 中之私家/保护是据作用域上的但是访问性, 在可访问性上之限制. JS 中是当限以作用域上. PS: 可见性是同作用域对应)
     
    // File 1.
     
    /** @constructor */
    AA_PublicClass = function() {
    };
     
    /** @private */
    AA_PublicClass.staticPrivateProp_ = 1;
     
    /** @private */
    AA_PublicClass.prototype.privateProp_ = 2;
     
    /** @protected */
    AA_PublicClass.staticProtectedProp = 31;
     
    /** @protected */
    AA_PublicClass.prototype.protectedProp = 4;
     
    // 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;     };

9. JavaScript 类型

  • 强烈建议你去用编译器.
  • 只要用 JSDoc, 那么尽量具体地, 准确地根据它们的平整来开类型说明. 目前支持少数栽
    JS2 和 JS1.x 类型规范.
  • JavaScript 类型语言
  • JS2 提议遭到涵盖了扳平栽描述
    JavaScript 类型的正式语法, 这里我们于 JSDoc 中应用该来描述函数参数和返回值的类型.
  • JSDoc 的种语言, 按照 JS2 规范, 也拓展了确切改, 但编译器仍然支撑旧语法.
     

名称

语法

描述

弃用语法

普通类型

{boolean} , {Window} , {goog.ui.Menu}

普通类型的描述方法.

 

复杂类型

{Array.<string>}
字符串数组. {Object.<string, number>}
键为字符串, 值为整数的对象类型.

参数化类型, 即指定了该类型中包含的一系列"类型参数". 类似于 Java 中的泛型.

 

联合类型

{(number|boolean)}
一个整数或者布尔值.

表示其值可能是 A 类型, 也可能是 B 类型

{(number,boolean)} , {number|boolean} , {(number||boolean)}

记录类型

myNum: number, myObject 
由现有类型组成的类型.

表示包含指定成员及类型的值. 这个例子中, myNum 为 number 类型, myObject 为任意类型.
注意大括号为类型语法的一部分. 比如, Array.<{length}> , 表示一具有 length 属性的 Array 对象.

 

可为空类型

{?number}
一个整型数或者为 NULL

表示一个值可能是 A 类型或者 null . 默认, 每个对象都是可为空的. 注意: 函数类型不可为空.

{number?}

非空类型

{!Object}
一个对象, 但绝不会是 null 值.

说明一个值是类型 A 且肯定不是 null. 默认情况下, 所有值类型 (boolean, number, string, 和 undefined) 不可为空.

{Object!}

函数类型

{function(string, boolean)}
具有两个参数 ( string 和 boolean) 的函数类型, 返回值未知.

说明一个函数.

 

函数返回类型

{function(): number}
函数返回一个整数.

说明函数的返回类型.

 

函数的 this 类型

{function(this:goog.ui.Menu, string)}
函数只带一个参数 (string), 并且在上下文 goog.ui.Menu 中执行.

说明函数类型的上下文类型.

 

可变参数

{function(string, …[number]): number}
带一个参数 (字符类型) 的函数类型, 并且函数的参数个数可变, 但参数类型必须为 number.

说明函数的可变长参数.

 

可变长的参数 (使用 @param 标记)

@param {…number} var_args
函数参数个数可变.

使用标记, 说明函数具有不定长参数.

 

函数的 缺省参数

{function(?string=, number=)}
函数带一个可空且可选的字符串型参数, 一个可选整型参数. = 语法只针对 function 类型有效.

说明函数的可选参数.

 

函数 可选参数 (使用 @param 标记)

@param {number=} opt_argument
number 类型的可选参数.

使用标记, 说明函数具有可选参数.

 

所有类型

{*}

表示变量可以是任何类型.

 

  • JavaScript中的型
     
     

类型示例

值示例

描述

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)

字符串对象

boolean

true
false
Boolean(0)

布尔值

Boolean

new Boolean(true)

布尔对象

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.<number>

[11, 22, 33]

整型数组

Array.<Array.<string>>

[[‘one’, ‘two’, ‘three’], [‘foo’, ‘bar’]]

字符串数组的数组

Object

{}
{foo: ‘abc’, bar: 123, baz: null}

 

Object.<string>

{‘foo’: ‘bar’}

值为字符串的对象.

Object.<number, string>

var obj = {};
obj[1] = ‘bar’;

键为整数, 值为字符串的对象. 注意, JavaScript 中, 键总是被转换成字符串, 所以 obj[‘1’] == obj[1] . 也所以, 键在 for…in 循环中是字符串类型. 但在编译器中会明确根据键的类型来查找对象.

Function

function(x, y) {
return x * y;
}

函数对象

function(number, number): number

function(x, y) {
return x * y;
}

函数值

SomeClass

/** @constructor */
function SomeClass() {}

new SomeClass();

 

SomeInterface

/** @interface */
function SomeInterface() {}

SomeInterface.prototype.draw = function() {};

 

project.MyClass

/** @constructor */
project.MyClass = function () {}

new project.MyClass()

 

project.MyEnum

/** @enum {string} */
project.MyEnum = {
BLUE: ‘#0000dd’,
RED: ‘#dd0000’
};

枚 举

Element

document.createElement(‘div’)

DOM 中的元素

Node

document.body.firstChild

DOM 中的节点.

HTMLInputElement

htmlDocument.getElementsByTagName(‘input’)[0]

DOM 中, 特定类型的元

    • 但空 vs. 可选 参数和属性
       
      JavaScript 是同种植弱类型语言, 明白不过挑选, 非空和莫定义参数或性能之间的细微差别还是大重大的.
       
      靶类型(引用类型)默认非空. 注意: 函数类型默认不能够也空. 除了字符串, 整型, 布尔, undefined 和 null 外, 对象好是外类型.
      /**
      * Some class, initialized with a value.
      * @param {Object} value Some value.
      * @constructor
      */
      function MyClass(value) {
      /**
      * Some value.
      * @type {Object}
      * @private
      */
      this.myValue_ = value;
      }
      语编译器 myValue_ 属性为平目标要 null. 如果 myValue_ 永远都不会见否 null, 就应当如下宣示:
      /**
      * Some class, initialized with a non-null value.
      * @param {!Object} value Some value.
      * @constructor
      */
      function MyClass(value) {
      /**
      * Some value.
      * @type {!Object}
      * @private
      */
          this.myValue_ = value;
      }
      这么, 当编译器在代码中相见 MyClass 为 null 时, 就见面吃出警告.

函数的可选参数可能当运转时无概念,
所以如果她们以受予以给类属性, 需要声明成:
/**
* Some class, initialized with an optional value.
* @param {Object=} opt_value Some value (optional).
* @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 也并无害处, 但鉴于可阅读性还是写成上述的样子.
 
终极, 属性的非空和可选并不矛盾, 属性既可是非空, 也不过可选的. 下面的季种声明各不相同:
/**
* Takes four arguments, two of which are nullable, and two of which
are
* optional.
* @param {!Object} nonNull Mandatory (must not be undefined), must not
be null.
* @param {Object} mayBeNull Mandatory (must not be undefined), may be
null.
* @param {!Object=} opt_nonNull Optional (may be undefined), but if
present,
* must not be null!
* @param {Object=} opt_mayBeNull Optional (may be undefined), may be
null.
*/
function strangeButTrue(nonNull, mayBeNull, opt_nonNull,
opt_mayBeNull) {
// …
};

10. 注释

A. 使用 JSDoc

 
咱俩利用
JSDoc 中的注解风格. 行内注释使用 // 变量 的形式. 另外, 我们啊仍 C++ 代码注释风格 . 这吗就是说公待:

  • 版权和著作权的消息,
  • 文件注释中当写清楚该公文之主干信息(如, 这段代码的效应摘要, 如何用, 与争东西有关), 来告诉那些不熟悉代码的读者.
  • 仿佛, 函数, 变量和必要之笺注,
  • 梦想在怎样浏览器被实行,
  • 对的尺寸写, 标点和拼写.
     
    为避免出现句子片段, 请以恰当的大/小写不过词开始, 并以适当的标点结束之句子.现在借而保障这段代码的凡一样各类新家. 这恐怕正是如此的! 目前广大编译器可自 JSDoc 中提类型信息, 来对代码进行求证, 删除和压缩. 因此, 你十分有必不可少去熟悉科学完好的 JSDoc .

B. 顶层/文件注释

 
顶层注释用于告诉不熟识这段代码的读者这个文件中含哪些东西.
应该提供文件的横内容, 它的撰稿人, 依赖关系和兼容性信息. 如下:
// Copyright 2009 Google Inc. All Rights Reserved.
 
/**
* @fileoverview Description of file, its uses and information
* about its dependencies.
* @author user@google.com (Firstname Lastname)
*/

C. 类注释

  • 每个接近的概念都使附带一份注释,
    描述类的效应以及用法. 也要征构造器参数. 如果此类继承自其它类, 应该采取 @extends 标记. 如果此类是对准接口的实现, 应该使用 @implements 标记.
    /**
    * Class making something fun and easy.
    * @param {string} arg1 An argument that makes this more
    interesting.
    * @param {Array.<number>} arg2 List of numbers to be
    processed.
    * @constructor
    * @extends {goog.Disposable}
    */
    project.MyClass = function(arg1, arg2) {
    // …
    };
    goog.inherits(project.MyClass, goog.Disposable);
  • 计及函数的注释. 提供参数的说明. 使用完的词, 并用第三人称来书写道说明.
     
    /**
    * Converts text to some completely different text.
    * @param {string} arg1 An argument that makes this more
    interesting.
    * @return {string} Some return value.
    */
    project.MyClass.prototype.someMethod = function(arg1) {
    // …
    };
     
    /**
    * Operates on an instance of MyClass and returns something.
    * @param {project.MyClass} obj Instance of MyClass which leads to a
    long
    * comment that needs to be wrapped to two lines.
    * @return {boolean} Whether something occured.
    */
    function PR_someMethod(obj) {
    // …
    }
  • 对有简约的, 不带来参数的 getters, 说明可以忽略.
    /**
    * @return {Element} The element for the component.
    */
    goog.ui.Component.prototype.getElement = function() {
        return this.element_;
    };

D. 属性注释

 
        需要针对性能进行注释.
 
/**
* Maximum number of things per pane.
* @type {number}
*/
project.MyClass.prototype.someProperty = 4;

E. 类型转换的诠释

奇迹, 类型检查不可知好纯粹地测算出表达式的档次, 所以应该于其填补加类型标记注释来明确的, 并且必须以表达式和路标签外面包裹括号.
/** @type {number} */ (x)
(/** @type {number} */ x)

F. JSDoc 缩进

  • 比方你当 @param , @return ,
    @supported , @this 或 @deprecated 中断行, 需要像于代码中一律, 使用4只空格作为一个缩进层次.
    /**
    * 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;
    };
  • 枚举 /**
    * Enum for tri-state values.
    * @enum {number}
    */
    project.TriState = {
        TRUE: 1,
        FALSE: -1,
        MAYBE: 0
    };
            注意一下, 枚举也不无行类 型, 所以可以算作参数类型来用.
    /**
    * Sets project state.
    * @param {project.TriState} state New project state.
    */
    project.setState = function(state) {
    // …
    };

G. Typedefs

偶尔类型会特别复杂. 比如下面的函数, 接收 Element 参数:
/**
* @param {string} tagName
* @param
{(string|Element|Text|Array.<Element>|Array.<Text>)}
contents
* @return {Element}
*/
goog.createElement = function(tagName, contents) {

};
 
 
公可采取 @typedef 标记来定义个常因此的型表达式.
/** @typedef
{(string|Element|Text|Array.<Element>|Array.<Text>)} */
goog.ElementContent;
 
/**
* @param {string} tagName
* @param {goog.ElementContent} contents
* @return {Element}
*/
goog.createElement = function(tagName, contents) {

};

H. JSDoc 标记表

标记

模板 & 例子

描述

类型检测支持

@param

@param {Type} 变量名 描述如: /**
* Queries a Baz for items.
* @param {number} groupNum Subgroup id to query.
* @param {string|number|null} term An itemName,
* or itemId, or null to search everything.
*/
goog.Baz.prototype.query = function(groupNum, term) {
// …
};

给方法, 函数, 构造器中的参数添加说明.

完全支持.

@return

@return {Type} 描述如: /**
* @return {string} The hex ID of the last item.
*/
goog.Baz.prototype.getLastId = function() {
// …
return id;
};

给方法, 函数的返回值添加说明. 在描述布尔型参数时, 用 "Whether the component is visible" 这种描述优于 "True if the component is visible, false otherwise". 如果函数没有返回值, 就不需要添加 @return 标记.

完全支持.

@author

@author username@google.com (first last)如: /**
* @fileoverview Utilities for handling textareas.
* @author kuth@google.com (Uthur Pendragon)
*/

表明文件的作者, 通常仅会在 @fileoverview 注释中使用到它.

不需要.

@see

@see Link如: /**
* Adds a single item, recklessly.
* @see #addSafely
* @see goog.Collect
* @see goog.RecklessAdder#add

给出引用链接, 用于进一步查看函数/方法的相关细节.

不需要.

@fileoverview

@fileoverview 描述如: /**
* @fileoverview Utilities for doing things that require this very long
* but not indented comment.
* @author kuth@google.com (Uthur Pendragon)
*/

文件通览.

不需要.

@constructor

@constructor如: /**
* A rectangle.
* @constructor
*/
function GM_Rect() {

}

指明类中的构造器.

会检查. 如果省略了, 编译器将禁止实例化.

@interface

@interface如: /**
* A shape.
* @interface
*/
function Shape() {};
Shape.prototype.draw = function() {};

/**
* A polygon.
* @interface
* @extends {Shape}
*/
function Polygon() {};
Polygon.prototype.getSides = function() {};

指明这个函数是一个接口.

会检查. 如果实例化一个接口, 编译器会警告.

@type

@type Type
@type {Type}如: /**
* The message hex ID.
* @type {string}
*/
var hexId = hexId;

标识变量, 属性或表达式的类型. 大多数类型是不需要加大括号的, 但为了保持一致, 建议统一加大括号.

会检查

@extends

@extends Type
@extends {Type}如: /**
* Immutable empty node list.
* @constructor
* @extends goog.ds.BasicNodeList
*/
goog.ds.EmptyNodeList = function() {

};

与 @constructor 一起使用, 用来表明该类是扩展自其它类的. 类型外的大括号可写可不写.

会检查

@implements

@implements Type
@implements {Type}如: /**
* A shape.
* @interface
*/
function Shape() {};
Shape.prototype.draw = function() {};

/**
* @constructor
* @implements {Shape}
*/
function Square() {};
Square.prototype.draw = function() {

};

与 @constructor 一起使用, 用来表明该类实现自一个接口. 类型外的大括号可写可不写.

会检查. 如果接口不完整, 编译器会警告.

@lends

@lends objectName
@lends {objectName}如: goog.object.extend(
Button.prototype,
/** @lends {Button.prototype} */ {
isButton: function() { return true; }
});

表示把对象的键看成是其他对象的属性. 该标记只能出现在对象语法中. 注意, 括号中的名称和其他标记中的类型名称不一样, 它是一个对象名, 以"借过来"的属性名命名. 如, @type {Foo} 表示 "Foo 的一个实例", but @lends {Foo} 表示 "Foo 构造器". 更多有关此标记的内容见 JSDoc Toolkit docs.

会检查

@private

@private如: /**
* Handlers that are listening to this logger.
* @type Array.<Function>
* @private
*/
this.handlers_ = [];

指明那些以下划线结尾的方法和属性是 私 有的. 不推荐使用后缀下划线, 而应改用 @private.

需要指定标志来开启.

@protected

@protected如: /**
* Sets the component’s root element to the given element. Considered
* protected and final.
* @param {Element} element Root element for the component.
* @protected
*/
goog.ui.Component.prototype.setElementInternal = function(element) {
// …
};

指明接下来的方法和属性是 被 保护的. 被保护的方法和属性的命名不需要以下划线结尾, 和普通变量名没区别.

需要指定标志来开启.

@this

@this Type
@this {Type}如: pinto.chat.RosterWidget.extern(‘getRosterElement’,
/**
* Returns the roster widget element.
* @this pinto.chat.RosterWidget
* @return {Element}
*/
function() {
return this.getWrappedComponent_().getElement();
});

指明调用这个方法时, 需要在哪个上下文中. 当 this 指向的不是原型方法的函数时必须使用这个标记.

会检查

@supported

@supported 描述如: /**
* @fileoverview Event Manager
* Provides an abstracted interface to the
* browsers’ event systems.
* @supported So far tested in IE6 and FF1.5
*/

在文件概述中用到, 表明支持哪些浏览器.

不需要.

@enum

@enum {Type}如: /**
* Enum for tri-state values.
* @enum {number}
*/
project.TriState = {
TRUE: 1,
FALSE: -1,
MAYBE: 0
};

用于枚举类型.

完全支持. 如果省略, 会认为是整型.

@deprecated

@deprecated 描述如: /**
* Determines whether a node is a field.
* @return {boolean} True if the contents of
* the element are editable, but the element
* itself is not.
* @deprecated Use isField().
*/
BN_EditUtil.isTopEditableField = function(node) {
// …
};

告诉其他开发人员, 此方法, 函数已经过时, 不要再使用. 同时也会给出替代方法或函数.

不需要

@override

@override如: /**
* @return {string} Human-readable representation of project.SubClass.
* @override
*/
project.SubClass.prototype.toString() {
// …
};

指明子类的方法和属性是故意隐藏了父类的方法和属性. 如果子类的方法和属性没有自己的文档, 就会继承父类的.

会检查

@inheritDoc

@inheritDoc如: /** @inheritDoc */
project.SubClass.prototype.toString() {
// …
};

指明子类的方法和属性是故意隐藏了父类的方法和属性, 它们具有相同的文档. 注意: 使用 @inheritDoc 意味着也同时使用了 @override.

会检查

@code

{@code …}如: /**
* Moves to the next position in the selection.
* Throws {@code goog.iter.StopIteration} when it
* passes the end of the range.
* @return {Node} The node at the next position.
*/
goog.dom.RangeIterator.prototype.next = function() {
// …
};

说明这是一段代码, 让它能在生成的文档中正确的格式化.

不适用.

@license or @preserve

@license 描述如: /**
* @preserve Copyright 2009 SomeThirdParty.
* Here is the full license text and copyright
* notice for this file. Note that the notice can span several
* lines and is only terminated by the closing star and slash:
*/

所有被标记为 @license 或 @preserve 的, 会被编译器保留不做任何修改而直接输出到最终文挡中. 这个标记让一些重要的信息(如法律许可或版权信息)原样保留, 同样, 文本中的换行也会被保留.

不需要.

@noalias

@noalias如: /** @noalias */
function Range() {}

在外部文件中使用, 告诉编译器不要为这个变量或函数重命名.

不需要.

@define

@define {Type} 描述如: /** @define {boolean} */
var TR_FLAGS_ENABLE_DEBUG = true;

/** @define {boolean} */
goog.userAgent.ASSUME_IE = false;

表示该变量可在编译时被编译器重新赋值. 在上面例子中, BUILD 文件中指定了 –define=’goog.userAgent.ASSUME_IE=true’ 这个编译之后, 常量 goog.userAgent.ASSUME_IE 将被全部直接替换为 true.

不需要.

@export

@export如: /** @export */
foo.MyPublicClass.prototype.myPublicMethod = function() {
// …
};

上面的例子代码, 当编译器运行时指定 –generate_exports 标志, 会生成下面的代码: goog.exportSymbol(‘foo.MyPublicClass.prototype.myPublicMethod’,
foo.MyPublicClass.prototype.myPublicMethod); 编译后, 将源代码中的名字原样导出. 使用 @export 标记时, 应该

  1. 包含 //javascript/closure/base.js, 或者
  2. 在代码库中自定义 goog.exportSymbol 和 goog.exportProperty 两个方法, 并保证有相同的调用方式.

不需要.

@const

@const如: /** @const */ var MY_BEER = ‘stout’;

/**
* My namespace’s favorite kind of beer.
* @const
* @type {string}
*/
mynamespace.MY_BEER = ‘stout’;

/** @const */ MyClass.MY_BEER = ‘stout’;

声明变量为只读, 直接写在一行上. 如果其他代码中重写该变量值, 编译器会警告.
常量应全部用大写字符, 不过使用这个标记, 可以帮你消除命名上依赖. 虽然 jsdoc.org 上列出的 @final 标记作用等价于 @const , 但不建议使用. @const 与 JS1.5 中的 const 关键字一致. 注意, 编译器不禁止修改常量对象的属性(这与 C++ 中的常量定义不一样). 如果可以准确推测出常量类型的话,那么类型申明可以忽略. 如果指定了类型, 应该也写在同一行上. 变量的额外注释可写可不写.

支持.

@nosideeffects

@nosideeffects如: /** @nosideeffects */
function noSideEffectsFn1() {
// …
};

/** @nosideeffects */
var noSideEffectsFn2 = function() {
// …
};

/** @nosideeffects */
a.prototype.noSideEffectsFn3 = function() {
// …
};

用于对函数或构造器声明, 说明调用此函数不会有副作用. 编译器遇到此标记时, 如果调用函数的返回值没有其他地方使用到, 则会将这个函数整个删除.

不需要检查.

@typedef

@typedef如: /** @typedef {(string|number)} */
goog.NumberLike;

/** @param {goog.NumberLike} x A number or a string. */
goog.readNumber = function(x) {

}

这个标记用于给一个复杂的类型取一个别名.

会检查

@externs

@externs如: /**
* @fileoverview This is an externs file.
* @externs
*/

var document;

指明一个外部文件.

不会检查

 
        在第三在代码中, 你还见面视其他部分 JSDoc 标记. 这些标记在 JSDoc Toolkit Tag
Reference 都来介绍至, 但在 Google 的代码中, 目前不推荐使用. 你可认为这些是未来见面为此到的 “保留” 名. 它们含有:

  • @augments
  • @argument
  • @borrows
  • @class
  • @constant
  • @constructs
  • @default
  • @event
  • @example
  • @field
  • @function
  • @ignore
  • @inner
  • @link
  • @memberOf
  • @name
  • @namespace
  • @property
  • @public
  • @requires
  • @returns
  • @since
  • @static
  • @version

    I. JSDoc 中的 HTML

恍如于 JavaDoc, JSDoc 支持广大 HTML 标签, 如 <code>, <pre>, <tt>,
<strong>, <ul>, <ol>, <li>, <a>,
等等. 这就是是说 JSDoc 不会见了本纯文本中书的格式. 所以, 不要在 JSDoc 中, 使用空白字符来开格式化:
/**
* Computes weight based on three factors:
* items sent
* items received
* last timestamp
*/
上面的笺注, 出来的结果是:
 
Computes weight based on three factors: items sent items received items
received
该这么写:
/**
* Computes weight based on three factors:
* <ul>
* <li>items sent
* <li>items received
* <li>last timestamp
* </ul>
*/

除此以外, 也不用含其他 HTML 或类 HTML 标签, 除非你便想吃她解析成 HTML 标签.
/**
* Changes <b> tags to <span> tags.
*/

出去的结果是:

Changes tags to tags.

另外, 也应该在源代码文件被叫其他人再可读, 所以不要过度使用 HTML 标签:
/**
* Changes <b> tags to <span> tags.
*/

面的代码中, 其他人即便充分麻烦理解您想干嘛, 直接改动成为下面的师就理解多矣:
/**
* Changes ‘b’ tags to ‘span’ tags.
*/

11. 编译

引进用
建议乃去动 JS 编译器, 如 Closure
Compiler.

12. Tips and Tricks

    A. JavaScript 小技巧

(1) True 和 False 布尔表达式

下面的布尔表达式都回去 false:

  • null
  • undefined
  • ” 空字符串
  • 0 数字0

可是小心下面的, 可还回 true:

  • ‘0’ 字符串0
  • [] 空数组
  • {} 空对象

脚段于不好之代码:
while (x != null) {
 
 
若得一直写成下面的花样(只要你指望 x 不是 0 和空字符串, 和 false):
while (x) {
 
 
假使你想检查字符串是否也 null
或空:
if (y != null && y != ”) {
 
 
但是如此见面又好:
if (y) {
 
 
留意: 还有不少内需注意的地方, 如:

  • Boolean(‘0’) == true
    ‘0’ != true
  • 0 != null
    0 == []
    0 == false
  • Boolean(null) == false
    null != true
    null != false
  • Boolean(undefined) == false
    undefined != true
    undefined != false
  • Boolean([]) == true
    [] != true
    [] == false
  • Boolean({}) == true
    {} != true
    {} != false

        (2) 条件(三元)操作符 (?:)

 
大年初一操作符用于代替下面的代码:
if (val != 0) {
return foo();
} else {
return bar();
}
 
 
乃可形容成:
return val ? foo() : bar();
 
 
当生成 HTML 代码时也是深有因此底:
var html = ‘<input type=”checkbox”‘ +
(isChecked ? ‘ checked’ : ”) +
(isEnabled ? ” : ‘ disabled’) +
‘ name=”foo”>’;

(3) && 和 ||

二元布尔操作符是不过堵塞的, 只有以必要时才见面算到最终一件. “||” 被如当 ‘default’ 操作符, 因为可以如此:
/* @param {=} opt_win */
function foo(opt_win) {
var win;
if (opt_win) {
    win = opt_win;
} else {
    win = window;
} // …
}
 
 
卿可以使她来简化上面的代码:
/* @param {=} opt_win */
function foo(opt_win) {
var win = opt_win || window;
// …
}
 
 
“&&” 也可略代码.比如:
if (node) {
if (node.kids) { if (node.kids[index]) {
    foo(node.kids[index]);
} } }
 
 
你可以像这样来利用:
if (node && node.kids && node.kids[index]) {
    foo(node.kids[index]);
}
 
 
或者:
var kid = node && node.kids && node.kids[index];
if (kid) {
    foo(kid);
}
 
 
但这样就算发出一定量过分了:
node && node.kids && node.kids[index] && foo(node.kids[index]);

(4) 使用 join() 来创造字符串

 
普普通通是这么使的:
function listHtml(items) {
var html = ‘<div>’;
for (var i = 0; i < items.length; ++i) {
    if (i > 0) {
        html += ‘, ‘;
    }
    html += itemHtml(items[i]);     }
    html += ‘</div>’;
    return html;
}
 
 
可是如此在 IE 下特别缓慢, 可以就此脚的办法:
function listHtml(items) {
var html = [];
for (var i = 0; i < items.length; ++i) {
    html[i] = itemHtml(items[i]);
}
return ‘<div>’ + html.join(‘, ‘) + ‘</div>’; }
你为堪是用数组作为字符串构造器,
然后透过 myArray.join(”) 转换成字符串. 不过鉴于赋值操作快被数组的 push() , 所以尽量采取赋值操作.

(5) 遍历 Node List

 
Node lists 是由此吃节点迭代器加一个过滤器来实现之. 这表示收获他的性质, 如 length 的时复杂度为 O(n), 通过 length 来遍历整个列表需要 O(n^2).
var paragraphs = document.getElementsByTagName(‘p’);
for (var i = 0; i < paragraphs.length; i++) {
    doSomething(paragraphs[i]);
}
 
 
这般做会再次好:
var paragraphs = document.getElementsByTagName(‘p’);
for (var i = 0, paragraph; paragraph = paragraphs[i]; i++) {
    doSomething(paragraph);
}
 
 
这种办法对具备的 collections
和数组(只要数组不带有 falsy 值) 都适用.
 
每当上头的例子中, 也足以通过 firstChild 和 nextSibling 来遍历孩子节点.
var parentNode = document.getElementById(‘foo’);
for (var child = parentNode.firstChild; child; child =
child.nextSibling) {
    doSomething(child);
}

Parting Words

 
    保持一致性.
 
    当你当编制代码之前, 先花片年华翻开转存世代码的风格. 如果他们被算术运算符添加了空格, 你啊应当补充加. 如果他们的注解使用一个个星号盒子, 那么也请而使用这种方式.
 
    代码风格受到一个关键点是整治一卖常因此词汇表, 开发者认同其又依照, 这样在代码中不怕可知统一表述. 我们以马上提出了有的大局上的风格规则, 但也只要考虑自身状况形成好的代码风格. 但只要您长的代码和水土保持的代码有深非常的区别, 这就是让阅读者感觉特别不与谐. 所以, 避免这种状况的发生.

Thanks

    Google[‘CopyRight’]
&& qiaohua 同学的辛苦翻译