js编写规范

Posted *润物无声*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js编写规范相关的知识,希望对你有一定的参考价值。

JavaScript编码规范


Bug----33条

1. 不要使用’==’和’!=’,使用’===’和’!==’替代

  • 等级:Major

  • 原因:==和!=在判断值相等前会判断类型是否相等。这容易因为类型不同而造成错误。比如:它会认为表达式:’\t\r\n’==0是正确的。因此,要采用===和!==替代这两个符号。

  • 建议如下的方式:

    if (var === ‘howdy‘) {
        ...
    }
    
  • 不建议如下的方式:

    if (var == ‘howdy‘) {
        ...
    }
    
  • 例外:在判断函数是否为空的情况下,使用==或!=是可以的。在下边的例子中,如果foo没有被初始化,它默认的值是undefined而不是null。当然underfined更不会等于null了。因此这种情况应该使用==和!=。

    if (foo == null) {
        ...
    }
    

2. "DELETE"不能在数组中使用

  • 等级:Critical

  • 原因:delete函数可以用来删除任何的对象。数组是对象,因此可以被delete操作。但是如果这样使用了,就会在数组中产生一个undefined元素,无法从下标中反应出delete操作。

    从含有下标的元素中移除元素的适当方法有:

    Array.prototype.splice – 从数组中移除元素

    Array.prototype.pop – 从数组的尾端移除元素

    Array.prototype.shift – 从数组的开始移除元素

  • 建议如下的方式:

    var myArray = [ ‘a‘, ‘b‘, ‘c‘, ‘d‘ ];
    // removes 1 element from index 2
    removed = myArray.splice(2, 1);  
    // myArray => [‘a‘, ‘b‘, ‘d‘]
    console.log(myArray[2]); // outputs ‘d‘
    
  • 不建议如下的方式:

    var myArray = [ ‘a‘, ‘b‘, ‘c‘, ‘d‘ ];
    delete myArray[2]; 
    // Noncompliant. myArray => [‘a‘, ‘b‘, undefined, ‘d‘]
    console.log(myArray[2]); 
    // expected value was ‘d‘ but output is ‘undefined‘ 
    

3. 不能使用"EVAL"和"ARGUMENTS"作为变量

  • 等级:Critical

  • 原因:在javascript中eval是一个将字符串转换为JavaScript代码执行的函数,而arguments则是JavaScript的一个内置对象。如果两者作为变量使用就会覆盖了原先的定义。同是,在较为严格的JavaScript检测中,这样做是不会通过的。

  • 建议如下的方式:

    result = 17;
    
    args++;
    
    ++result;
    
    var obj = {
        set p(arg) {
        }
    };
    
    var result;
    
    try {
    } 
    catch (args) {
    }
    
    function x(arg) {
    }
    
    function args() {
    }
    
    var y = function fun() {
    };
    
    var f = new Function(‘args‘, ‘return 17;‘);
    
    function fun() {
        if (arguments.length == 0) {
            // do something
        }
    }
    
  • 不建议如下的方式:

    eval = 17; // Noncompliant
    
    arguments++; // Noncompliant
    
    ++eval; // Noncompliant
    
    var obj = {
        set p(arguments) {
        }
    }; // Noncompliant
    
    var eval; // Noncompliant
    
    try {
    } 
    catch (arguments) {
    } // Noncompliant
    
    function x(eval) {
    } // Noncompliant
    
    function arguments() {
    } // Noncompliant
    
    var y = function eval() {
    }; // Noncompliant
    
    var f = new Function(‘arguments‘, ‘return 17;‘); // Noncompliant
    
    function fun() {
        if (arguments.length == 0) { // Compliant
            // do something
        }
    }
    

4. "FOR"循环在每次执行时,都要修改控制循环的值

  • 等级:Critical

  • 原因:如果for循环永远无法完成就会产生错误。即便不会产生错误,也会对以后的变量值造成无法确定的影响,因此不能够这样使用。

  • 建议如下的方式:

    for (i = 0; i < 10; i++) {
        // ...
    }
    
  • 不建议如下的方式:

    for (i = 0; i < 10; j++) { // Noncompliant
        // ...
    }
    

5. "FOR … IN"这种循环在每次操作前需要进行过滤判断

  • 等级:Major

  • 原因:"for … in"这种循环允许开发人员按照属性的名字遍历对象。不幸的是,这个属性的集合包括了对象自身和对象继承的对象的所有属性。如果程序不考虑这点就会出现错误。
    因此,对于每个”for … in”循环,都应该包括一个if判断来过滤你需要的属性。

  • 建议如下的方式:

    for (name in object) {
        if (object.hasOwnProperty(name)) {
            doSomething(name);
        }
    }
    
  • 不建议如下的方式:

    for (name in object) {
        doSomething(name); // Noncompliant
    }
    

6. "INDEXOF"的检测需要包括0

  • 等级:Major

  • 原因:大部分字符串或者数组的indexof方法的判断需要和-1而不是0作比较。因为0代表该元素存在于字符串或者数组中。因此所有的indexof(..)>0的判断都忽略的0这种情况,是一个典型的错误。

  • 建议如下的方式:

    var color = ‘blue‘;
    var name = ‘ishmael‘;
    var number = 123;
    var arr = [color, name];
    if (arr.indexOf(‘blue‘) >= 0) {
        // ...
    }
    if (arr[0].indexOf(‘ish‘) > - 1{
        // ...
    }
    
  • 不建议如下的方式:

    var color = ‘blue‘;
    var name = ‘ishmael‘;
    var number = 123;
    var arr = [color, name];
    if (arr.indexOf(‘blue‘) > 0) { // Noncompliant
        // ...
    }
    if (arr[0].indexOf(‘ish‘) > 0{ // Noncompliant
        // ...
    }
    

7. "NAN"不能用在比较中

  • 等级:Blocker

  • 原因:NAN不等于包括自身在内的任何值。因此与NAN作比较是得不到你需要的结果的,但是这种错误有可能会出现。事实上,判断值是否等于NAN最好的方法就是和它自己作比较即NAN!==NAN,因为正常的变量都是等于自身的,如果不等于自身成立,就说明这个值是NAN。

  • 建议如下的方式:

    if (a !== a) {
        console.log(‘a is not a number‘);
    }
    
    if (a === a) {
        console.log(‘a is not NaN‘);
    }
    
  • 不建议如下的方式:

    var a = NaN;
    if (a === NaN) { // Noncompliant; always false
        console.log(‘a is not a number‘); // this is dead code
    }
    
    if (a !== NaN) { // Noncompliant; always true
        console.log(‘a is not NaN‘); // this statement is not necessarily true
    }
    

8. "new"关键字应该和构造函数一起使用

  • 等级:Critical

  • 原因:new这个关键字应该在定义了构造函数的对象中使用。如果在其他地方使用就会出现错误因为没有构造方法可以供new调用。

  • 建议如下的方式:

    /**
    * @constructor
    */
    function MyClass() {
        this.foo = bar‘;
    }
    
    var someClass = function () {
        this.prop = 1;
    }
    
    var obj1 = new someClass; // Compliant
    var obj2 = new MyClass(); // Compliant regardless of considerJSDoc value
    
  • 不建议如下的方式:

    var someClass = 1;
    
    var obj1 = new someClass; // Noncompliant;
    

9. 不能使用”WITH”代码块

  • 等级:Major

  • 原因:使用with关键字在一些较为严格的JavaScript检测中会报错。然而,这并不是最糟的,诚然使用with可以方便的访问到对象中既定的属性,但是如果属性在对象中尚未定义,则访问范围就会扩大到全局,有可能覆盖某些重名的变量。显然这种效果完全依赖于被访问的对象,并且产生的危害是不可测的,因此with不能使用。

  • 建议如下的方式:

    var x = ‘a‘;
    var foo = {
        y: 1
    }
    foo.y = 4;
    foo.x = 3;
    print(foo.x + ‘ ‘ + x); // shows: 3 a
    
  • 不建议如下的方式:

    var x = ‘a‘;
    var foo = {
        y: 1
    }
    with (foo) { // Noncompliant
        y = 4; // updates foo.x
        x = 3; // does NOT add a foo.x property; updates x var in outer scope
    }
    print(foo.x + ‘ ‘ + x); // shows: undefined 3
    

10. "FOR"循环块里的控制数值增长的方向必须准确

  • 等级:Blocker

  • 原因:如果for循环里的控制变量增长方向错误则会导致for循环永远无法执行完成。虽然有时候构建无限循环是故意的,比如使用while构建无限循环。但是,大部分情况下是存在错误。

  • 建议如下的方式:

    for (var i = 0; i < strings.length; i++) {
        //...
    }
    
  • 不建议如下的方式:

    for (var i = 0; i < strings.length; i--) { // Noncompliant;
        //...
    }
    

11. 不要使用ARRAY和OBJECT的构造方法

  • 等级:Major

  • 原因:由于有着对变量的特定解释方法,数组的构造方法是容易出错的。如果超过一个参量,数组的长度将会等于参量的数量。然而,如果使用一个参量将会产生三种可能结果:

    如果这个参数是个数字并且是个正整数,则会产生一个长度等于该参数的数组;

    如果这个参数是个数字但是不是个正整数,将会抛出异常;

    其他情况下将会产生长度为1的数组。

  • 建议如下的方式:

    var a = [x1, x2, x3];
    var a2 = [x1, x2];
    var a3 = [x1];
    var a4 = [];
    var o = {};
    var o2 = {
        a: 0,
        b: 1,
        c: 2,
        ‘strange key‘: 3
    };
    
  • 不建议如下的方式:

    var a3 = new Array(x1); // Noncompliant and variable in results
    var a4 = new Array(); // Noncompliant. Results in 0-element array.
    var a1 = new Array(x1, x2, x3); // Noncompliant. Results in 3-element array.
    var o = new Object(); // Noncompliant
    var o2 = new Object(); // Noncompliant
    o2.a = 0;
    o2.b = 1;
    o2.c = 2;
    o2[‘strange key‘] = 3;
    

12. 子表达式中不要出现赋值语句

  • 等级:Major

  • 原因:赋值语句在子表达式中容易产生错误,并且降低程序的可读性。像将==写成=是一种常见的错误。

  • 建议如下的方式:

    i = 42;
    doSomething(i);
    // or
    doSomething(i == 42); // Perhaps in fact the comparison operator was expected
    
  • 不建议如下的方式:

    doSomething(i = 42);
    
  • 例外:赋值语句可以在while循环或者关系表达式中出现。

    while ((line = nextLine()) != null) {
        ...
    } // Compliant
    
    while (line = nextLine()) {
        ...
    } // Compliant
    
    if (line = nextLine()) {
        ...
    } // Noncompliant
    

13. 内置对象不能被重载

  • 等级:Major

  • 原因:重载一个对象改变了它自身的行为可能会影响到代码中的其它对象。如果不小心重载内置对象可能会对其它的代码产生灾难性的危害。这条规则检测如下内置对象是否被重载:

    基本对象 - Object, Function, Boolean, Symbol, Error, EvalError, InternalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError;

    数据和时间- Number, Math, Date;

    文本处理-String, RegExp;

    各种数组- Array, Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Unit16Array, Int32Array, Uint32Array, Float32Array, Float64Array;

    集合-Map, Set, WeakMap, WeakSet;

    结构化数据- ArrayBuffer, DataView, JSON;

    控制抽象的关键字-Promise;

    反射-Reflect,Proxy;

    国际化-Intl;

    非标准的对象-Generator, Iterator, ParallelArray, StopIteration.

14. 没有用的存储应该被及时的移除

  • 等级:Major

  • 原因:如果一个变量在赋值后没有被使用,则会产生无用的存储。只有尽快释放它,才不会对代码造成危害。即便不产生危害,对资源也是一种浪费。因此,要保证所有定义的变量都要被用到。

  • 建议如下的方式:

    function pow(a, b) {
        if (b == 0) {
            return 0;
        }
        var x = a;
        for (var i = 1, i < b, i++) {
            x = x * a;
        }
        return x;
    }
    
  • 不建议如下的方式:

    function pow(a, b) {
        if (b == 0) {
            return 0;
        }
        var x = a;
        for (var i = 1, i < b, i++) {
            x = x * a; //Dead store because the last return statement should return x instead of returning a
        }
        return a;
    }
    

15. 保证函数调用时传入的参数都被使用

  • 等级:Critical

  • 原因:在JavaScript中你可以在调用函数时传入比函数自身要求的更多的参数,但是,要保证额外的参数能够被使用。

  • 建议如下的方式:

    function doSomething(a, b) {
        compute(arguments);
    }
    doSomething(1, 2, 3) // Compliant
    
  • 不建议如下的方式:

    function say(a, b) {
        print(a + ‘ ‘ + b);
    }
    say(‘hello‘, ‘world‘, ‘!‘); // Noncompliant; last argument is not used
    

16. 不要在循环内部定义函数

  • 等级:Major

  • 原因:在循环内部定义函数会造成不可预料的结果,因为这样定义的函数生命周期很短,同时其中的变量值也会不断被更新。

  • 不建议如下的方式:

    var funs = [];
    for (var i = 0; i < 13; i++) {
      funs[i] = function () { // Non-Compliant
        return i;
      };
    }
    print(funs[0] ()); // 13 instead of 0
    print(funs[1] ()); // 13 instead of 1
    print(funs[2] ()); // 13 instead of 2
    print(funs[3] ()); // 13 instead of 3
    ...
    

17. 函数不能被二次定义

  • 等级:Major

  • 原因:这条规则检测在同一个作用域内是否有同名的函数。事实上,很有可能产生这种现象,但是JavaScript引擎只会执行最后一次声明的那个函数。这种重复声明函数的代码通常会带来bug并且会让代码很乱。

  • 建议如下的方式:

    fun(); // prints "foo"
    function fun() {
      print(‘foo‘);
    }
    fun(); // prints "foo"
    
    或者是:
    
    fun(); // prints "foo"
    function fun() {
      print(‘foo‘);
    }
    fun(); // prints "foo"
    function printBar() {
      print(‘bar‘);
    }
    fun(); // prints "foo"
    
  • 不建议如下的方式:

    fun(); // prints "bar"
    // first declaration of the function
    function fun() {
      print(‘foo‘);
    }
    fun(); // prints "bar"
    // redeclaration of the "fun" function: this definition overrides the previous one
    function fun() {
      print(‘bar‘);
    }
    fun(); // prints "bar"
    

18. 关于HTML-STYLE的注释不能使用

  • 等级:Major

  • 原因:这种注释的风格不是JavaScript规范的一部分所以不能够使用

  • 建议如下的方式:

    // Compliant
    /* Compliant */
    
  • 不建议如下的方式:

    <!-- Noncompliant -->
    

19. 二元运算符两侧不能使用相同的式子

  • 等级:Critical

  • 原因:
    使用相同值的二元运算符往往会造成错误。这种情况的逻辑操作符,要么是个粘贴拷贝的错误,要么就是在浪费代码,需要修改。如果出现在布尔表达式中,结果就是可以确定的,没有意义。

  • 建议如下的方式:

    doZ();
    if (a == b) {
      doX();
    }
    if (a == b) {
      doW();
    }
    var j = 1;
    var k = 0;
    
  • 不建议如下的方式:

    if (a == a) { // always true
      doZ();
    }
    if (a != a) { // always false
      doY();
    }
    if (a == b && a == b) { // if the first one is true, the second one is too
        doX();
    }
    if (a == b || a == b) { // if the first one is true, the second one is too
      doW();
    }
    var j = 5 / 5; //always  1
    var k = 5 - 5; //always  0
    
  • 例外:在测试值是否是NAN情况下是可以使用的,因为只有NAN不等于自身。

    f(f !== f) { // test for NaN value
      console.log(‘f is NaN‘);
    }
    var i = 1 << 1; // Compliant
    var j = a << a; // Noncompliant
    

20. 嵌套的代码块不能为空

  • 等级:Major
  • 原因:大部分为空的嵌套代码块是忘记了,或者丢失了。这种代码块没有任何意义。
  • 不建议如下的方式:

    for (var i = 0; i < length; i++) {
    } // Empty on purpose or missing piece of code ?
    
  • 例外:如果代码块中嵌套着注释,则这个代码块可以为空。

21. 属性名称在文本对象中重复

  • 等级:Critical
  • 原因:JavaScript允许属性名在文本对象中重复。但是,将会以最后一次声明的属性为最终的值。因此,改变相同属性名的值将会产生意想不到的错误。并且在较为严格的检测中这种重复是不允许的。
  • 建议如下的方式:

    var data = {
      ‘key‘: ‘value‘,
      ‘1‘: ‘value‘,
      ‘key2‘: ‘value‘,
      ‘key3‘: ‘value‘,
      key4: ‘value‘,
      \u006bey5: ‘value‘,
      ‘\u006bey6‘: ‘value‘,
      ‘\x6bey7‘: ‘value‘,
      1b: ‘value‘
    }
    
  • 不建议如下的方式:

    var data = {
      ‘key‘: ‘value‘,
      ‘1‘: ‘value‘,
      ‘key‘: ‘value‘, // Noncompliant - duplicate of "key"
      ‘key‘: ‘value‘, // Noncompliant - duplicate of "key"
       key: ‘value‘, // Noncompliant - duplicate of "key"
       key: ‘value‘, // Noncompliant - duplicate of "key"
      ‘key‘: ‘value‘, // Noncompliant - duplicate of "key"
      ‘key‘: ‘value‘, // Noncompliant - duplicate of "key"
      1: ‘value‘ // Noncompliant - duplicate of "1"
    }
    

22. 在”IF/ELSE IF”和”SWITCH/CASES”代码块中,不能出现相同的条件

  • 等级:Critical
  • 原因: 这两种分支代码块会执行第一个符合条件的语句,如果出现两个相同的条件,很有可能是copy/paste错误,或者是程序员考虑不周。无论是哪个都会产生错误。对于switch代码块,如果条件中存在break则不会执行接下来的条件,直接跳出该代码块。对于if代码块虽然没有break,但会覆盖前一个条件设定的值,出现错误。
  • 建议如下的方式:

    if (param == 1)
    openWindow();
     else if (param == 2)
    closeWindow();
     else if (param == 3)
    moveWindowToTheBackground();
    switch (i) {
      case 1:
        //...
        break;
      case 3:
        //...
        break;
      default:
        // ...
        break;
    }
    
  • 不建议如下的方式:

    if (param == 1)
    openWindow();
     else if (param == 2)
    closeWindow();
     else if (param == 1) // Noncompliant
    moveWindowToTheBackground();
    switch (i) {
      case 1:
        //...
        break;
      case 3:
        //...
        break;
      case 1: // Noncompliant
        //...
        break;
      default:
        // ...
        break;
    }
    

23. ==和!=不要用在FOR循环中控制终止条件

  • 等级:Critical
  • 原因:使用==和!=控制for循环的终止条件是比较危险的。因为可能造成无限循环。
  • 建议如下的方式:

    for (var i = 1; i <= 10; i += 2) // Compliant
    {
      //...
    }
    
  • 不建议如下的方式:

    for (var i = 1; i != 10; i += 2) // Noncompliant. Infinite; i goes from 9 straight to 11.
    {
      //...
    }
    
  • 例外:如果测试的是null则可以使用==和!=,比如:

    for (inti = 0; arr[i] != null; i++) {
      // ...
    }
    for (inti = 0; (item = arr[i]) != null; i++) {
      // ...
    }
    

24. 选择器得到的结果一定要用LENGTH判断