在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ 編寫高質(zhì)量 JavaScript 代碼的基本要點(diǎn)
代碼復(fù)用模式(避免篇)
S.O.L.I.D 五大原則之接口隔離原則 ISP
設(shè)計(jì)模式之狀態(tài)模式
JavaScript 核心(晉級(jí)高手必讀篇)
設(shè)計(jì)模式之建造者模式
JavaScript 與 DOM(上)——也適用于新手
設(shè)計(jì)模式之中介者模式
設(shè)計(jì)模式之裝飾者模式
設(shè)計(jì)模式之模板方法
設(shè)計(jì)模式之外觀模式
強(qiáng)大的原型和原型鏈
設(shè)計(jì)模式之構(gòu)造函數(shù)模式
揭秘命名函數(shù)表達(dá)式
深入理解J avaScript 系列(結(jié)局篇)
執(zhí)行上下文(Execution Contexts)
函數(shù)(Functions)
《你真懂 JavaScript 嗎?》答案詳解
設(shè)計(jì)模式之適配器模式
設(shè)計(jì)模式之組合模式
設(shè)計(jì)模式之命令模式
S.O.L.I.D 五大原則之單一職責(zé) SRP
編寫高質(zhì)量 JavaScript 代碼的基本要點(diǎn)
求值策略
閉包(Closures)
對(duì)象創(chuàng)建模式(上篇)
This? Yes,this!
設(shè)計(jì)模式之代理模式
變量對(duì)象(Variable Object)
S.O.L.I.D 五大原則之里氏替換原則 LSP
面向?qū)ο缶幊讨话憷碚?/span>
設(shè)計(jì)模式之單例模式
Function 模式(上篇)
S.O.L.I.D 五大原則之依賴倒置原則 DIP
設(shè)計(jì)模式之迭代器模式
立即調(diào)用的函數(shù)表達(dá)式
設(shè)計(jì)模式之享元模式
設(shè)計(jì)模式之原型模式
根本沒(méi)有“JSON 對(duì)象”這回事!
JavaScript 與 DOM(下)
面向?qū)ο缶幊讨?ECMAScript 實(shí)現(xiàn)
全面解析 Module 模式
對(duì)象創(chuàng)建模式(下篇)
設(shè)計(jì)模式之職責(zé)鏈模式
S.O.L.I.D 五大原則之開閉原則 OCP
設(shè)計(jì)模式之橋接模式
設(shè)計(jì)模式之策略模式
設(shè)計(jì)模式之觀察者模式
代碼復(fù)用模式(推薦篇)
作用域鏈(Scope Chain)
Function 模式(下篇)
設(shè)計(jì)模式之工廠模式

編寫高質(zhì)量 JavaScript 代碼的基本要點(diǎn)

才華橫溢的 Stoyan Stefanov,在他寫的由 O’Reilly 初版的新書《JavaScript Patterns》(JavaScript 模式)中,我想要是為我們的讀者貢獻(xiàn)其摘要,那會(huì)是件很美妙的事情。具體一點(diǎn)就是編寫高質(zhì)量 JavaScript 的一些要素,例如避免全局變量,使用單變量聲明,在循環(huán)中預(yù)緩存 length(長(zhǎng)度),遵循代碼閱讀,以及更多。

此摘要也包括一些與代碼不太相關(guān)的習(xí)慣,但對(duì)整體代碼的創(chuàng)建息息相關(guān),包括撰寫 API 文檔、執(zhí)行同行評(píng)審以及運(yùn)行 JSLint。這些習(xí)慣和最佳做法可以幫助你寫出更好的,更易于理解和維護(hù)的代碼,這些代碼在幾個(gè)月或是幾年之后再回過(guò)頭看看也是會(huì)覺(jué)得很自豪的。

書寫可維護(hù)的代碼(Writing Maintainable Code )

軟件 bug 的修復(fù)是昂貴的,并且隨著時(shí)間的推移,這些 bug 的成本也會(huì)增加,尤其當(dāng)這些 bug 潛伏并慢慢出現(xiàn)在已經(jīng)發(fā)布的軟件中時(shí)。當(dāng)你發(fā)現(xiàn) bug 的時(shí)候就立即修復(fù)它是最好的,此時(shí)你代碼要解決的問(wèn)題在你腦中還是很清晰的。否則,你轉(zhuǎn)移到其他任務(wù),忘了那個(gè)特定的代碼,一段時(shí)間后再去查看這些代碼就 需要:

  • 花時(shí)間學(xué)習(xí)和理解這個(gè)問(wèn)題
  • 花時(shí)間是了解應(yīng)該解決的問(wèn)題代碼

還有問(wèn)題,特別對(duì)于大的項(xiàng)目或是公司,修復(fù) bug 的這位伙計(jì)不是寫代碼的那個(gè)人(且發(fā)現(xiàn) bug 和修復(fù) bug 的不是同一個(gè)人)。因此,必須降低理解代碼花費(fèi)的時(shí)間,無(wú)論是一段時(shí)間前你自己寫的代碼還是團(tuán)隊(duì)中的其他成員寫的代碼。這關(guān)系到底線(營(yíng)業(yè)收入)和開發(fā)人員的幸福,因?yàn)槲覀兏鼞?yīng)該去開發(fā)新的激動(dòng) 人心的事物而不是花幾小時(shí)幾天的時(shí)間去維護(hù)遺留代碼。

另一個(gè)相關(guān)軟件開發(fā)生命的事實(shí)是,讀代碼花費(fèi)的時(shí)間要比寫來(lái)得多。有時(shí)候,當(dāng)你專注并深入思考某個(gè)問(wèn)題的時(shí)候,你可以坐下來(lái),一個(gè)下午寫大量的代碼。

你的代碼很能很快就工作了,但是,隨著應(yīng)用的成熟,還會(huì)有很多其他的事情發(fā)生,這就要求你的進(jìn)行進(jìn)行審查,修改,和調(diào)整。例如:

  • bug 是暴露的
  • 新功能被添加到應(yīng)用程序
  • 程序在新的環(huán)境下工作(例如,市場(chǎng)上出現(xiàn)新想瀏覽器)
  • 代碼改變用途
  • 代碼得完全從頭重新,或移植到另一個(gè)架構(gòu)上或者甚至使用另一種語(yǔ)言

由于這些變化,很少人力數(shù)小時(shí)寫的代碼最終演變成花數(shù)周來(lái)閱讀這些代碼。這就是為什么創(chuàng)建可維護(hù)的代碼對(duì)應(yīng)用程序的成功至關(guān)重要。

可維護(hù)的代碼意味著:

  • 可讀的
  • 一致的
  • 可預(yù)測(cè)的
  • 看上去就像是同一個(gè)人寫的
  • 已記錄

最小全局變量(Minimizing Globals)

JavaScript 通過(guò)函數(shù)管理作用域。在函數(shù)內(nèi)部聲明的變量只在這個(gè)函數(shù)內(nèi)部,函數(shù)外面不可用。另一方面,全局變量就是在任何函數(shù)外面聲明的或是未聲明直接簡(jiǎn)單使用的。

每個(gè) JavaScript 環(huán)境有一個(gè)全局對(duì)象,當(dāng)你在任意的函數(shù)外面使用 this 的時(shí)候可以訪問(wèn)到。你創(chuàng)建的每一個(gè)全部變量都成了這個(gè)全局對(duì)象的屬 性。在瀏覽器中,方便起見,該全局對(duì)象有個(gè)附加屬性叫做 window,此 window(通常)指向該全局對(duì)象本身。下面的代碼片段顯示了如何在瀏覽器環(huán)境 中創(chuàng)建和訪問(wèn)的全局變量:

myglobal = "hello"; // 不推薦寫法
console.log(myglobal); // "hello"
console.log(window.myglobal); // "hello"
console.log(window["myglobal"]); // "hello"
console.log(this.myglobal); // "hello"

全局變量的問(wèn)題

全局變量的問(wèn)題在于,你的 JavaScript 應(yīng)用程序和 web 頁(yè)面上的所有代碼都共享了這些全局變量,他們住在同一個(gè)全局命名空間,所以當(dāng)程序的兩個(gè)不同部分定義同名但不同作用的全局變量的時(shí)候,命名沖突在所難免。

web 頁(yè)面包含不是該頁(yè)面開發(fā)者所寫的代碼也是比較常見的,例如:

  • 第三方的 JavaScript 庫(kù)
  • 廣告方的腳本代碼
  • 第三方用戶跟蹤和分析腳本代碼
  • 不同類型的小組件,標(biāo)志和按鈕

比方說(shuō),該第三方腳本定義了一個(gè)全局變量,叫做 result;接著,在你的函數(shù)中也定義一個(gè)名為 result 的全局變量。其結(jié)果就是后面的變量覆蓋前面的,第三方腳本就一下子嗝屁啦!

因此,要想和其他腳本成為好鄰居的話,盡可能少的使用全局變量是很重要的。在書中后面提到的一些減少全局變量的策略,例如命名空間模式或是函數(shù)立即自動(dòng)執(zhí)行,但是要想讓全局變量少最重要的還是始終使用 var 來(lái)聲明變量。

由于 JavaScript 的兩個(gè)特征,不自覺(jué)地創(chuàng)建出全局變量是出乎意料的容易。首先,你可以甚至不需要聲明就可以使用變量;第二,JavaScrip t有隱含的全局概念,意味著你不聲明的任何變量都會(huì)成為一個(gè)全局對(duì)象屬性。參考下面的代碼:

function sum(x, y) {
   // 不推薦寫法: 隱式全局變量 
   result = x + y;
   return result;
}

此段代碼中的 result 沒(méi)有聲明。代碼照樣運(yùn)作正常,但在調(diào)用函數(shù)后你最后的結(jié)果就多一個(gè)全局命名空間,這可以是一個(gè)問(wèn)題的根源。

經(jīng)驗(yàn)法則是始終使用 var 聲明變量,正如改進(jìn)版的 sum()函數(shù)所演示的:

function sum(x, y) {
   var result = x + y;
   return result;
}

另一個(gè)創(chuàng)建隱式全局變量的反例就是使用任務(wù)鏈進(jìn)行部分 var 聲明。下面的片段中,a 是本地變量但是 b 確實(shí)全局變量,這可能不是你希望發(fā)生的:

// 反例,勿使用 
function foo() {
   var a = b = 0;
   // ...
}

此現(xiàn)象發(fā)生的原因在于這個(gè)從右到左的賦值,首先,是賦值表達(dá)式 b = 0,此情況下 b 是未聲明的。這個(gè)表達(dá)式的返回值是 0,然后這個(gè) 0 就分配給了通過(guò) var 定義的這個(gè)局部變量 a。換句話說(shuō),就好比你輸入了:

var a = (b = 0);

如果你已經(jīng)準(zhǔn)備好聲明變量,使用鏈分配是比較好的做法,不會(huì)產(chǎn)生任何意料之外的全局變量,如:

function foo() {
   var a, b;
   // ... a = b = 0; // 兩個(gè)均局部變量
}

然而,另外一個(gè)避免全局變量的原因是可移植性。如果你想你的代碼在不同的環(huán)境下(主機(jī)下)運(yùn)行,使用全局變量如履薄冰,因?yàn)槟銜?huì)無(wú)意中覆蓋你最初環(huán)境下不存在的主機(jī)對(duì)象(所以你原以為名稱可以放心大膽地使用,實(shí)際上對(duì)于有些情況并不適用)。

忘記 var 的副作用(Side Effects When Forgetting var)

隱式全局變量和明確定義的全局變量間有些小的差異,就是通過(guò) delete 操作符讓變量未定義的能力。

  • 通過(guò) var 創(chuàng)建的全局變量(任何函數(shù)之外的程序中創(chuàng)建)是不能被刪除的。
  • 無(wú)var創(chuàng)建的隱式全局變量(無(wú)視是否在函數(shù)中創(chuàng)建)是能被刪除的。

這表明,在技術(shù)上,隱式全局變量并不是真正的全局變量,但它們是全局對(duì)象的屬性。屬性是可以通過(guò) delete 操作符刪除的,而變量是不能的:

// 定義三個(gè)全局變量
var global_var = 1;
global_novar = 2; // 反面教材
(function () {
   global_fromfunc = 3; // 反面教材
}());
// 試圖刪除
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true
// 測(cè)試該刪除
typeof global_var; // "number"
typeof global_novar; // "undefined"
typeof global_fromfunc; // "undefined"

在 ES5 嚴(yán)格模式下,未聲明的變量(如在前面的代碼片段中的兩個(gè)反面教材)工作時(shí)會(huì)拋出一個(gè)錯(cuò)誤。

訪問(wèn)全局對(duì)象(Access to the Global Object)

在瀏覽器中,全局對(duì)象可以通過(guò) window 屬性在代碼的任何位置訪問(wèn)(除非你做了些比較出格的事情,像是聲明了一個(gè)名為 window 的局部變量)。但是在其他環(huán)境下,這個(gè)方便的屬性可能被叫做其他什么東西(甚至在程序中不可用)。如果你需要在沒(méi)有硬編碼的 window 標(biāo)識(shí)符下訪問(wèn)全局對(duì)象,你可以在任何層級(jí)的函數(shù)作用域中做如下操作:

var global = (function () {
   return this;
}());

這種方法可以隨時(shí)獲得全局對(duì)象,因?yàn)槠湓诤瘮?shù)中被當(dāng)做函數(shù)調(diào)用了(不是通過(guò) new 構(gòu)造),this 總 是指向全局對(duì)象。實(shí)際上這個(gè)病不適用于 ECMAScript 5 嚴(yán)格模式,所以,在嚴(yán)格模式下時(shí),你必須采取不同的形式。例如,你正在開發(fā)一個(gè) JavaScript 庫(kù),你可以將你的代碼包裹在一個(gè)即時(shí)函數(shù)中,然后從 全局作用域中,傳遞一個(gè)引用指向 this 作為你即時(shí)函數(shù)的參數(shù)。

單 var 形式(Single var Pattern)

在函數(shù)頂部使用單 var 語(yǔ)句是比較有用的一種形式,其好處在于:

  • 提供了一個(gè)單一的地方去尋找功能所需要的所有局部變量
  • 防止變量在定義之前使用的邏輯錯(cuò)誤
  • 幫助你記住聲明的全局變量,因此較少了全局變量//zxx:此處我自己是有點(diǎn)暈乎的…
  • 少代碼(類型啊傳值啊單線完成)

單 var 形式長(zhǎng)得就像下面這個(gè)樣子:

function func() {
   var a = 1,
       b = 2,
       sum = a + b,
       myobject = {},
       i,
       j;
   // function body...
}

您可以使用一個(gè) var 語(yǔ)句聲明多個(gè)變量,并以逗號(hào)分隔。像這種初始化變量同時(shí)初始化值的做法是很好的。這樣子可以防止邏輯錯(cuò)誤(所有未初始化但聲明的變量的初始值是 undefined)和增加代碼的可讀性。在你看到代碼后,你可以根據(jù)初始化的值知道這些變量大致的用途,例如是要當(dāng)作對(duì)象呢還是當(dāng)作整數(shù)來(lái)使。

你也可以在聲明的時(shí)候做一些實(shí)際的工作,例如前面代碼中的 sum = a + b 這個(gè)情況,另外一個(gè)例子就是當(dāng)你使用 DOM(文檔對(duì)象模型)引用時(shí),你可以使用單一的 var 把 DOM 引用一起指定為局部變量,就如下面代碼所示的:

function updateElement() {
   var el = document.getElementById("result"),
       style = el.style;
   // 使用el和style干點(diǎn)其他什么事...
}

預(yù)解析:var散布的問(wèn)題(Hoisting: A Problem with Scattered vars)

JavaScript 中,你可以在函數(shù)的任何位置聲明多個(gè) var 語(yǔ)句,并且它們就好像是在函數(shù)頂部聲明一樣發(fā)揮作用,這種行為稱為 hoisting(懸置/置頂解析/預(yù)解析)。當(dāng)你使用了一個(gè)變量,然后不久在函數(shù)中又重新聲明的話,就可能產(chǎn)生邏輯錯(cuò)誤。對(duì)于 JavaScript,只 要你的變量是在同一個(gè)作用域中(同一函數(shù)),它都被當(dāng)做是聲明的,即使是它在 var 聲明前使用的時(shí)候。看下面這個(gè)例子:

// 反例
myname = "global"; // 全局變量
function func() {
    alert(myname); // "undefined"
    var myname = "local";
    alert(myname); // "local"
}
func();

在這個(gè)例子中,你可能會(huì)以為第一個(gè) alert 彈出的是”global”,第二個(gè)彈出”loacl”。這種期許是可以理解的,因?yàn)樵诘谝粋€(gè) alert 的時(shí)候,myname 未聲明,此時(shí)函數(shù)肯定很自然而然地看全局變量 myname,但是,實(shí)際上并不是這么工作的。第一個(gè) alert 會(huì)彈 出”undefined”是因?yàn)?myname 被當(dāng)做了函數(shù)的局部變量(盡管是之后聲明的),所有的變量聲明當(dāng)被懸置到函數(shù)的頂部了。因此,為了避免這種混 亂,最好是預(yù)先聲明你想使用的全部變量。

上面的代碼片段執(zhí)行的行為可能就像下面這樣:

myname = "global"; // global variable
function func() {
   var myname; // 等同于 -> var myname = undefined;
   alert(myname); // "undefined"
   myname = "local";
   alert(myname); // "local"}
func();

為了完整,我們?cè)偬嵋惶釄?zhí)行層面的稍微復(fù)雜點(diǎn)的東西。代碼處理分兩個(gè)階段,第一階段是變量,函數(shù)聲明,以及正常格式的參數(shù)創(chuàng)建,這是一個(gè)解析和進(jìn)入上下文 的階段。第二個(gè)階段是代碼執(zhí)行,函數(shù)表達(dá)式和不合格的標(biāo)識(shí)符(為聲明的變量)被創(chuàng)建。但是,出于實(shí)用的目的,我們就采用了“hoisting”這個(gè)概念, 這種 ECMAScript 標(biāo)準(zhǔn)中并未定義,通常用來(lái)描述行為。

for 循環(huán)(for Loops)

在 for 循環(huán)中,你可以循環(huán)取得數(shù)組或是數(shù)組類似對(duì)象的值,譬如 arguments 和 HTMLCollection 對(duì)象。通常的循環(huán)形式如下:

// 次佳的循環(huán)
for (var i = 0; i < myarray.length; i++) {
   // 使用myarray[i]做點(diǎn)什么
}

這種形式的循環(huán)的不足在于每次循環(huán)的時(shí)候數(shù)組的長(zhǎng)度都要去獲取下。這回降低你的代碼,尤其當(dāng) myarray 不是數(shù)組,而是一個(gè) HTMLCollection 對(duì)象的時(shí)候。

HTMLCollections 指的是 DOM 方法返回的對(duì)象,例如:

document.getElementsByName()
document.getElementsByClassName()
document.getElementsByTagName()

還有其他一些 HTMLCollections,這些是在 DOM 標(biāo)準(zhǔn)之前引進(jìn)并且現(xiàn)在還在使用的。有:

document.images: 頁(yè)面上所有的圖片元素
document.links : 所有a標(biāo)簽元素
document.forms : 所有表單
document.forms[0].elements : 頁(yè)面上第一個(gè)表單中的所有域

集合的麻煩在于它們實(shí)時(shí)查詢基本文檔(HTML 頁(yè)面)。這意味著每次你訪問(wèn)任何集合的長(zhǎng)度,你要實(shí)時(shí)查詢 DOM,而 DOM 操作一般都是比較昂貴的。

這就是為什么當(dāng)你循環(huán)獲取值時(shí),緩存數(shù)組(或集合)的長(zhǎng)度是比較好的形式,正如下面代碼顯示的:

for (var i = 0, max = myarray.length; i < max; i++) {
   // 使用myarray[i]做點(diǎn)什么
}

這樣,在這個(gè)循環(huán)過(guò)程中,你只檢索了一次長(zhǎng)度值。

在所有瀏覽器下,循環(huán)獲取內(nèi)容時(shí)緩存 HTMLCollection s 的長(zhǎng)度是更快的,2 倍(Safari3)到 190 倍(IE7)之間。//zxx:此數(shù)據(jù)貌似很老,僅供參考

注意到,當(dāng)你明確想要修改循環(huán)中的集合的時(shí)候(例如,添加更多的 DOM 元素),你可能更喜歡長(zhǎng)度更新而不是常量。

伴隨著單 var 形式,你可以把變量從循環(huán)中提出來(lái),就像下面這樣:

function looper() {
   var i = 0,
        max,
        myarray = [];
   // ...
   for (i = 0, max = myarray.length; i < max; i++) {
      // 使用myarray[i]做點(diǎn)什么
   }
}

這種形式具有一致性的好處,因?yàn)槟銏?jiān)持了單一 var 形式。不足在于當(dāng)重構(gòu)代碼的時(shí)候,復(fù)制和粘貼整個(gè)循環(huán)有點(diǎn)困難。例如,你從一個(gè)函數(shù)復(fù)制了一個(gè)循環(huán)到另一個(gè)函數(shù),你不得不去確定你能夠把 i 和 max 引入新的函數(shù)(如果在這里沒(méi)有用的話,很有可能你要從原函數(shù)中把它們刪掉)。

最后一個(gè)需要對(duì)循環(huán)進(jìn)行調(diào)整的是使用下面表達(dá)式之一來(lái)替換 i++。

i = i + 1
i += 1

JSLint 提示您這樣做,原因是++和–-促進(jìn)了“過(guò)分棘手(excessive trickiness)”。//zxx:這里比較難翻譯,我想本意應(yīng)該是讓代碼變得更加的棘手

如果你直接無(wú)視它,JSLint 的 plusplus 選項(xiàng)會(huì)是 false(默認(rèn)是 default)。

還有兩種變化的形式,其又有了些微改進(jìn),因?yàn)椋?/p>

  • 少了一個(gè)變量(無(wú) max)
  • 向下數(shù)到 0,通常更快,因?yàn)楹?0 做比較要比和數(shù)組長(zhǎng)度或是其他不是 0 的東西作比較更有效率
//第一種變化的形式:
var i, myarray = [];
for (i = myarray.length; i–-;) {
   // 使用myarray[i]做點(diǎn)什么
}
//第二種使用while循環(huán):
var myarray = [],
    i = myarray.length;
while (i–-) {
// 使用myarray[i]做點(diǎn)什么
}

這些小的改進(jìn)只體現(xiàn)在性能上,此外 JSLint 會(huì)對(duì)使用 i–-加以抱怨。

for-in 循環(huán)(for-in Loops)

for-in 循環(huán)應(yīng)該用在非數(shù)組對(duì)象的遍歷上,使用 for-in 進(jìn)行循環(huán)也被稱為“枚舉”。

從技術(shù)上將,你可以使用 for-in 循環(huán)數(shù)組(因?yàn)?JavaScript 中數(shù)組也是對(duì)象),但這是不推薦的。因?yàn)槿绻麛?shù)組對(duì)象已被自定義的功能增強(qiáng),就可能發(fā)生邏輯錯(cuò)誤。另外,在 for-in 中,屬性列表的順序(序列)是不能保證的。所以最好數(shù)組使用正常的 for 循環(huán),對(duì)象使用 for-in 循環(huán)。

有個(gè)很重要的 hasOwnProperty()方法,當(dāng)遍歷對(duì)象屬性的時(shí)候可以過(guò)濾掉從原型鏈上下來(lái)的屬性。

思考下面一段代碼:

// 對(duì)象
var man = {
   hands: 2,
   legs: 2,
   heads: 1
};
// 在代碼的某個(gè)地方
// 一個(gè)方法添加給了所有對(duì)象
if (typeof Object.prototype.clone === "undefined") {
   Object.prototype.clone = function () {};
}

在這個(gè)例子中,我們有一個(gè)使用對(duì)象字面量定義的名叫 man 的對(duì)象。在 man 定義完成后的某個(gè)地方,在對(duì)象原型上增加了一個(gè)很有用的名叫 clone()的方法。此原型鏈?zhǔn)菍?shí)時(shí)的,這就意味著所有的對(duì)象自動(dòng)可以訪問(wèn)新的方法。為了避免枚舉 man 的時(shí)候出現(xiàn) clone()方法,你需要應(yīng)用 hasOwnProperty()方法過(guò)濾原型屬性。如果不做過(guò)濾,會(huì)導(dǎo)致 clone()函數(shù)顯示出來(lái),在大多數(shù)情況下這是不希望出現(xiàn)的。

// 1.
// for-in 循環(huán)
for (var i in man) {
   if (man.hasOwnProperty(i)) { // 過(guò)濾
      console.log(i, ":", man[i]);
   }
}
/* 控制臺(tái)顯示結(jié)果
hands : 2
legs : 2
heads : 1
*/
// 2.
// 反面例子:
// for-in loop without checking hasOwnProperty()
for (var i in man) {
   console.log(i, ":", man[i]);
}
/*
控制臺(tái)顯示結(jié)果
hands : 2
legs : 2
heads : 1
clone: function()
*/

另外一種使用 hasOwnProperty()的形式是取消 Object.prototype 上的方法。像是:

for (var i in man) {
   if (Object.prototype.hasOwnProperty.call(man, i)) { // 過(guò)濾
      console.log(i, ":", man[i]);
   }
}

其好處在于在 man 對(duì)象重新定義 hasOwnProperty 情況下避免命名沖突。也避免了長(zhǎng)屬性查找對(duì)象的所有方法,你可以使用局部變量“緩存”它。

var i, hasOwn = Object.prototype.hasOwnProperty;
for (i in man) {
    if (hasOwn.call(man, i)) { // 過(guò)濾
        console.log(i, ":", man[i]);
    }
}

嚴(yán)格來(lái)說(shuō),不使用 hasOwnProperty()并不是一個(gè)錯(cuò)誤。根據(jù)任務(wù)以及你對(duì)代碼的自信程度,你可以跳過(guò)它以提高些許的循環(huán)速度。但是當(dāng)你對(duì)當(dāng)前對(duì)象內(nèi)容(和其原型鏈)不確定的時(shí)候,添加 hasOwnProperty()更加保險(xiǎn)些。

格式化的變化(通不過(guò) JSLint)會(huì)直接忽略掉花括號(hào),把 if 語(yǔ)句放到同一行上。其優(yōu)點(diǎn)在于循環(huán)語(yǔ)句讀起來(lái)就像一個(gè)完整的想法(每個(gè)元素都有一個(gè)自己的屬性”X”,使用”X”干點(diǎn)什么):

// 警告: 通不過(guò)JSLint檢測(cè)
var i, hasOwn = Object.prototype.hasOwnProperty;
for (i in man) if (hasOwn.call(man, i)) { // 過(guò)濾
    console.log(i, ":", man[i]);
}

(不)擴(kuò)展內(nèi)置原型((Not) Augmenting Built-in Prototypes)

擴(kuò)增構(gòu)造函數(shù)的 prototype 屬性是個(gè)很強(qiáng)大的增加功能的方法,但有時(shí)候它太強(qiáng)大了。

增加內(nèi)置的構(gòu)造函數(shù)原型(如 Object(), Array(),,或Function())挺誘人的,但是這嚴(yán)重降低了可維護(hù)性,因?yàn)樗屇愕拇a變得難以預(yù)測(cè)。使用你代碼的其他開發(fā)人員很可能更期望使用內(nèi)置的 JavaScript 方法來(lái)持續(xù)不斷地工作,而不是你另加的方法。

另外,屬性添加到原型中,可能會(huì)導(dǎo)致不使用 hasOwnProperty 屬性時(shí)在循環(huán)中顯示出來(lái),這會(huì)造成混亂。

因此,不增加內(nèi)置原型是最好的。你可以指定一個(gè)規(guī)則,僅當(dāng)下面的條件均滿足時(shí)例外:

  • 可以預(yù)期將來(lái)的 ECMAScript 版本或是 JavaScript 實(shí)現(xiàn)將一直將此功能當(dāng)作內(nèi)置方法來(lái)實(shí)現(xiàn)。例如,你可以添加 ECMAScript 5 中描述的方法,一直到各個(gè)瀏覽器都迎頭趕上。這種情況下,你只是提前定義了有用的方法。
  • 如果您檢查您的自定義屬性或方法已不存在——也許已經(jīng)在代碼的其他地方實(shí)現(xiàn)或已經(jīng)是你支持的瀏覽器 JavaScript 引擎部分。
  • 你清楚地文檔記錄并和團(tuán)隊(duì)交流了變化。

如果這三個(gè)條件得到滿足,你可以給原型進(jìn)行自定義的添加,形式如下:

if (typeof Object.protoype.myMethod !== "function") {
   Object.protoype.myMethod = function () {
      // 實(shí)現(xiàn)...
   };
}

switch 模式(switch Pattern)

你可以通過(guò)類似下面形式的 switch 語(yǔ)句增強(qiáng)可讀性和健壯性:

var inspect_me = 0,
    result = '';
switch (inspect_me) {
case 0:
   result = "zero";
   break;
case 1:
   result = "one";
   break;
default:
   result = "unknown";
}

這個(gè)簡(jiǎn)單的例子中所遵循的風(fēng)格約定如下:

  • 每個(gè) case 和 switch 對(duì)齊(花括號(hào)縮進(jìn)規(guī)則除外)
  • 每個(gè) case 中代碼縮進(jìn)
  • 每個(gè) case 以 break 清除結(jié)束
  • 避免貫穿(故意忽略 break)。如果你非常確信貫穿是最好的方法,務(wù)必記錄此情況,因?yàn)閷?duì)于有些閱讀人而言,它們可能看起來(lái)是錯(cuò)誤的。
  • 以 default 結(jié)束 switch:確??傆薪∪慕Y(jié)果,即使無(wú)情況匹配。

避免隱式類型轉(zhuǎn)換(Avoiding Implied Typecasting

JavaScript 的變量在比較的時(shí)候會(huì)隱式類型轉(zhuǎn)換。這就是為什么一些諸如:false == 0 或 “” == 0 返回的結(jié)果是 true。為避免引起混亂的隱含類型轉(zhuǎn)換,在你比較值和表達(dá)式類型的時(shí)候始終使用===和!==操作符。

var zero = 0;
if (zero === false) {
   // 不執(zhí)行,因?yàn)閦ero為0, 而不是false
}
// 反面示例
if (zero == false) {
   // 執(zhí)行了...
}

還有另外一種思想觀點(diǎn)認(rèn)為==就足夠了===是多余的。例如,當(dāng)你使用 typeof 你就知道它會(huì)返回一個(gè)字符串,所以沒(méi)有使用嚴(yán)格相等的理由。然而,JSLint 要求嚴(yán)格相等,它使代碼看上去更有一致性,可以降低代碼閱讀時(shí)的精力消耗。(“==是故意的還是一個(gè)疏漏?”)

避免(Avoiding) eval()

如果你現(xiàn)在的代碼中使用了 eval(),記住該咒語(yǔ)“eval()是魔鬼”。此方法接受任意的字符串,并當(dāng)作 JavaScript 代碼來(lái)處理。當(dāng)有 問(wèn)題的代碼是事先知道的(不是運(yùn)行時(shí)確定的),沒(méi)有理由使用 eval()。如果代碼是在運(yùn)行時(shí)動(dòng)態(tài)生成,有一個(gè)更好的方式不使用 eval 而達(dá)到同樣的目標(biāo)。例如,用方括號(hào)表示法來(lái)訪問(wèn)動(dòng)態(tài)屬性會(huì)更好更簡(jiǎn)單:

// 反面示例
var property = "name";
alert(eval("obj." + property));
// 更好的
var property = "name";
alert(obj[property]);

使用 eval()也帶來(lái)了安全隱患,因?yàn)楸粓?zhí)行的代碼(例如從網(wǎng)絡(luò)來(lái))可能已被篡改。這是個(gè)很常見的反面教材,當(dāng)處理 Ajax 請(qǐng)求得到的 JSON 相應(yīng)的時(shí)候。在這些情況下,最好使用 JavaScript 內(nèi)置方法來(lái)解析 JSON 相應(yīng),以確保安全和有效。若瀏覽器不支持 JSON.parse(),你可 以使用來(lái)自 JSON.org的庫(kù)。

同樣重要的是要記住,給 setInterval(), setTimeout()和 Function()構(gòu)造函數(shù)傳遞字符串,大部分情況下,與使用 eval()是類似的,因此要避免。在幕后,JavaScrip t仍需要評(píng)估和執(zhí)行你給程序傳遞的字符串:

// 反面示例
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);
// 更好的
setTimeout(myFunc, 1000);
setTimeout(function () {
   myFunc(1, 2, 3);
}, 1000);

使用新的 Function()構(gòu)造就類似于 eval(),應(yīng)小心接近。這可能是一個(gè)強(qiáng)大的構(gòu)造,但往往被誤用。如果你絕對(duì)必須使用 eval(),你 可以考慮使用 new Function()代替。有一個(gè)小的潛在好處,因?yàn)樵谛?Function()中作代碼評(píng)估是在局部函數(shù)作用域中運(yùn)行,所以代碼中任何被評(píng)估的通過(guò) var 定義的變量都不會(huì)自動(dòng)變成全局變量。另一種方法來(lái)阻止自動(dòng)全局變量是封裝 eval()調(diào)用到一個(gè)即時(shí)函數(shù)中。

考慮下面這個(gè)例子,這里僅 un 作為全局變量污染了命名空間。

console.log(typeof un);    // "undefined"
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"
var jsstring = "var un = 1; console.log(un);";
eval(jsstring); // logs "1"
jsstring = "var deux = 2; console.log(deux);";
new Function(jsstring)(); // logs "2"
jsstring = "var trois = 3; console.log(trois);";
(function () {
   eval(jsstring);
}()); // logs "3"
console.log(typeof un); // number
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"

另一間 eval()和 Function 構(gòu)造不同的是 eval()可以干擾作用域鏈,而Function()更安分守己些。不管你在哪里執(zhí)行 Function(),它只看到全局作用域。所以其能很好的避免本地變量污染。在下面這個(gè)例子中,eval()可以訪問(wèn)和修改它外部作用域中的變量,這是 Function做不來(lái)的(注意到使用 Function 和 new Function 是相同的)。

(function () {
   var local = 1;
   eval("local = 3; console.log(local)"); // logs "3"
   console.log(local); // logs "3"
}());
(function () {
   var local = 1;
   Function("console.log(typeof local);")(); // logs undefined
}());

parseInt()下的數(shù)值轉(zhuǎn)換(Number Conversions with parseInt())

使用 parseInt()你可以從字符串中獲取數(shù)值,該方法接受另一個(gè)基數(shù)參數(shù),這經(jīng)常省略,但不應(yīng)該。當(dāng)字符串以”0″開頭的時(shí)候就有可能會(huì)出問(wèn) 題,例如,部分時(shí)間進(jìn)入表單域,在 ECMAScript 3 中,開頭為”0″的字符串被當(dāng)做8進(jìn)制處理了,但這已在 ECMAScript 5 中改變了。為了避免矛盾和意外的結(jié)果,總是指定基數(shù)參數(shù)。

var month = "06",
    year = "09";
month = parseInt(month, 10);
year = parseInt(year, 10);

此例中,如果你忽略了基數(shù)參數(shù),如 parseInt(year),返回的值將是 0,因?yàn)椤?9”被當(dāng)做 8 進(jìn)制(好比執(zhí)行 parseInt( year, 8 )),而 09 在 8 進(jìn)制中不是個(gè)有效數(shù)字。

替換方法是將字符串轉(zhuǎn)換成數(shù)字,包括:

+"08" // 結(jié)果是 8
Number("08") // 8

這些通??煊?parseInt(),因?yàn)?parseInt()方法,顧名思意,不是簡(jiǎn)單地解析與轉(zhuǎn)換。但是,如果你想輸入例如“08 hello”,parseInt()將返回?cái)?shù)字,而其它以 NaN 告終。

編碼規(guī)范(Coding Conventions)

建立和遵循編碼規(guī)范是很重要的,這讓你的代碼保持一致性,可預(yù)測(cè),更易于閱讀和理解。一個(gè)新的開發(fā)者加入這個(gè)團(tuán)隊(duì)可以通讀規(guī)范,理解其它團(tuán)隊(duì)成員書寫的代碼,更快上手干活。

許多激烈的爭(zhēng)論發(fā)生會(huì)議上或是郵件列表上,問(wèn)題往往針對(duì)某些代碼規(guī)范的特定方面(例如代碼縮進(jìn),是 Tab 制表符鍵還是 space 空格鍵)。如果你是 你組織中建議采用規(guī)范的,準(zhǔn)備好面對(duì)各種反對(duì)的或是聽起來(lái)不同但很強(qiáng)烈的觀點(diǎn)。要記住,建立和堅(jiān)定不移地遵循規(guī)范要比糾結(jié)于規(guī)范的細(xì)節(jié)重要的多。

縮進(jìn)(Indentation)

代碼沒(méi)有縮進(jìn)基本上就不能讀了。唯一糟糕的事情就是不一致的縮進(jìn),因?yàn)樗瓷先ハ袷亲裱艘?guī)范,但是可能一路上伴隨著混亂和驚奇。重要的是規(guī)范地使用縮進(jìn)。

一些開發(fā)人員更喜歡用 tab 制表符縮進(jìn),因?yàn)槿魏稳硕伎梢哉{(diào)整他們的編輯器以自己喜歡的空格數(shù)來(lái)顯示 Tab。有些人喜歡空格——通常四個(gè),這都無(wú)所謂,只要團(tuán)隊(duì)每個(gè)人都遵循同一個(gè)規(guī)范就好了。這本書,例如,使用四個(gè)空格縮進(jìn),這也是 JSLint 中默認(rèn)的縮進(jìn)。

什么應(yīng)該縮進(jìn)呢?規(guī)則很簡(jiǎn)單——花括號(hào)里面的東西。這就意味著函數(shù)體,循環(huán) (do,while,for, for-in),if,switch,以及對(duì)象字面量中的對(duì)象屬性。下面的代碼就是使用縮進(jìn)的示例:

function outer(a, b) {
    var c = 1,
        d = 2,
        inner;
    if (a > b) {
        inner = function () {
            return {
                r: c - d
            };
        };
    } else {
        inner = function () {
            return {
                r: c + d
            };
        };
    }
    return inner;
}

花括號(hào){}(Curly Braces)

花括號(hào)(亦稱大括號(hào),下同)應(yīng)總被使用,即使在它們?yōu)榭蛇x的時(shí)候。技術(shù)上將,在 in 或是 for 中如果語(yǔ)句僅一條,花括號(hào)是不需要的,但是你還是應(yīng)該總是使用它們,這會(huì)讓代碼更有持續(xù)性和易于更新。

想象下你有一個(gè)只有一條語(yǔ)句的 for 循環(huán),你可以忽略花括號(hào),而沒(méi)有解析的錯(cuò)誤。

// 糟糕的實(shí)例
for (var i = 0; i < 10; i += 1)
   alert(i);

但是,如果,后來(lái),主體循環(huán)部分又增加了行代碼?

// 糟糕的實(shí)例
for (var i = 0; i < 10; i += 1)
   alert(i);
   alert(i + " is " + (i % 2 ? "odd" : "even"));

第二個(gè) alert 已經(jīng)在循環(huán)之外,縮進(jìn)可能欺騙了你。為了長(zhǎng)遠(yuǎn)打算,最好總是使用花括號(hào),即時(shí)值一行代碼:

// 好的實(shí)例
for (var i = 0; i < 10; i += 1) {
   alert(i);
}

if條件類似:

// 壞
if (true)
   alert(1);
else
   alert(2);
// 好
if (true) {
   alert(1);
} else {
   alert(2);
}

左花括號(hào)的位置(Opening Brace Location)

開發(fā)人員對(duì)于左大括號(hào)的位置有著不同的偏好——在同一行或是下一行。

if (true) {
   alert("It's TRUE!");
}
//或
if (true)
{
   alert("It's TRUE!");
}

這個(gè)實(shí)例中,仁者見仁智者見智,但也有個(gè)案,括號(hào)位置不同會(huì)有不同的行為表現(xiàn)。這是因?yàn)榉痔?hào)插入機(jī)制(semicolon insertion mechanism)——JavaScript 是不挑剔的,當(dāng)你選擇不使用分號(hào)結(jié)束一行代碼時(shí) JavaScript 會(huì)自己幫你補(bǔ)上。這種行為可能會(huì)導(dǎo)致麻 煩,如當(dāng)你返回對(duì)象字面量,而左括號(hào)卻在下一行的時(shí)候:

// 警告: 意外的返回值
function func() {
   return
  // 下面代碼不執(zhí)行
   {
      name : "Batman"
   }
}

如果你希望函數(shù)返回一個(gè)含有 name 屬性的對(duì)象,你會(huì)驚訝。由于隱含分號(hào),函數(shù)返回 undefined。前面的代碼等價(jià)于:

// 警告: 意外的返回值
function func() {
   return undefined;
  // 下面代碼不執(zhí)行
   {
      name : "Batman"
   }
}

總之,總是使用花括號(hào),并始終把在與之前的語(yǔ)句放在同一行:

function func() {
   return {
      name : "Batman"
   };
}

關(guān)于分號(hào)注:就像使用花括號(hào),你應(yīng)該總是使用分號(hào),即使他們可由 JavaScript 解析器隱式創(chuàng)建。這不僅促進(jìn)更科學(xué)和更嚴(yán)格的代碼,而且有助于解決存有疑惑的地方,就如前面的例子顯示。

空格(White Space)

空格的使用同樣有助于改善代碼的可讀性和一致性。在寫英文句子的時(shí)候,在逗號(hào)和句號(hào)后面會(huì)使用間隔。在 JavaScript 中,你可以按照同樣的邏輯在列表模樣表達(dá)式(相當(dāng)于逗號(hào))和結(jié)束語(yǔ)句(相對(duì)于完成了“想法”)后面添加間隔。

適合使用空格的地方包括:

  • for循環(huán)分號(hào)分開后的的部分:如 for (var i = 0; i < 10; i += 1) {...};
  • for 循環(huán)中初始化的多變量(i 和 max):for (var i = 0, max = 10; i < max; i += 1) {...};
  • 分隔數(shù)組項(xiàng)的逗號(hào)的后面:var a = [1, 2, 3];
  • 對(duì)象屬性逗號(hào)的后面以及分隔屬性名和屬性值的冒號(hào)的后面:var o = {a: 1, b: 2};
  • 限定函數(shù)參數(shù):myFunc(a, b, c);
  • 函數(shù)聲明的花括號(hào)的前面:function myFunc() {};
  • 匿名函數(shù)表達(dá)式function的后面:var myFunc = function () {};

使用空格分開所有的操作符和操作對(duì)象是另一個(gè)不錯(cuò)的使用,這意味著在+,-,*,=,<,>,<=,>=,===,!==,&&,||,+=等前后都需要空格。

// 寬松一致的間距
// 使代碼更易讀
// 使得更加“透氣”
var d = 0,
    a = b + 1;
if (a && b && c) {
    d = a % c;
    a += d;
}
// 反面例子
// 缺失或間距不一
// 使代碼變得疑惑
var d = 0,
    a = b + 1;
if (a&&b&&c) {
    d=a % c;
    a+= d;
}

最后需要注意的一個(gè)空格——花括號(hào)間距。最好使用空格:

  • 函數(shù)、if-else 語(yǔ)句、循環(huán)、對(duì)象字面量的左花括號(hào)的前面({)
  • else 或 while 之間的右花括號(hào)(})

空格使用的一點(diǎn)不足就是增加了文件的大小,但是壓縮無(wú)此問(wèn)題。

有一個(gè)經(jīng)常被忽略的代碼可讀性方面是垂直空格的使用。你可以使用空行來(lái)分隔代碼單元,就像是文學(xué)作品中使用段落分隔一樣。

命名規(guī)范(Naming Conventions)

另一種方法讓你的代碼更具可預(yù)測(cè)性和可維護(hù)性是采用命名規(guī)范。這就意味著你需要用同一種形式給你的變量和函數(shù)命名。

下面是建議的一些命名規(guī)范,你可以原樣采用,也可以根據(jù)自己的喜好作調(diào)整。同樣,遵循規(guī)范要比規(guī)范是什么更重要。

以大寫字母寫構(gòu)造函數(shù)(Capitalizing Constructors)

JavaScript 并沒(méi)有類,但有 new 調(diào)用的構(gòu)造函數(shù):

var adam = new Person();  

因?yàn)闃?gòu)造函數(shù)仍僅僅是函數(shù),僅看函數(shù)名就可以幫助告訴你這應(yīng)該是一個(gè)構(gòu)造函數(shù)還是一個(gè)正常的函數(shù)。

命名構(gòu)造函數(shù)時(shí)首字母大寫具有暗示作用,使用小寫命名的函數(shù)和方法不應(yīng)該使用new調(diào)用:

function MyConstructor() {...}
function myFunction() {...}

分隔單詞(Separating Words)

當(dāng)你的變量或是函數(shù)名有多個(gè)單詞的時(shí)候,最好單詞的分離遵循統(tǒng)一的規(guī)范,有一個(gè)常見的做法被稱作“駝峰(Camel)命名法”,就是單詞小寫,每個(gè)單詞的首字母大寫。

對(duì)于構(gòu)造函數(shù),可以使用大駝峰式命名法(upper camel case),如MyConstructor()。對(duì)于函數(shù)和方法名稱,你可以使用小駝峰式命名法(lower camel case),像是 myFunction(), calculateArea()和 getFirstName()。

要是變量不是函數(shù)呢?開發(fā)者通常使用小駝峰式命名法,但還有另外一種做法就是所有單詞小寫以下劃線連接:例如,first_name, favorite_bands,和 old_company_name,這種標(biāo)記法幫你直觀地區(qū)分函數(shù)和其他標(biāo)識(shí)——原型和對(duì)象。

ECMAScript 的屬性和方法均使用 Camel標(biāo)記法,盡管多字的屬性名稱是罕見的(正則表達(dá)式對(duì)象的 lastIndex 和 ignoreCase 屬性)。

其它命名形式(Other Naming Patterns)

有時(shí),開發(fā)人員使用命名規(guī)范來(lái)彌補(bǔ)或替代語(yǔ)言特性。

例如,JavaScript 中沒(méi)有定義常量的方法(盡管有些內(nèi)置的像 Number,MAX_VALUE),所以開發(fā)者都采用全部單詞大寫的規(guī)范來(lái)命名這個(gè)程序生命周期中都不會(huì)改變的變量,如:

// 珍貴常數(shù),只可遠(yuǎn)觀
var PI = 3.14,
    MAX_WIDTH = 800;

還有另外一個(gè)完全大寫的慣例:全局變量名字全部大寫。全部大寫命名全局變量可以加強(qiáng)減小全局變量數(shù)量的實(shí)踐,同時(shí)讓它們易于區(qū)分。

另外一種使用規(guī)范來(lái)模擬功能的是私有成員。雖然可以在 JavaScript 中實(shí)現(xiàn)真正的私有,但是開發(fā)者發(fā)現(xiàn)僅僅使用一個(gè)下劃線前綴來(lái)表示一個(gè)私有屬性或方法會(huì)更容易些??紤]下面的例子:

var person = {
    getName: function () {
        return this._getFirst() + ' ' + this._getLast();
    },
    _getFirst: function () {
        // ...
    },
    _getLast: function () {
        // ...
    }
};

在此例中,getName()就表示公共方法,部分穩(wěn)定的 API。而_getFirst()和_getLast()則表明了私有。它們?nèi)匀皇钦5墓卜椒?,但是使用下劃線前綴來(lái)警告 person 對(duì)象的使用者這些方法在下一個(gè)版本中時(shí)不能保證工作的,是不能直接使用的。注意,JSLint有些不鳥下劃線前綴,除非你設(shè)置了 noman 選項(xiàng)為:false。

下面是一些常見的_private 規(guī)范:

  • 使用尾下劃線表示私有,如 name和 getElements\()
  • 使用一個(gè)下劃線前綴表protected(保護(hù))屬性,兩個(gè)下劃線前綴表示\_private (私有)屬性
  • Firefox 中一些內(nèi)置的變量屬性不屬于該語(yǔ)言的技術(shù)部分,使用兩個(gè)前下劃線和兩個(gè)后下劃線表示,如__proto__和__parent__。

注釋(Writing Comments)

你必須注釋你的代碼,即使不會(huì)有其他人向你一樣接觸它。通常,當(dāng)你深入研究一個(gè)問(wèn)題,你會(huì)很清楚的知道這個(gè)代碼是干嘛用的,但是,當(dāng)你一周之后再回來(lái)看的時(shí)候,想必也要耗掉不少腦細(xì)胞去搞明白到底怎么工作的。

很顯然,注釋不能走極端:每個(gè)單獨(dú)變量或是單獨(dú)一行。但是,你通常應(yīng)該記錄所有的函數(shù),它們的參數(shù)和返回值,或是任何不尋常的技術(shù)和方法。要想到注 釋可以給你代碼未來(lái)的閱讀者以諸多提示;閱讀者需要的是(不要讀太多的東西)僅注釋和函數(shù)屬性名來(lái)理解你的代碼。例如,當(dāng)你有五六行程序執(zhí)行特定的任務(wù), 如果你提供了一行代碼目的以及為什么在這里的描述的話,閱讀者就可以直接跳過(guò)這段細(xì)節(jié)。沒(méi)有硬性規(guī)定注釋代碼比,代碼的某些部分(如正則表達(dá)式)可能注釋 要比代碼多。

最重要的習(xí)慣,然而也是最難遵守的,就是保持注釋的及時(shí)更新,因?yàn)檫^(guò)時(shí)的注釋比沒(méi)有注釋更加的誤導(dǎo)人。

關(guān)于作者(About the Author)

Stoyan Stefanov 是 Yahoo!web 開發(fā)人員,多個(gè)O'Reilly書籍的作者、投稿者和技術(shù)評(píng)審。他經(jīng)常在會(huì)議和他的博客www.phpied.com上發(fā)表 web 開發(fā)主題的演講。Stoyan 還是 smush.it 圖片優(yōu)化工具的創(chuàng)造者,YUI 貢獻(xiàn)者,雅虎性能優(yōu)化工具 YSlow 2.0 的架構(gòu)設(shè)計(jì)師。