日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
如何編寫高質(zhì)量的JavaScript代碼

優(yōu)秀的Stoyan Stefanov在他的新書中(《Javascript Patterns》)介紹了很多編寫高質(zhì)量代碼的技巧,比如避免使用全局變量,使用單一的var關(guān)鍵字,循環(huán)式預(yù)存長度等等。

創(chuàng)新互聯(lián)是一家專業(yè)提供北海企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計、H5技術(shù)、小程序制作等業(yè)務(wù)。10年已為北海眾多企業(yè)、政府機構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)絡(luò)公司優(yōu)惠進(jìn)行中。

這篇文章不僅僅從代碼本身來考慮如何優(yōu)化編碼,也從代碼的設(shè)計階段來考慮,包括書寫API文檔,同事的review,使用JSLint。這些習(xí)慣都能幫助你編寫更加高質(zhì)量的、更易于理解的、可維護(hù)的代碼(讓你的代碼在多年之后仍使你引以為傲)。

編寫可維護(hù)的代碼

軟件的BUG修復(fù)需要花費大量的精力。尤其當(dāng)代碼已經(jīng)發(fā)布之后,隨著時間的增長,維護(hù)的成本愈發(fā)的高。當(dāng)你一發(fā)現(xiàn)BUG的時候,就立即去修復(fù),這時候你的代碼還是熱乎的,你也不需要回憶,因為就是剛剛寫好的。但是當(dāng)你做了其他任務(wù),幾乎完全忘記了這份代碼,這時候就需要:

◆重新學(xué)習(xí)和理解問題

◆理解代碼是如何解決問題的

另外一個問題是,在大項目或者大公司里面,經(jīng)常是解決BUG的人不是產(chǎn)生BUG的人,而且也不是發(fā)現(xiàn)BUG的人。所以減少理解代碼的時間就是最重要的問題,無論這個代碼是你自己以前寫的還是團(tuán)隊中的其他成員寫的,因為我們都想去搞搞新的有意思的東西,而不是去維護(hù)那些個陳舊的代碼。

還有一個開發(fā)中的普遍問題就是,往往讀代碼的時間比寫代碼的時間還要多。有時候你鉆研一個問題,可以花整整一個下午的時間來考慮代碼的編寫。這個代碼當(dāng)時是可以工作的,但是隨著開發(fā)的進(jìn)行,其他東西發(fā)生了很大的變化,這時候也就需要你自己來重新審查修改編寫代碼。比如:

◆還有BUG沒有解決

◆添加了新的功能

◆程序需要在新的環(huán)境中運行(比如一個新上市的瀏覽器)

◆代碼有問題

◆代碼需要重寫因為修改了架構(gòu)甚至要使用另一個語言

因為這些原因,也許你當(dāng)時一個下午寫好的代碼,后面需要花費幾周的時間來閱讀。所以編寫可維護(hù)的代碼對于軟件的成功至關(guān)重要。

可維護(hù)的代碼包括:

◆可讀性

◆連續(xù)性

◆預(yù)見性

◆看起來是一個人寫的

◆有文檔

最少化全局變量

Javascript使用函數(shù)來約定作用域。一個在函數(shù)內(nèi)部聲明的變量在外部是不可見的。所以,全局變量也就是聲明在任何函數(shù)之外的或者沒有被聲明的變量。

Javascript中,在任何函數(shù)之外有個可訪問的全局對象,每一個你創(chuàng)建的全局變量都是這個對象的一個屬性。在瀏覽器中,為了方便,通常用window來指代這個全局變量。下面的代碼就是說明如何創(chuàng)建一個全局變量:

 
 
 
  1. myglobal = "hello"; // antipattern  
  2. console.log(myglobal); // "hello"  
  3. console.log(window.myglobal); // "hello"  
  4. console.log(window["myglobal"]); // "hello"  
  5. console.log(this.myglobal); // "hello 

全局變量的問題

全局變量的問題在于,他在你的所有代碼或者一個頁面中都共享。他們在同一個命名空間下面,這通常會造成變量名沖突–兩個同名的變量,但是確實不同的用處。

通常在一些頁面中需要引入一些其他人的代碼,比如:

◆第三方的JS庫

◆廣告伙伴的腳本

◆第三方的用戶行為分析或者統(tǒng)計腳本

◆不同的組件、按鈕等等

加入其中一個第三方組件定義了一個全局變量:result。然后在你的程序中,也定義了一個全局變量result。***的這個result會覆蓋點之前的result,這樣第三方的腳本就會停止工作。

所以,為了對其他的腳本友好,在一個頁面中使用越少的全局變量越好。在后面會有一些方法來告訴你如何減少全局變量,比如使用命名空間,或者自執(zhí)行的匿名函數(shù),但是***的避免全局變量的方法就是使用var關(guān)鍵字來聲明變量。

因為javascript的兩個特性,創(chuàng)建一個全局變量非常的簡單。***,你可以使用一個甚至沒有聲明的變量,第二,在javascript中,所有未聲明的變量都會成為全局對象的一個屬性(就像一個聲明了的全局變量一樣)??纯催@個例子:

 
 
 
  1. function sum(x,y){  
  2.      result = x + y;  
  3.      return result;  

在這個代碼中,result在沒有被聲明的情況下就被使用了,這個代碼也能很好的工作,但是在調(diào)用了這個函數(shù)之后,就會多一個名為result的全局變量,這是所有問題的根源了。

解決這個問題的辦法就是使用var:

 
 
 
  1. function sum(x,y){  
  2.      var result  = x + y;  
  3.      return result;  

兩外一個不好的習(xí)慣就是在聲明變量的時候使用鏈?zhǔn)降姆椒▉碣x值,這時候,a是局部變量,但是b就成為了全局變量。

 
 
 
  1. function foo(){  
  2.      var a=b=0;  
  3.      ....  

這是因為,b = 0這個表達(dá)式先執(zhí)行,執(zhí)行的時候b并沒有被聲明,所以b就成為了全局變量,然后返回這個表達(dá)式的值0,給聲明了的變量a,換句話說,就好像你輸入的是:

 
 
 
  1. var a = (b=0); 

如果你已經(jīng)聲明變量,那么這種鏈?zhǔn)降馁x值沒有問題:

 
 
 
  1. function foo(){  
  2.      var a,b;  
  3.      ...  

另外一個避免使用全局變量的原因是考慮到程序的可移植性。如果你想讓你的代碼在不同的環(huán)境中都可以工作,那么使用全局變量就很可能會與新的系統(tǒng)中的全局變量沖突(或許在之前的系統(tǒng)中沒有問題)。

忘記var的影響

使用var聲明的全局變量和沒有使用var生成的全局變量還有一個區(qū)別在于刪除:

使用var聲明創(chuàng)建的全局變量不能被刪除

沒有使用var聲明的全局變量可以被刪除

這說明沒有使用var聲明生成的全局變量不是真正的變量,他們只是全局對象的屬性。屬性可以通過delete刪除,但是變量不行:

 
 
 
  1. // define three globals  
  2. var global_var = 1;  
  3. global_novar = 2; // antipattern  
  4. (function () {  
  5.    global_fromfunc = 3; // antipattern  
  6. }());   
  7.    
  8. // attempt to delete  
  9. delete global_var; // false  
  10. delete global_novar; // true  
  11. delete global_fromfunc; // true   
  12.    
  13. // test the deletion  
  14. typeof global_var; // "number"  
  15. typeof global_novar; // "undefined"  
  16. typeof global_fromfunc; // "undefined" 

在ES5的嚴(yán)格模式下,給一個為聲明的變量賦值會報錯。

讀取全局對象

在瀏覽器中,你可以通過window變量來讀取全局對象(除非你在函數(shù)內(nèi)部重新定義了window對象)。但在有的環(huán)境中,可能不叫window,那么你可以使用下面的代碼來獲取全局對象:

 
 
 
  1. var global = (function(){  
  2.      return this;  
  3. })(); 

這樣可以獲取到全局對象的原因是在function的內(nèi)部,this指向全局對象。但是這在ES5的嚴(yán)格模式下會不起作用,你需要適配一些其他模式。當(dāng)你開發(fā)自己的庫的時候,你可以把你的代碼封裝在一個立即函數(shù)中,然后將this作為一個參數(shù)傳進(jìn)來。

單個var模式

在你的代碼的頂部只是用一個var關(guān)鍵字,會有以下的好處:

◆對于所有需要的變量,在一個地方就可以全部看到

◆避免使用一個未定義的變量

◆幫助你記憶聲明的變量,減少全局變量

◆更精簡的代碼

書寫很簡單:

 
 
 
  1. function func() {  
  2.    var a = 1,  
  3.        b = 2,  
  4.        sum = a + b,  
  5.        myobject = {},  
  6.        i,  
  7.        j;  
  8.    // function body...  

通過一個var和逗號來聲明多個變量。在聲明的時候給變量賦默認(rèn)值也是不錯的做法,可以避免一些邏輯錯誤,提高代碼的可讀性。而后你閱讀的代碼的時候也可以根據(jù)變量的默認(rèn)值來方便的猜測變量的用途。

你也可以在聲明變量的時候做一些實際的工作,比如sum = a + b;另外,在操作DOM元素的時候,你也可以把DOM元素的引用保存在一個變量中:

 
 
 
  1. function updateElement() {  
  2.    var el = document.getElementById("result"),  
  3.        style = el.style;  
  4.    // do something with el and style...  

濫用了的var

JavaScript允許你在函數(shù)內(nèi)部有多個var語句,但是卻都表現(xiàn)的如同在函數(shù)的頂部聲明一樣。這個特性在你使用一個變量然后在后面又聲明了這個變量時會導(dǎo)致一些奇怪的邏輯問題。對于JavaScript來說,只要變量在同一個作用域,那么就認(rèn)為是聲明了的,就算是在var語句之前使用也一樣??纯催@個例子:

 
 
 
  1. myname = "global"; // global variable  
  2. function func() {  
  3.     alert(myname); // "undefined"  
  4.     var myname = "local";  
  5.     alert(myname); // "local"  
  6. }  
  7. func(); 

在這個例子中,或許你期望***次會彈出global,第二次彈出local。因為***次的時候沒有還沒有使用var聲明myname,這是應(yīng)該是全局變量的myname,第二次聲明了,然后alert之后應(yīng)該是local的值。而事實上不是這樣的,只要你在函數(shù)中出現(xiàn)了var myname,那么js就認(rèn)為你在這個函數(shù)中聲明了這個變量,但是在讀取這個變量的值的時候,因為var語句還沒有執(zhí)行,所以是undefined,很奇怪的邏輯吧。上面的代碼相當(dāng)于:

 
 
 
  1. myname = "global"; // global variable  
  2. function func() {  
  3.    var myname; // same as -> var myname = undefined;  
  4.    alert(myname); // "undefined"  
  5.    myname = "local";  
  6.    alert(myname); // "local"  
  7. }  
  8. func(); 

我們來解釋一下這個現(xiàn)象,在代碼的解析中,分兩個步驟,***步先處理變量函數(shù)的聲明,這一步處理整個代碼的上下文。第二步就是代碼的運行時,創(chuàng)建函數(shù)表達(dá)式以及未定義的變量。實際上,我們只是假設(shè)了這個概念,這并不在ECMAScript的規(guī)范中,但是這個行為常常就是這樣解釋的。

#p#

for循環(huán)

在for循環(huán)中你會去迭代一些數(shù)組元素或者一些HTML元素。for循環(huán)常常如此:

 
 
 
  1. for (var i = 0; i < myarray.length; i++) {  
  2.    // do something with myarray[i]  

這樣寫的問題在于,每一次迭代的時候都會計算數(shù)組的長度,尤其在這個參數(shù)不是一個數(shù)組而是一組HTML元素的時候會降低你的程序的性能。

HTML元素的集合在頁面上,這樣每次都會去再頁面上查找相應(yīng)的元素,這是非常耗時的。所以對于for循環(huán),你需要預(yù)先保存數(shù)組的長度,這樣寫:

 
 
 
  1. for (var i = 0, max = myarray.length; i < max; i++) {  
  2.    // do something with myarray[i]  

這樣緩存了參數(shù)的長度,在每次迭代的時候就不用再去查找計算了。

在查找HTML元素集合的時候,緩存參數(shù)長度可以帶來可觀的性能提升,Safari下面提高兩倍的速度,在IE7下面提高190倍的速度。

需要注意的是,當(dāng)你需要操作修改DOM元素的數(shù)量的時候,你肯定希望這個值是隨時更新的而不是一個常量。

使用下面的單一var模式,你也可以把var提到循環(huán)之外:

 
 
 
  1. function looper() {  
  2.    var i = 0,  
  3.         max,  
  4.         myarray = [];  
  5.    // ...  
  6.    for (i = 0, max = myarray.length; i < max; i++) {  
  7.       // do something with myarray[i]  
  8.    }  

這個模式可以增強整個代碼的連續(xù)性,但是不好的一點是當(dāng)你重構(gòu)代碼的時候復(fù)制粘貼就沒那么容易了。例如:如果你想在其他函數(shù)中也使用這個循環(huán),那你需要確定在新的函數(shù)中處理好了i和max(或許還需要刪掉這個)。

這個函數(shù)還有兩個點可以優(yōu)化的:

◆可以少一個變量(不需要max)

◆遞減到0,一個數(shù)字與0比較比這個數(shù)字與另外一個數(shù)字比較更快

所以就可以寫為:

 
 
 
  1. var i, myarray = [];  
  2. for (i = myarray.length; i--;) {  
  3.    // do something with myarray[i]  

針對第二點:

 
 
 
  1. var myarray = [],  
  2.     i = myarray.length;  
  3. while (i--) {  
  4.    // do something with myarray[i]  

這是兩個比較微小的點的優(yōu)化。另外,JSLint可能對于i–會有意見。

for-in循環(huán)

for-in循環(huán)用來迭代非數(shù)組的對象。使用for-in循環(huán)通常也成為枚舉。

從技術(shù)上來說,你也可以用for-in來循環(huán)數(shù)組,因為數(shù)組也是對象,但是不推薦。如果數(shù)組有一些自定義的擴展函數(shù),那么就會出錯。另外,對象屬性的順序在for-in循環(huán)中也是不確定的。所以***還是用普通的循環(huán)來循環(huán)數(shù)組用for-in來循環(huán)對象。

在循環(huán)對象的過程中,使用hasOwnProperty()方法來檢驗是對象本身的屬性還是原型鏈上的屬性很重要。

看看下面的這個例子。

 
 
 
  1. // the object  
  2. var man = {  
  3.    hands: 2,  
  4.    legs: 2,  
  5.    heads: 1  
  6. };   
  7.    
  8. // somewhere else in the code  
  9. // a method was added to all objects  
  10. if (typeof Object.prototype.clone === "undefined") {  
  11.    Object.prototype.clone = function () {};  

在這個例子中,我們有一個簡單的稱作man的對象字面量。在其他man定義之前或之后的地方,對象原型有一個很有用的clone()方法。因為原型鏈的原因,所有的對象都自動獲得了這個方法。為了在枚舉man對象的時候出現(xiàn)clone方法,你需要使用hasOwnProperty方法來區(qū)別。如果沒有區(qū)別來自原型鏈的方法,那么就會有一些意想不到的事情發(fā)生:

 
 
 
  1. // 1.  
  2. // for-in loop  
  3. for (var i in man) {  
  4.    if (man.hasOwnProperty(i)) { // filter  
  5.       console.log(i, ":", man[i]);  
  6.    }  
  7. }  
  8. /* result in the console  
  9. hands : 2  
  10. legs : 2  
  11. heads : 1  
  12. */ 
  13. // 2.  
  14. // antipattern:  
  15. // for-in loop without checking hasOwnProperty()  
  16. for (var i in man) {  
  17.    console.log(i, ":", man[i]);  
  18. }  
  19. /*  
  20. result in the console  
  21. hands : 2  
  22. legs : 2  
  23. heads : 1  
  24. clone: function()  
  25. */ 

另外一種使用方法如下:

 
 
 
  1. for (var i in man) {  
  2.    if (Object.prototype.hasOwnProperty.call(man, i)) { // filter  
  3.       console.log(i, ":", man[i]);  
  4.    }  

這樣寫的好處是可以防止man重新定義了hasOwnProperty方法導(dǎo)致的沖突。如果不想寫這么長的一串,你也可以這樣:

 
 
 
  1. var i, hasOwn = Object.prototype.hasOwnProperty;  
  2. for (i in man) {  
  3.     if (hasOwn.call(man, i)) { // filter  
  4.         console.log(i, ":", man[i]);  
  5.     }  

嚴(yán)格意義上講,不適用hasOwnProperty也不是什么錯誤。根據(jù)任務(wù)的難度和你對代碼的自信程度,你也可以不用這個直接循環(huán)。但是當(dāng)你不確定的時候,***還是使用這個方法檢測一下。

另外一種格式上的改變(不會通過jsLint的檢查),去掉for的大括號,然后把if放在同一行。這樣做的好處可以讓循環(huán)體更加突出,縮進(jìn)也就少一些:

 
 
 
  1. // Warning: doesn't pass JSLint  
  2. var i, hasOwn = Object.prototype.hasOwnProperty;  
  3. for (i in man) if (hasOwn.call(man, i)) { // filter  
  4.     console.log(i, ":", man[i]);  

不要擴展內(nèi)建的原型

擴展原型的構(gòu)造函數(shù),可以提供一些很強大的功能,但是有時候他太強大了。

有時候你會去擴展Object(),Array(),Fucntion()的原型方法,這樣會導(dǎo)致可維護(hù)性的問題,因為這會讓你的代碼的移植性變差。其他的開發(fā)人員使用你的代碼的時候,可能只需要原生的方法,并不需要額外的功能。

另外,你添加進(jìn)去的方法,如果在循環(huán)的時候沒有使用hasOwnProperty方法就會被遍歷出來,這會讓人很迷惑。

所以,***還是不要擴展基本的對象。除非是下面的情況:

◆你確定在將來根據(jù)ECMAScript規(guī)范,瀏覽器會添加相應(yīng)的原型方法,那么是可以的,你只不過是提前實現(xiàn)了這個功能。

◆你確定的你要實現(xiàn)的方法不存在–或許有時候在代碼的其他的地方實現(xiàn)了,或者有的瀏覽器支持,這都是不行的。

◆有非常清晰的文檔,并且與團(tuán)隊成員溝通過

如果在這些情況之下,那么你就可以添加,***是下面這種形式:

 
 
 
  1. if (typeof Object.prototype.myMethod !== "function") {  
  2.    Object.prototype.myMethod = function () {  
  3.       // implementation...  
  4.    };  

switch模式

按照下面的風(fēng)格寫switch的話,可以提高你的代碼可讀性和健壯性:

 
 
 
  1. var inspect_me = 0,  
  2.     result = '';  
  3. switch (inspect_me) {  
  4. case 0:  
  5.    result = "zero";  
  6.    break;  
  7. case 1:  
  8.    result = "one";  
  9.    break;  
  10. default:  
  11.    result = "unknown";  

需要注意下面幾個方面:

◆將case和switch對齊。

◆case的內(nèi)容縮進(jìn)

◆每一個case之后都有一個清晰的break

◆避免順序往下執(zhí)行case,非要如此的話,文檔一定要寫清楚

◆***使用default,保證在沒有命中case的情況下也有反饋

避免隱藏的類型轉(zhuǎn)換

Javascript在你比較兩個變量的時候會進(jìn)行類型的轉(zhuǎn)換,這就是為什么 false == 0或者”" == 0會返回true。

為了避免這種隱藏的類型轉(zhuǎn)換帶來的迷惑,***使用===或者!==操作符來比較:

 
 
 
  1. var zero = 0;  
  2. if (zero === false) {  
  3.    // not executing because zero is 0, not false  
  4. }   
  5.    
  6. // antipattern  
  7. if (zero == false) {  
  8.    // this block is executed...  

還有另外一種流派持這樣的觀點:當(dāng)==夠用時使用===就是多余的。比如,當(dāng)你使用typeof的時候你知道會返回string,所以沒必要使用嚴(yán)格的檢驗。然而,JSLint要求嚴(yán)格檢驗;他最大程度使代碼在閱讀的時候減少歧義,(“這個==是故意呢還是疏漏?”)。

避免使用eval()

如果你在你的代碼中使用eval(),那么要記住”eval() is evil”。這個方法會將傳入的字符串當(dāng)做js代碼來執(zhí)行。如果代碼是在運行前就確定的,那么沒有必要使用eval()。如果代碼是在運行時動態(tài)確定的,那么也有其他更安全的辦法。例如使用方括號形式訪問元素的屬性:

 
 
 
  1. // antipattern  
  2. var property = "name";  
  3. alert(eval("obj." + property));    
  4.    
  5. // preferred  
  6. var property = "name";  
  7. alert(obj[property]); 

使用eval()還有安全問題,比如你運行網(wǎng)絡(luò)上的一段代碼,而這段代碼又被別人篡改了。在處理Ajax請求返回的JSON數(shù)據(jù)的時候,***還是使用瀏覽器內(nèi)建的處理方法,如果對于低端的瀏覽器不支持的,可以從JSON.org上下載對應(yīng)的處理庫。

另外還要記住使用setTimeout、setInterval以及Function的構(gòu)造函數(shù)的是,傳入的字符串的參數(shù),js的處理方法跟eval()類似,所以也要注意。因為,js會把你傳入的字符串解析執(zhí)行:

 
 
 
  1. // antipatterns  
  2. setTimeout("myFunc()", 1000);  
  3. setTimeout("myFunc(1, 2, 3)", 1000);    
  4.    
  5. // preferred  
  6. setTimeout(myFunc, 1000);  
  7. setTimeout(function () {  
  8.    myFunc(1, 2, 3);  
  9. }, 1000); 

使用Function的構(gòu)造函數(shù),跟eval()差不多,也要注意。這是個非常有用的功能,但是常常被錯用。如果你必須使用eval(),那么可以考慮new一個Function來替代。另外的一個好處就是,使用Function的構(gòu)造函數(shù),函數(shù)的作用域在本方法內(nèi),這樣你使用var聲明的變量就不會變成全局的。另外一個防止eval()生成全局變量的辦法就是使用匿名函數(shù)。

看看下面這個例子,只有un變量最終是全局的:

 
 
 
  1. console.log(typeof un); // "undefined"  
  2. console.log(typeof deux); // "undefined"  
  3. console.log(typeof trois); // "undefined"    
  4.    
  5. var jsstring = "var un = 1; console.log(un);";  
  6. eval(jsstring); // logs "1"    
  7.    
  8. jsstring = "var deux = 2; console.log(deux);";  
  9. new Function(jsstring)(); // logs "2"    
  10.    
  11.  jsstring = "var trois = 3; console.log(trois);";  
  12.  (function () {  
  13.     eval(jsstring);  
  14.  }()); // logs "3"    
  15.    
  16.  console.log(typeof un); // number  
  17.  console.log(typeof deux); // undefined  
  18.  console.log(typeof trois); // undefined 

eval()和Function構(gòu)造函數(shù)的另一個區(qū)別就是eval()會影響到作用域,而Function則相當(dāng)于一個沙盒。例如:

 
 
 
  1. (function () {  
  2.    var local = 1;  
  3.    eval("local = 3; console.log(local)"); // logs 3  
  4.    console.log(local); // logs 3  
  5. }());    
  6.    
  7. (function () {  
  8.    var local = 1;  
  9.    Function("console.log(typeof local);")(); // logs undefined  
  10.  }()); 

使用parseInt()轉(zhuǎn)換處理數(shù)字

使用parseInt()你可以將字符串轉(zhuǎn)為數(shù)字。這個方法支持第二個表示進(jìn)制的參數(shù),常常被忽略。問題常常在處理一段以0開始的字符串的時候。在ECMAS3標(biāo)準(zhǔn)中,以0開始表示八進(jìn)制,但是在ES5中又改了,所以為了避免麻煩,***還是標(biāo)明第二個參數(shù)。

 
 
 
  1. var month = "06",  
  2.     year = "09";  
  3. month = parseInt(month, 10);  
  4. year = parseInt(year, 10); 

在這個例子中,如果你使用parseInt(year),就會返回0,因為09被認(rèn)為是8進(jìn)制數(shù)字,然而9是非法的八進(jìn)制字符,所以返回0。

其他的可以把字符串轉(zhuǎn)為數(shù)字的方法有:

 
 
 
  1. +"08" // result is 8  
  2. umber("08") // 8 

這些通常都比parseInt()快一些,因為parseInt并不只是簡單的轉(zhuǎn)換。但是如果你的輸入是”08 hello”這樣的,那么parseInt()也會返回8,但是其他的方法就只能返回NaN。

#p#

編碼規(guī)范

編碼的時候遵循一定的規(guī)范,可以讓你的代碼增強可移植性,并且更加便于閱讀和理解。加入團(tuán)隊的新人,在閱讀了代碼規(guī)范之后,可以更加快速的溶入團(tuán)隊,并理解其他人員開發(fā)的代碼。

在一些討論會議上,規(guī)范往往都是爭論的焦點(比如縮進(jìn)的形式)。所以如果你打算為你團(tuán)隊的編碼規(guī)范提一些建議,那就準(zhǔn)備好一場激烈的辯論和反對意見。要記住,建立和實施規(guī)范是非常重要的。

縮進(jìn)

代碼如果沒有縮進(jìn),那基本上沒法閱讀了。比這更糟的是不規(guī)范的縮進(jìn),看著好像縮進(jìn)了,但是亂七八糟摸不著頭腦。所以縮進(jìn)的使用必須規(guī)范。

有些開發(fā)人員喜歡使用tab鍵來縮進(jìn),因為在每一個編輯器里面都可以自己設(shè)置想要的tab值。有的人喜歡四個空格。如果團(tuán)隊遵循統(tǒng)一的規(guī)范,這也不是什么問題。比如本文就是四個空格,這也是JSLint推薦的。

那么什么該縮進(jìn)呢?很簡單,大括號。這樣就是說包括函數(shù)體,循環(huán),ifs,switch,以及對象字面量的屬性??纯催@個例子:

 
 
 
  1. function outer(a, b) {  
  2.     var c = 1,  
  3.         d = 2,  
  4.         inner;  
  5.     if (a > b) {  
  6.         inner = function () {  
  7.             return {  
  8.                 r: c - d  
  9.             };  
  10.          };  
  11.      } else {  
  12.          inner = function () {  
  13.              return {  
  14.                  r: c + d  
  15.              };  
  16.          };  
  17.      }  
  18.      return inner;  
  19.  } 

大括號

應(yīng)該使用大括號,尤其在那些可用可不用的地方,如果你的if語句或者for循環(huán)只有一句話,那么大括號不是必須的,但是這種時候***用大括號。這可以讓代碼保持一致,并且便于升級。

假設(shè)你的for循環(huán)只有一句。你可以不用大括號,也不會有什么錯誤。

 
 
 
  1. // bad practice  
  2. for (var i = 0; i < 10; i += 1)  
  3.    alert(i); 

但是假如你以后要在這個循環(huán)里面添加其他東西呢?

 
 
 
  1. // bad practice  
  2. for (var i = 0; i < 10; i += 1)  
  3.    alert(i);  
  4.    alert(i + " is " + (i % 2 ? "odd" : "even")); 

這時候,雖然第二個alert有縮進(jìn),但他還是在循環(huán)之外的。所以,無論何時,都應(yīng)該是用大括號。if語句一樣:

 
 
 
  1. // bad  
  2. if (true)  
  3.    alert(1);  
  4. else 
  5.    alert(2);    
  6.    
  7. // better  
  8. if (true) {  
  9.    alert(1);  
  10.  } else {  
  11.     alert(2);  
  12.  } 

大括號位置

開發(fā)人員也經(jīng)常爭論大括號的位置,放在同一行還是下一行呢?

在具體的例子中,這是個見仁見智的問題。但也有例外,假如程序根據(jù)不同的位置做不同的解析呢?這是因為插入分號機制,js對此并不挑剔,他會在你沒有添加分號的行之后幫你添加。這在函數(shù)返回一個對象字面量然后大括號寫在下一行的時候出問題:

 
 
 
  1. // warning: unexpected return value  
  2. function func() {  
  3.    return 
  4.   // 下面的讀取不到  
  5.    {  
  6.       name : "Batman" 
  7.    }  

如果你想讓這個函數(shù)返回一個有name屬性的對象字面量,這個函數(shù)是做不到的,因為插入的分號,返回的應(yīng)該是一個undefied值。

所以,***的結(jié)論是,必須使用大括號,并且寫在同一行。

 
 
 
  1. function func() {  
  2.    return {  
  3.       name : "Batman" 
  4.    };  

關(guān)于分號:跟大括號一樣,必須寫。這不只是推行嚴(yán)格的寫程序的規(guī)范,更是在必要的時候解決一些不清楚的地方,比如前面的例子。

空格

正確的使用空格也可以增加程序的可讀性和連貫性。寫句子的時候你會在逗號和句號之后有一些停頓。在js中可以模仿這樣的邏輯。

應(yīng)該使用空格地方有:

◆循環(huán)中的分號之后

◆循環(huán)中的變量初始化for (var i = 0, max = 10; i < max; i += 1) {…}

◆數(shù)組中的逗號分隔符之后var a = [1, 2, 3];

◆對象字面量中的逗號var o = {a: 1, b: 2}

◆函數(shù)參數(shù)間myFunc(a, b, c)

◆在函數(shù)聲明時候的大括號前面function myFunc() {}

◆匿名函數(shù)var myFunc = function () {};

另外一些使用空格比較好的地方就是在那些操作符的兩邊,比如+, -, *, =, <, >, <=, >=, ===, !==, &&, ||, +=,等等。

 
 
 
  1. // generous and consistent spacing  
  2. // makes the code easier to read  
  3. // allowing it to "breathe"  
  4. var d = 0,  
  5.     a = b + 1;  
  6. if (a && b && c) {  
  7.     d = a % c;  
  8.     a += d;  
  9. }    
  10.    
  11.  // antipattern  
  12.  // missing or inconsistent spaces  
  13.  // make the code confusing  
  14.  var d = 0,  
  15.      a = b + 1;  
  16.  if (a && b && c) {  
  17.      d = a % c;  
  18.      a += d;  
  19.  } 

***一個關(guān)于空格要注意的,大括號前面的空格。***使用空格:

◆在函數(shù)定義,id-else,case,循環(huán)以及對象字面量的大括號前面使用空格

◆在大括號}與else、while之間使用空格

反對增加空格的一個說法是增加文件體積,但是在壓縮之后并不存在這個問題。提高代碼可讀性經(jīng)常被忽視的一個方面就是垂直的空格,你可以使用空行來分開代碼,就好像寫文章時候的段落一樣。

命名規(guī)范

可以提高代碼移植性和可維護(hù)性的一個方面是命名規(guī)范。也就是說,在取變量名的時候總是采取一貫的做法。

無論采用什么樣的命名規(guī)范,其實都不是很重要,重要的是確定下來這個規(guī)范,然后遵守它。

構(gòu)造函數(shù)首字母大寫

javascript中沒有類,但是可以使用new來達(dá)到同樣的目的。

因為構(gòu)造函數(shù)也是函數(shù),如果能從名字上就能區(qū)別它是構(gòu)造函數(shù)還是普通函數(shù),對于開發(fā)者是非常有用的。所以將構(gòu)造函數(shù)的首字母大寫,普通函數(shù)的首字母小寫作為提示。這樣一眼就能區(qū)別。

單詞的分隔

當(dāng)你的變量名或者函數(shù)名是由好幾個單詞構(gòu)成的時候,如果能順利區(qū)分變量名由那幾個單詞構(gòu)成,也是非常不錯的體驗。這種命名規(guī)范成為駝峰式。所謂駝峰式就是以小寫字母開始,后面的每個單詞***個字母大寫。

對于構(gòu)造函數(shù)***個字母大寫,MyConstructor(),對于普通的函數(shù),就采用駝峰式myFunction(), calculateArea()。

那么變量怎么辦呢,有的人使用駝峰式,但是更好的辦法是使用下劃線來區(qū)分。first_name,favorite_bands, 以及 old_company_name。這也可以讓你一眼就能區(qū)分函數(shù)和變量。

其他命名規(guī)范

有時候,開發(fā)人員也會使用命名規(guī)范來替代和彌補一些語言的特性。

例如,在javascript中,并沒有提供定義常量的辦法(雖然有Number.MAX_VALUE),所以開發(fā)人員使用全大寫的名稱來表示不可更改的常量。var PI = 3.14, MAX_WIDTH = 800。

另外一種規(guī)范是使用全局變量名的首字母。這樣做可以強化開發(fā)者使全局變量最少,并且容易辨認(rèn)。

另外一種規(guī)范是在函數(shù)中模擬私有成員。雖然可以在javascript中實現(xiàn)私有變量,但是開發(fā)人員為了更加容易區(qū)別,所以給他加一個下劃線的前綴。例如:

 
 
 
  1. var person = {  
  2.     getName: function () {  
  3.         return this._getFirst() + ' ' + this._getLast();  
  4.     },    
  5.    
  6.     _getFirst: function () {  
  7.         // ...  
  8.     },  
  9.     _getLast: function () {  
  10.          // ...  
  11.      }  
  12.  }; 

在這個例子中,getName是一個公有函數(shù),是API的一部分,_getFirst,_getLast本意是私有的。雖然仍然是公有函數(shù),但hi加上了這個前綴,表示在以后的版本中不保證能運行,所以不應(yīng)該被直接使用。注意在JSLint中不推薦這樣做,除非你設(shè)置nomen選項為false。

還有其他幾種表示私有成員的規(guī)范:

◆在末尾使用下劃線,比如name_以及getElements_

◆使用一個下劃線表示保護(hù)成員_protected,兩個下劃線表示私有成員__private

◆在firefox中,有些不是語言原生的變量,以兩個下劃線開始,兩個下劃線結(jié)束__proto__以及__parent__

寫注釋

必須給你的代碼寫注釋,就算它看起來不會被別人接手。有時候,你研究完一個問題,然后你看著代碼覺得那是顯而易見的,但是過一兩周之后回頭再看,你也會摸不著頭腦的。

當(dāng)然,也不能過分的注釋:每個變量每一行代碼都注釋。但是通常都需要對函數(shù)的功能,參數(shù),返回值寫文檔,以及一些其他的復(fù)雜的邏輯和算法。想想,你的代碼的閱讀者,只需要讀注釋就能大體上了解你的代碼在做什么需要什么,這比直接讀代碼理解要快的多。當(dāng)你有五六行的代碼是做一個具體的任務(wù),那么閱讀者就可以通過一行代碼了解你的目的,然后跳過這些代碼。關(guān)于注釋,沒有硬性的比例說是多少代碼需要多少注釋。有時候,有些代碼(比如正則表達(dá)式)注釋的內(nèi)容肯定比代碼本身多。

寫注釋是必須遵守的規(guī)范,而且要保持注釋的更新,一個過時的注釋帶給人的迷惑還不如不寫注釋。

原文鏈接:http://www.cnblogs.com/beiyu/archive/2011/03/03/essential-javascript.html

【編輯推薦】

  1. 通過JavaScript或PHP檢測Android設(shè)備
  2. 深入理解JavaScript的閉包特性
  3. JavaScript跨域總結(jié)與解決辦法
  4. 黑客調(diào)查:最流行JavaScript庫是什么?
  5. JavaScript版幾種常見排序算法分享

分享文章:如何編寫高質(zhì)量的JavaScript代碼
文章源于:http://www.5511xx.com/article/cdcjcho.html