W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
所謂”編程風格”(programming style),指的是編寫代碼的樣式規(guī)則。不同的程序員,往往有不同的編程風格。
有人說,編譯器的規(guī)范叫做”語法規(guī)則”(grammar),這是程序員必須遵守的;而編譯器忽略的部分,就叫”編程風格”(programming style),這是程序員可以自由選擇的。這種說法不完全正確,程序員固然可以自由選擇編程風格,但是好的編程風格有助于寫出質(zhì)量更高、錯誤更少、更易于維護的程序。
所以,”編程風格”的選擇不應該基于個人愛好、熟悉程度、打字量等因素,而要考慮如何盡量使代碼清晰易讀、減少出錯。你選擇的,不是你喜歡的風格,而是一種能夠清晰表達你的意圖的風格。這一點,對于JavaScript這種語法自由度很高的語言尤其重要。
必須牢記的一點是,如果你選定了一種“編程風格”,就應該堅持遵守,切忌多種風格混用。如果你加入他人的項目,就應該遵守現(xiàn)有的風格。
空格和Tab鍵,都可以產(chǎn)生縮進效果(indent)。
Tab鍵可以節(jié)省擊鍵次數(shù),但不同的文本編輯器對Tab的顯示不盡相同,有的顯示四個空格,有的顯示兩個空格,所以有人覺得,空格鍵可以使得顯示效果更統(tǒng)一。
無論你選擇哪一種方法,都是可以接受的,要做的就是始終堅持這一種選擇。不要一會使用Tab鍵,一會使用空格鍵。
如果循環(huán)和判斷的代碼體只有一行,JavaScript允許該區(qū)塊(block)省略大括號。
if (a)
b();
c();
上面代碼的原意可能是下面這樣。
if (a) {
b();
c();
}
但是,實際效果卻是下面這樣。
if (a) {
b();
}
c();
因此,總是使用大括號表示區(qū)塊。
另外,區(qū)塊起首的大括號的位置,有許多不同的寫法。最流行的有兩種。一種是起首的大括號另起一行:
block
{
// ...
}
另一種是起首的大括號跟在關鍵字的后面。
block {
// ...
}
一般來說,這兩種寫法都可以接受。但是,JavaScript要使用后一種,因為JavaScript會自動添加句末的分號,導致一些難以察覺的錯誤。
return
{
key: value
};
// 相當于
return;
{
key: value
};
上面的代碼的原意,是要返回一個對象,但實際上返回的是undefined
,因為JavaScript自動在return
語句后面添加了分號。為了避免這一類錯誤,需要寫成下面這樣。
return {
key : value
};
因此,表示區(qū)塊起首的大括號,不要另起一行。
圓括號(parentheses)在JavaScript中有兩種作用,一種表示函數(shù)的調(diào)用,另一種表示表達式的組合(grouping)。
// 圓括號表示函數(shù)的調(diào)用
console.log('abc');
// 圓括號表示表達式的組合
(1 + 2) * 3
我們可以用空格,區(qū)分這兩種不同的括號。
表示函數(shù)調(diào)用時,函數(shù)名與左括號之間沒有空格。
表示函數(shù)定義時,函數(shù)名與左括號之間沒有空格。
其他情況時,前面位置的語法元素與左括號之間,都有一個空格。
按照上面的規(guī)則,下面的寫法都是不規(guī)范的。
foo (bar)
return(a+b);
if(a === 0) {...}
function foo (b) {...}
function(x) {...}
上面代碼的最后一行是一個匿名函數(shù),function是語法關鍵字,不是函數(shù)名,所以與左括號之間應該要有一個空格。
分號表示一條語句的結(jié)束。JavaScript規(guī)定,行尾的分號可以省略。事實上,確實有一些開發(fā)者行尾從來不寫分號。但是,由于下面要討論的原因,建議還是不要省略這個分號。
有一些語法結(jié)構(gòu)不需要在語句的結(jié)尾添加分號,主要是以下三種情況。
(1)for和while循環(huán)
for ( ; ; ) {
} // 沒有分號
while (true) {
} // 沒有分號
需要注意的是do...while
循環(huán)是有分號的。
do {
a--;
} while(a > 0); // 分號不能省略
(2)分支語句:if,switch,try
if (true) {
} // 沒有分號
switch () {
} // 沒有分號
try {
} catch {
} // 沒有分號
(3)函數(shù)的聲明語句
function f() {
} // 沒有分號
但是函數(shù)表達式仍然要使用分號。
var f = function f() {
};
以上三種情況,如果使用了分號,并不會出錯。因為,解釋引擎會把這個分號解釋為空語句。
除了上一節(jié)的三種情況,所有語句都應該使用分號。但是,如果沒有使用分號,大多數(shù)情況下,JavaScript會自動添加。
var a = 1
// 等同于
var a = 1;
這種語法特性被稱為“分號的自動添加”(Automatic Semicolon Insertion,簡稱ASI)。
因此,有人提倡省略句尾的分號。麻煩的是,如果下一行的開始可以與本行的結(jié)尾連在一起解釋,JavaScript就不會自動添加分號。
// 等同于 var a = 3
var
a
=
3
// 等同于 'abc'.length
'abc'
.length
// 等同于 return a + b;
return a +
b;
// 等同于 obj.foo(arg1, arg2);
obj.foo(arg1,
arg2);
// 等同于 3 * 2 + 10 * (27 / 6)
3 * 2
+
10 * (27 / 6)
上面代碼都會多行放在一起解釋,不會每一行自動添加分號。這些例子還是比較容易看出來的,但是下面這個例子就不那么容易看出來了。
x = y
(function () {
// ...
})();
// 等同于
x = y(function () {...})();
下面是更多不會自動添加分號的例子。
// 解釋為 c(d+e)
var a = b + c
(d+e).toString();
// 解釋為 a = b/hi/g.exec(c).map(d)
// 正則表達式的斜杠,會當作除法運算符
a = b
/hi/g.exec(c).map(d);
// 解釋為'b'['red', 'green'],
// 即把字符串當作一個數(shù)組,按索引取值
var a = 'b'
['red', 'green'].forEach(function (c) {
console.log(c);
})
// 解釋為 function(x) { return x }(a++)
// 即調(diào)用匿名函數(shù),結(jié)果f等于0
var a = 0;
var f = function(x) { return x }
(a++)
只有下一行的開始與本行的結(jié)尾,無法放在一起解釋,JavaScript引擎才會自動添加分號。
if (a < 0) a = 0
console.log(a)
// 等同于下面的代碼,
// 因為0console沒有意義
if (a < 0) a = 0;
console.log(a)
另外,如果一行的起首是“自增”(++
)或“自減”(--
)運算符,則它們的前面會自動添加分號。
a = b = c = 1
a
++
b
--
c
console.log(a, b, c)
// 1 2 0
上面代碼之所以會得到“1 2 0”的結(jié)果,原因是自增和自減運算符前,自動加上了分號。上面的代碼實際上等同于下面的形式。
a = b = c = 1;
a;
++b;
--c;
如果continue
、break
、return
和throw
這四個語句后面,直接跟換行符,則會自動添加分號。這意味著,如果return
語句返回的是一個對象的字面量,起首的大括號一定要寫在同一行,否則得不到預期結(jié)果。
return
{ first: 'Jane' };
// 解釋成
return;
{ first: 'Jane' };
由于解釋引擎自動添加分號的行為難以預測,因此編寫代碼的時候不應該省略行尾的分號。
不應該省略結(jié)尾的分號,還有一個原因。有些JavaScript代碼壓縮器不會自動添加分號,因此遇到?jīng)]有分號的結(jié)尾,就會讓代碼保持原狀,而不是壓縮成一行,使得壓縮無法得到最優(yōu)的結(jié)果。
另外,不寫結(jié)尾的分號,可能會導致腳本合并出錯。所以,有的代碼庫在第一行語句開始前,會加上一個分號。
;var a = 1;
// ...
上面這種寫法就可以避免與其他腳本合并時,排在前面的腳本最后一行語句沒有分號,導致運行出錯的問題。
JavaScript最大的語法缺點,可能就是全局變量對于任何一個代碼塊,都是可讀可寫。這對代碼的模塊化和重復使用,非常不利。
因此,避免使用全局變量。如果不得不使用,用大寫字母表示變量名,比如UPPER_CASE
。
JavaScript會自動將變量聲明”提升”(hoist)到代碼塊(block)的頭部。
if (!o) {
var o = {};
}
// 等同于
var o;
if (!o) {
o = {};
}
為了避免可能出現(xiàn)的問題,最好把變量聲明都放在代碼塊的頭部。
for (var i = 0; i < 10; i++) {
// ...
}
// 寫成
var i;
for (i = 0; i < 10; i++) {
// ...
}
另外,所有函數(shù)都應該在使用之前定義,函數(shù)內(nèi)部的變量聲明,都應該放在函數(shù)的頭部。
JavaScript使用new
命令,從構(gòu)造函數(shù)生成一個新對象。
var o = new myObject();
上面這種做法的問題是,一旦你忘了加上new
,myObject()
內(nèi)部的this
關鍵字就會指向全局對象,導致所有綁定在this
上面的變量,都變成全局變量。
因此,建議使用Object.create()
命令,替代new
命令。如果不得不使用new
,為了防止出錯,最好在視覺上把構(gòu)造函數(shù)與其他函數(shù)區(qū)分開來。比如,構(gòu)造函數(shù)的函數(shù)名,采用首字母大寫(InitialCap),其他函數(shù)名一律首字母小寫。
with
可以減少代碼的書寫,但是會造成混淆。
with (o) {
foo = bar;
}
上面的代碼,可以有四種運行結(jié)果:
o.foo = bar;
o.foo = o.bar;
foo = bar;
foo = o.bar;
這四種結(jié)果都可能發(fā)生,取決于不同的變量是否有定義。因此,不要使用with
語句。
JavaScript有兩個表示”相等”的運算符:”相等”(==
)和”嚴格相等”(===
)。
因為”相等”運算符會自動轉(zhuǎn)換變量類型,造成很多意想不到的情況:
0 == ''// true
1 == true // true
2 == true // false
0 == '0' // true
false == 'false' // false
false == '0' // true
' \t\r\n ' == 0 // true
因此,不要使用“相等”(==
)運算符,只使用“嚴格相等”(===
)運算符。
有些程序員追求簡潔,喜歡合并不同目的的語句。比如,原來的語句是
a = b;
if (a) {
// ...
}
他喜歡寫成下面這樣。
if (a = b) {
// ...
}
雖然語句少了一行,但是可讀性大打折扣,而且會造成誤讀,讓別人誤解這行代碼的意思是下面這樣。
if (a === b){
// ...
}
建議不要將不同目的的語句,合并成一行。
自增(++
)和自減(--
)運算符,放在變量的前面或后面,返回的值不一樣,很容易發(fā)生錯誤。事實上,所有的++
運算符都可以用+= 1
代替。
++x
// 等同于
x += 1;
改用+= 1
,代碼變得更清晰了。有一個很可笑的例子,某個JavaScript函數(shù)庫的源代碼中出現(xiàn)了下面的片段:
++x;
++x;
這個程序員忘了,還有更簡單、更合理的寫法。
x += 2;
建議自增(++
)和自減(--
)運算符盡量使用+=
和-=
代替。
switch...case
結(jié)構(gòu)要求,在每一個case
的最后一行必須是break
語句,否則會接著運行下一個case
。這樣不僅容易忘記,還會造成代碼的冗長。
而且,switch...case
不使用大括號,不利于代碼形式的統(tǒng)一。此外,這種結(jié)構(gòu)類似于goto
語句,容易造成程序流程的混亂,使得代碼結(jié)構(gòu)混亂不堪,不符合面向?qū)ο缶幊痰脑瓌t。
function doAction(action) {
switch (action) {
case 'hack':
return 'hack';
break;
case 'slash':
return 'slash';
break;
case 'run':
return 'run';
break;
default:
throw new Error('Invalid action.');
}
}
上面的代碼建議改寫成對象結(jié)構(gòu)。
function doAction(action) {
var actions = {
'hack': function () {
return 'hack';
},
'slash': function () {
return 'slash';
},
'run': function () {
return 'run';
}
};
if (typeof actions[action] !== 'function') {
throw new Error('Invalid action.');
}
return actions[action]();
}
建議避免使用switch...case
結(jié)構(gòu),用對象結(jié)構(gòu)代替。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: