[譯] Javascript代碼約定

本文譯自Javascript大師Douglas Crockford的文章(2016.10.27版)憔杨,以饗英文不太好的同學(xué)福青。如果英文過關(guān)旦签,建議讀原文

原文 Code Conventions for the JavaScript Programming Language

排版規(guī)則

粗體:Javascript關(guān)鍵詞拾稳、操作符等
斜體:譯者補(bǔ)充說明
部分代碼塊為譯者所加颊乘,前面注有:// 譯者加

譯文全文

本文是Javascript編程過程中用到的一系列約定和規(guī)則参淹。
對于一個組織來說,從長遠(yuǎn)來看乏悄,軟件的價值與其代碼的質(zhì)量成正比例浙值。在一個程序的整個生命中,會經(jīng)歷很多雙眼檩小、很多雙手开呐。如果一個程序能清晰的傳達(dá)其結(jié)構(gòu)和特性,那么未來修改時规求,這些結(jié)構(gòu)和特性被破壞的可能性會較小筐付。代碼約定就是為了降低程序的脆弱性(brittleness)。
JavaScript代碼都是要公開發(fā)布的阻肿,所以它總是需要具有發(fā)布質(zhì)量瓦戚。簡潔是有價值的。

JavaScript文件

應(yīng)該保存為 .js 文件丛塌。
JavaScript代碼不應(yīng)該嵌入到HTML文件中较解,除非此代碼僅為這一個HTML文件所用(譯的欠妥)。將JavaScript嵌入到HTML會增大文件姨伤,導(dǎo)致無法通過緩存哨坪、壓縮等機(jī)制減小文件。

空白(Whitespace)

下面這些規(guī)則一直以來都是文字書寫的好習(xí)慣乍楚。除非有明顯的好處当编,否則不應(yīng)該被打破。

空行(blank line)徒溪,將邏輯上有關(guān)聯(lián)的代碼放在一塊忿偷,可以提高可讀性金顿。
空格(blank space),在以下情況中都應(yīng)該使用:

  • 一個關(guān)鍵詞后跟一個 ( 時鲤桥,應(yīng)該用一個空格隔開揍拆。應(yīng)用空格,可以使不是調(diào)用的地方看起來不像調(diào)用(Spaces are used to make things that are not invocations look less like invocations.)茶凳。如下例嫂拴,ifwhile 之后應(yīng)該有空格:
while (true) {
  • 在function和調(diào)用( ( )之間不應(yīng)該有空格。這樣可以將關(guān)鍵詞和函數(shù)調(diào)用區(qū)分開來贮喧。
// 譯者加
some_func(a, b);
  • 關(guān)鍵詞 function 后面總是要跟空格
// 譯者加
function foo() { ...
var bar = function () { ...
  • 一元操作符和其操作數(shù)之間不應(yīng)該有空格筒狠,除非操作符是一個單詞,比如 typeof
// 譯者加
some_var++;
++some_var;
  • 二元操作符和其操作數(shù)之間總是用一個空格隔開箱沦,這幾個例外:. ( [
// 譯者加
var c = a + b;
  • 逗號 , 之后總是跟空格或換行
  • 用于語句結(jié)束的分號 ; 后總是需要換行
  • for 語句中的分號 ; 后總是跟一個空格
// 譯者加
for (var i = 0; i < 5; i++) {

每一個語句都應(yīng)該跟當(dāng)前縮進(jìn)對齊辩恼,最外層縮進(jìn)對齊編輯區(qū)左側(cè)。當(dāng)上一行的最后一個標(biāo)識為 { [ ( 時谓形,本行縮進(jìn)4個空格灶伊;相應(yīng)的關(guān)閉標(biāo)識 } ] ) 應(yīng)新起一行,縮進(jìn)減4個空格

// 譯者加
function foo() {
      while (true) {
          console.log('hello');
      }    
}

三元操作符看起來比較暈寒跳,所以聘萨,? 總是新起一行并縮進(jìn)4個空格,: 也總是新起一行冯袍,與 ? 對齊匈挖。條件判斷需用 ( ) 包起來:

var integer = function (
      value,
      default_value
) {
      value = resolve(value);
      return (typeof value === "number")
          ? Math.floor(value)
          : (typeof value === "string")
               ? value.charCodeAt(0)
               : default_value;
};

如果 . 是一行的第一個字符,縮進(jìn)4個空格康愤。

應(yīng)避免一行過于長儡循。如果一個語句在一行放不下,那就有必要將它分開征冷。最好在 { [ ( ,換行择膝,或者 . ? :換行。如果在這地方換行不合適检激,那就在操作符之后換行肴捉,新行縮進(jìn)8個空格。但是這8個空格不改變當(dāng)前縮進(jìn)叔收。

塊(case catch default else finally)不是語句齿穗,故不需要縮進(jìn)。

Tab(制表符)和空格不應(yīng)該混用饺律。二者只選其一窃页,以避免兩者都用帶來的問題。個人偏好設(shè)置并不可靠。Tab空格并不比對方更具優(yōu)勢脖卖。50年前乒省,Tab的優(yōu)勢在于節(jié)省內(nèi)存,但摩爾定律已經(jīng)否定了這一優(yōu)勢(此處不是很懂)畦木。空格Tab有一個明確的優(yōu)勢:目前還沒有一個可依賴的標(biāo)準(zhǔn)規(guī)定一個Tab占幾個空格袖扛,但毫無爭議的是,一個空格確切的占一個空格十籍。所以蛆封,總是使用空格。如果必須妓雾,你可以在編輯時使用Tab娶吞,但確保在提交(commit)時轉(zhuǎn)為空格⌒狄觯或許有一天我們將最終有一個關(guān)于Tab的統(tǒng)一標(biāo)準(zhǔn),不過在那天到來之前机断,使用空格楷拳,是明智的選擇。

注釋(Comment)

應(yīng)該不吝嗇注釋吏奸。留下一些信息欢揖,有助于未來的人(包括你自己)理解你做了什么、為什么要做奋蔚。注釋應(yīng)該好好寫她混、寫清楚,要像寫代碼一樣寫注釋泊碑。一些小幽默也是鼓勵的坤按,不過困難和抱怨就不要寫了。

有一點很重要:注釋應(yīng)該保持“新鮮”(up-to-date)馒过。錯誤的注釋反而會使程序更難讀臭脓、更難懂。

注釋應(yīng)該有意義腹忽,著重說明不能從代碼里一眼就看出來的隱含意義来累。但也不要浪費時間寫下面這樣的注釋:

i = 0; // 把i設(shè)為0

變量聲明(Variable Declarations)

所有的變量都應(yīng)該在使用之前聲明。JavaScript并不強(qiáng)制如此窘奏,但這樣做可以使程序更易讀嘹锁,并且容易發(fā)現(xiàn)未聲明的變量可能是隱式的(這句譯的欠妥)。隱式的全局變量應(yīng)該杜絕着裹。盡量少用全局變量领猾。

推薦:變量的聲明語句后跟注釋。如果可能,以字母順序排列:

var currentEntry; // currently selected table entry
var level;        // indentation level
var size;         // size of table

JavaScript中的var沒有作用域瘤运,故窍霞,將變量聲明在塊(block)中會給有C語言經(jīng)歷的同學(xué)造成迷惑。

函數(shù)聲明(Function Declaration)

所有的function都應(yīng)該先聲明后使用拯坟。內(nèi)部函數(shù)(inner function)應(yīng)跟在var后面(即先聲明變量但金,再聲明內(nèi)部函數(shù)),這樣可以清楚知道當(dāng)前作用域(scope)有哪些變量郁季。

函數(shù)名和 ( 之間不應(yīng)該有空格冷溃;){ 之間應(yīng)該有一個空格。函數(shù)體縮進(jìn)4個空格梦裂,} 應(yīng)和函數(shù)聲明的那一行開始對齊似枕。

function outer(c, d) {
    var e = c * d;
    var x;  // no use

    function inner(a, b) {
        return (e * a) + b;
    }

    return inner(0, 1);
}

這樣的約定很適合JavaScript,因為在Javascript中函數(shù)和object定義(object literal)可以在任何可以放表達(dá)式的地方年柠≡浼撸可以最大程度的提高內(nèi)部函數(shù)和復(fù)雜結(jié)構(gòu)的可讀性。

function getElementsByClassName(className) {
    var results = [];
    walkTheDOM(document.body, function (node) {
        var array;                // array of class names
        var ncn = node.className; // the node's classname

// If the node has a class name, then split it into a list of simple names.
// If any of them match the requested name, then append the node to the list of results.

        if (ncn && ncn.split(" ").indexOf(className) >= 0) {
            results.push(node);
        }
    });
    return results;
}

如果是匿名函數(shù)冗恨,在關(guān)鍵詞 function( 之間應(yīng)該有一個空格答憔。如果沒有,看起來好像這個函數(shù)的名字是function掀抹,這當(dāng)然是錯誤的解讀虐拓。

div.onclick = function (e) {
    return false;
};

that = {
    method: function () {
        return this.datum;
    },
    datum: 0
};

應(yīng)盡量少用全局函數(shù)

如果一個函數(shù)被即刻調(diào)用(to be invoked immediately),那么整個調(diào)用表達(dá)式應(yīng)用 ( ) 包起來傲武,以清楚地表達(dá):產(chǎn)生的值是函數(shù)執(zhí)行的結(jié)果蓉驹,而非函數(shù)本身

var collection = (function () {
    var keys = [];
    var values = [];

    return {
        get: function (key) {
            var at = keys.indexOf(key);
            if (at >= 0) {
                return values[at];
            }
        },
        set: function (key, value) {
            var at = keys.indexOf(key);
            if (at < 0) {
                at = keys.length;
            }
            keys[at] = key;
            values[at] = value;
        },
        remove: function (key) {
            var at = keys.indexOf(key);
            if (at >= 0) {
                keys.splice(at, 1);
                values.splice(at, 1);
            }
        }
    };
}());

命名(Names)

名字應(yīng)該由26個字母的大小寫(A...Z, a...z),10個數(shù)字(0...9)揪利,以及下劃線:_ 組合而成态兴。避免使用國際字符,因為他們可能被誤讀土童。不要使用 $ 和 \

不要將 _ 用于名字首字母诗茎。這樣做有時是為了表示“私有”(privacy),但并不能真正的提供私有(保護(hù))献汗。如果私有很重要敢订,應(yīng)使用閉包(closure)。避免使用這種名不副實的做法罢吃。

絕大多數(shù)變量名和function名應(yīng)該以小寫字母開頭楚午。

必須用 new 調(diào)用的構(gòu)造函數(shù)(constructor function),名字應(yīng)該以大寫字母開頭尿招。如果 new 缺失矾柜,JavaScript并不視為一個編譯時(compile-time)錯誤阱驾,也不視為一個運(yùn)行時(run-time)錯誤,但卻可能有非預(yù)期的結(jié)果怪蔑。首字母大寫是我們唯一的保護(hù)機(jī)制里覆。

全局變量應(yīng)該全部用大寫字母組成。

語句(Statements)

簡單語句(Simple Statements)

一行應(yīng)最多包含一個語句缆瓣。每一個簡單語句都應(yīng)以 ; 結(jié)束喧枷。注意:函數(shù)定義(function literal)或?qū)ο蠖x(object literal)的賦值語句(assignment statement)也是賦值語句,故也應(yīng)以 ; 結(jié)束弓坞。

// 譯者加
var foo = {
    name: 'x'
};

var bar = function () {
    return 'bar';
};

JavaScript允許任何表達(dá)式(expression)作為語句(statement)使用隧甚。這會掩蓋一些錯誤,有 ; 時更甚渡冻∑莅猓可以作為語句的表達(dá)式僅建議:賦值調(diào)用族吻、delete

復(fù)合語句(Compound Statements)

復(fù)合語句:由 { } 包起來的一系列語句

  • 包起來的語句應(yīng)縮進(jìn)4個空格
  • { 應(yīng)該在復(fù)合語句開始的那一行行尾
  • } 應(yīng)該新起一行帽借,并與相應(yīng)的 { 所在行行首對齊
  • { } 應(yīng)包起所有的語句,即使只有一條語句(當(dāng)它作為控制結(jié)構(gòu)(control structure)的一部分時超歌,比如 if for)宜雀,這樣可以避免后續(xù)添加語句時引入錯誤。
// 譯者加
if (true) {
      console.log('true');
      // do_some_th
} else {
      console.log('false');
}
標(biāo)簽(Labels)

應(yīng)避免使用語句標(biāo)簽握础。只有下面語句才可應(yīng)用:while do for switch

return語句

返回的值表達(dá)式(value expression)必須與 return 關(guān)鍵詞在同一行,以避免插入 ; (后半句不很懂)

if語句

if 類的語句應(yīng)該有如下形式:

    if (condition) {
        statements
    }
    
    if (condition) {
        statements
    } else {
        statements
    }
    
    if (condition) {
        statements
    } else if (condition) {
        statements
    } else {
        statements
    }
for語句

for 類的語句應(yīng)該有如下形式:

    for (initialization; condition; update) {
        statements
    }
while語句

while 語句應(yīng)該有如下形式:

    while (condition) {
        statements
    }
do語句

do 語句應(yīng)該有如下形式:

    do {
        statements
    } while (condition);

跟其他復(fù)合語句不同的是:do 語句總是以 ; 結(jié)束

switch語句

switch 語句應(yīng)該有如下形式:

    switch (expression) {
    case expression:
        statements
    default:
        statements
    }

caseswitch 對齊悴品,以避免縮進(jìn)太多禀综。因 case 不是語句,故不需要“像”語句苔严。

每一組statements(default除外)都應(yīng)該以 break / return / throw 結(jié)束定枷。不應(yīng)穿透(fall through)

continue語句

避免使用該語句。因它會使控制流(control flow)不清晰届氢。

with語句

不應(yīng)該使用

{ } 和 [ ]

使用 { } 欠窒,而不用 new Object()。
使用 [ ] 退子,而不用 new Array()岖妄。
當(dāng)成員的名字是整數(shù)序列時,使用數(shù)組(array)寂祥。
當(dāng)成員的名字是無序字符串或名字時荐虐,使用對象(object)。

逗號操作符(, Operator)

不應(yīng)使用逗號操作符丸凭。(并不是指我們廣泛使用的逗號分隔符

賦值表達(dá)式(Assignment Expressions)

避免在 if while 語句的條件判斷中進(jìn)行賦值操作 福扬,下面這句:

if (a = b) {

是正確的嗎腕铸?還是下面這句:

if (a == b) {

才是本意?所以铛碑,應(yīng)避免這種容易引起歧義的寫法

=== and !== 操作符

請使用 ===!== 操作符狠裹。==!= 有強(qiáng)制轉(zhuǎn)換,應(yīng)避免使用汽烦。

引起混淆的加號涛菠、減號

不要在 + 后面跟另一個 +++,因這種做法會引起混淆刹缝。而是應(yīng)該加上 **( ) ** 碗暗,以清晰表達(dá)你的意圖。

total = subtotal + +myInput.value;

最好改寫為:

total = subtotal + (+myInput.value);

如此梢夯,+ + 就不會誤讀為 ++言疗。

eval是惡魔(eval is Evil)

eval 函數(shù)是JavaScript中最被誤用的,不要用它颂砸。
eval 有別名噪奄。(不很懂)
不要使用 Function 構(gòu)造函數(shù)。(不很懂)
不要給 setTimeout setInterval 傳字符串人乓。

用心編程勤篮,你也能長滿大胡子 ;)


800px-Douglas_Crockford.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市色罚,隨后出現(xiàn)的幾起案子碰缔,更是在濱河造成了極大的恐慌,老刑警劉巖戳护,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件金抡,死亡現(xiàn)場離奇詭異,居然都是意外死亡腌且,警方通過查閱死者的電腦和手機(jī)梗肝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铺董,“玉大人巫击,你說我怎么就攤上這事【” “怎么了坝锰?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長驻右。 經(jīng)常有香客問我什黑,道長,這世上最難降的妖魔是什么堪夭? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任愕把,我火速辦了婚禮拣凹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恨豁。我一直安慰自己嚣镜,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布橘蜜。 她就那樣靜靜地躺著菊匿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪计福。 梳的紋絲不亂的頭發(fā)上跌捆,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機(jī)與錄音象颖,去河邊找鬼佩厚。 笑死,一個胖子當(dāng)著我的面吹牛说订,可吹牛的內(nèi)容都是我干的抄瓦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼陶冷,長吁一口氣:“原來是場噩夢啊……” “哼钙姊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起埂伦,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤煞额,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沾谜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體立镶,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年类早,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嗜逻。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡涩僻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出栈顷,到底是詐尸還是另有隱情逆日,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布萄凤,位于F島的核電站室抽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏靡努。R本人自食惡果不足惜坪圾,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一晓折、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧兽泄,春花似錦漓概、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蜓陌,卻和暖如春觅彰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钮热。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工填抬, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人霉旗。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓痴奏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親厌秒。 傳聞我的和親對象是個殘疾皇子读拆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容