• JavaScript编码规范
    • 目录" level="2">目录
    • 类型" level="2">类型
    • 对象" level="2">对象
    • 数组" level="2">数组
    • 字符串" level="2">字符串
    • 函数" level="2">函数
    • 属性" level="2">属性
    • 变量" level="2">变量
    • 提升" level="2">提升
    • 比较运算符 & 等号" level="2">比较运算符 & 等号
    • 块" level="2">块
    • 注释" level="2">注释
    • 空白" level="2">空白
    • 逗号" level="2">逗号
    • 分号" level="2">分号
    • 类型转换" level="2">类型转换
    • 命名规则" level="2">命名规则
    • 存取器" level="2">存取器
    • 构造函数" level="2">构造函数
    • 事件" level="2">事件
    • 模块" level="2">模块
    • jQuery" level="2">jQuery
    • ECMAScript 5 兼容性" level="2">ECMAScript 5 兼容性
    • 测试" level="2">测试
    • 性能" level="2">性能
    • 资源" level="2">资源

    JavaScript编码规范

    主要依据下面的文档整理,局部有修改。

    https://raw.githubusercontent.com/sivan/javascript-style-guide
    https://github.com/airbnb/javascript
    JavaScript Standard Style


    目录" class="reference-link">目录

    1. 类型
    2. 对象
    3. 数组
    4. 字符串
    5. 函数
    6. 属性
    7. 变量
    8. 提升
    9. 比较运算符 & 等号
    10. 注释
    11. 空白
    12. 逗号
    13. 分号
    14. 类型转化
    15. 命名规则
    16. 存取器
    17. 构造函数
    18. 事件
    19. 模块
    20. jQuery
    21. ECMAScript 5 兼容性
    22. 测试
    23. 性能
    24. 资源

    类型" class="reference-link">类型

    • 原始值: 存取直接作用于它自身。

      • string
      • number
      • boolean
      • null
      • undefined
      1. var foo = 1;
      2. var bar = foo;
      3. bar = 9;
      4. console.log(foo, bar); // => 1, 9
    • 复杂类型: 存取时作用于它自身值的引用。

      • object
      • array
      • function
      1. var foo = [1, 2];
      2. var bar = foo;
      3. bar[0] = 9;
      4. console.log(foo[0], bar[0]); // => 9, 9

    ⬆ 回到顶部

    对象" class="reference-link">对象

    • 使用直接量创建对象。

      1. // bad
      2. var item = new Object();
      3. // good
      4. var item = {};
    • 不要使用保留字作为键名,它们在 IE8 下不工作。更多信息。

      1. // bad
      2. var superman = {
      3. default: { clark: 'kent' },
      4. privated: true
      5. };
      6. // good
      7. var superman = {
      8. defaults: { clark: 'kent' },
      9. hidden: true
      10. };
    • 使用同义词替换需要使用的保留字。

      1. // bad
      2. var superman = {
      3. class: 'alien'
      4. };
      5. // bad
      6. var superman = {
      7. klass: 'alien'
      8. };
      9. // good
      10. var superman = {
      11. type: 'alien'
      12. };

    ⬆ 回到顶部

    数组" class="reference-link">数组

    • 使用直接量创建数组。

      1. // bad
      2. var items = new Array();
      3. // good
      4. var items = [];
    • 向数组增加元素时使用 Array#push 来替代直接赋值。

      ```javascript
      var someStack = [];

    1. // bad
    2. someStack[someStack.length] = 'abracadabra';
    3. // good
    4. someStack.push('abracadabra');
    5. ```
    • 当你需要拷贝数组时,使用 Array#slice。jsPerf

      1. var len = items.length;
      2. var itemsCopy = [];
      3. var i;
      4. // bad
      5. for (i = 0; i < len; i++) {
      6. itemsCopy[i] = items[i];
      7. }
      8. // good
      9. itemsCopy = items.slice();
    • 使用 Array#slice 将类数组对象转换成数组。

      1. function trigger() {
      2. var args = Array.prototype.slice.call(arguments);
      3. ...
      4. }

    ⬆ 回到顶部

    字符串" class="reference-link">字符串

    • 使用单引号 '' 包裹字符串。

      1. // bad
      2. var name = "Bob Parr";
      3. // good
      4. var name = 'Bob Parr';
      5. // bad
      6. var fullName = "Bob " + this.lastName;
      7. // good
      8. var fullName = 'Bob ' + this.lastName;
    • 超过 100 个字符的字符串应该使用连接符写成多行。

    • 注:若过度使用,通过连接符连接的长字符串可能会影响性能。jsPerf & 讨论.

      1. // bad
      2. var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
      3. // bad
      4. var errorMessage = 'This is a super long error that was thrown because \
      5. of Batman. When you stop to think about how Batman had anything to do \
      6. with this, you would get nowhere \
      7. fast.';
      8. // good
      9. var errorMessage = 'This is a super long error that was thrown because ' +
      10. 'of Batman. When you stop to think about how Batman had anything to do ' +
      11. 'with this, you would get nowhere fast.';
    • 程序化生成的字符串使用 Array#join 连接而不是使用连接符。尤其是 IE 下:jsPerf.

      1. var items;
      2. var messages;
      3. var length;
      4. var i;
      5. messages = [{
      6. state: 'success',
      7. message: 'This one worked.'
      8. }, {
      9. state: 'success',
      10. message: 'This one worked as well.'
      11. }, {
      12. state: 'error',
      13. message: 'This one did not work.'
      14. }];
      15. length = messages.length;
      16. // bad
      17. function inbox(messages) {
      18. items = '<ul>';
      19. for (i = 0; i < length; i++) {
      20. items += '<li>' + messages[i].message + '</li>';
      21. }
      22. return items + '</ul>';
      23. }
      24. // good
      25. function inbox(messages) {
      26. items = [];
      27. for (i = 0; i < length; i++) {
      28. // use direct assignment in this case because we're micro-optimizing.
      29. items[i] = '<li>' + messages[i].message + '</li>';
      30. }
      31. return '<ul>' + items.join('') + '</ul>';
      32. }

    ⬆ 回到顶部

    函数" class="reference-link">函数

    • 函数表达式:

      1. // 匿名函数表达式
      2. var anonymous = function() {
      3. return true;
      4. };
      5. // 命名函数表达式
      6. var named = function named() {
      7. return true;
      8. };
      9. // 立即调用的函数表达式(IIFE)
      10. (function () {
      11. console.log('Welcome to the Internet. Please follow me.');
      12. }());
    • 永远不要在一个非函数代码块(if、while 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。

    • 注: ECMA-262 把 定义为一组语句。函数声明不是语句。阅读对 ECMA-262 这个问题的说明。

      1. // bad
      2. if (currentUser) {
      3. function test() {
      4. console.log('Nope.');
      5. }
      6. }
      7. // good
      8. var test;
      9. if (currentUser) {
      10. test = function test() {
      11. console.log('Yup.');
      12. };
      13. }
    • 永远不要把参数命名为 arguments。这将取代函数作用域内的 arguments 对象。

      1. // bad
      2. function nope(name, options, arguments) {
      3. // ...stuff...
      4. }
      5. // good
      6. function yup(name, options, args) {
      7. // ...stuff...
      8. }

    ⬆ 回到顶部

    属性" class="reference-link">属性

    • 使用 . 来访问对象的属性。

      1. var luke = {
      2. jedi: true,
      3. age: 28
      4. };
      5. // bad
      6. var isJedi = luke['jedi'];
      7. // good
      8. var isJedi = luke.jedi;
    • 当通过变量访问属性时使用中括号 []

      1. var luke = {
      2. jedi: true,
      3. age: 28
      4. };
      5. function getProp(prop) {
      6. return luke[prop];
      7. }
      8. var isJedi = getProp('jedi');

    ⬆ 回到顶部

    变量" class="reference-link">变量

    • 总是使用 var 来声明变量。不这么做将导致产生全局变量。我们要避免污染全局命名空间。

      1. // bad
      2. superPower = new SuperPower();
      3. // good
      4. var superPower = new SuperPower();
    • 使用 var 声明每一个变量。
      这样做的好处是增加新变量将变的更加容易,而且你永远不用再担心调换错 ;,

      1. // bad
      2. var items = getItems(),
      3. goSportsTeam = true,
      4. dragonball = 'z';
      5. // bad
      6. // (跟上面的代码比较一下,看看哪里错了)
      7. var items = getItems(),
      8. goSportsTeam = true;
      9. dragonball = 'z';
      10. // good
      11. var items = getItems();
      12. var goSportsTeam = true;
      13. var dragonball = 'z';
    • 最后再声明未赋值的变量。当你需要引用前面的变量赋值时这将变的很有用。

      1. // bad
      2. var i, len, dragonball,
      3. items = getItems(),
      4. goSportsTeam = true;
      5. // bad
      6. var i;
      7. var items = getItems();
      8. var dragonball;
      9. var goSportsTeam = true;
      10. var len;
      11. // good
      12. var items = getItems();
      13. var goSportsTeam = true;
      14. var dragonball;
      15. var length;
      16. var i;
    • 在作用域顶部声明变量。这将帮你避免变量声明提升相关的问题。

      1. // bad
      2. function () {
      3. test();
      4. console.log('doing stuff..');
      5. //..other stuff..
      6. var name = getName();
      7. if (name === 'test') {
      8. return false;
      9. }
      10. return name;
      11. }
      12. // good
      13. function () {
      14. var name = getName();
      15. test();
      16. console.log('doing stuff..');
      17. //..other stuff..
      18. if (name === 'test') {
      19. return false;
      20. }
      21. return name;
      22. }
      23. // bad - 不必要的函数调用
      24. function () {
      25. var name = getName();
      26. if (!arguments.length) {
      27. return false;
      28. }
      29. this.setFirstName(name);
      30. return true;
      31. }
      32. // good
      33. function () {
      34. var name;
      35. if (!arguments.length) {
      36. return false;
      37. }
      38. name = getName();
      39. this.setFirstName(name);
      40. return true;
      41. }

    ⬆ 回到顶部

    提升" class="reference-link">提升

    • 变量声明会提升至作用域顶部,但赋值不会。

      1. // 我们知道这样不能正常工作(假设这里没有名为 notDefined 的全局变量)
      2. function example() {
      3. console.log(notDefined); // => throws a ReferenceError
      4. }
      5. // 但由于变量声明提升的原因,在一个变量引用后再创建它的变量声明将可以正常工作。
      6. // 注:变量赋值为 `true` 不会提升。
      7. function example() {
      8. console.log(declaredButNotAssigned); // => undefined
      9. var declaredButNotAssigned = true;
      10. }
      11. // 解释器会把变量声明提升到作用域顶部,意味着我们的例子将被重写成:
      12. function example() {
      13. var declaredButNotAssigned;
      14. console.log(declaredButNotAssigned); // => undefined
      15. declaredButNotAssigned = true;
      16. }
    • 匿名函数表达式会提升它们的变量名,但不会提升函数的赋值。

      1. function example() {
      2. console.log(anonymous); // => undefined
      3. anonymous(); // => TypeError anonymous is not a function
      4. var anonymous = function () {
      5. console.log('anonymous function expression');
      6. };
      7. }
    • 命名函数表达式会提升变量名,但不会提升函数名或函数体。

      1. function example() {
      2. console.log(named); // => undefined
      3. named(); // => TypeError named is not a function
      4. superPower(); // => ReferenceError superPower is not defined
      5. var named = function superPower() {
      6. console.log('Flying');
      7. };
      8. }
      9. // 当函数名跟变量名一样时,表现也是如此。
      10. function example() {
      11. console.log(named); // => undefined
      12. named(); // => TypeError named is not a function
      13. var named = function named() {
      14. console.log('named');
      15. }
      16. }
    • 函数声明提升它们的名字和函数体。

      1. function example() {
      2. superPower(); // => Flying
      3. function superPower() {
      4. console.log('Flying');
      5. }
      6. }
    • 了解更多信息在 JavaScript Scoping & Hoisting by Ben Cherry.

    ⬆ 回到顶部

    比较运算符 & 等号" class="reference-link">比较运算符 & 等号

    • 优先使用 ===!== 而不是 ==!=.
    • 条件表达式例如 if 语句通过抽象方法 ToBoolean 强制计算它们的表达式并且总是遵守下面的规则:

      • 对象 被计算为 true
      • Undefined 被计算为 false
      • Null 被计算为 false
      • 布尔值 被计算为 布尔的值
      • 数字 如果是 +0、-0 或 NaN 被计算为 false,否则为 true
      • 字符串 如果是空字符串 '' 被计算为 false,否则为 true
      1. if ([0]) {
      2. // true
      3. // 一个数组就是一个对象,对象被计算为 true
      4. }
    • 使用快捷方式。

      1. // bad
      2. if (name !== '') {
      3. // ...stuff...
      4. }
      5. // good
      6. if (name) {
      7. // ...stuff...
      8. }
      9. // bad
      10. if (collection.length > 0) {
      11. // ...stuff...
      12. }
      13. // good
      14. if (collection.length) {
      15. // ...stuff...
      16. }
    • 了解更多信息在 Truth Equality and JavaScript by Angus Croll.

    ⬆ 回到顶部

    块" class="reference-link">

    • 使用大括号包裹所有的多行代码块。

      1. // bad
      2. if (test)
      3. return false;
      4. // good
      5. if (test) return false;
      6. // good
      7. if (test) {
      8. return false;
      9. }
      10. // bad
      11. function () { return false; }
      12. // good
      13. function () {
      14. return false;
      15. }
    • 如果通过 ifelse 使用多行代码块,把 else 放在 if 代码块关闭括号的同一行。

      1. // bad
      2. if (test) {
      3. thing1();
      4. thing2();
      5. }
      6. else {
      7. thing3();
      8. }
      9. // good
      10. if (test) {
      11. thing1();
      12. thing2();
      13. } else {
      14. thing3();
      15. }

    ⬆ 回到顶部

    注释" class="reference-link">注释

    • 使用 /** ... */ 作为多行注释。包含描述、指定所有参数和返回值的类型和值。

      1. // bad
      2. // make() returns a new element
      3. // based on the passed in tag name
      4. //
      5. // @param {String} tag
      6. // @return {Element} element
      7. function make(tag) {
      8. // ...stuff...
      9. return element;
      10. }
      11. // good
      12. /**
      13. * make() returns a new element
      14. * based on the passed in tag name
      15. *
      16. * @param {String} tag
      17. * @return {Element} element
      18. */
      19. function make(tag) {
      20. // ...stuff...
      21. return element;
      22. }
    • 使用 // 作为单行注释。在评论对象上面另起一行使用单行注释。在注释前插入空行。

      1. // bad
      2. var active = true; // is current tab
      3. // good
      4. // is current tab
      5. var active = true;
      6. // bad
      7. function getType() {
      8. console.log('fetching type...');
      9. // set the default type to 'no type'
      10. var type = this._type || 'no type';
      11. return type;
      12. }
      13. // good
      14. function getType() {
      15. console.log('fetching type...');
      16. // set the default type to 'no type'
      17. var type = this._type || 'no type';
      18. return type;
      19. }
    • 给注释增加 FIXMETODO 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 FIXME -- need to figure this out 或者 TODO -- need to implement

    • 使用 // FIXME: 标注问题。

      1. function Calculator() {
      2. // FIXME: shouldn't use a global here
      3. total = 0;
      4. return this;
      5. }
    • 使用 // TODO: 标注问题的解决方式。

      1. function Calculator() {
      2. // TODO: total should be configurable by an options param
      3. this.total = 0;
      4. return this;
      5. }

    ⬆ 回到顶部

    空白" class="reference-link">空白

    • 使用 2 个空格作为缩进。

      1. // bad
      2. function () {
      3. ∙∙∙∙var name;
      4. }
      5. // bad
      6. function () {
      7. var name;
      8. }
      9. // good
      10. function () {
      11. ∙∙var name;
      12. }
    • 在大括号前放一个空格。

      1. // bad
      2. function test(){
      3. console.log('test');
      4. }
      5. // good
      6. function test() {
      7. console.log('test');
      8. }
      9. // bad
      10. dog.set('attr',{
      11. age: '1 year',
      12. breed: 'Bernese Mountain Dog'
      13. });
      14. // good
      15. dog.set('attr', {
      16. age: '1 year',
      17. breed: 'Bernese Mountain Dog'
      18. });
    • 在控制语句(ifwhile 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。

      1. // bad
      2. if(isJedi) {
      3. fight ();
      4. }
      5. // good
      6. if (isJedi) {
      7. fight();
      8. }
      9. // bad
      10. function fight () {
      11. console.log ('Swooosh!');
      12. }
      13. // good
      14. function fight() {
      15. console.log('Swooosh!');
      16. }
    • 使用空格把运算符隔开。

      1. // bad
      2. var x=y+5;
      3. // good
      4. var x = y + 5;
    • 在文件末尾插入一个空行。

      1. // bad
      2. (function (global) {
      3. // ...stuff...
      4. })(this);
      1. // bad
      2. (function (global) {
      3. // ...stuff...
      4. })(this);↵
      1. // good
      2. (function (global) {
      3. // ...stuff...
      4. })(this);↵
    • 在使用长方法链时进行缩进。使用前面的点 . 强调这是方法调用而不是新语句。

      1. // bad
      2. $('#items').find('.selected').highlight().end().find('.open').updateCount();
      3. // bad
      4. $('#items').
      5. find('.selected').
      6. highlight().
      7. end().
      8. find('.open').
      9. updateCount();
      10. // good
      11. $('#items')
      12. .find('.selected')
      13. .highlight()
      14. .end()
      15. .find('.open')
      16. .updateCount();
      17. // bad
      18. var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
      19. .attr('width', (radius + margin) * 2).append('svg:g')
      20. .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
      21. .call(tron.led);
      22. // good
      23. var leds = stage.selectAll('.led')
      24. .data(data)
      25. .enter().append('svg:svg')
      26. .classed('led', true)
      27. .attr('width', (radius + margin) * 2)
      28. .append('svg:g')
      29. .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
      30. .call(tron.led);
    • 在块末和新语句前插入空行。

      1. // bad
      2. if (foo) {
      3. return bar;
      4. }
      5. return baz;
      6. // good
      7. if (foo) {
      8. return bar;
      9. }
      10. return baz;
      11. // bad
      12. var obj = {
      13. foo: function () {
      14. },
      15. bar: function () {
      16. }
      17. };
      18. return obj;
      19. // good
      20. var obj = {
      21. foo: function () {
      22. },
      23. bar: function () {
      24. }
      25. };
      26. return obj;

    ⬆ 回到顶部

    逗号" class="reference-link">逗号

    • 行首逗号: 不需要

      1. // bad
      2. var story = [
      3. once
      4. , upon
      5. , aTime
      6. ];
      7. // good
      8. var story = [
      9. once,
      10. upon,
      11. aTime
      12. ];
      13. // bad
      14. var hero = {
      15. firstName: 'Bob'
      16. , lastName: 'Parr'
      17. , heroName: 'Mr. Incredible'
      18. , superPower: 'strength'
      19. };
      20. // good
      21. var hero = {
      22. firstName: 'Bob',
      23. lastName: 'Parr',
      24. heroName: 'Mr. Incredible',
      25. superPower: 'strength'
      26. };
    • 额外的行末逗号:不需要。这样做会在 IE6/7 和 IE9 怪异模式下引起问题。同样,多余的逗号在某些 ES3 的实现里会增加数组的长度。在 ES5 中已经澄清了 (source):

      Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitialiser does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this.

      1. // bad
      2. var hero = {
      3. firstName: 'Kevin',
      4. lastName: 'Flynn',
      5. };
      6. var heroes = [
      7. 'Batman',
      8. 'Superman',
      9. ];
      10. // good
      11. var hero = {
      12. firstName: 'Kevin',
      13. lastName: 'Flynn'
      14. };
      15. var heroes = [
      16. 'Batman',
      17. 'Superman'
      18. ];

    ⬆ 回到顶部

    分号" class="reference-link">分号

    • 使用分号。

      1. // bad
      2. (function () {
      3. var name = 'Skywalker'
      4. return name
      5. })()
      6. // good
      7. (function () {
      8. var name = 'Skywalker';
      9. return name;
      10. })();
      11. // good (防止函数在两个 IIFE 合并时被当成一个参数
      12. ;(function () {
      13. var name = 'Skywalker';
      14. return name;
      15. })();

      了解更多.

    ⬆ 回到顶部

    类型转换" class="reference-link">类型转换

    • 在语句开始时执行类型转换。
    • 字符串:

      1. // => this.reviewScore = 9;
      2. // bad
      3. var totalScore = this.reviewScore + '';
      4. // good
      5. var totalScore = '' + this.reviewScore;
      6. // bad
      7. var totalScore = '' + this.reviewScore + ' total score';
      8. // good
      9. var totalScore = this.reviewScore + ' total score';
    • 使用 parseInt 转换数字时总是带上类型转换的基数。

      1. var inputValue = '4';
      2. // bad
      3. var val = new Number(inputValue);
      4. // bad
      5. var val = +inputValue;
      6. // bad
      7. var val = inputValue >> 0;
      8. // bad
      9. var val = parseInt(inputValue);
      10. // good
      11. var val = Number(inputValue);
      12. // good
      13. var val = parseInt(inputValue, 10);
    • 如果因为某些原因 parseInt 成为你所做的事的瓶颈而需要使用位操作解决性能问题时,留个注释说清楚原因和你的目的。

      1. // good
      2. /**
      3. * parseInt was the reason my code was slow.
      4. * Bitshifting the String to coerce it to a
      5. * Number made it a lot faster.
      6. */
      7. var val = inputValue >> 0;
    • 注: 小心使用位操作运算符。数字会被当成 64 位值,但是位操作运算符总是返回 32 位的整数(source)。位操作处理大于 32 位的整数值时还会导致意料之外的行为。讨论。最大的 32 位整数是 2,147,483,647:

      1. 2147483647 >> 0 //=> 2147483647
      2. 2147483648 >> 0 //=> -2147483648
      3. 2147483649 >> 0 //=> -2147483647
    • 布尔:

      1. var age = 0;
      2. // bad
      3. var hasAge = new Boolean(age);
      4. // good
      5. var hasAge = Boolean(age);
      6. // good
      7. var hasAge = !!age;

    ⬆ 回到顶部

    命名规则" class="reference-link">命名规则

    • 避免单字母命名。命名应具备描述性。

      1. // bad
      2. function q() {
      3. // ...stuff...
      4. }
      5. // good
      6. function query() {
      7. // ..stuff..
      8. }
    • 使用驼峰式命名对象、函数和实例。

      1. // bad
      2. var OBJEcttsssss = {};
      3. var this_is_my_object = {};
      4. var o = {};
      5. function c() {}
      6. // good
      7. var thisIsMyObject = {};
      8. function thisIsMyFunction() {}
    • 使用帕斯卡式命名构造函数或类。

      1. // bad
      2. function user(options) {
      3. this.name = options.name;
      4. }
      5. var bad = new user({
      6. name: 'nope'
      7. });
      8. // good
      9. function User(options) {
      10. this.name = options.name;
      11. }
      12. var good = new User({
      13. name: 'yup'
      14. });
    • 使用下划线 _ 开头命名私有属性。

      1. // bad
      2. this.__firstName__ = 'Panda';
      3. this.firstName_ = 'Panda';
      4. // good
      5. this._firstName = 'Panda';
    • 使用 _this 保存 this 的引用。

      1. // bad
      2. function () {
      3. var self = this;
      4. return function () {
      5. console.log(self);
      6. };
      7. }
      8. // bad
      9. function () {
      10. var that = this;
      11. return function () {
      12. console.log(that);
      13. };
      14. }
      15. // good
      16. function () {
      17. var _this = this;
      18. return function () {
      19. console.log(_this);
      20. };
      21. }
    • 给函数命名。这在做堆栈轨迹时很有帮助。

      1. // bad
      2. var log = function (msg) {
      3. console.log(msg);
      4. };
      5. // good
      6. var log = function log(msg) {
      7. console.log(msg);
      8. };
    • 注: IE8 及以下版本对命名函数表达式的处理有些怪异。了解更多信息到 http://kangax.github.io/nfe/。

    • 如果你的文件导出一个类,你的文件名应该与类名完全相同。

      1. // file contents
      2. class CheckBox {
      3. // ...
      4. }
      5. module.exports = CheckBox;
      6. // in some other file
      7. // bad
      8. var CheckBox = require('./checkBox');
      9. // bad
      10. var CheckBox = require('./check_box');
      11. // good
      12. var CheckBox = require('./CheckBox');

    ⬆ 回到顶部

    存取器" class="reference-link">存取器

    • 属性的存取函数不是必须的。
    • 如果你需要存取函数时使用 getVal()setVal('hello')

      1. // bad
      2. dragon.age();
      3. // good
      4. dragon.getAge();
      5. // bad
      6. dragon.age(25);
      7. // good
      8. dragon.setAge(25);
    • 如果属性是布尔值,使用 isVal()hasVal()

      1. // bad
      2. if (!dragon.age()) {
      3. return false;
      4. }
      5. // good
      6. if (!dragon.hasAge()) {
      7. return false;
      8. }
    • 创建 get() 和 set() 函数是可以的,但要保持一致。

      1. function Jedi(options) {
      2. options || (options = {});
      3. var lightsaber = options.lightsaber || 'blue';
      4. this.set('lightsaber', lightsaber);
      5. }
      6. Jedi.prototype.set = function set(key, val) {
      7. this[key] = val;
      8. };
      9. Jedi.prototype.get = function get(key) {
      10. return this[key];
      11. };

    ⬆ 回到顶部

    构造函数" class="reference-link">构造函数

    • 给对象原型分配方法,而不是使用一个新对象覆盖原型。覆盖原型将导致继承出现问题:重设原型将覆盖原有原型!

      1. function Jedi() {
      2. console.log('new jedi');
      3. }
      4. // bad
      5. Jedi.prototype = {
      6. fight: function fight() {
      7. console.log('fighting');
      8. },
      9. block: function block() {
      10. console.log('blocking');
      11. }
      12. };
      13. // good
      14. Jedi.prototype.fight = function fight() {
      15. console.log('fighting');
      16. };
      17. Jedi.prototype.block = function block() {
      18. console.log('blocking');
      19. };
    • 方法可以返回 this 来实现方法链式使用。

      1. // bad
      2. Jedi.prototype.jump = function jump() {
      3. this.jumping = true;
      4. return true;
      5. };
      6. Jedi.prototype.setHeight = function setHeight(height) {
      7. this.height = height;
      8. };
      9. var luke = new Jedi();
      10. luke.jump(); // => true
      11. luke.setHeight(20); // => undefined
      12. // good
      13. Jedi.prototype.jump = function jump() {
      14. this.jumping = true;
      15. return this;
      16. };
      17. Jedi.prototype.setHeight = function setHeight(height) {
      18. this.height = height;
      19. return this;
      20. };
      21. var luke = new Jedi();
      22. luke.jump()
      23. .setHeight(20);
    • 写一个自定义的 toString() 方法是可以的,但是确保它可以正常工作且不会产生副作用。

      1. function Jedi(options) {
      2. options || (options = {});
      3. this.name = options.name || 'no name';
      4. }
      5. Jedi.prototype.getName = function getName() {
      6. return this.name;
      7. };
      8. Jedi.prototype.toString = function toString() {
      9. return 'Jedi - ' + this.getName();
      10. };

    ⬆ 回到顶部

    事件" class="reference-link">事件

    • 当给事件附加数据时(无论是 DOM 事件还是私有事件),传入一个哈希而不是原始值。这样可以让后面的贡献者增加更多数据到事件数据而无需找出并更新事件的每一个处理器。例如,不好的写法:

      1. // bad
      2. $(this).trigger('listingUpdated', listing.id);
      3. ...
      4. $(this).on('listingUpdated', function (e, listingId) {
      5. // do something with listingId
      6. });

      更好的写法:

      1. // good
      2. $(this).trigger('listingUpdated', { listingId : listing.id });
      3. ...
      4. $(this).on('listingUpdated', function (e, data) {
      5. // do something with data.listingId
      6. });

      ⬆ 回到顶部

    模块" class="reference-link">模块

    • 模块应该以 ! 开始。这样确保了当一个不好的模块忘记包含最后的分号时,在合并代码到生产环境后不会产生错误。详细说明
    • 文件应该以驼峰式命名,并放在同名的文件夹里,且与导出的名字一致。
    • 增加一个名为 noConflict() 的方法来设置导出的模块为前一个版本并返回它。
    • 永远在模块顶部声明 'use strict';

      1. // fancyInput/fancyInput.js
      2. !function (global) {
      3. 'use strict';
      4. var previousFancyInput = global.FancyInput;
      5. function FancyInput(options) {
      6. this.options = options || {};
      7. }
      8. FancyInput.noConflict = function noConflict() {
      9. global.FancyInput = previousFancyInput;
      10. return FancyInput;
      11. };
      12. global.FancyInput = FancyInput;
      13. }(this);

    ⬆ 回到顶部

    jQuery" class="reference-link">jQuery

    • 使用 $ 作为存储 jQuery 对象的变量名前缀。

      1. // bad
      2. var sidebar = $('.sidebar');
      3. // good
      4. var $sidebar = $('.sidebar');
    • 缓存 jQuery 查询。

      1. // bad
      2. function setSidebar() {
      3. $('.sidebar').hide();
      4. // ...stuff...
      5. $('.sidebar').css({
      6. 'background-color': 'pink'
      7. });
      8. }
      9. // good
      10. function setSidebar() {
      11. var $sidebar = $('.sidebar');
      12. $sidebar.hide();
      13. // ...stuff...
      14. $sidebar.css({
      15. 'background-color': 'pink'
      16. });
      17. }
    • 对 DOM 查询使用层叠 $('.sidebar ul') 或 父元素 > 子元素 $('.sidebar > ul')。 jsPerf

    • 对有作用域的 jQuery 对象查询使用 find

      1. // bad
      2. $('ul', '.sidebar').hide();
      3. // bad
      4. $('.sidebar').find('ul').hide();
      5. // good
      6. $('.sidebar ul').hide();
      7. // good
      8. $('.sidebar > ul').hide();
      9. // good
      10. $sidebar.find('ul').hide();

    ⬆ 回到顶部

    ECMAScript 5 兼容性" class="reference-link">ECMAScript 5 兼容性

    • 参考 Kangax 的 ES5 兼容表.

    ⬆ 回到顶部

    测试" class="reference-link">测试

    • Yup.

      1. function () {
      2. return true;
      3. }

    ⬆ 回到顶部

    性能" class="reference-link">性能

    • On Layout & Web Performance
    • String vs Array Concat
    • Try/Catch Cost In a Loop
    • Bang Function
    • jQuery Find vs Context, Selector
    • innerHTML vs textContent for script text
    • Long String Concatenation
    • Loading…

    ⬆ 回到顶部

    资源" class="reference-link">资源

    推荐阅读

    • Annotated ECMAScript 5.1

    工具

    • Code Style Linters
      • JSHint - Airbnb Style .jshintrc
      • JSCS - Airbnb Style Preset

    其它风格指南

    • Google JavaScript Style Guide
    • jQuery Core Style Guidelines
    • Principles of Writing Consistent, Idiomatic JavaScript
    • JavaScript Standard Style

    其它风格

    • Naming this in nested functions - Christian Johansen
    • Conditional Callbacks - Ross Allen
    • Popular JavaScript Coding Conventions on Github - JeongHoon Byun
    • Multiple var statements in JavaScript, not superfluous - Ben Alman

    ⬆ 回到顶部