开发规范:Javascript开发规范

  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. 资源
  25. 谁在使用


类     型

  • 原始值: 存取直接作用于它自身。
  • string
  • number
  • boolean
  • null
  • undefined
var  foo = 1;
var  bar = foo;
bar = 9;
console.log(foo, bar);  // => 1, 9
  • 复杂类型: 存取时作用于它自身值的引用。
  • object
  • array
  • function
var  foo = [1, 2];
var  bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]);  // => 9, 9


对象

  • 使用直接量创建对象。
// bad
var  item =  new  Object();
// good
var  item = {};
  • 不要使用保留字作为键名,它们在 IE8 下不工作。
// bad
var  superman = {
     default : { clark:  'kent'  },
     private:  true
};
 
// good
var  superman = {
     defaults: { clark:  'kent'  },
     hidden:  true
};
  • 使用同义词替换需要使用的保留字。
// bad
var  superman = {
     class:  'alien'
};
 
// bad
var  superman = {
     klass:  'alien'
};
 
// good
var  superman = {
     type:  'alien'
};


数组

  • 使用直接量创建数组。
// bad
var  items =  new  Array();
 
// good
var  items = [];
  • 向数组增加元素时使用 Array#push 来替代直接赋值。
var  someStack = [];
 
// bad
someStack[someStack.length] =  'abracadabra' ;
 
// good
someStack.push( 'abracadabra' );
  • 当你需要拷贝数组时,使用 Array#slice。jsPerf
var  len = items.length;
var  itemsCopy = [];
var  i;
 
// bad
for  (i = 0; i < len; i++) {
     itemsCopy[i] = items[i];
}
 
// good
itemsCopy = items.slice();
  • 使用 Array#slice 将类数组对象转换成数组。
function  trigger() {
     var  args = Array.prototype.slice.call(arguments);
     ...
}


字符串

  • 使用单引号 '' 包裹字符串。
// bad
var  name =  "Bob Parr" ;
 
 
// good
var  name =  'Bob Parr' ;
 
// bad
var  fullName =  "Bob "  this .lastName;
 
// good
var  fullName =  'Bob '  this .lastName;
  • 超过 100 个字符的字符串应该使用连接符写成多行。
  • 注:若过度使用,通过连接符连接的长字符串可能会影响性能。jsPerf
// bad
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.' ;
 
// bad
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.' ;
 
// good
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.' ;
  • 程序化生成的字符串使用 Array#join 连接而不是使用连接符。尤其是 IE 下:jsPerf.(http://jsperf.com/ya-string-concat)
var  items;
var  messages;
var  length;
var  i;
 
messages = [{
     state:  'success' ,
     message:  'This one worked.'
}, {
     state:  'success' ,
     message:  'This one worked as well.'
}, {
     state:  'error' ,
     message:  'This one did not work.'
}];
 
length = messages.length;
 
// bad
function  inbox(messages) {
     items =  '
    ' ;
 
     for  (i = 0; i < length; i++) {
         items +=  '
  • '  + messages[i].message +  '
  • ' ;
         }
         return  items +  '' ;
    }
     
    // good
    function  inbox(messages) {
         items = [];
     
         for  (i = 0; i < length; i++) {
             // use direct assignment in this case because we're micro-optimizing.
             items[i] = '
  • ' + messages[i].message + '
  • ';
         }
     
         return '
      ' + items.join(' ') + '
    ';
    }


    函数

    • 函数表达式
    // 匿名函数表达式
    var  anonymous =  function () {
         return  true ;
    };
     
    // 命名函数表达式
    var  named =  function  named() {
         return  true ;
    };
     
    // 立即调用的函数表达式(IIFE)
    ( function  () {
         console.log( 'Welcome to the Internet. Please follow me.' );
    }());
    • 永远不要在一个非函数代码块(if、while 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。
    • 注: ECMA-262 把  定义为一组语句。函数声明不是语句。阅读对 ECMA-262 这个问题的说明。(http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97)
    // bad
    if  (currentUser) {
         function  test() {
             console.log( 'Nope.' );
         }
    }
     
    // good
    var  test;
    if  (currentUser) {
         test =  function  test() {
             console.log( 'Yup.' );
         };
    }
    • 永远不要把参数命名为 arguments。这将取代函数作用域内的 arguments 对象。
    // bad
    function  nope(name, options, arguments) {
         // ...stuff...
    }
     
    // good
    function  yup(name, options, args) {
         // ...stuff...
    }


    属性

    • 使用 . 来访问对象的属性。
    var  luke = {
         jedi:  true ,
         age: 28
    };
     
    // bad
    var  isJedi = luke[ 'jedi' ];
     
    // good
    var  isJedi = luke.jedi;
    • 当通过变量访问属性时使用中括号 []
    var  luke = {
         jedi:  true ,
         age: 28
    };
     
    function  getProp(prop) {
         return  luke[prop];
    }
     
    var  isJedi = getProp( 'jedi' );


    变量

    • 总是使用 var 来声明变量。不这么做将导致产生全局变量。我们要避免污染全局命名空间。
    // bad
    superPower =  new  SuperPower();
     
    // good
    var  superPower =  new  SuperPower();
    • 使用 var 声明每一个变量。
      这样做的好处是增加新变量将变的更加容易,而且你永远不用再担心调换错 ; 跟 ,
    // bad
    var  items = getItems(),
         goSportsTeam =  true ,
         dragonball =  'z' ;
     
    // bad
    // (跟上面的代码比较一下,看看哪里错了)
    var  items = getItems(),
         goSportsTeam =  true ;
         dragonball =  'z' ;
     
    // good
    var  items = getItems();
    var  goSportsTeam =  true ;
    var  dragonball =  'z' ;
    • 最后再声明未赋值的变量。当你需要引用前面的变量赋值时这将变的很有用。
    // bad
    var  i, len, dragonball,
         items = getItems(),
         goSportsTeam =  true ;
     
    // bad
    var  i;
    var  items = getItems();
    var  dragonball;
    var  goSportsTeam =  true ;
    var  len;
     
    // good
    var  items = getItems();
    var  goSportsTeam =  true ;
    var  dragonball;
    var  length;
    var  i;
    • 在作用域顶部声明变量。这将帮你避免变量声明提升相关的问题。
    // bad
    function  () {
         test();
         console.log( 'doing stuff..' );
     
         //..other stuff..
     
         var  name = getName();
     
         if  (name ===  'test' ) {
             return  false ;
         }
     
         return  name;
    }
     
    // good
    function  () {
         var  name = getName();
     
         test();
         console.log( 'doing stuff..' );
     
         //..other stuff..
     
         if  (name ===  'test' ) {
             return  false ;
         }
     
         return  name;
    }
     
    // bad - 不必要的函数调用
    function  () {
         var  name = getName();
     
         if  (!arguments.length) {
             return  false ;
         }
     
         this .setFirstName(name);
     
         return  true ;
    }
     
    // good
    function  () {
         var  name;
     
         if  (!arguments.length) {
             return  false ;
         }
     
         name = getName();
         this .setFirstName(name);
     
         return  true ;
    }


    提升

    • 变量声明会提升至作用域顶部,但赋值不会。
    // 我们知道这样不能正常工作(假设这里没有名为 notDefined 的全局变量)
    function  example() {
         console.log(notDefined);  // => throws a ReferenceError
    }
     
    // 但由于变量声明提升的原因,在一个变量引用后再创建它的变量声明将可以正常工作。
    // 注:变量赋值为 `true` 不会提升。
    function  example() {
         console.log(declaredButNotAssigned);  // => undefined
         var  declaredButNotAssigned =  true ;
    }
     
    // 解释器会把变量声明提升到作用域顶部,意味着我们的例子将被重写成:
    function  example() {
         var  declaredButNotAssigned;
         console.log(declaredButNotAssigned);  // => undefined
         declaredButNotAssigned =  true ;
    }
    • 匿名函数表达式会提升它们的变量名,但不会提升函数的赋值。
    function  example() {
         console.log(anonymous);  // => undefined
     
         anonymous();  // => TypeError anonymous is not a function
     
         var  anonymous =  function  () {
             console.log( 'anonymous function expression' );
         };
    }
    • 命名函数表达式会提升变量名,但不会提升函数名或函数体。
    function  example() {
         console.log(named);  // => undefined
     
         named();  // => TypeError named is not a function
     
         superPower();  // => ReferenceError superPower is not defined
     
         var  named =  function  superPower() {
             console.log( 'Flying' );
         };
    }
     
    // 当函数名跟变量名一样时,表现也是如此。
    function  example() {
         console.log(named);  // => undefined
     
         named();  // => TypeError named is not a function
     
         var  named =  function  named() {
             console.log( 'named' );
         }
    }
    • 函数声明提升它们的名字和函数体。
    function  example() {
         superPower();  // => Flying
     
         function  superPower() {
             console.log( 'Flying' );
         }
    }
    • 了解更多信息在 JavaScript Scoping & Hoisting by Ben Cherry.(http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting)


    比较运算符 & 等号

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

      • 对象 被计算为 true
      • Undefined 被计算为 false
      • Null 被计算为 false
      • 布尔值 被计算为 布尔的值
      • 数字 如果是 +0、-0 或 NaN 被计算为 false,否则为 true
      • 字符串 如果是空字符串 '' 被计算为 false,否则为 true
    if  ([0]) {
         // true
         // 一个数组就是一个对象,对象被计算为 true
    }
    • 使用快捷方式。
    // bad
    if  (name !==  '' ) {
         // ...stuff...
    }
     
    // good
    if  (name) {
         // ...stuff...
    }
     
    // bad
    if  (collection.length > 0) {
         // ...stuff...
    }
     
    // good
    if  (collection.length) {
         // ...stuff...
    }
    • 了解更多信息在 Truth Equality and JavaScript by Angus Croll.(http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108)

    • 使用大括号包裹所有的多行代码块。
    // bad
    if  (test)
    return  false ;
     
    // good
    if  (test)  return  false ;
     
    // good
    if  (test) {
         return  false ;
    }
     
    // bad
    function  () {  return  false ; }
     
    // good
    function  () {
         return  false ;
    }
    • 如果通过 if 和 else 使用多行代码块,把 else 放在 if 代码块关闭括号的同一行。
    // bad
    if  (test) {
         thing1();
         thing2();
    }
    else  {
         thing3();
    }
     
    // good
    if  (test) {
         thing1();
         thing2();
    else  {
         thing3();
    }


    注释

    • 使用 /** ... */ 作为多行注释。包含描述、指定所有参数和返回值的类型和值。
    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param {String} tag
    // @return {Element} element
    function  make(tag) {
         // ...stuff...
     
     
         return  element;
    }
     
    // good
    /**
    * make() returns a new element
    * based on the passed in tag name
    *
    * @param {String} tag
    * @return {Element} element
    */
    function  make(tag) {
     
     
         // ...stuff...
     
     
         return  element;
    }
    • 使用 // 作为单行注释。在评论对象上面另起一行使用单行注释。在注释前插入空行。
    // bad
    var  active =  true ;   // is current tab
     
    // good
    // is current tab
    var  active =  true ;
     
    // bad
    function  getType() {
         console.log( 'fetching type...' );
         // set the default type to 'no type'
         var  type =  this .type ||  'no type' ;
     
         return  type;
    }
     
    // good
    function  getType() {
         console.log( 'fetching type...' );
     
         // set the default type to 'no type'
         var  type =  this .type ||  'no type' ;
     
         return  type;
    }
    • 给注释增加 FIXME 或 TODO 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 FIXME -- need to figure this out 或者 TODO -- need to implement

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

    function  Calculator() {
     
         // FIXME: shouldn't use a global here
         total = 0;
     
         return  this ;
    }
    • 使用 // TODO: 标注问题的解决方式。
    function  Calculator() {
     
         // TODO: total should be configurable by an options param
         this .total = 0;
      
         return  this ;
    }


    空白

    • 使用 2 个空格作为缩进(如果习惯了用Tab 可以在编辑器中把Tab设置为2个空格。
    // bad
    function  () {
    ∙∙∙∙ var  name;
    }
     
    // bad
    function  () {
    var  name;
    }
     
    // good
    function  () {
    ∙∙ var  name;
    }
    • 在大括号前放一个空格。
    // bad
    function  test(){
         console.log( 'test' );
    }
     
    // good
    function  test() {
         console.log( 'test' );
    }
     
    // bad
    dog.set( 'attr' ,{
         age:  '1 year' ,
         breed:  'Bernese Mountain Dog'
    });
     
    // good
    dog.set( 'attr' , {
         age:  '1 year' ,
         breed:  'Bernese Mountain Dog'
    });
    • 在控制语句(ifwhile 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。
    // bad
    if (isJedi) {
         fight ();
    }
     
    // good
    if  (isJedi) {
         fight();
    }
     
    // bad
    function  fight () {
         console.log ( 'Swooosh!' );
    }
     
    // good
    function  fight() {
         console.log( 'Swooosh!' );
    }
    • 使用空格把运算符隔开。
    // bad
    var  x=y+5;
     
    // good
    var  x = y + 5;
    • 在文件末尾插入一个空行。
    // bad
    ( function  (global) {
         // ...stuff...
    })( this );
     
    // bad
    ( function  (global) {
         // ...stuff...
    })( this );↵
     
    // good
    ( function  (global) {
         // ...stuff...
    })( this );↵
    • 在使用长方法链时进行缩进。使用前面的点 . 强调这是方法调用而不是新语句。
    // bad
    $( '#items' ).find( '.selected' ).highlight().end().find( '.open' ).updateCount();
     
    // bad
    $( '#items' ).
         find( '.selected' ).
             highlight().
             end().
         find( '.open' ).
             updateCount();
     
    // good
    $( '#items' )
         .find( '.selected' )
             .highlight()
             .end()
         .find( '.open' )
             .updateCount();
     
    // bad
    var  leds = stage.selectAll( '.led' ).data(data).enter().append( 'svg:svg' ).classed( 'led' true )
         .attr( 'width' , (radius + margin) * 2).append( 'svg:g' )
         .attr( 'transform' 'translate('  + (radius + margin) +  ','  + (radius + margin) +  ')' )
         .call(tron.led);
     
    // good
    var  leds = stage.selectAll( '.led' )
             .data(data)
         .enter().append( 'svg:svg' )
             .classed( 'led' true )
             .attr( 'width' , (radius + margin) * 2)
         .append( 'svg:g' )
             .attr( 'transform' 'translate('  + (radius + margin) +  ','  + (radius + margin) +  ')' )
             .call(tron.led);
    • 在块末和新语句前插入空行。
    // bad
    if  (foo) {
         return  bar;
    }
    return  baz;
     
    // good
    if  (foo) {
         return  bar;
    }
     
    return  baz;
     
    // bad
    var  obj = {
         foo:  function  () {
    },
    bar:  function  () {
         }
    };
    return  obj;
     
    // good
    var  obj = {
         foo:  function  () {
         },
     
         bar:  function  () {
         }
    };
     
    return  obj;


    逗号

    • 行首逗号: 不需要
    // bad
    var  story = [
         once
         , upon
         , aTime
    ];
     
    // good
    var  story = [
         once,
         upon,
         aTime
    ];
     
    // bad
    var  hero = {
         firstName:  'Bob'
         , lastName:  'Parr'
         , heroName:  'Mr. Incredible'
         , superPower:  'strength'
    };
     
    // good
    var  hero = {
         firstName:  'Bob' ,
         lastName:  'Parr' ,
         heroName:  'Mr. Incredible' ,
         superPower:  'strength'
    };
    • 额外的行末逗号:不需要。这样做会在 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.

    // bad
    var  hero = {
         firstName:  'Kevin' ,
         lastName:  'Flynn' ,
    };
     
    var  heroes = [
         'Batman' ,
         'Superman' ,
    ];
     
    // good
    var  hero = {
         firstName:  'Kevin' ,
         lastName:  'Flynn'
    };
     
    var  heroes = [
         'Batman' ,
         'Superman'
    ];


    分号

    • 使用分号。
    // bad
    ( function  () {
         var  name =  'Skywalker'
         return  name
    })()
     
    // good
    ( function  () {
         var  name =  'Skywalker' ;
         return  name;
    })();
     
    // good (防止函数在两个 IIFE 合并时被当成一个参数
    ;( function  () {
         var  name =  'Skywalker' ;
         return  name;
    })();
    [了解更多](http://stackoverflow.com/a/7365214/1712802).
    


    类型转换

    • 在语句开始时执行类型转换。
    • 字符串:
    //  => this.reviewScore = 9;
     
    // bad
    var  totalScore =  this .reviewScore +  '' ;
     
    // good
    var  totalScore =  ''  this .reviewScore;
     
    // bad
    var  totalScore =  ''  this .reviewScore +  ' total score' ;
     
    // good
    var  totalScore =  this .reviewScore +  ' total score' ;
    • 使用 parseInt 转换数字时总是带上类型转换的基数。
    var  inputValue =  '4' ;
     
    // bad
    var  val =  new  Number(inputValue);
     
    // bad
    var  val = +inputValue;
     
    // bad
    var  val = inputValue >> 0;
     
    // bad
    var  val = parseInt(inputValue);
     
    // good
    var  val = Number(inputValue);
     
    // good
    var  val = parseInt(inputValue, 10);
    • 如果因为某些原因 parseInt 成为你所做的事的瓶颈而需要使用位操作解决性能问题(http://jsperf.com/coercion-vs-casting/3)时,留个注释说清楚原因和你的目的。
    // good
    /**
    * parseInt was the reason my code was slow.
    * Bitshifting the String to coerce it to a
    * Number made it a lot faster.
    */
    var  val = inputValue >> 0;
    • 注: 小心使用位操作运算符。数字会被当成 64 位值(http://es5.github.io/#x4.3.19),但是位操作运算符总是返回 32 位的整数(source(http://es5.github.io/#x11.7))。位操作处理大于 32 位的整数值时还会导致意料之外的行为。最大的 32 位整数是 2,147,483,647:
    2147483647 >> 0  //=> 2147483647
    2147483648 >> 0  //=> -2147483648
    2147483649 >> 0  //=> -2147483647
    • 布尔:
    var  age = 0;
     
    // bad
    var  hasAge =  new  Boolean(age);
     
     
    // good
    var  hasAge = Boolean(age);
     
    // good
    var  hasAge = !!age;


     

    存取器

    • 属性的存取函数不是必须的。
    • 如果你需要存取函数时使用 getVal() 和 setVal('hello')
    // bad
    dragon.age();
     
    // good
    dragon.getAge();
     
    // bad
    dragon.age(25);
     
    // good
    dragon.setAge(25);
    • 如果属性是布尔值,使用 isVal() 或 hasVal()
    // bad
    if  (!dragon.age()) {
         return  false ;
    }
     
    // good
    if  (!dragon.hasAge()) {
         return  false ;
    }
    • 创建 get() 和 set() 函数是可以的,但要保持一致。
    function  Jedi(options) {
         options || (options = {});
         var  lightsaber = options.lightsaber ||  'blue' ;
         this .set( 'lightsaber'

    你可能感兴趣的:(开发规范:Javascript开发规范)