既然要寫JS,必須要遵循一定的編程規范吧。以下是來自Google的JS語言規范,直接翻譯過來的(可參考英文原版)。
1,變量:大部分情況下請使用var聲明
如果不顯示使用var,這個變量就會被附著在全局上下文中,可能引起重名的沖突。而且,如果不使用var聲明,也 很難分辨這個變量的作用域(如:可能附著在Document或Window對象上,也可能附著在局部變量上)。所以,大部 分情況下使用var來聲明變量。
當然,如果申請一個隻屬於某一個“類”的變量,則不要使用var。如jQuery(版本為1.6.4)中為jQuery的第41 行,要為jQuery對象增加屬性,所以不能使用var來聲明。
2,常量:使用NAME_LIKE_THIS的命名方法,適當使用@const,不要使用const關鍵詞。
對於簡單的“非引用”類型,這種命名方法足矣。如:
Js代碼
<span style="font-size: medium;">/**
* The number of seconds in a minute.
* @type {number}
*/
goog.example.SECONDS_IN_A_MINUTE = 60;</span>
對於“引用”類型,使用@const註解。如:
Js代碼
<span style="font-size: medium;">/**
* The number of seconds in each of the given units.
* @type {Object.<number>}
* @const
*/
goog.example.SECONDS_TABLE = {
minute: 60,
hour: 60 * 60
day: 60 * 60 * 24
}</span>
這樣可以保證編譯器保證常量的意義。
至於const關鍵字,由於IE不支持,所以不要使用。
3,分號:使用之。
不顯式使用分號,有可能導致難以察覺的問題。特別是如下幾處:
Js代碼
<span style="font-size: medium;">//1.
MyClass.prototype.myMethod = function(){
return 42;
} // 這裡沒有分號
(function(){
//初始化一些變量,作用域為該匿名函數
})();
var x = {
'i':1,
'j':2
} //這裡沒有分號
//2.
[normalVersion,ffVersion][isIE]();
var THINGS_TO_EAT = [apples,oysters,sprayOnCheese] //沒有分號
//3.
-1 == resultOfOperation() || die();
</span>
發生什麼呢?
第一處:JS錯誤-首先,返回24的函數會執行,因為後面有一個圓括號,而且參數是一個函數;然後返回值42 被調用,出錯。
第二處:執行的時候你非常可能得到一個“no such property in undefined”的錯誤,因為實際上是在執行 x[ffVersion][isIE]()這個函數。
第三處:函數die隻有在resultOfOperation()為NaN,THINGS_TO_EAT會被賦值成die()的返回值。
為什麼呢?
JS的語法要求一個語句要以分號結尾,除非能安全的推斷出分號的位置。在上述例子中,函數聲明,對象聲明, 數組等被用在一個語句中。類似如“}”,“]”的符號不足以證明語句的結束。如果下一個字符是運算符或者"{","[",則 JS會認為語句沒有結束。
這寫錯誤令人詫異,所以確保賦值語句以分號結尾。
4,嵌套函數:可以使用
嵌套函數非常有用,比如在創建持續任務或者隱藏工具函數的時候。不用擔心,使用之。
5,在語言塊中聲明函數:不要使用!
不要寫如下代碼:
Js代碼
<span style="font-size: medium;">if(x){
function ff(){}
}</span>
盡管大多數腳本引擎支持這種函數聲明的方式,但是這並不是ECMAScript標準裡面的。ECMAScript隻支持在 根語句聲明函數。如果需要,可以使用變量來保存這個函數。如下:
Js代碼
<span style="font-size: medium;">if(x){
var ff = function(){}
}</span>
6,異常:可以使用
如果不是從0開始寫,那麼基本上避免不瞭使用異常,如使用程序開發框架的時候。
7,自定義異常:可以使用
沒有自定義異常,那麼一個函數既可以返回正常值,又可以返回一個錯誤信息,這令人費解。不大優雅的解決方 法包括返回執行錯誤信息的引用類型和返回包含潛在錯誤的對象。這些可以說是比較古老的異常處理方法。所以,在 合適的情況下可以使用自定義異常。
8,標準特性:使用標準特性而不是使用非標準的
為瞭最大化的實現可移植和兼容。比如使用string.charAt(4),而不是使用string[4];訪問元素要使用DOM函 數,而不是使用某個專屬於一個工程的簡寫。
9,為原始類型包裝:不要使用!
沒有必要為原始類型包裝,而且包裝還很容易出錯,如下:
Js代碼
<span style="font-size: medium;">var x = new Boolean(false);
if(x){
alert('hi');//會執行
}</span>
不要這樣做!
然而,類型轉換還是可以的。
Js代碼
<span style="font-size: medium;">var x = Boolean(0);
if(x){
alert('hi');//不執行
}
typeof Boolean(0) == 'boolean';
typeof new Boolean(0) == 'object';</span>
這個特點在將對象轉型成number,string,boolean的時候特別有用。
10,多級原型層次:不建議使用
多級原型層次可以用來實現繼承。多級原型很難維護。
(這個本人保留意見)
11,方法定義:Foo.prototype.bar = function(){};
盡管有好幾種方式將方法和屬性綁定到一個類,最好的還是這種。
12,閉包:可以使用,但是要小心!
閉包也許是JS最有用的特點,或許也是最被濫用的特性。
但是,要記住,閉包持有對它的關閉范圍的引用。如果將一個閉包賦值給DOM元素,則可能導致循環引用,從 而引起內存泄露,如:
Js代碼
<span style="font-size: medium;">function foo(element,a,b){
element.onclick = function(){ /* 使用a和b */
}</span>
函數本身的閉包引用瞭element,a,和b,即使從來沒有使用到element;因為element也保存瞭指向該閉 包的引用,所以形成瞭一個環,不能被GC回收。在這種情況下,可以這樣:
Js代碼
<span style="font-size: medium;">function foo(element,a,b){
element.onclick = bar(a,b);
}
function bar(a,b){
return function(){/* 使用a和b*/}
}</span>
13,eval():隻用於反序列化
eval()會造成令人困惑的語義,而且如果包含用戶輸入的字符串的時候也很危險。通常會有更好的方法來寫這種需求的代碼,所以通常不 用。但是,eval使得反序列化非常簡單,所以可以接受。
反序列化是將一系列的字符轉換成內存的數據結構的過程。例如,你可能將下面的對象寫到一個文件中去:
Js代碼
<span style="font-size: medium;">users = [
{},
{},
…
];</span>
要將這個對象讀到內存中,就可以使用eval。
類似的,eval也可以簡化解碼RPC返回值的任務。如:
Js代碼
<span style="font-size: medium;">var userOnline = false;
var user = 'nusrat';
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', 'https://chat.google.com/isUserOnline?user=' + user, false);
xmlhttp.send('');
// Server returns:
// userOnline = true;
if (xmlhttp.status == 200) {
eval(xmlhttp.responseText);
}
// userOnline is now true.</span>
14,with(){}:不要使用!
使用with會使代碼更有迷惑性。因為with裡面的對象可能會有和局部變量沖突的屬性,所以可能會導致程序的原 意完全變化。例如:
Js代碼
<span style="font-size: medium;">with(foo){
var x = 3;
return x;
}</span>
局部變量x可能與foo的屬性沖突,甚至如果foo的那個屬性有setter,還會導致其他的代碼去執行。所以,不要使 用with!
15,this:隻用在構造函數,方法,和構建閉包的時候
使用this容易使人產生疑惑。this可以指向全局對象(window),可以指向調用者,可以指向DOM節點,可以 指向新建的對象,可以指向別的對象(如果方法是用call或者apply調用的)。
因為this很容易出錯,所以限制適用於以下情況:
構造函數
對象的方法(包括創建閉包)
16,for-in 循環
for-in循環經常被錯誤的用於遍歷Array中的元素。錯誤原因在於並不隻是遍歷瞭從0到length-1的元素,而且 還遍歷瞭原型鏈。以下是幾個經常出錯的:
Js代碼
<span style="font-size: medium;">function printArray(arr) {
for (var key in arr) {
print(arr[key]);
}
}
printArray([0,1,2,3]); // This works.
var a = new Array(10);
printArray(a); // This is wrong.
a = document.getElementsByTagName('*');
printArray(a); // This is wrong.
a = [0,1,2,3];
a.buhu = 'wine';
printArray(a); // This is wrong again.
a = new Array;
a[3] = 3;
printArray(a); // This is wrong again.</span>
所以,要使用普通的遍歷。
17,數組:不要將數組作為map,哈希,聯合的數組
數組不允許使用非數字的索引,如果需要非數字的索引,可以使用Object。Array可以,是因為Array繼承自 Object。
18,多行字符串:不要使用
不要這樣:
Js代碼
<span style="font-size: medium;">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\'ve got an error and all the extraneous whitespace is \
just gravy. Have a nice day.';</span>
每一行前面的空格在編譯的時候不能被安全的跳過;\後面的空格也可能導致莫名其妙的錯誤;而且,這種語法在 ECMAScript中也是不支持的。
使用字符串相加即可:
Js代碼
<span style="font-size: medium;">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\'ve got an error and all the extraneous whitespace is ' +
'just gravy. Have a nice day.';</span>
19,字面數組和對象:建議使用
通常使用字面數組和對象來代替構造器。
Array構造器會因為參數不當而出錯。
Js代碼
<span style="font-size: medium;">// Length is 3.
var a1 = new Array(x1, x2, x3);
// Length is 2.
var a2 = new Array(x1, x2);
// If x1 is a number and it is a natural number the length will be x1.
// If x1 is a number but not a natural number this will throw an exception.
// Otherwise the array will have one element with x1 as its value.
var a3 = new Array(x1);
// Length is 0.
var a4 = new Array();</span>
因為這個原因,如果有人更改代碼傳瞭一個參數進去,而不是兩個參數,代碼可能會背離原意。
為瞭避免這種情況,這樣:
Js代碼
<span style="font-size: medium;">var a = [x1, x2, x3];
var a2 = [x1, x2];
var a3 = [x1];
var a4 = [];</span>
Object的構造器雖然沒有這個問題,但是為瞭可讀性和連貫性,建議使用字面對象。如:
Js代碼
<span style="font-size: medium;">var o = {};
var o2 = {
a: 0,
b: 1,
c: 2,
'strange key': 3
};</span>
20,更改內置對象的prototype:禁止!
更改內置對象的原型是被嚴厲禁止的。
作者“技術愛好者”