亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

JavaScript編碼規(guī)范 1

jsliang / 1363人閱讀

摘要:強(qiáng)制參數(shù)和返回值注釋必須包含類型信息和說(shuō)明。如果重寫(xiě)的形參個(gè)數(shù)類型順序和返回值類型均未發(fā)生變化,可省略,僅用標(biāo)識(shí),否則仍應(yīng)作完整注釋。

轉(zhuǎn)載:原地址

1 前言

JavaScript在百度一直有著廣泛的應(yīng)用,特別是在瀏覽器端的行為管理。本文檔的目標(biāo)是使JavaScript代碼風(fēng)格保持一致,容易被理解和被維護(hù)。

雖然本文檔是針對(duì)JavaScript設(shè)計(jì)的,但是在使用各種JavaScript的預(yù)編譯語(yǔ)言時(shí)(如TypeScript等)時(shí),適用的部分也應(yīng)盡量遵循本文檔的約定。

2 代碼風(fēng)格 2.1 文件
[建議] JavaScript 文件使用無(wú) BOMUTF-8 編碼。

解釋:

UTF-8 編碼具有更廣泛的適應(yīng)性。BOM 在使用程序或工具處理文件時(shí)可能造成不必要的干擾。

[建議] 在文件結(jié)尾處,保留一個(gè)空行。
2.2 結(jié)構(gòu) 2.2.1 縮進(jìn)
[強(qiáng)制] 使用 4 個(gè)空格做為一個(gè)縮進(jìn)層級(jí),不允許使用 2 個(gè)空格 或 tab 字符。
[強(qiáng)制] switch 下的 casedefault 必須增加一個(gè)縮進(jìn)層級(jí)。

示例:

javascript// good
switch (variable) {

    case "1":
        // do...
        break;

    case "2":
        // do...
        break;

    default:
        // do...

}

// bad
switch (variable) {

case "1":
    // do...
    break;

case "2":
    // do...
    break;

default:
    // do...

}
2.2.2 空格
[強(qiáng)制] 二元運(yùn)算符兩側(cè)必須有一個(gè)空格,一元運(yùn)算符與操作對(duì)象之間不允許有空格。

示例:

javascriptvar a = !arr.length;
a++;
a = b + c;
[強(qiáng)制] 用作代碼塊起始的左花括號(hào) { 前必須有一個(gè)空格。

示例:

javascript// good
if (condition) {
}

while (condition) {
}

function funcName() {
}

// bad
if (condition){
}

while (condition){
}

function funcName(){
}
[強(qiáng)制] if / else / for / while / function / switch / do / try / catch / finally 關(guān)鍵字后,必須有一個(gè)空格。

示例:

javascript// good
if (condition) {
}

while (condition) {
}

(function () {
})();

// bad
if(condition) {
}

while(condition) {
}

(function() {
})();
[強(qiáng)制] 在對(duì)象創(chuàng)建時(shí),屬性中的 : 之后必須有空格,: 之前不允許有空格。

示例:

javascript// good
var obj = {
    a: 1,
    b: 2,
    c: 3
};

// bad
var obj = {
    a : 1,
    b:2,
    c :3
};
[強(qiáng)制] 函數(shù)聲明、具名函數(shù)表達(dá)式、函數(shù)調(diào)用中,函數(shù)名和 ( 之間不允許有空格。

示例:

javascript// good
function funcName() {
}

var funcName = function funcName() {
};

funcName();

// bad
function funcName () {
}

var funcName = function funcName () {
};

funcName ();
[強(qiáng)制] ,; 前不允許有空格。

示例:

javascript// good
callFunc(a, b);

// bad
callFunc(a , b) ;
[強(qiáng)制] 在函數(shù)調(diào)用、函數(shù)聲明、括號(hào)表達(dá)式、屬性訪問(wèn)、if / for / while / switch / catch 等語(yǔ)句中,()[] 內(nèi)緊貼括號(hào)部分不允許有空格。

示例:

javascript// good

callFunc(param1, param2, param3);

save(this.list[this.indexes[i]]);

needIncream && (variable += increament);

if (num > list.length) {
}

while (len--) {
}


// bad

callFunc( param1, param2, param3 );

save( this.list[ this.indexes[ i ] ] );

needIncreament && ( variable += increament );

if ( num > list.length ) {
}

while ( len-- ) {
}
[強(qiáng)制] 單行聲明的數(shù)組與對(duì)象,如果包含元素,{}[] 內(nèi)緊貼括號(hào)部分不允許包含空格。

解釋:

聲明包含元素的數(shù)組與對(duì)象,只有當(dāng)內(nèi)部元素的形式較為簡(jiǎn)單時(shí),才允許寫(xiě)在一行。元素復(fù)雜的情況,還是應(yīng)該換行書(shū)寫(xiě)。

示例:

javascript// good
var arr1 = [];
var arr2 = [1, 2, 3];
var obj1 = {};
var obj2 = {name: "obj"};
var obj3 = {
    name: "obj",
    age: 20,
    sex: 1
};

// bad
var arr1 = [ ];
var arr2 = [ 1, 2, 3 ];
var obj1 = { };
var obj2 = { name: "obj" };
var obj3 = {name: "obj", age: 20, sex: 1};
[強(qiáng)制] 行尾不得有多余的空格。
2.2.3 換行
[強(qiáng)制] 每個(gè)獨(dú)立語(yǔ)句結(jié)束后必須換行。
[強(qiáng)制] 每行不得超過(guò) 120 個(gè)字符。

解釋:

超長(zhǎng)的不可分割的代碼允許例外,比如復(fù)雜的正則表達(dá)式。長(zhǎng)字符串不在例外之列。

[強(qiáng)制] 運(yùn)算符處換行時(shí),運(yùn)算符必須在新行的行首。

示例:

javascript// good
if (user.isAuthenticated()
    && user.isInRole("admin")
    && user.hasAuthority("add-admin")
    || user.hasAuthority("delete-admin")
) {
    // Code
}

var result = number1 + number2 + number3
    + number4 + number5;


// bad
if (user.isAuthenticated() &&
    user.isInRole("admin") &&
    user.hasAuthority("add-admin") ||
    user.hasAuthority("delete-admin")) {
    // Code
}

var result = number1 + number2 + number3 +
    number4 + number5;
[強(qiáng)制] 在函數(shù)聲明、函數(shù)表達(dá)式、函數(shù)調(diào)用、對(duì)象創(chuàng)建、數(shù)組創(chuàng)建、for語(yǔ)句等場(chǎng)景中,不允許在 ,; 前換行。

示例:

javascript// good
var obj = {
    a: 1,
    b: 2,
    c: 3
};

foo(
    aVeryVeryLongArgument,
    anotherVeryLongArgument,
    callback
);


// bad
var obj = {
    a: 1
    , b: 2
    , c: 3
};

foo(
    aVeryVeryLongArgument
    , anotherVeryLongArgument
    , callback
);
[建議] 不同行為或邏輯的語(yǔ)句集,使用空行隔開(kāi),更易閱讀。

示例:

javascript// 僅為按邏輯換行的示例,不代表setStyle的最優(yōu)實(shí)現(xiàn)
function setStyle(element, property, value) {
    if (element == null) {
        return;
    }

    element.style[property] = value;
}
[建議] 在語(yǔ)句的行長(zhǎng)度超過(guò) 120 時(shí),根據(jù)邏輯條件合理縮進(jìn)。

示例:

javascript// 較復(fù)雜的邏輯條件組合,將每個(gè)條件獨(dú)立一行,邏輯運(yùn)算符放置在行首進(jìn)行分隔,或?qū)⒉糠诌壿嫲催壿嫿M合進(jìn)行分隔。
// 建議最終將右括號(hào) ) 與左大括號(hào) { 放在獨(dú)立一行,保證與 if 內(nèi)語(yǔ)句塊能容易視覺(jué)辨識(shí)。
if (user.isAuthenticated()
    && user.isInRole("admin")
    && user.hasAuthority("add-admin")
    || user.hasAuthority("delete-admin")
) {
    // Code
}

// 按一定長(zhǎng)度截?cái)嘧址?,并使?+ 運(yùn)算符進(jìn)行連接。
// 分隔字符串盡量按語(yǔ)義進(jìn)行,如不要在一個(gè)完整的名詞中間斷開(kāi)。
// 特別的,對(duì)于HTML片段的拼接,通過(guò)縮進(jìn),保持和HTML相同的結(jié)構(gòu)。
var html = "" // 此處用一個(gè)空字符串,以便整個(gè)HTML片段都在新行嚴(yán)格對(duì)齊
    + "
" + "

Title here

" + "

This is a paragraph

" + "
Complete
" + "
"; // 也可使用數(shù)組來(lái)進(jìn)行拼接,相對(duì) + 更容易調(diào)整縮進(jìn)。 var html = [ "
", "

Title here

", "

This is a paragraph

", "
Complete
", "
" ]; html = html.join(""); // 當(dāng)參數(shù)過(guò)多時(shí),將每個(gè)參數(shù)獨(dú)立寫(xiě)在一行上,并將結(jié)束的右括號(hào) ) 獨(dú)立一行。 // 所有參數(shù)必須增加一個(gè)縮進(jìn)。 foo( aVeryVeryLongArgument, anotherVeryLongArgument, callback ); // 也可以按邏輯對(duì)參數(shù)進(jìn)行組合。 // 最經(jīng)典的是baidu.format函數(shù),調(diào)用時(shí)將參數(shù)分為“模板”和“數(shù)據(jù)”兩塊 baidu.format( dateFormatTemplate, year, month, date, hour, minute, second ); // 當(dāng)函數(shù)調(diào)用時(shí),如果有一個(gè)或以上參數(shù)跨越多行,應(yīng)當(dāng)每一個(gè)參數(shù)獨(dú)立一行。 // 這通常出現(xiàn)在匿名函數(shù)或者對(duì)象初始化等作為參數(shù)時(shí),如setTimeout函數(shù)等。 setTimeout( function () { alert("hello"); }, 200 ); order.data.read( "id=" + me.model.id, function (data) { me.attchToModel(data.result); callback(); }, 300 ); // 鏈?zhǔn)秸{(diào)用較長(zhǎng)時(shí)采用縮進(jìn)進(jìn)行調(diào)整。 $("#items") .find(".selected") .highlight() .end(); // 三元運(yùn)算符由3部分組成,因此其換行應(yīng)當(dāng)根據(jù)每個(gè)部分的長(zhǎng)度不同,形成不同的情況。 var result = thisIsAVeryVeryLongCondition ? resultA : resultB; var result = condition ? thisIsAVeryVeryLongResult : resultB; // 數(shù)組和對(duì)象初始化的混用,嚴(yán)格按照每個(gè)對(duì)象的 { 和結(jié)束 } 在獨(dú)立一行的風(fēng)格書(shū)寫(xiě)。 var array = [ { // ... }, { // ... } ];
[建議] 對(duì)于 if...else...、try...catch...finally 等語(yǔ)句,推薦使用在 } 號(hào)后添加一個(gè)換行 的風(fēng)格,使代碼層次結(jié)構(gòu)更清晰,閱讀性更好。

示例:

javascriptif (condition) {
    // some statements;
}
else {
    // some statements;
}

try {
    // some statements;
}
catch (ex) {
    // some statements;
}
2.2.4 語(yǔ)句
[強(qiáng)制] 不得省略語(yǔ)句結(jié)束的分號(hào)。
[強(qiáng)制] 在 if / else / for / do / while 語(yǔ)句中,即使只有一行,也不得省略塊 {...}。

示例:

javascript// good
if (condition) {
    callFunc();
}

// bad
if (condition) callFunc();
if (condition)
    callFunc();
[強(qiáng)制] 函數(shù)定義結(jié)束不允許添加分號(hào)。

示例:

javascript// good
function funcName() {
}

// bad
function funcName() {
};

// 如果是函數(shù)表達(dá)式,分號(hào)是不允許省略的。
var funcName = function () {
};
[強(qiáng)制] IIFE 必須在函數(shù)表達(dá)式外添加 (,非 IIFE 不得在函數(shù)表達(dá)式外添加 (。

解釋:

IIFE = Immediately-Invoked Function Expression.

額外的 ( 能夠讓代碼在閱讀的一開(kāi)始就能判斷函數(shù)是否立即被調(diào)用,進(jìn)而明白接下來(lái)代碼的用途。而不是一直拖到底部才恍然大悟。

示例:

javascript// good
var task = (function () {
   // Code
   return result;
})();

var func = function () {
};


// bad
var task = function () {
    // Code
    return result;
}();

var func = (function () {
});
2.3 命名
[強(qiáng)制] 變量 使用 Camel命名法

示例:

javascriptvar loadingModules = {};
[強(qiáng)制] 常量 使用 全部字母大寫(xiě),單詞間下劃線分隔 的命名方式。

示例:

javascriptvar HTML_ENTITY = {};
[強(qiáng)制] 函數(shù) 使用 Camel命名法。

示例:

javascriptfunction stringFormat(source) {
}
[強(qiáng)制] 函數(shù)的 參數(shù) 使用 Camel命名法。

示例:

javascriptfunction hear(theBells) {
}
[強(qiáng)制] 使用 Pascal命名法。

示例:

javascriptfunction TextNode(options) {
}
[強(qiáng)制] 類的 方法 / 屬性 使用 Camel命名法

示例:

javascriptfunction TextNode(value, engine) {
    this.value = value;
    this.engine = engine;
}

TextNode.prototype.clone = function () {
    return this;
};
[強(qiáng)制] 枚舉變量 使用 Pascal命名法,枚舉的屬性 使用 全部字母大寫(xiě),單詞間下劃線分隔 的命名方式。

示例:

javascriptvar TargetState = {
    READING: 1,
    READED: 2,
    APPLIED: 3,
    READY: 4
};
[強(qiáng)制] 命名空間 使用 Camel命名法。

示例:

javascriptequipments.heavyWeapons = {};
[強(qiáng)制] 由多個(gè)單詞組成的縮寫(xiě)詞,在命名中,根據(jù)當(dāng)前命名法和出現(xiàn)的位置,所有字母的大小寫(xiě)與首字母的大小寫(xiě)保持一致。

示例:

javascriptfunction XMLParser() {
}

function insertHTML(element, html) {
}

var httpRequest = new HTTPRequest();
[強(qiáng)制] 類名 使用 名詞

示例:

javascriptfunction Engine(options) {
}
[建議] 函數(shù)名 使用 動(dòng)賓短語(yǔ)。

示例:

javascriptfunction getStyle(element) {
}
[建議] boolean 類型的變量使用 ishas 開(kāi)頭。

示例:

javascriptvar isReady = false;
var hasMoreCommands = false;
[建議] Promise對(duì)象動(dòng)賓短語(yǔ)的進(jìn)行時(shí) 表達(dá)。

示例:

javascriptvar loadingData = ajax.get("url");
loadingData.then(callback);
2.4 注釋 2.4.1 單行注釋
[強(qiáng)制] 必須獨(dú)占一行。// 后跟一個(gè)空格,縮進(jìn)與下一行被注釋說(shuō)明的代碼一致。
2.4.2 多行注釋
[建議] 避免使用 /*...*/ 這樣的多行注釋。有多行注釋內(nèi)容時(shí),使用多個(gè)單行注釋。
2.4.3 文檔化注釋
[強(qiáng)制] 為了便于代碼閱讀和自文檔化,以下內(nèi)容必須包含以 /**...*/ 形式的塊注釋中。

解釋:

文件

namespace

函數(shù)或方法

類屬性

事件

全局變量

常量

AMD 模塊

[強(qiáng)制] 文檔注釋前必須空一行。
[建議] 自文檔化的文檔說(shuō)明 what,而不是 how。
2.4.4 類型定義
[強(qiáng)制] 類型定義都是以{開(kāi)始, 以}結(jié)束。

解釋:

常用類型如:{string}, {number}, {boolean}, {Object}, {Function}, {RegExp}, {Array}, {Date}。

類型不僅局限于內(nèi)置的類型,也可以是自定義的類型。比如定義了一個(gè)類 Developer,就可以使用它來(lái)定義一個(gè)參數(shù)和返回值的類型。

[強(qiáng)制] 對(duì)于基本類型 {string}, {number}, {boolean},首字母必須小寫(xiě)。
類型定義 語(yǔ)法示例 解釋
String {string} --
Number {number} --
Boolean {boolean} --
Object {Object} --
Function {Function} --
RegExp {RegExp} --
Array {Array} --
Date {Date} --
單一類型集合 {Array.} string 類型的數(shù)組
多類型 {(number|boolean)} 可能是 number 類型, 也可能是 boolean 類型
允許為null {?number} 可能是 number, 也可能是 null
不允許為null {!Object} Object 類型, 但不是 null
Function類型 {function(number, boolean)} 函數(shù), 形參類型
Function帶返回值 {function(number, boolean):string} 函數(shù), 形參, 返回值類型
參數(shù)可選 @param {string=} name 可選參數(shù), =為類型后綴
可變參數(shù) @param {...number} args 變長(zhǎng)參數(shù), ...為類型前綴
任意類型 {*} 任意類型
可選任意類型 @param {*=} name 可選參數(shù),類型不限
可變?nèi)我忸愋?/td> @param {...*} args 變長(zhǎng)參數(shù),類型不限
2.4.5 文件注釋
[強(qiáng)制] 文件頂部必須包含文件注釋,用 @file 標(biāo)識(shí)文件說(shuō)明。

示例:

javascript/**
 * @file Describe the file
 */
[建議] 文件注釋中可以用 @author 標(biāo)識(shí)開(kāi)發(fā)者信息。

解釋:

開(kāi)發(fā)者信息能夠體現(xiàn)開(kāi)發(fā)人員對(duì)文件的貢獻(xiàn),并且能夠讓遇到問(wèn)題或希望了解相關(guān)信息的人找到維護(hù)人。通常情況文件在被創(chuàng)建時(shí)標(biāo)識(shí)的是創(chuàng)建者。隨著項(xiàng)目的進(jìn)展,越來(lái)越多的人加入,參與這個(gè)文件的開(kāi)發(fā),新的作者應(yīng)該被加入 @author 標(biāo)識(shí)。

@author 標(biāo)識(shí)具有多人時(shí),原則是按照 責(zé)任 進(jìn)行排序。通常的說(shuō)就是如果有問(wèn)題,就是找第一個(gè)人應(yīng)該比找第二個(gè)人有效。比如文件的創(chuàng)建者由于各種原因,模塊移交給了其他人或其他團(tuán)隊(duì),后來(lái)因?yàn)樾略鲂枨?,其他人在新增代碼時(shí),添加 @author 標(biāo)識(shí)應(yīng)該把自己的名字添加在創(chuàng)建人的前面。

@author 中的名字不允許被刪除。任何勞動(dòng)成果都應(yīng)該被尊重。

業(yè)務(wù)項(xiàng)目中,一個(gè)文件可能被多人頻繁修改,并且每個(gè)人的維護(hù)時(shí)間都可能不會(huì)很長(zhǎng),不建議為文件增加 @author 標(biāo)識(shí)。通過(guò)版本控制系統(tǒng)追蹤變更,按業(yè)務(wù)邏輯單元確定模塊的維護(hù)責(zé)任人,通過(guò)文檔與wiki跟蹤和查詢,是更好的責(zé)任管理方式。

對(duì)于業(yè)務(wù)邏輯無(wú)關(guān)的技術(shù)型基礎(chǔ)項(xiàng)目,特別是開(kāi)源的公共項(xiàng)目,應(yīng)使用 @author 標(biāo)識(shí)。

示例:

javascript/**
 * @file Describe the file
 * @author author-name(mail-name@domain.com)
 *         author-name2(mail-name2@domain.com)
 */
2.4.6 命名空間注釋
[建議] 命名空間使用 @namespace 標(biāo)識(shí)。

示例:

javascript/**
 * @namespace
 */
var util = {};
2.4.7 類注釋
[建議] 使用 @class 標(biāo)記類或構(gòu)造函數(shù)。

解釋:

對(duì)于使用對(duì)象 constructor 屬性來(lái)定義的構(gòu)造函數(shù),可以使用 @constructor 來(lái)標(biāo)記。

示例:

javascript/**
 * 描述
 *
 * @class
 */
function Developer() {
    // constructor body
}
[建議] 使用 @extends 標(biāo)記類的繼承信息。

示例:

javascript/**
 * 描述
 *
 * @class
 * @extends Developer
 */
function Fronteer() {
    Developer.call(this);
    // constructor body
}
util.inherits(Fronteer, Developer);
[強(qiáng)制] 使用包裝方式擴(kuò)展類成員時(shí), 必須通過(guò) @lends 進(jìn)行重新指向。

解釋:

沒(méi)有 @lends 標(biāo)記將無(wú)法為該類生成包含擴(kuò)展類成員的文檔。

示例:

javascript/**
 * 類描述
 *
 * @class
 * @extends Developer
 */
function Fronteer() {
    Developer.call(this);
    // constructor body
}

util.extend(
    Fronteer.prototype,
    /** @lends Fronteer.prototype */{
        _getLevel: function () {
            // TODO
        }
    }
);
[強(qiáng)制] 類的屬性或方法等成員信息使用 @public / @protected / @private 中的任意一個(gè),指明可訪問(wèn)性。

解釋:

生成的文檔中將有可訪問(wèn)性的標(biāo)記,避免用戶直接使用非 public 的屬性或方法。

示例:

javascript/**
 * 類描述
 *
 * @class
 * @extends Developer
 */
var Fronteer = function () {
    Developer.call(this);

    /**
     * 屬性描述
     *
     * @type {string}
     * @private
     */
    this._level = "T12";

    // constructor body
};
util.inherits(Fronteer, Developer);

/**
 * 方法描述
 *
 * @private
 * @return {string} 返回值描述
 */
Fronteer.prototype._getLevel = function () {
};
2.4.8 函數(shù)/方法注釋
[強(qiáng)制] 函數(shù)/方法注釋必須包含函數(shù)說(shuō)明,有參數(shù)和返回值時(shí)必須使用注釋標(biāo)識(shí)。
[強(qiáng)制] 參數(shù)和返回值注釋必須包含類型信息和說(shuō)明。
[建議] 當(dāng)函數(shù)是內(nèi)部函數(shù),外部不可訪問(wèn)時(shí),可以使用 @inner 標(biāo)識(shí)。

示例:

javascript/**
 * 函數(shù)描述
 *
 * @param {string} p1 參數(shù)1的說(shuō)明
 * @param {string} p2 參數(shù)2的說(shuō)明,比較長(zhǎng)
 *     那就換行了.
 * @param {number=} p3 參數(shù)3的說(shuō)明(可選)
 * @return {Object} 返回值描述
 */
function foo(p1, p2, p3) {
    var p3 = p3 || 10;
    return {
        p1: p1,
        p2: p2,
        p3: p3
    };
}
[強(qiáng)制] 對(duì) Object 中各項(xiàng)的描述, 必須使用 @param 標(biāo)識(shí)。

示例:

javascript/**
 * 函數(shù)描述
 *
 * @param {Object} option 參數(shù)描述
 * @param {string} option.url option項(xiàng)描述
 * @param {string=} option.method option項(xiàng)描述,可選參數(shù)
 */
function foo(option) {
    // TODO
}
[建議] 重寫(xiě)父類方法時(shí), 應(yīng)當(dāng)添加 @override 標(biāo)識(shí)。如果重寫(xiě)的形參個(gè)數(shù)、類型、順序和返回值類型均未發(fā)生變化,可省略 @param、@return,僅用 @override 標(biāo)識(shí),否則仍應(yīng)作完整注釋。

解釋:

簡(jiǎn)而言之,當(dāng)子類重寫(xiě)的方法能直接套用父類的方法注釋時(shí)可省略對(duì)參數(shù)與返回值的注釋。

2.4.9 事件注釋
[強(qiáng)制] 必須使用 @event 標(biāo)識(shí)事件,事件參數(shù)的標(biāo)識(shí)與方法描述的參數(shù)標(biāo)識(shí)相同。

示例:

javascript/**
 * 值變更時(shí)觸發(fā)
 *
 * @event
 * @param {Object} e e描述
 * @param {string} e.before before描述
 * @param {string} e.after after描述
 */
onchange: function (e) {
}
[強(qiáng)制] 在會(huì)廣播事件的函數(shù)前使用 @fires 標(biāo)識(shí)廣播的事件,在廣播事件代碼前使用 @event 標(biāo)識(shí)事件。
[建議] 對(duì)于事件對(duì)象的注釋,使用 @param 標(biāo)識(shí),生成文檔時(shí)可讀性更好。

示例:

javascript/**
 * 點(diǎn)擊處理
 *
 * @fires Select#change
 * @private
 */
Select.prototype.clickHandler = function () {
    /**
     * 值變更時(shí)觸發(fā)
     *
     * @event Select#change
     * @param {Object} e e描述
     * @param {string} e.before before描述
     * @param {string} e.after after描述
     */
    this.fire(
        "change",
        {
            before: "foo",
            after: "bar"
        }
    );
};
2.4.10 常量注釋
[強(qiáng)制] 常量必須使用 @const 標(biāo)記,并包含說(shuō)明和類型信息。

示例:

javascript/**
 * 常量說(shuō)明
 *
 * @const
 * @type {string}
 */
var REQUEST_URL = "myurl.do";
2.4.11 復(fù)雜類型注釋
[建議] 對(duì)于類型未定義的復(fù)雜結(jié)構(gòu)的注釋,可以使用 @typedef 標(biāo)識(shí)來(lái)定義。

示例:

javascript// `namespaceA~` 可以換成其它 namepaths 前綴,目的是為了生成文檔中能顯示 `@typedef` 定義的類型和鏈接。
/**
 * 服務(wù)器
 *
 * @typedef {Object} namespaceA~Server
 * @property {string} host 主機(jī)
 * @property {number} port 端口
 */

/**
 * 服務(wù)器列表
 *
 * @type {Array.}
 */
var servers = [
    {
        host: "1.2.3.4",
        port: 8080
    },
    {
        host: "1.2.3.5",
        port: 8081
    }
];
2.4.12 AMD 模塊注釋
[強(qiáng)制] AMD 模塊使用 @module@exports 標(biāo)識(shí)。

解釋:

@exports 與 @module 都可以用來(lái)標(biāo)識(shí)模塊,區(qū)別在于 @module 可以省略模塊名稱。而只使用 @exports 時(shí)在 namepaths 中可以省略 module: 前綴。

示例:

javascriptdefine(
    function (require) {

        /**
         * foo description
         *
         * @exports Foo
         */
        var foo = {
            // TODO
        };

        /**
         * baz description
         *
         * @return {boolean} return description
         */
        foo.baz = function () {
            // TODO
        };

        return foo;

    }
);

也可以在 exports 變量前使用 @module 標(biāo)識(shí):

javascriptdefine(
    function (require) {

        /**
         * module description.
         *
         * @module foo
         */
        var exports = {};


        /**
         * bar description
         *
         */
        exports.bar = function () {
            // TODO
        };

        return exports;
    }
);

如果直接使用 factory 的 exports 參數(shù),還可以:

javascript/**
 * module description.
 *
 * @module
 */
define(
    function (require, exports) {

        /**
         * bar description
         *
         */
        exports.bar = function () {
            // TODO
        };
        return exports;
    }
);
[強(qiáng)制] 對(duì)于已使用 @module 標(biāo)識(shí)為 AMD模塊 的引用,在 namepaths 中必須增加 module: 作前綴。

解釋:

namepaths 沒(méi)有 module: 前綴時(shí),生成的文檔中將無(wú)法正確生成鏈接。

示例:

javascript/**
 * 點(diǎn)擊處理
 *
 * @fires module:Select#change
 * @private
 */
Select.prototype.clickHandler = function () {
    /**
     * 值變更時(shí)觸發(fā)
     *
     * @event module:Select#change
     * @param {Object} e e描述
     * @param {string} e.before before描述
     * @param {string} e.after after描述
     */
    this.fire(
        "change",
        {
            before: "foo",
            after: "bar"
        }
    );
};
[建議] 對(duì)于類定義的模塊,可以使用 @alias 標(biāo)識(shí)構(gòu)建函數(shù)。

示例:

javascript/**
 * A module representing a jacket.
 * @module jacket
 */
define(
    function () {

        /**
         * @class
         * @alias module:jacket
         */
        var Jacket = function () {
        };

        return Jacket;
    }
);
[建議] 多模塊定義時(shí),可以使用 @exports 標(biāo)識(shí)各個(gè)模塊。

示例:

javascript// one module
define("html/utils",
    /**
     * Utility functions to ease working with DOM elements.
     * @exports html/utils
     */
    function () {
        var exports = {
        };

        return exports;
    }
);

// another module
define("tag",
    /** @exports tag */
    function () {
        var exports = {
        };

        return exports;
    }
);
[建議] 對(duì)于 exports 為 Object 的模塊,可以使用@namespace標(biāo)識(shí)。

解釋:

使用 @namespace 而不是 @module 或 @exports 時(shí),對(duì)模塊的引用可以省略 module: 前綴。

[建議] 對(duì)于 exports 為類名的模塊,使用 @class@exports 標(biāo)識(shí)。

示例:

javascript
// 只使用 @class Bar 時(shí),類方法和屬性都必須增加 @name Bar#methodName 來(lái)標(biāo)識(shí),與 @exports 配合可以免除這一麻煩,并且在引用時(shí)可以省去 module: 前綴。 // 另外需要注意類名需要使用 var 定義的方式。 /** * Bar description * * @see foo * @exports Bar * @class */ var Bar = function () { // TODO }; /** * baz description * * @return {(string|Array)} return description */ Bar.prototype.baz = function () { // TODO };
2.4.13 細(xì)節(jié)注釋

對(duì)于內(nèi)部實(shí)現(xiàn)、不容易理解的邏輯說(shuō)明、摘要信息等,我們可能需要編寫(xiě)細(xì)節(jié)注釋。

[建議] 細(xì)節(jié)注釋遵循單行注釋的格式。說(shuō)明必須換行時(shí),每行是一個(gè)單行注釋的起始。

示例:

javascriptfunction foo(p1, p2) {
    // 這里對(duì)具體內(nèi)部邏輯進(jìn)行說(shuō)明
    // 說(shuō)明太長(zhǎng)需要換行
    for (...) {
        ....
    }
}
[強(qiáng)制] 有時(shí)我們會(huì)使用一些特殊標(biāo)記進(jìn)行說(shuō)明。特殊標(biāo)記必須使用單行注釋的形式。下面列舉了一些常用標(biāo)記:

解釋:

TODO: 有功能待實(shí)現(xiàn)。此時(shí)需要對(duì)將要實(shí)現(xiàn)的功能進(jìn)行簡(jiǎn)單說(shuō)明。

FIXME: 該處代碼運(yùn)行沒(méi)問(wèn)題,但可能由于時(shí)間趕或者其他原因,需要修正。此時(shí)需要對(duì)如何修正進(jìn)行簡(jiǎn)單說(shuō)明。

HACK: 為修正某些問(wèn)題而寫(xiě)的不太好或者使用了某些詭異手段的代碼。此時(shí)需要對(duì)思路或詭異手段進(jìn)行描述。

XXX: 該處存在陷阱。此時(shí)需要對(duì)陷阱進(jìn)行描述。

3 語(yǔ)言特性 3.1 變量
[強(qiáng)制] 變量在使用前必須通過(guò) var 定義。

解釋:

不通過(guò) var 定義變量將導(dǎo)致變量污染全局環(huán)境。

示例:

javascript// good
var name = "MyName";

// bad
name = "MyName";
[強(qiáng)制] 每個(gè) var 只能聲明一個(gè)變量。

解釋:

一個(gè) var 聲明多個(gè)變量,容易導(dǎo)致較長(zhǎng)的行長(zhǎng)度,并且在修改時(shí)容易造成逗號(hào)和分號(hào)的混淆。

示例:

javascript// good
var hangModules = [];
var missModules = [];
var visited = {};

// bad
var hangModules = [],
    missModules = [],
    visited = {};
[強(qiáng)制] 變量必須 即用即聲明,不得在函數(shù)或其它形式的代碼塊起始位置統(tǒng)一聲明所有變量。

解釋:

變量聲明與使用的距離越遠(yuǎn),出現(xiàn)的跨度越大,代碼的閱讀與維護(hù)成本越高。雖然JavaScript的變量是函數(shù)作用域,還是應(yīng)該根據(jù)編程中的意圖,縮小變量出現(xiàn)的距離空間。

示例:

javascript// good
function kv2List(source) {
    var list = [];

    for (var key in source) {
        if (source.hasOwnProperty(key)) {
            var item = {
                k: key,
                v: source[key]
            };
            list.push(item);
        }
    }

    return list;
}

// bad
function kv2List(source) {
    var list = [];
    var key;
    var item;

    for (key in source) {
        if (source.hasOwnProperty(key)) {
            item = {
                k: key,
                v: source[key]
            };
            list.push(item);
        }
    }

    return list;
}
3.2 條件
[強(qiáng)制] 在 Equality Expression 中使用類型嚴(yán)格的 ===。僅當(dāng)判斷 null 或 undefined 時(shí),允許使用 == null。

解釋:

使用 === 可以避免等于判斷中隱式的類型轉(zhuǎn)換。

示例:

javascript// good
if (age === 30) {
    // ......
}

// bad
if (age == 30) {
    // ......
}
[建議] 盡可能使用簡(jiǎn)潔的表達(dá)式。

示例:

javascript// 字符串為空

// good
if (!name) {
    // ......
}

// bad
if (name === "") {
    // ......
}
javascript// 字符串非空

// good
if (name) {
    // ......
}

// bad
if (name !== "") {
    // ......
}
javascript// 數(shù)組非空

// good
if (collection.length) {
    // ......
}

// bad
if (collection.length > 0) {
    // ......
}
javascript// 布爾不成立

// good
if (!notTrue) {
    // ......
}

// bad
if (notTrue === false) {
    // ......
}
javascript// null 或 undefined

// good
if (noValue == null) {
  // ......
}

// bad
if (noValue === null || typeof noValue === "undefined") {
  // ......
}
[建議] 按執(zhí)行頻率排列分支的順序。

解釋:

按執(zhí)行頻率排列分支的順序好處是:

閱讀的人容易找到最常見(jiàn)的情況,增加可讀性。

提高執(zhí)行效率。

[建議] 對(duì)于相同變量或表達(dá)式的多值條件,用 switch 代替 if。

示例:

javascript// good
switch (typeof variable) {
    case "object":
        // ......
        break;
    case "number":
    case "boolean":
    case "string":
        // ......
        break;
}

// bad
var type = typeof variable;
if (type === "object") {
    // ......
} 
else if (type === "number" || type === "boolean" || type === "string") {
    // ......
}
[建議] 如果函數(shù)或全局中的 else 塊后沒(méi)有任何語(yǔ)句,可以刪除 else。

示例:

javascript// good
function getName() {
    if (name) {
        return name;
    }

    return "unnamed";
}

// bad
function getName() {
    if (name) {
        return name;
    }
    else {
        return "unnamed";
    }
}
3.3 循環(huán)
[建議] 不要在循環(huán)體中包含函數(shù)表達(dá)式,事先將函數(shù)提取到循環(huán)體外。

解釋:

循環(huán)體中的函數(shù)表達(dá)式,運(yùn)行過(guò)程中會(huì)生成循環(huán)次數(shù)個(gè)函數(shù)對(duì)象。

示例:

javascript// good
function clicker() {
    // ......
}

for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    addListener(element, "click", clicker);
}


// bad
for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    addListener(element, "click", function () {});
}
[建議] 對(duì)循環(huán)內(nèi)多次使用的不變值,在循環(huán)外用變量緩存。

示例:

javascript// good
var width = wrap.offsetWidth + "px";
for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    element.style.width = width;
    // ......
}


// bad
for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    element.style.width = wrap.offsetWidth + "px";
    // ......
}
[建議] 對(duì)有序集合進(jìn)行遍歷時(shí),緩存 length。

解釋:

雖然現(xiàn)代瀏覽器都對(duì)數(shù)組長(zhǎng)度進(jìn)行了緩存,但對(duì)于一些宿主對(duì)象和老舊瀏覽器的數(shù)組對(duì)象,在每次 length 訪問(wèn)時(shí)會(huì)動(dòng)態(tài)計(jì)算元素個(gè)數(shù),此時(shí)緩存 length 能有效提高程序性能。

示例:

javascriptfor (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    // ......
}
[建議] 對(duì)有序集合進(jìn)行順序無(wú)關(guān)的遍歷時(shí),使用逆序遍歷。

解釋:

逆序遍歷可以節(jié)省變量,代碼比較優(yōu)化。

示例:

javascriptvar len = elements.length;
while (len--) {
    var element = elements[len];
    // ......
}
3.4 類型 3.4.1 類型檢測(cè)
[建議] 類型檢測(cè)優(yōu)先使用 typeof。對(duì)象類型檢測(cè)使用 instanceof。nullundefined 的檢測(cè)使用 == null。

示例:

javascript// string
typeof variable === "string"

// number
typeof variable === "number"

// boolean
typeof variable === "boolean"

// Function
typeof variable === "function"

// Object
typeof variable === "object"

// RegExp
variable instanceof RegExp

// Array
variable instanceof Array

// null
variable === null

// null or undefined
variable == null

// undefined
typeof variable === "undefined"
3.4.2 類型轉(zhuǎn)換
[建議] 轉(zhuǎn)換成 string 時(shí),使用 + ""。

示例:

javascript// good
num + "";

// bad
new String(num);
num.toString();
String(num);
[建議] 轉(zhuǎn)換成 number 時(shí),通常使用 +

示例:

javascript// good
+str;

// bad
Number(str);
[建議] string 轉(zhuǎn)換成 number,要轉(zhuǎn)換的字符串結(jié)尾包含非數(shù)字并期望忽略時(shí),使用 parseInt。

示例:

javascriptvar width = "200px";
parseInt(width, 10);
[強(qiáng)制] 使用 parseInt 時(shí),必須指定進(jìn)制。

示例:

javascript// good
parseInt(str, 10);

// bad
parseInt(str);
[建議] 轉(zhuǎn)換成 boolean 時(shí),使用 !!。

示例:

javascriptvar num = 3.14;
!!num;
[建議] number 去除小數(shù)點(diǎn),使用 Math.floor / Math.round / Math.ceil,不使用 parseInt。

示例:

javascript// good
var num = 3.14;
Math.ceil(num);

// bad
var num = 3.14;
parseInt(num, 10);
3.5 字符串
[強(qiáng)制] 字符串開(kāi)頭和結(jié)束使用單引號(hào) "

解釋:

輸入單引號(hào)不需要按住 shift,方便輸入。

實(shí)際使用中,字符串經(jīng)常用來(lái)拼接 HTML。為方便 HTML 中包含雙引號(hào)而不需要轉(zhuǎn)義寫(xiě)法。

示例:

javascriptvar str = "我是一個(gè)字符串";
var html = "
拼接HTML可以省去雙引號(hào)轉(zhuǎn)義
";
[建議] 使用 數(shù)組+ 拼接字符串。

解釋:

使用 + 拼接字符串,如果拼接的全部是 StringLiteral,壓縮工具可以對(duì)其進(jìn)行自動(dòng)合并的優(yōu)化。所以,靜態(tài)字符串建議使用 + 拼接。

在現(xiàn)代瀏覽器下,使用 + 拼接字符串,性能較數(shù)組的方式要高。

如需要兼顧老舊瀏覽器,應(yīng)盡量使用數(shù)組拼接字符串。

示例:

javascript// 使用數(shù)組拼接字符串
var str = [
    // 推薦換行開(kāi)始并縮進(jìn)開(kāi)始第一個(gè)字符串, 對(duì)齊代碼, 方便閱讀.
    "

    ", "
  • 第一項(xiàng)
  • ", "
  • 第二項(xiàng)
  • ", "
" ].join(""); // 使用 + 拼接字符串 var str2 = "" // 建議第一個(gè)為空字符串, 第二個(gè)換行開(kāi)始并縮進(jìn)開(kāi)始, 對(duì)齊代碼, 方便閱讀 + "
    ", + "
  • 第一項(xiàng)
  • ", + "
  • 第二項(xiàng)
  • ", + "
";
[建議] 復(fù)雜的數(shù)據(jù)到視圖字符串的轉(zhuǎn)換過(guò)程,選用一種模板引擎。

解釋:

使用模板引擎有如下好處:

在開(kāi)發(fā)過(guò)程中專注于數(shù)據(jù),將視圖生成的過(guò)程由另外一個(gè)層級(jí)維護(hù),使程序邏輯結(jié)構(gòu)更清晰。

優(yōu)秀的模板引擎,通過(guò)模板編譯技術(shù)和高質(zhì)量的編譯產(chǎn)物,能獲得比手工拼接字符串更高的性能。

artTemplate: 體積較小,在所有環(huán)境下性能高,語(yǔ)法靈活。

dot.js: 體積小,在現(xiàn)代瀏覽器下性能高,語(yǔ)法靈活。

etpl: 體積較小,在所有環(huán)境下性能高,模板復(fù)用性高,語(yǔ)法靈活。

handlebars: 體積大,在所有環(huán)境下性能高,擴(kuò)展性高。

hogon: 體積小,在現(xiàn)代瀏覽器下性能高。

nunjucks: 體積較大,性能一般,模板復(fù)用性高。

3.6 對(duì)象
[強(qiáng)制] 使用對(duì)象字面量 {} 創(chuàng)建新 Object。

示例:

javascript// good
var obj = {};

// bad
var obj = new Object();
[強(qiáng)制] 對(duì)象創(chuàng)建時(shí),如果一個(gè)對(duì)象的所有 屬性 均可以不添加引號(hào),則所有 屬性 不得添加引號(hào)。

示例:

javascriptvar info = {
    name: "someone",
    age: 28
};
[強(qiáng)制] 對(duì)象創(chuàng)建時(shí),如果任何一個(gè) 屬性 需要添加引號(hào),則所有 屬性 必須添加 "。

解釋:

如果屬性不符合 Identifier 和 NumberLiteral 的形式,就需要以 StringLiteral 的形式提供。

示例:

javascript// good
var info = {
    "name": "someone",
    "age": 28,
    "more-info": "..."
};

// bad
var info = {
    name: "someone",
    age: 28,
    "more-info": "..."
};
[強(qiáng)制] 不允許修改和擴(kuò)展任何原生對(duì)象和宿主對(duì)象的原型。

示例:

javascript// 以下行為絕對(duì)禁止
String.prototype.trim = function () {
};
[建議] 屬性訪問(wèn)時(shí),盡量使用 .。

解釋:

屬性名符合 Identifier 的要求,就可以通過(guò) . 來(lái)訪問(wèn),否則就只能通過(guò) [expr] 方式訪問(wèn)。

通常在 JavaScript 中聲明的對(duì)象,屬性命名是使用 Camel 命名法,用 . 來(lái)訪問(wèn)更清晰簡(jiǎn)潔。部分特殊的屬性(比如來(lái)自后端的JSON),可能采用不尋常的命名方式,可以通過(guò) [expr] 方式訪問(wèn)。

示例:

javascriptinfo.age;
info["more-info"];
[建議] for in 遍歷對(duì)象時(shí), 使用 hasOwnProperty 過(guò)濾掉原型中的屬性。

示例:

javascriptvar newInfo = {};
for (var key in info) {
    if (info.hasOwnProperty(key)) {
        newInfo[key] = info[key];
    }
}
3.7 數(shù)組
[強(qiáng)制] 使用數(shù)組字面量 [] 創(chuàng)建新數(shù)組,除非想要?jiǎng)?chuàng)建的是指定長(zhǎng)度的數(shù)組。

示例:

javascript// good
var arr = [];

// bad
var arr = new Array();
[強(qiáng)制] 遍歷數(shù)組不使用 for in

解釋:

數(shù)組對(duì)象可能存在數(shù)字以外的屬性, 這種情況下 for in 不會(huì)得到正確結(jié)果.

示例:

javascriptvar arr = ["a", "b", "c"];
arr.other = "other things"; // 這里僅作演示, 實(shí)際中應(yīng)使用Object類型

// 正確的遍歷方式
for (var i = 0, len = arr.length; i < len; i++) {
    console.log(i);
}

// 錯(cuò)誤的遍歷方式
for (i in arr) {
    console.log(i);
}
[建議] 不因?yàn)樾阅艿脑蜃约簩?shí)現(xiàn)數(shù)組排序功能,盡量使用數(shù)組的 sort 方法。

解釋:

自己實(shí)現(xiàn)的常規(guī)排序算法,在性能上并不優(yōu)于數(shù)組默認(rèn)的 sort 方法。以下兩種場(chǎng)景可以自己實(shí)現(xiàn)排序:

需要穩(wěn)定的排序算法,達(dá)到嚴(yán)格一致的排序結(jié)果。

數(shù)據(jù)特點(diǎn)鮮明,適合使用桶排。

[建議] 清空數(shù)組使用 .length = 0
3.8 函數(shù) 3.8.1 函數(shù)長(zhǎng)度
[建議] 一個(gè)函數(shù)的長(zhǎng)度控制在 50 行以內(nèi)。

解釋:

將過(guò)多的邏輯單元混在一個(gè)大函數(shù)中,易導(dǎo)致難以維護(hù)。一個(gè)清晰易懂的函數(shù)應(yīng)該完成單一的邏輯單元。復(fù)雜的操作應(yīng)進(jìn)一步抽取,通過(guò)函數(shù)的調(diào)用來(lái)體現(xiàn)流程。

特定算法等不可分割的邏輯允許例外。

示例:

javascriptfunction syncViewStateOnUserAction() {
    if (x.checked) {
        y.checked = true;
        z.value = "";
    }
    else {
        y.checked = false;
    }

    if (!a.value) {
        warning.innerText = "Please enter it";
        submitButton.disabled = true;
    }
    else {
        warning.innerText = "";
        submitButton.disabled = false;
    }
}

// 直接閱讀該函數(shù)會(huì)難以明確其主線邏輯,因此下方是一種更合理的表達(dá)方式:

function syncViewStateOnUserAction() {
    syncXStateToView();
    checkAAvailability();
}

function syncXStateToView() {
    if (x.checked) {
        y.checked = true;
        z.value = "";
    }
    else {
        y.checked = false;
    }
}

function checkAAvailability() {
    if (!a.value) {
        displayWarningForAMissing();
    }
    else {
        clearWarnignForA();
    }
}
3.8.2 參數(shù)設(shè)計(jì)
[建議] 一個(gè)函數(shù)的參數(shù)控制在 6 個(gè)以內(nèi)。

解釋:

除去不定長(zhǎng)參數(shù)以外,函數(shù)具備不同邏輯意義的參數(shù)建議控制在 6 個(gè)以內(nèi),過(guò)多參數(shù)會(huì)導(dǎo)致維護(hù)難度增大。

某些情況下,如使用 AMD Loader 的 require 加載多個(gè)模塊時(shí),其 callback 可能會(huì)存在較多參數(shù),因此對(duì)函數(shù)參數(shù)的個(gè)數(shù)不做強(qiáng)制限制。

[建議] 通過(guò) options 參數(shù)傳遞非數(shù)據(jù)輸入型參數(shù)。

解釋:

有些函數(shù)的參數(shù)并不是作為算法的輸入,而是對(duì)算法的某些分支條件判斷之用,此類參數(shù)建議通過(guò)一個(gè) options 參數(shù)傳遞。

如下函數(shù):

javascript/**
 * 移除某個(gè)元素
 *
 * @param {Node} element 需要移除的元素
 * @param {boolean} removeEventListeners 是否同時(shí)將所有注冊(cè)在元素上的事件移除
 */
function removeElement(element, removeEventListeners) {
    element.parent.removeChild(element);
    if (removeEventListeners) {
        element.clearEventListeners();
    }
}

可以轉(zhuǎn)換為下面的簽名:

javascript/**
 * 移除某個(gè)元素
 *
 * @param {Node} element 需要移除的元素
 * @param {Object} options 相關(guān)的邏輯配置
 * @param {boolean} options.removeEventListeners 是否同時(shí)將所有注冊(cè)在元素上的事件移除
 */
function removeElement(element, options) {
    element.parent.removeChild(element);
    if (options.removeEventListeners) {
        element.clearEventListeners();
    }
}

這種模式有幾個(gè)顯著的優(yōu)勢(shì):

boolean 型的配置項(xiàng)具備名稱,從調(diào)用的代碼上更易理解其表達(dá)的邏輯意義。

當(dāng)配置項(xiàng)有增長(zhǎng)時(shí),無(wú)需無(wú)休止地增加參數(shù)個(gè)數(shù),不會(huì)出現(xiàn) removeElement(element, true, false, false, 3) 這樣難以理解的調(diào)用代碼。

當(dāng)部分配置參數(shù)可選時(shí),多個(gè)參數(shù)的形式非常難處理重載邏輯,而使用一個(gè) options 對(duì)象只需判斷屬性是否存在,實(shí)現(xiàn)得以簡(jiǎn)化。

3.8.3 閉包
[建議] 在適當(dāng)?shù)臅r(shí)候?qū)㈤]包內(nèi)大對(duì)象置為 null

解釋:

在 JavaScript 中,無(wú)需特別的關(guān)鍵詞就可以使用閉包,一個(gè)函數(shù)可以任意訪問(wèn)在其定義的作用域外的變量。需要注意的是,函數(shù)的作用域是靜態(tài)的,即在定義時(shí)決定,與調(diào)用的時(shí)機(jī)和方式?jīng)]有任何關(guān)系。

閉包會(huì)阻止一些變量的垃圾回收,對(duì)于較老舊的JavaScript引擎,可能導(dǎo)致外部所有變量均無(wú)法回收。

首先一個(gè)較為明確的結(jié)論是,以下內(nèi)容會(huì)影響到閉包內(nèi)變量的回收:

嵌套的函數(shù)中是否有使用該變量。

嵌套的函數(shù)中是否有 直接調(diào)用eval

是否使用了 with 表達(dá)式。

Chakra、V8 和 SpiderMonkey 將受以上因素的影響,表現(xiàn)出不盡相同又較為相似的回收策略,而JScript.dll和Carakan則完全沒(méi)有這方面的優(yōu)化,會(huì)完整保留整個(gè) LexicalEnvironment 中的所有變量綁定,造成一定的內(nèi)存消耗。

由于對(duì)閉包內(nèi)變量有回收優(yōu)化策略的 Chakra、V8 和 SpiderMonkey 引擎的行為較為相似,因此可以總結(jié)如下,當(dāng)返回一個(gè)函數(shù) fn 時(shí):

如果 fn 的 [[Scope]] 是ObjectEnvironment(with 表達(dá)式生成 ObjectEnvironment,函數(shù)和 catch 表達(dá)式生成 DeclarativeEnvironment),則:

如果是 V8 引擎,則退出全過(guò)程。

如果是 SpiderMonkey,則處理該 ObjectEnvironment 的外層 LexicalEnvironment。

獲取當(dāng)前 LexicalEnvironment 下的所有類型為 Function 的對(duì)象,對(duì)于每一個(gè) Function 對(duì)象,分析其 FunctionBody:

如果 FunctionBody 中含有 直接調(diào)用eval,則退出全過(guò)程。

否則得到所有的 Identifier。

對(duì)于每一個(gè) Identifier,設(shè)其為 name,根據(jù)查找變量引用的規(guī)則,從 LexicalEnvironment 中找出名稱為 name 的綁定 binding。

對(duì) binding 添加 notSwap 屬性,其值為 true。

檢查當(dāng)前 LexicalEnvironment 中的每一個(gè)變量綁定,如果該綁定有 notSwap 屬性且值為 true,則:

如果是V8引擎,刪除該綁定。

如果是SpiderMonkey,將該綁定的值設(shè)為 undefined,將刪除 notSwap 屬性。

對(duì)于Chakra引擎,暫無(wú)法得知是按 V8 的模式還是按 SpiderMonkey 的模式進(jìn)行。

如果有 非常龐大 的對(duì)象,且預(yù)計(jì)會(huì)在 老舊的引擎 中執(zhí)行,則使用閉包時(shí),注意將閉包不需要的對(duì)象置為空引用。

[建議] 使用 IIFE 避免 Lift 效應(yīng)。

解釋:

在引用函數(shù)外部變量時(shí),函數(shù)執(zhí)行時(shí)外部變量的值由運(yùn)行時(shí)決定而非定義時(shí),最典型的場(chǎng)景如下:

javascriptvar tasks = [];
for (var i = 0; i < 5; i++) {
    tasks[tasks.length] = function () {
        console.log("Current cursor is at " + i);
    };
}

var len = tasks.length;
while (len--) {
    tasks[len]();
}

以上代碼對(duì) tasks 中的函數(shù)的執(zhí)行均會(huì)輸出 Current cursor is at 5,往往不符合預(yù)期。

此現(xiàn)象稱為 Lift 效應(yīng) 。解決的方式是通過(guò)額外加上一層閉包函數(shù),將需要的外部變量作為參數(shù)傳遞來(lái)解除變量的綁定關(guān)系:

javascriptvar tasks = [];
for (var i = 0; i < 5; i++) {
    // 注意有一層額外的閉包
    tasks[tasks.length] = (function (i) {
        return function () {
            console.log("Current cursor is at " + i);
        };
    })(i);
}

var len = tasks.length;
while (len--) {
    tasks[len]();
}
3.8.4 空函數(shù)
[建議] 空函數(shù)不使用 new Function() 的形式。

示例:

javascriptvar emptyFunction = function () {};
[建議] 對(duì)于性能有高要求的場(chǎng)合,建議存在一個(gè)空函數(shù)的常量,供多處使用共享。

示例:

javascriptvar EMPTY_FUNCTION = function () {};

function MyClass() {
}

MyClass.prototype.abstractMethod = EMPTY_FUNCTION;
MyClass.prototype.hooks.before = EMPTY_FUNCTION;
MyClass.prototype.hooks.after = EMPTY_FUNCTION;
3.9 面向?qū)ο?/b>
[強(qiáng)制] 類的繼承方案,實(shí)現(xiàn)時(shí)需要修正 constructor。

解釋:

通常使用其他 library 的類繼承方案都會(huì)進(jìn)行 constructor 修正。如果是自己實(shí)現(xiàn)的類繼承方案,需要進(jìn)行 constructor 修正。

示例:

javascript/**
 * 構(gòu)建類之間的繼承關(guān)系
 * 
 * @param {Function} subClass 子類函數(shù)
 * @param {Function} superClass 父類函數(shù)
 */
function inherits(subClass, superClass) {
    var F = new Function();
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;
}
[建議] 聲明類時(shí),保證 constructor 的正確性。

示例:

javascriptfunction Animal(name) {
    this.name = name;
}

// 直接prototype等于對(duì)象時(shí),需要修正constructor
Animal.prototype = {
    constructor: Animal,

    jump: function () {
        alert("animal " + this.name + " jump");
    }
};

// 這種方式擴(kuò)展prototype則無(wú)需理會(huì)constructor
Animal.prototype.jump = function () {
    alert("animal " + this.name + " jump");
};
[建議] 屬性在構(gòu)造函數(shù)中聲明,方法在原型中聲明。

解釋:

原型對(duì)象的成員被所有實(shí)例共享,能節(jié)約內(nèi)存占用。所以編碼時(shí)我們應(yīng)該遵守這樣的原則:原型對(duì)象包含程序不會(huì)修改的成員,如方法函數(shù)或配置項(xiàng)。

javascriptfunction TextNode(value, engine) {
    this.value = value;
    this.engine = engine;
}

TextNode.prototype.clone = function () {
    return this;
};
[強(qiáng)制] 自定義事件的 事件名 必須全小寫(xiě)。

解釋:

在 JavaScript 廣泛應(yīng)用的瀏覽器環(huán)境,絕大多數(shù) DOM 事件名稱都是全小寫(xiě)的。為了遵循大多數(shù) JavaScript 開(kāi)發(fā)者的習(xí)慣,在設(shè)計(jì)自定義事件時(shí),事件名也應(yīng)該全小寫(xiě)。

[強(qiáng)制] 自定義事件只能有一個(gè) event 參數(shù)。如果事件需要傳遞較多信息,應(yīng)仔細(xì)設(shè)計(jì)事件對(duì)象。

解釋:

一個(gè)事件對(duì)象的好處有:

順序無(wú)關(guān),避免事件監(jiān)聽(tīng)者需要記憶參數(shù)順序。

每個(gè)事件信息都可以根據(jù)需要提供或者不提供,更自由。

擴(kuò)展方便,未來(lái)添加事件信息時(shí),無(wú)需考慮會(huì)破壞監(jiān)聽(tīng)器參數(shù)形式而無(wú)法向后兼容。

[建議] 設(shè)計(jì)自定義事件時(shí),應(yīng)考慮禁止默認(rèn)行為。

解釋:

常見(jiàn)禁止默認(rèn)行為的方式有兩種:

事件監(jiān)聽(tīng)函數(shù)中 return false。

事件對(duì)象中包含禁止默認(rèn)行為的方法,如 preventDefault。

3.10 動(dòng)態(tài)特性 3.10.1 eval
[強(qiáng)制] 避免使用直接 eval 函數(shù)。

解釋:

直接 eval,指的是以函數(shù)方式調(diào)用 eval 的調(diào)用方法。直接 eval 調(diào)用執(zhí)行代碼的作用域?yàn)楸镜刈饔糜颍瑧?yīng)當(dāng)避免。

如果有特殊情況需要使用直接 eval,需在代碼中用詳細(xì)的注釋說(shuō)明為何必須使用直接 eval,不能使用其它動(dòng)態(tài)執(zhí)行代碼的方式,同時(shí)需要其他資深工程師進(jìn)行 Code Review。

[建議] 盡量避免使用 eval 函數(shù)。
3.10.2 動(dòng)態(tài)執(zhí)行代碼
[建議] 使用 new Function 執(zhí)行動(dòng)態(tài)代碼。

解釋:

通過(guò) new Function 生成的函數(shù)作用域是全局使用域,不會(huì)影響當(dāng)當(dāng)前的本地作用域。如果有動(dòng)態(tài)代碼執(zhí)行的需求,建議使用 new Function。

示例:

javascriptvar handler = new Function("x", "y", "return x + y;");
var result = handler($("#x").val(), $("#y").val());
3.10.3 with
[建議] 盡量不要使用 with

解釋:

使用 with 可能會(huì)增加代碼的復(fù)雜度,不利于閱讀和管理;也會(huì)對(duì)性能有影響。大多數(shù)使用 with 的場(chǎng)景都能使用其他方式較好的替代。所以,盡量不要使用 with。

3.10.4 delete
[建議] 減少 delete 的使用。

解釋:

如果沒(méi)有特別的需求,減少或避免使用delete。delete的使用會(huì)破壞部分 JavaScript 引擎的性能優(yōu)化。

[建議] 處理 delete 可能產(chǎn)生的異常。

解釋:

對(duì)于有被遍歷需求,且值 null 被認(rèn)為具有業(yè)務(wù)邏輯意義的值的對(duì)象,移除某個(gè)屬性必須使用 delete 操作。

在嚴(yán)格模式或IE下使用 delete 時(shí),不能被刪除的屬性會(huì)拋出異常,因此在不確定屬性是否可以刪除的情況下,建議添加 try-catch 塊。

示例:

javascripttry {
    delete o.x;
}
catch (deleteError) {
    o.x = null;
}
3.10.5 對(duì)象屬性
[建議] 避免修改外部傳入的對(duì)象。

解釋:

JavaScript 因其腳本語(yǔ)言的動(dòng)態(tài)特性,當(dāng)一個(gè)對(duì)象未被 seal 或 freeze 時(shí),可以任意添加、刪除、修改屬性值。

但是隨意地對(duì) 非自身控制的對(duì)象 進(jìn)行修改,很容易造成代碼在不可預(yù)知的情況下出現(xiàn)問(wèn)題。因此,設(shè)計(jì)良好的組件、函數(shù)應(yīng)該避免對(duì)外部傳入的對(duì)象的修改。

下面代碼的 selectNode 方法修改了由外部傳入的 datasource 對(duì)象。如果 datasource 用在其它場(chǎng)合(如另一個(gè) Tree 實(shí)例)下,會(huì)造成狀態(tài)的混亂。

javascriptfunction Tree(datasource) {
    this.datasource = datasource;
}

Tree.prototype.selectNode = function (id) {
    // 從datasource中找出節(jié)點(diǎn)對(duì)象
    var node = this.findNode(id);
    if (node) {
        node.selected = true;
        this.flushView();
    }
};

對(duì)于此類場(chǎng)景,需要使用額外的對(duì)象來(lái)維護(hù),使用由自身控制,不與外部產(chǎn)生任何交互的 selectedNodeIndex 對(duì)象來(lái)維護(hù)節(jié)點(diǎn)的選中狀態(tài),不對(duì) datasource 作任何修改。

javascriptfunction Tree(datasource) {
    this.datasource = datasource;
    this.selectedNodeIndex = {};
}

Tree.prototype.selectNode = function (id) {
    // 從datasource中找出節(jié)點(diǎn)對(duì)象
    var node = this.findNode(id);
    if (node) {
        this.selectedNodeIndex[id] = true;
        this.flushView();
    }
};

除此之外,也可以通過(guò) deepClone 等手段將自身維護(hù)的對(duì)象與外部傳入的分離,保證不會(huì)相互影響。

[建議] 具備強(qiáng)類型的設(shè)計(jì)。

解釋:

如果一個(gè)屬性被設(shè)計(jì)為 boolean 類型,則不要使用 1 / 0 作為其值。對(duì)于標(biāo)識(shí)性的屬性,如對(duì)代碼體積有嚴(yán)格要求,可以從一開(kāi)始就設(shè)計(jì)為 number 類型且將 0 作為否定值。

從 DOM 中取出的值通常為 string 類型,如果有對(duì)象或函數(shù)的接收類型為 number 類型,提前作好轉(zhuǎn)換,而不是期望對(duì)象、函數(shù)可以處理多類型的值。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/87682.html

相關(guān)文章

  • JavaScript 編碼規(guī)范

    摘要:這樣的變量增加了代碼量,并且混淆讀者。錯(cuò)誤代碼示例變量雖然聲明了,但沒(méi)被使用持續(xù)更新 JavaScript 編碼規(guī)范 一、命名規(guī)范 1. 變量 命名方法:小駝峰式命名法(由小寫(xiě)字母開(kāi)始,后續(xù)每個(gè)單詞首字母都大寫(xiě)) 命名建議:語(yǔ)義化的名詞 特殊:布爾值變量建議添加符合其含義的前綴動(dòng)詞 is:是否 can:能不能 has:有沒(méi)有 示例: // 頁(yè)面標(biāo)題 let pageT...

    wenshi11019 評(píng)論0 收藏0
  • 在 React-CRA 應(yīng)用中配合 VSCode 使用 ESLint 實(shí)踐前端代碼規(guī)范

    摘要:編碼規(guī)范是獨(dú)角獸公司內(nèi)部的編碼規(guī)范,該項(xiàng)目是上很受歡迎的一個(gè)開(kāi)源項(xiàng)目,在前端開(kāi)發(fā)中使用廣泛,本文的配置規(guī)則就是以編碼規(guī)范和編碼規(guī)范作為基礎(chǔ)的。 更新時(shí)間:2019-01-22React.js create-react-app 項(xiàng)目 + VSCode 編輯器 + ESLint 代碼檢查工具 + Airbnb 編碼規(guī)范 前言 為什么要使用 ESLint 在項(xiàng)目開(kāi)發(fā)過(guò)程中,編寫(xiě)符合團(tuán)隊(duì)編碼規(guī)...

    Hujiawei 評(píng)論0 收藏0
  • HTML編碼規(guī)范

    摘要:當(dāng)然我們還可以引入框架,這些框架一般都自帶模板處理引擎,比如等語(yǔ)義化命名和語(yǔ)義化標(biāo)簽我們盡量多采用語(yǔ)義化來(lái)命名,并且采用語(yǔ)義化標(biāo)簽來(lái)書(shū)寫(xiě)代碼,多用中新增的標(biāo)簽來(lái)書(shū)寫(xiě)。 1.黃金法則(Golden rule) 不管有多少人參與同一個(gè)項(xiàng)目,一定要確保每一行代碼都像是同一個(gè)人編寫(xiě)的。 Every line of code should appear to be written by a si...

    nifhlheimr 評(píng)論0 收藏0
  • 編碼規(guī)范-html.md

    摘要:寫(xiě)在前面對(duì)于不同的編程語(yǔ)言來(lái)說(shuō),具體的編碼規(guī)范各不相同,但是其宗旨都是一致的,就是保證代碼在高質(zhì)量完成需求的同時(shí)具備良好的可讀性可維護(hù)性。減少標(biāo)簽的數(shù)量編寫(xiě)代碼時(shí),盡量避免多余的父元素。 寫(xiě)在前面 對(duì)于不同的編程語(yǔ)言來(lái)說(shuō),具體的編碼規(guī)范各不相同,但是其宗旨都是一致的,就是保證代碼在高質(zhì)量完成需求的同時(shí)具備良好的可讀性、可維護(hù)性。 本文大部分內(nèi)容來(lái)自網(wǎng)上,僅供個(gè)人參考學(xué)習(xí)! 網(wǎng)絡(luò)上的知...

    tomlingtm 評(píng)論0 收藏0
  • 編碼規(guī)范 —— 編寫(xiě)靈活、穩(wěn)定、高質(zhì)量的 HTML 和 CSS 代碼的規(guī)范

    摘要:用兩個(gè)空格代替制表符這是唯一能保證在所有環(huán)境下獲得一致展現(xiàn)的方法。編輯器配置將你的編輯器按照下面的配置進(jìn)行設(shè)置,以免常見(jiàn)的代碼不一致和差異用兩個(gè)空格代替制表符保存文件時(shí)刪除尾部的空白符設(shè)置文件編碼為在文件結(jié)尾添加一個(gè)空白行。 黃金定律 永遠(yuǎn)遵循同一套編碼規(guī)范 - 可以是這里列出的,也可以是你自己總結(jié)的。如果發(fā)現(xiàn)規(guī)范中有任何錯(cuò)誤,敬請(qǐng)指正。 HTML 語(yǔ)法 用兩個(gè)空格代替制表符 (ta...

    Karuru 評(píng)論0 收藏0
  • 編寫(xiě)靈活、穩(wěn)定、高質(zhì)量的HTML代碼的規(guī)范

    摘要:六字符編碼通過(guò)明確聲明字符編碼,能夠確保瀏覽器快速并容易的判斷頁(yè)面內(nèi)容的渲染方式。十一減少標(biāo)簽的數(shù)量編寫(xiě)代碼時(shí),盡量避免多余的父元素。未完待續(xù)編寫(xiě)靈活穩(wěn)定高質(zhì)量的代碼的規(guī)范閱讀更多 一、唯一定律 無(wú)論有多少人共同參與同一項(xiàng)目,一定要確保每一行代碼都像是唯一個(gè)人編寫(xiě)的。 二、HTML 2.1 語(yǔ)法 (1)用兩個(gè)空格來(lái)代替制表符(tab) -- 這是唯一能保證在所有環(huán)境下獲得一致展現(xiàn)的方法...

    anquan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<