等級:Major程序員
緣由:==和!=在判斷值相等前會判斷類型是否相等。這容易由於類型不一樣而形成錯誤。好比:它會認爲表達式:’\t\r\n’==0是正確的。所以,要採用===和!==替代這兩個符號。正則表達式
建議以下的方式:數據庫
if (var === 'howdy') { ... }
不建議以下的方式:express
if (var == 'howdy') { ... }
例外:在判斷函數是否爲空的狀況下,使用==或!=是能夠的。在下邊的例子中,若是foo沒有被初始化,它默認的值是undefined而不是null。固然underfined更不會等於null了。所以這種狀況應該使用==和!=。編程
if (foo == null) { ... }
等級: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'
等級: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 } }
等級:Critical
緣由:若是for循環永遠沒法完成就會產生錯誤。即使不會產生錯誤,也會對之後的變量值形成沒法肯定的影響,所以不可以這樣使用。
建議以下的方式:
for (i = 0; i < 10; i++) { // ... }
不建議以下的方式:
for (i = 0; i < 10; j++) { // Noncompliant // ... }
等級:Major
緣由:"for … in"這種循環容許開發人員按照屬性的名字遍歷對象。不幸的是,這個屬性的集合包括了對象自身和對象繼承的對象的全部屬性。若是程序不考慮這點就會出現錯誤。
所以,對於每一個」for … in」循環,都應該包括一個if判斷來過濾你須要的屬性。
建議以下的方式:
for (name in object) { if (object.hasOwnProperty(name)) { doSomething(name); } }
不建議以下的方式:
for (name in object) { doSomething(name); // Noncompliant }
等級: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 // ... }
等級: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 }
等級: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;
等級: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
等級:Blocker
緣由:若是for循環裏的控制變量增加方向錯誤則會致使for循環永遠沒法執行完成。雖然有時候構建無限循環是故意的,好比使用while構建無限循環。可是,大部分狀況下是存在錯誤。
建議以下的方式:
for (var i = 0; i < strings.length; i++) { //... }
不建議以下的方式:
for (var i = 0; i < strings.length; i--) { // Noncompliant; //... }
等級: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;
等級: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
等級: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.
等級: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; }
等級: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
等級: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 ...
等級: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"
等級:Major
緣由:這種註釋的風格不是JavaScript規範的一部分因此不可以使用
建議以下的方式:
// Compliant
/* Compliant */
不建議以下的方式:
<!-- Noncompliant -->
等級: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
不建議以下的方式:
for (var i = 0; i < length; i++) { } // Empty on purpose or missing piece of code ?
例外:若是代碼塊中嵌套着註釋,則這個代碼塊能夠爲空。
建議以下的方式:
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" }
建議以下的方式:
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; }
建議以下的方式:
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++) { // ... }
建議以下的方式:
// Testing whether a selection contains elements.
if ($('div.foo').length > 0) { // this code only runs if elements were found // ... }
不建議以下的方式:
if ($('div.foo')) { // Noncompliant // this code always runs, even when the selector didn't match any elements // ... }
建議以下的方式:
var person = { // ... set name(name) { this.name = name; } }
不建議以下的方式:
var person = { // ... set name(name) { this.name = name; return 42; // Noncompliant } }
建議以下的方式:
if (str != null && str.length == 0) { console.log('String is empty'); } if (str != undefined && str.length == 0) { console.log('String is empty'); } if (str == null || str.length > 0) { console.log('String is not empty'); } if (str == undefined || str.length > 0) { console.log('String is not empty'); }
不建議以下的方式:
if (str == null && str.length == 0) { console.log('String is empty'); } if (str == undefined && str.length == 0) { console.log('String is empty'); } if (str != null || str.length > 0) { console.log('String is not empty'); } if (str != undefined || str.length > 0) { console.log('String is not empty'); }
好的方法:
parseInt("010", 10);
不建議以下的方式:
parseInt("010"); // Noncompliant; pre-2013 browsers may return 8
建議以下的方式:
switch (i) { case 1: case 3: doSomething(); break; case 2: doSomethingDifferent(); break; default: doTheRest(); } if ((a >= 0 && a < 10) || (a >= 20 && a < 50)) { doTheThing(); else if (a >= 10 && a < 20) { doTheOtherThing(); } else { doTheRest(); } 或者是: switch (i) { case 1: doSomething(); break; case 2: doSomethingDifferent(); break; case 3: doThirdThing(); break; default: doTheRest(); } if (a >= 0 && a < 10) { doTheThing(); else if (a >= 10 && a < 20) { doTheOtherThing(); } else if (a >= 20 && a < 50) { doTheThirdThing(); } else { doTheRest(); }
不建議以下的方式:
switch (i) { case 1: doSomething(); break; case 2: doSomethingDifferent(); break; case 3: // Noncompliant; duplicates case 1's implementation doSomething(); break; default: doTheRest(); } if (a >= 0 && a < 10) { doTheThing(); else if (a >= 10 && a < 20) { doTheOtherThing(); } else if (a >= 20 && a < 50) { doTheThing(); // Noncompliant; duplicates first condition } else { doTheRest(); } CompliantSolution: switch (i) { case 1: case 3: doSomething(); break; case 2: doSomethingDifferent(); break; default: doTheRest(); } if ((a >= 0 && a < 10) || (a >= 20 && a < 50)) { doTheThing(); else if (a >= 10 && a < 20) { doTheOtherThing(); } else { doTheRest(); }
建議以下的方式:
var i = 0; i++;
不建議以下的方式:
var i = 0; i = i++; // Noncompliant; i is still zero
建議以下的方式:
var a = 'foo'; function otherName() { } console.log(a); function myFunc(arg) { var newName = 'event'; } fun(); // prints "foo" function fun() { print('foo'); } fun(); // prints "foo" function printBar() { print('bar'); } printBar(); // prints "bar"
不建議以下的方式:
var a = 'foo'; function a() { } // Noncompliant console.log(a); // prints "foo" function myFunc(arg) { var arg = 'event'; // Noncompliant, argument value is lost } fun(); // prints "bar" function fun() { console.log('foo'); } fun(); // prints "bar" function fun() { // Noncompliant console.log('bar'); } fun(); // prints "bar"
建議以下的方式:
var a = 'foo'; var b = 'bar'; function f(e) { var g = 'event'; }
不建議以下的方式:
var a = 'foo'; var a = 'bar'; // Non-Compliant function f(e) { var e = 'event'; // Non-Compliant }
建議以下的方式:
function setName(name) { this.name = name; }
不建議以下的方式:
function setName(name) { name = name; }
建議以下的方式:
for (i = 0; i < 10; i++) { if (i != 5) { /* Compliant */ alert('i = ' + i); } }
不建議以下的方式:
for (i = 0; i < 10; i++) { if (i == 5) { continue; /* Non-Compliant */ } alert('i = ' + i); }
建議以下的方式:
if (variable == 0) { doSomething(); } else { doSomethingElse(); }
不建議以下的方式:
switch (variable) { case 0: doSomething(); break; default: doSomethingElse(); break; }
建議以下的方式:
a += 2; i = a + b;
不建議以下的方式:
i = a += 2, a + b; // What's the value of i ?
例外:在for循環中的控制部分是可使用逗號分割表達式的。
for(i = 0, j = 5; i < 6; i++, j++) { ... }
4. 代碼段不該該被註釋掉
建議以下的方式:
function doSomething(b) { return compute(b); }
不建議以下的方式:
function doSomething(a, b) { // "a" is unused return compute(b); }
例外:當函數存在返回值時,有些變量可能須要做爲某些函數的標誌。例如:
$(['first','last']).each(function (i, value) { computeSomethingWithValue(value); }); var myFirsCallBackFunction = function (p1, p2, p3, p4) { //unused p2 is not reported but p4 is return p1 + p3; } var mySecondCallBackFunction = function (p1, p2, p3, p4) { //unused p1, p2 and p3 are not reported return p4; } var myThirdCallBackFunction = function (p1, p2, p3, p4) { //unused p1 is not reported but p3 and p4 are return p2; }
緣由:如下的單詞是JavaScript保留字,用於JavaScript之後的拓展,不能做爲標識符使用。
await
class const enum exports extends implements import interface let package private protected public static super yield
建議以下的方式:
var elements = document.getElementsByName('foo'); // Compliant
不建議以下的方式:
var package = document.getElementsByName('foo'); // Noncompliant var someData = { package: true }; // Compliant, as it is not used as an identifier here
緣由:即使是合法的,這樣作也會大大下降代碼可讀性,嚴重時,會形成意想不到的錯誤。
建議以下的方式:
Case1
switch (day) { case MONDAY: case TUESDAY: case WEDNESDAY: doSomething(); break; ... } Case2 switch (day) { case MONDAY: break; case TUESDAY: compute(args); // put the content of the labelled "for" statement in a dedicated method break; /* ... */ }
不建議以下的方式:
Case1, The code is syntactically correct but the behavior is not the expecte done switch (day) { case MONDAY: case TUESDAY: WEDNESDAY: // instead of "case WEDNESDAY" doSomething(); break; ... } Case2,the code is correct and behaves as expected but is hardly readable switch (day) { case MONDAY: break; case TUESDAY: foo: for (i = 0; i < X; i++) { /* ... */ break foo; // this break statement doesn't relate to the nesting case TUESDAY /* ... */ } break; /* ... */ }
緣由:undefined是一個屬性還沒有建立的標誌。若是將它賦值給已經存在的屬性,你將沒法區分變量是否建立。更好的方式是你可使用null代替。
建議以下的方式:
var myObject = { }; // ... myObject.fname = null; // ... if (myObject.lname == undefined) { // property not yet created } if (myObject.fname == undefined) { // no real way of knowing the true state of myObject.fname }
不建議以下的方式:
var myObject = { }; // ... myObject.fname = undefined; // Noncompliant // ... if (myObject.lname == undefined) { // property not yet created } if (myObject.fname == undefined) { // no real way of knowing the true state of myObject.fname }
緣由:JavaScript沒有integer類型,可是它有安位操做符<<, >>, >>>, ~, &,I。這種操做會首先將float類型轉換爲integer類型,而後再轉換回來,並不能像C那樣高效。更況且,支持這種操做的瀏覽器也不多。
建議以下的方式:
if (a && b) { ... } var oppositeSigns = false; if ((x < 0 && y > 0) || (x > 0 && y < 0)) { oppositeSigns = true; }
不建議以下的方式:
if (a & b) { ... } // Noncompliant; & used in error var oppositeSigns = ((x ^ y) < 0); // Noncompliant; there's a clearer way to test for this
緣由:有些工程師喜歡單獨調用構造方法而不將值賦值給變量。這是有百害無一利的作法,由於這樣構造的對象就沒法在其它地方使用了。
建議以下的方式:
var something = new MyConstructor(); // Compliant
不建議以下的方式:
new MyConstructor(); // Non-Compliant
緣由:雖然沒有語法的錯誤,可是不使用大括號會下降代碼的可讀性。還有可能形成邏輯上的錯誤。
建議以下的方式:
if (condition) { executeSomething(); checkSomething(); }
不建議以下的方式:
// the two statements seems to be attached to the if statement, but that is only true for the first one:
if (condition) executeSomething(); checkSomething();
緣由:函數的參數名應該不同以防操做產生混亂。實際上,若是存在相同的參數名,最後一個參數將會覆蓋前邊相同的參數。這種作法是沒有意義的,下降了可讀性和可維護性。
建議以下的方式:
function compute(a, b, c) { // Compliant }
不建議以下的方式:
function compute(a, a, c) { // Noncompliant }
緣由:由於「;」一行的結束符在JavaScript中不是必須的,若是函數調用的參數在新的一行開始就會讓代碼可讀性大大下降。可能會致使錯誤和之後維護的問題。
建議以下的方式:
// define a function
Either
var fn = function () { //... }; // <-- semicolon added // then execute some code inside a closure (function () { //... }) (); Or var fn = function () { //... }(function () { // <-- start function call arguments on same line //... }) ();
不建議以下的方式:
var fn = function () { //... }(function () { // Noncompliant //... }) ();
緣由:開發人員有可能使用undefined做爲變量,可是這個關鍵字是區別變量是否建立的標誌。若是被覆蓋,你將沒法區別變量是否存在。
建議以下的方式:
function foo() { var bob = 1; // anything is better than naming it 'undefined' if (nonExistantVar == undefined) { // ... } }
不建議以下的方式:
function foo() { var undefined = 1; // Noncompliant if (nonExistantVar == undefined) { // this logic doesn't work now // ... } }
10. 八進制不能被使用
緣由:儘管JavaScript是徹底支持八進制的,可是大部分開發人員不能熟練的使用八進制。他們可能會將八進制當作十進制數字來處理。
建議以下的方式:
var myNumber = 8;
不建議以下的方式:
var myNumber = 010; // myNumber will hold 8, not 10 - was this really expected?
緣由:在任何代碼塊中均可以識別label,可是隻能在」while」,」do」和」for」使用label。在其餘結構中使用label都會使結構混亂,代碼難以理解。
建議以下的方式:
myLabel: for (i = 0; i < 10; i++) { // Compliant print('Loop'); break myLabel; }
不建議以下的方式:
myLabel: if (i % 2 == 0) { // Noncompliant if (i == 12) { print('12'); break myLabel; } print('Odd number, but not 12'); }
12. 源文件中不能有重複的模塊
緣由:若是條件中沒有break,那麼程序就會繼續往下執行。雖然有時候這是開發人員有意設置的,可是更大可能的是代碼錯誤。
建議以下的方式:
switch (myVariable) { case 1: foo(); break; case 2: doSomething(); break; default: doSomethingElse(); break; }
不建議以下的方式:
switch (myVariable) { case 1: foo(); break; case 2: // Both 'doSomething()' and 'doSomethingElse()' will be executed. Is it on purpose ? doSomething(); default: doSomethingElse(); break; }
例外:如下狀況,該規則認爲是合理的:
switch (myVariable) { case 0: // Empty case used to specify the same behavior for a group of cases. case 1: doSomething(); break; case 2: // Use of return statement return; case 3: // Use of throw statement throw new IllegalStateException(); case 4: // Use of continue statement continue; default: // For the last case, use of break statement is optional doSomethingElse(); }
14. 不能在對象外使用THIS
緣由:若是在對象外使用this,它將指代全局的對象window。顯而易見,這樣將會形成難以控制的錯誤。
建議以下的方式:
foo = 1; console.log(foo); function MyObj() { this.foo = 1; } MyObj.func1 = function () { if (this.foo == 1) { // ... } }
不建議以下的方式:
this.foo = 1; // Noncompliant console.log(this.foo); // Noncompliant function MyObj() { this.foo = 1; // Compliant } MyObj.func1 = function () { if (this.foo == 1) { // Compliant // ... } }
緣由:不能在一個做用域內使用相同的名子聲明變量或函數。這不但會下降代碼可讀性,並且會致使沒必要要的錯誤。
建議以下的方式:
var fun = function fun() { } * 不建議以下的方式: var fun; function fun() { }
緣由:JavaScript變量的做用域很難掌握準確。若是存在全局變量會讓這種狀況變得更糟。
建議以下的方式:
function f() { var i = 1; for (var j = 0; j < array.length; j++) { // ... } }
不建議以下的方式:
function f() { i = 1; // Noncompliant; i is global for (j = 0; j < array.length; j++) { // Noncompliant; j is global now too // ... } }
緣由:JavaScript困擾開發人員的最大問題就是做用域。主要的緣由是雖然JavaScript看起來像是相似C語言的。可是實際並非。C語言家族有明顯的的做用域標誌,它們是經過塊來控制的,好比if塊,你能夠在裏邊創建新的變量,這樣並不會影響塊之外的做用域,而JavaScript卻不能夠。爲了儘可能避免做用域的困擾,在變量使用前必定要先聲明。
建議以下的方式:
var x = 1; function fun() { print(x); if (something) { x = 42; } } fun(); // Print "1"
不建議以下的方式:
var x = 1; function fun() { alert(x); // Noncompliant as x is declared later in the same scope if (something) { var x = 42; // Declaration in function scope (not block scope!) shadowsglobal variable } } fun(); // Unexpectedly alerts "undefined" instead of "1"
緣由:覆蓋一個在外域的變量會下降代碼可讀性和可維護性。更有甚者,會引入錯誤。
建議以下的方式:
show: function (point, element) { if (!this.drops.length) return; var drop, affected = [ ]; this.drops.each(function (aDrop) { if (Droppables.isAffected(point, element, aDrop)) affected.push(aDrop); });
不建議以下的方式:
show: function (point, element) { if (!this.drops.length) return; var drop, affected = [ ]; this.drops.each(function (drop) { // Non-Compliant; defines a new 'drop' parameter if (Droppables.isAffected(point, element, drop)) affected.push(drop); });
緣由:使用基本類型包裝的對象定義變量是沒有意義的。
建議以下的方式:
var x = false; if (x) { alert('hi'); }
不建議以下的方式:
var x = new Boolean(false); if (x) { alert('hi'); // Shows 'hi'. }
安全相關——7條
緣由:在開發的過程當中,會使用alert()進行debug,可是發佈的應用中,這種彈出方式可能會給攻擊者泄露敏感信息。
不建議以下使用方式:
if (unexpectedCondition) { alert('Unexpected Condition'); }
2. 代碼不該該動態注入執行,以防止出現EVAL注入問題
緣由:eval是在運行的時候執行任意代碼的函數,通常來講,用eval函數是很危險的,由於它能夠執行任意的代碼,若是通過必須使用該函數,則要特別注意該函數處理的任何用戶輸入數據。
不建議以下使用方式:
eval(code_to_be_dynamically_executed)
緣由:Debug信息在開發過程當中頗有用,可是在發佈的版本中,特別是客戶端保留Debug信息,會形成敏感信息泄露,使瀏覽器運行緩慢,甚至是瀏覽器進程崩潰錯誤。
不建議以下使用方式:
console.log(password_entered);
緣由:HTML5引入了一個在跨域頁面之間通信的方法,爲了下降向目標域以及未知域中傳遞敏感消息的危險,每次調用Window.postmessage方法的時候都須多加註意,不該該使用通配符*。
不建議以下的使用方式:
var myWindow = document.getElementById('myIFrame').contentWindow; myWindow.postMessage(message, '*'); // Noncompliant; how do you know what you loaded in 'myIFrame' is still there?
緣由:Debugger語句能夠在程序的任何地方聲明來暫停程序執行。利用debugger語句就像在代碼中加了一個斷點同樣。在發佈的代碼中,任何debugger語句都必須被移除。
不建議以下的使用方式:
for (i = 1; i < 5; i++) { // Print i to the Output window. Debug.write('loop index is ' + i); // Wait for user to resume. debugger; }
建議以下的使用方式:
for (i = 1; i < 5; i++) { // Print i to the Output window. Debug.write('loop index is ' + i); }
不建議以下的使用方式:
if (true) { // Noncompliant doSomething(); }...if (false) { // Noncompliant doSomethingElse(); } if (!options || options === true) { doThirdThing(); } // Noncompliant; always true
建議的使用方式:
doSomething(); doThirdThing();
緣由:本地數據庫標準在W3C標準中已經不推薦使用,此外,使用本地數據庫也會產生相應的安全問題。
不建議以下的使用方式:
var db = window.openDatabase('myDb', '1.0', 'Personal secrets stored here', 2 * 1024 * 1024); //Noncompliant
1. 在靠類型選擇元素的時候應該利用「[TYPE=...]」
緣由:在JQuery中,和type="<element_type>"均可以用來選擇元素,可是type="<element_type>"由於利用了本地的DOM querySelectorAll()方法,因此更快一些。
不建議以下的方式:
var input = $( 'form input:radio' ); // Noncompliant
建議以下的方式:
var input = $( 'form input[type=radio]' ); // Compliant
不建議以下的方式:
var $productIds = $('#products div.id'); // Noncompliant - a nested query for Sizzle selector engine
建議以下的方式:
var $productIds = $('#products').find('div.id'); // Compliant - #products is already selected by document.getElementById() so only div.id needs to go through Sizzle selector engine
jQuery不會替你緩存元素,若是你選擇了你可能還會用到的變量,你應該將選擇結果保存在變量中。
不推薦以下的方式:
$( 'p' ).hide(); $( 'p' ).show();
推薦以下的方式:
var paragraph = $( 'p' ); paragraph.hide(); paragraph.show();
例外狀況:DOM變化時,保存的selections沒有更新, 以下:
var paragraph = $('p'); // ... paragraph = $('p');
觸發本條規則的重複值爲2
5. 通配選擇器不該該被使用
不建議以下的方式:
$( '.buttons > *' ); // Noncompliant; extremely expensive
建議以下的方式:
$( '.buttons' ).children(); // Compliant
1. 註釋不該該寫在每一行的最後面
緣由:關於單行的註釋,不建議將註釋寫在該行代碼的最後,爲了增長程序的可讀性,建議將註釋寫在代碼的前一個空行上。
不建議以下的方式:
var a1 = b + c; // This is a trailing comment that can be very very long
建議以下的方式:
// This very long comment is better placed before the line of code
var a2 = b + c; 當註釋只有一個單詞的時候,容許註釋寫在代碼的後面,這是一種特例 doSomething(); //FIXME
緣由:雖然在JavaScript中,在聲明後面添加「;」不是強制性的,可是省略「;」是一種不值得提倡的作法,在有些狀況下可能會引發意想不到的結果。
不建議以下的方式:
function fun() { return // Noncompliant. ';' implicitly inserted at end of line 5 // Noncompliant. ';' implicitly inserted at end of line } print(fun()); // prints "undefined", not "5"
建議以下的方式:
function fun() { return 5; } print(fun());
緣由:這條規則會使得在利用一些工具,例如Git的時候配合的更好。
建議以下的使用方式:
class Test { } \\newline at end of file
不建議以下的方式:
function DoSomething(){...}
建議以下的方式:
function doSomething(){...}
默認的規範正則表達式爲:^[a-z][a-zA-Z0-9]*$
緣由:和第4點相同,JQuery的變量命名也須要符合必定的規範。
默認的命名檢查正則表達式爲:^\$[a-z][a-zA-Z0-9]*$
7. 一行代碼結束後不該該額外的空格
緣由:結尾的空格是無用的,且不該該保留在代碼中,在比較不一樣版本的相同文件時,末尾的空格可能會形成影響。
不建議以下的方式:
// The following string will error if there is a whitespace after '\'
var str = "Hello \ World";
緣由:將字符串用單引號聲明而非雙引號。
不建議以下的方式:
var firstParameter = "something";
建議以下的方式:
var firstParameter = 'something';
緣由:爲了便於閱讀,不要將許多statement放在一行
不建議以下的方式:
if(someCondition) doSomething();
建議以下的方式:
if(someCondition) { doSomething(); }
例外狀況:遇到只包含一個statement的匿名函數時例外,以下:
onEvent(function() { doSomething(); }); // Compliant onEvent(function(p) { doSomething(); return p %2 ;}); // Noncompliant
瀏覽器兼容性問題----2條
緣由:某些瀏覽器不支持命名函數表達式,好比IE8
不建議以下的方式:
f = function fun(){}; // Non-Compliant; named function expression
建議以下的方式:
fun = function(){}; // Compliant; function expression
例外狀況:ECMAScript6的generator function不被包含在內,以下:
function* f() {} // Compliant; generator function.
緣由:雖然大多數script引擎支持在塊中聲明函數,可是它不是ECMAScript5以及其以前版本的標準,且各個瀏覽器的處理方式是不一致的。若是你的目標瀏覽器不支持ECMAScript6,那麼在塊中利用變量定義一個函數表達式。
不建議以下的使用方式:
if (x) { function foo() {} }
建議以下的方式:
if (x) { var foo = function() {} }
緣由:嵌套太深的代碼難以閱讀,重構以及維護
不建議以下的方式:
if (condition1) { // Compliant - depth = 1 /* ... */ if (condition2) { // Compliant - depth = 2 /* ... */ for (inti = 0; i < 10; i++) { // Compliant - depth = 3, not exceeding the limit /* ... */ if (condition4) { // Non-Compliant - depth = 4 if (condition5) { // Depth = 5, exceeding the limit, but issues are only reported on depth = 4 /* ... */ } return; } } } }
默認觸發問題報告的嵌套深度爲3.
緣由:表達式的複雜程度是由&&,||,以及?,ifTrue:ifFalse操做符定義的,一個表達式不該該有超過三個的操做符,以增長表達式的可讀性。
默認觸發值爲3.
例外狀況:
這個函數忽略了Immediately Invoked Function Expressions (IIFE),函數被建立或者調用時沒有分配名字。以下:
(function () { // Ignored by this rule function open() { // Classic function declaration; not ignored // ... } function read() { // ... } function readlines() { // ... } }) ();
觸發此條件的函數的最大行爲300
不建議以下的方式:
function doSomething(param1, param2, param3, param4, param5) { ... }
建議以下的方式:
public void doSomething(intparam1, intparam2, intparam3, Stringparam4) { ... }
觸發該問題的參數臨界值爲7,建議用數組或對象代替多個參數。
不建議以下的方式:
for (var i = 1; i <= 10; i++) { // Noncompliant - 2 continue - one might be tempted to add some logic in between if (i % 2 == 0) { continue; } if (i % 3 == 0) { continue; } alert('i = ' + i); }
簡單說明以下:
return 3; // Compliant return (x); // Non-Compliant return (x + 1); // Non-Compliant intx = (y / 2 + 1); // Non-Compliant inty = (4 + X) * y; // Compliant
緣由:若是一個本地的變量被聲明而沒有被使用,它應該被移除,這樣會提升代碼維護的效率。
不建議以下的方式:
function numberOfMinutes(hours) { var seconds = 0; // seconds is never used return hours * 60; }
建議以下的方式:
function numberOfMinutes(hours) { return hours * 60; }
緣由:這兩個函數在最新的Javascript版本中不建議被使用,可能會對優化形成影響。在ECMAScript5中,這兩個函數在strict模式下都被禁止使用。
不建議以下的方式:
function whoCalled() { if (arguments.caller == null) //Noncompliant console.log('I was called from the global scope.'); else console.log(arguments.caller + ' called me!'); // Noncompliant console.log(whoCalled.caller); // Noncompliant console.log(whoCalled.arguments); // Noncompliant }
1. 多行的STRING變量不該該使用\
緣由:雖然不一樣的script引擎能夠識別多行的string變量(用\方式),可是這種形式沒有被規定在ECMAScript標準中。
不建議以下的方式:
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 have got an error and all the extraneous whitespace is \ just gravy. Have a nice day.'; // Noncompliant
建議以下的方式:
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 have got an error and all the extraneous whitespace is ' + 'just gravy. Have a nice day.';
緣由:當for循環中之定義了狀態時應該用while循環代替
不建議以下的方式:
for (; condition; ) { /*...*/ }
建議以下的方式:
while (condition) { /*...*/ }
3. 可摺疊的IF語句應該被合併
緣由:合併可摺疊的if語句,從而增長代碼的可讀性
不建議以下的方式:
if (x != undefined) { if (x === 2) { // ... } }
建議以下的方式:
if (x != undefined && x === 2) { // ... }
不建議以下的方式:
if (booleanVariable == true) { /* ... */ } if (booleanVariable != true) { /* ... */ } if (booleanVariable || false) { /* ... */ } doSomething(!false);
建議以下的方式:
if (booleanVariable) { /* ... */ } if (!booleanVariable) { /* ... */ } if (booleanVariable) { /* ... */ } doSomething(true);
例外狀況:若是文字的布爾值出如今恆等運算符中則被忽略,以下:
(=== and !==)
5. 返回BOOLEAN類型的表達式不該該被放在IF-THEN-ELSE語句中
不建議以下的方式:
if (expression) { return true; } else { return false; }
建議以下的方式:
return expression; return !!expression;
不建議被使用的方式:
var settings = { 'foo': oof, 'bar': rab, // Noncompliant - trailing comma };
建議的方式:
var settings = { 'foo': oof, 'bar': rab };
1. 」TODO」標籤不能出現
緣由:該標籤是一個標記開發人員未來將要在此處實現某些代碼的標誌。有時開發人員會忘記這事,須要對開發人員做出提醒。
不建議以下的方式:
function doSomething() { // TODO }
緣由:FIXME是開發人員對出現錯誤的代碼進行的標記,有時開發人員可能會忘記,須要進行一下提醒。
function divide(numerator, denominator) { return numerator / denominator; // FIXME denominator value might be 0 }