前端开发规范文档(html,css,js)
首先吐槽一句,本來想上傳word文檔的,可是發(fā)現(xiàn)博客不能上傳word文檔,這就很尷尬了。
首先聲明該規(guī)范不是本人寫的,網(wǎng)上搜前端規(guī)范發(fā)現(xiàn)這個(gè)很詳細(xì)就先復(fù)制下來做筆記,當(dāng)然不可能啥都按規(guī)范來,每個(gè)公司的規(guī)范都不一樣..僅供參考
?
前端開發(fā)規(guī)范文檔
?
Html規(guī)范
1 代碼風(fēng)格
1.1 縮進(jìn)
**【強(qiáng)制】**使用?4?個(gè)空格作為一個(gè)縮進(jìn)層級,不允許使用?2?個(gè)空格或?tab?字符;
2 屬性
2.1 屬性引號
**【強(qiáng)制】**對于屬性的定義使用雙引號,不允許使用單引號,不允許不使用引號;
示例:
<!-- Not so great -->
<img class='avatar' src="./img/avatar.png" alt='avatar'>
?
<!-- Better -->
<img class="avatar" src="./img/avatar.png" alt="avatar">
2.2 屬性大小寫
**【強(qiáng)制】**屬性名應(yīng)該小寫,不允許大寫或大小寫混合;
示例:
<!-- Not so great -->
<table cellSpacing="0">...</table>
?
<!-- Better -->
<table cellspacing="0">...</table>
2.3 屬性布爾值
**【建議】**布爾類型的屬性,建議不添加屬性值,至少同一項(xiàng)目要保持一致;
示例:
<input type="text" disabled>
<input type="checkbox" checked>
2.4 屬性聲明順序
**【建議】**HTML 屬性建議盡量按照以下給出的順序依次排列,確保代碼的易讀性。
- class
- id,?name
- data-*
- src,?for,?type,?href
- title,?alt
- aria-*,?role
class 用于標(biāo)識高度可復(fù)用組件,因此應(yīng)該排在首位。id 用于標(biāo)識具體組件,應(yīng)當(dāng)謹(jǐn)慎使用(例如,頁面內(nèi)的書簽),建議預(yù)留更多的id命名給技術(shù),因此排在第二位。
<a class="..." id="..." data-modal="toggle" href="#">Example link</a>
?
<input class="form-control" type="text">
?
<img src="..." alt="...">
2.5 自定義屬性
**【建議】**使用自定義屬性作為JS的hook,建議以data-為前綴;
示例:
<input data-role="getPic" type="button">
2.6 鏈接屬性
**【強(qiáng)制】**禁止?a?標(biāo)簽的?href?取值為空或不寫?href?屬性,重構(gòu)時(shí)默認(rèn)可用?#?代替;
如果不需要使用鏈接功能,請不要使用不帶?href?的?a?標(biāo)簽,既不符合標(biāo)簽的語義,也可能會產(chǎn)生未知的兼容性問題;
示例:
<!-- Not so great -->
<a href="" title="title">歡聚時(shí)代</a>
<a class="xxx">歡聚時(shí)代</a>
?
<!-- Better -->
<a href="#" title="title">歡聚時(shí)代</a>
[?]
3 標(biāo)簽
3.1 標(biāo)簽大小寫
**【強(qiáng)制】**標(biāo)簽名應(yīng)該小寫,不允許大寫或大小寫混合;
示例:
<!-- Not so great -->
<DIV clsss="xxx">...</DIV>
?
<!-- Better -->
<div clsss="xxx">...</div>
3.2 標(biāo)簽自閉合
**【建議】**對于無需自閉合的標(biāo)簽,建議不自閉合,至少同一項(xiàng)目要保持一致;
常見無需自閉合標(biāo)簽有input、img、br、hr等
示例:
<input type="checkbox" value="1">
3.3 標(biāo)簽嵌套
**【強(qiáng)制】**標(biāo)簽使用必須符合標(biāo)簽嵌套規(guī)則;
例如:內(nèi)聯(lián)元素不能嵌套塊元素,<p>元素和<h1~6>元素不能嵌套塊元素等,詳見?Allowed nesting of elements in HTML 4 Strict (and XHTML 1.0 Strict)?與?HTML5 Content models;
**【建議】**實(shí)用為王,盡量遵循 HTML 標(biāo)準(zhǔn)和語義,但是不要以犧牲實(shí)用性為代價(jià)。任何時(shí)候都要盡量使用最少的標(biāo)簽并保持最小的復(fù)雜度。
<!-- Not so great -->
<span class="avatar">
? <img src="...">
</span>
?
<!-- Better -->
<img class="avatar" src="...">
3.4 避免過時(shí)標(biāo)簽
**【強(qiáng)制】**不允許使用過時(shí)的舊標(biāo)簽,請使用新標(biāo)簽或者CSS代替:
- acronym?→?abbr
- applet?→?object
- b?→?strong
- dir?→?ul
- strike?→?del
- basefont
- big
- center
- font
- isindex
- tt
- u
請參詳:http://www.w3schools.com/tags/
[?]
4 head設(shè)定
4.1 doctype
**【強(qiáng)制】**doctype使用 HTML5 的 doctype 來啟用標(biāo)準(zhǔn)模式。
其中?doctype?建議使用大寫的 DOCTYPE;?關(guān)于doctype該使用大寫還是小寫的討論
示例:
<!DOCTYPE html>
4.2 頁面編碼
**【強(qiáng)制】**頁面必須明確指定字符編碼,讓瀏覽器快速確定適合網(wǎng)頁內(nèi)容的渲染方式。指定字符編碼的 meta 必須是 head 的第一個(gè)直接子元素。建議使用無 BOM 的 UTF-8 編碼;
示例:
<meta charset="UTF-8">
4.3 兼容模式
**【建議】**PC端啟用 IE Edge 模式,并針對360瀏覽器啟用webkit渲染模式;
示例:
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="renderer" content="webkit">
4.4 引入CSS
**【強(qiáng)制】**引入 CSS 時(shí)必須指明 rel="stylesheet";
建議在 head 中引入頁面需要的所有 CSS 資源,因?yàn)樵陧撁驿秩镜倪^程中,新的CSS可能導(dǎo)致元素的樣式重新計(jì)算和繪制,頁面閃爍;
示例:
<link rel="stylesheet" src="global.css">
4.5 引入JavaScript
**【建議】**JavaScript應(yīng)當(dāng)放在頁面尾部;出于性能方面的考慮,如非必要,請遵守此條建議;
示例:
<body>
??? <!-- a lot of elements -->
??? <script src="main.js"></script>
</body>
4.6 favicon
**【強(qiáng)制】**保證?favicon?可訪問;
在未指定 favicon 時(shí),大多數(shù)瀏覽器會請求 Web Server 根目錄下的 favicon.ico 。為了保證favicon可訪問,避免404,必須遵循以下兩種方法之一:
示例:
<link type="image/x-icon" rel="shortcut icon" href="path/to/favicon.ico">
附:工作流中默認(rèn)的PC端head設(shè)定
<!DOCTYPE html>
<html>
<head>
??? <meta charset="UTF-8">
??? <meta http-equiv="X-UA-Compatible" content="IE=edge">
??? <meta name="renderer" content="webkit">
??? <meta name="viewport" content="width=device-width, initial-scale=1">
??? <meta name="Keywords" content="多玩游戲">
??? <meta name="description" content="多玩游戲">
??? <!-- a lot of elements -->
</head>
<body>
??? <!-- a lot of elements -->
</body>
</html>
附:工作流中默認(rèn)的移動端head設(shè)定
<!DOCTYPE html>
<html>
<head>
??? <meta charset="UTF-8">
??? <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
??? <meta name="format-detection" content="telephone=no,address=no,email=no">
??? <meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">
??? <meta name="keywords" content="多玩游戲">
??? <meta name="description" content="多玩游戲">
??? <!-- a lot of elements -->
</head>
<body>
??? <!-- a lot of elements -->
</body>
</html>
注意:當(dāng)該項(xiàng)目有相關(guān)的app在app store中,設(shè)置metaapple-itunes-app,如上面最后一條,并填上對應(yīng)的app-id。詳細(xì)請看:Promoting Apps with Smart App Banners
更詳細(xì)的meta屬性設(shè)置可以參詳:https://github.com/hzlzh/cool-head
[?]
5 圖片
**【強(qiáng)制】**禁止?img?的?src?取值為空;延遲加載的圖片也要增加默認(rèn)的?src;
src?取值為空,會導(dǎo)致部分瀏覽器重新加載一次當(dāng)前頁面,參考?Yahoo performance rules
**【建議】**為重要圖片添加?alt?屬性;
可以提高圖片加載失敗時(shí)的用戶體驗(yàn)。
**【建議】**添加?width?和?height?屬性,以避免頁面抖動;
**【建議】**有下載需求或者預(yù)期會靈活變動的圖片采用?img?標(biāo)簽實(shí)現(xiàn),無下載需求的圖片采用 CSS 背景圖實(shí)現(xiàn);
- 用戶頭像、用戶產(chǎn)生的圖片等有潛在下載需求的圖片,以 img 形式實(shí)現(xiàn),能方便用戶下載;
- 無下載需求的圖片,比如:icon、背景、代碼使用的圖片等,盡可能采用 css 背景圖實(shí)現(xiàn)。
[?]
6 表單
**【強(qiáng)制】**有文本標(biāo)題的控件必須使用?label?標(biāo)簽將其與其標(biāo)題相關(guān)聯(lián);
有兩種方式:
推薦使用第一種,減少不必要的 id。如果 DOM 結(jié)構(gòu)不允許直接嵌套,則應(yīng)使用第二種。
示例:
<label><input name="confirm" type="checkbox" value="on"> 我已確認(rèn)上述條款</label>
?
<label for="username">用戶名:</label> <input id="username" name="username" type="checkbox">
**【建議】**盡量不要使用按鈕類元素的 name 屬性;
由于瀏覽器兼容性問題,使用按鈕的 name 屬性會帶來許多難以發(fā)現(xiàn)的問題。具體情況可參考?此文;
**【建議】**在針對移動設(shè)備開發(fā)的頁面時(shí),根據(jù)內(nèi)容類型指定輸入框的?type?屬性;
根據(jù)內(nèi)容類型指定輸入框類型,能獲得能友好的輸入體驗(yàn)。
示例:
<input type="number" value="1">
[?]
7 注釋
【建議】對超過10行的頁面模塊進(jìn)行注釋, 以降低開發(fā)人員的嵌套成本和后期的維護(hù)成本。建議使用結(jié)尾注釋方式,例如:
當(dāng)模塊代碼量較少時(shí),可以省略?start。
<!-- 文章內(nèi)容 start -->
<section id="post">
?? do some things...
</section>
<!-- 文章內(nèi)容 end -->
或者標(biāo)注模塊的class或者id:
<!-- #post start -->
<section id="post">
??? do some things...
</section>
<!-- #post end -->
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
CSS規(guī)范
1 命名規(guī)范
該命名規(guī)范主要解決以下問題:
- 從類名可以清晰區(qū)分出其功能作用,使頁面結(jié)構(gòu)清晰【命名空間、標(biāo)識符】;
- 以組件、模塊的思想去寫一個(gè)區(qū)塊的結(jié)構(gòu),強(qiáng)化結(jié)構(gòu)的模塊化【BEM模塊思想、基類、子類、擴(kuò)展類】;
- 減少多人合作、項(xiàng)目耦合等情況下的命名沖突【命名空間】;
1.1 命名思想
【強(qiáng)制】?區(qū)塊、模塊、組件等一個(gè)整個(gè)的結(jié)構(gòu)遵循BEM命名思想;
當(dāng)你能確定組件內(nèi)最后一級的結(jié)構(gòu)不會再發(fā)生變化時(shí),最后一級可省略類名,使用兩層嵌套;
- .block?代表了更高級別的抽象或組件;
- .block__element?代表.block的后代,用于形成一個(gè)完整的.block的整體;
- .is-?|?.has-?|?.ext-?代表.block的修飾符,不使用雙中劃線--。
相關(guān)鏈接:
- BEM—源自Yandex的CSS 命名方法論
- BEM官網(wǎng)
1.2 多單詞連接
【強(qiáng)制】?(所有的)多個(gè)單詞使用小駝峰式命名,不允許使用中劃線或者下劃線連接多個(gè)單詞;
多個(gè)單詞使用小駝峰式命名,以提升名稱的識別度,例如:newsList;
1.3 命名空間
【強(qiáng)制】?在合適的地方使用命名空間;
- 布局:以g為命名空間,例如:.g-wrap?、.g-header、.g-content、.g-mian、.g-aside?等;
- 工具:以u為命名空間,表示不耦合業(yè)務(wù)邏輯的、可復(fù)用的的工具,例如:.u-clearfix、.u-ellipsis?等;
- 狀態(tài):以is為命名空間,表示動態(tài)的、具有交互性質(zhì)的狀態(tài),例如:.is-open、.is-active、.is-selected?等;
- 組件:以ui或者mod為命名空間,表示可復(fù)用、移植的組件模塊,例如:.ui-slider、.mod-dropMenu等;
- 擴(kuò)展:以ext為命名空間,表示對組件基類的視覺形態(tài)的擴(kuò)展,例如:.ext-cover、、.ext-alignLeft?等;
狀態(tài)類或擴(kuò)展類一般出現(xiàn)在組件的父級節(jié)點(diǎn),并且不允許單獨(dú)使用。舉個(gè)例子,同一個(gè)頁面有可能會在不同的地方都會使用is-active,并且每個(gè)is-active所操縱的節(jié)點(diǎn)的是不同的,所以要使用.ui-userCard.is-active?或?.ui-userCard .is-active來定義
1.4 圖片命名
- 圖標(biāo):以ico作為命名空間,例如:.ico-close?等;
- LOGO:以logo作為命名空間,例如:.logo-duowan?等;
- 內(nèi)容圖像:以img作為命名空間,例如:.img-userGuide?等;
1.5 區(qū)塊命名
【推薦】?一般區(qū)塊都可以劃分為頭部、身體和尾部,因此建議給你的區(qū)塊分別以?hd、bd、ft來劃分;
示例:
.ui-card__hd {
??? margin: 0;
}
?
.ui-card__bd {
??? margin: 0;
}
?
.ui-card__ft {
??? margin: 0;
}
附:命名示例
?
[?]
2 代碼風(fēng)格
2.1 縮進(jìn)
【強(qiáng)制】?使用?4?個(gè)空格做為一個(gè)縮進(jìn)層級,不允許使用?2?個(gè)空格 或?tab?字符;
示例:
/* Not so great */
.selector {
? margin: 0;
}
?
/* Better */
.selector {
??? margin: 0;
}
2.2 空格
【強(qiáng)制】?選擇器 與?{之間必須包含空格;
示例:
/* Not so great */
.selector{
}
?
/* Better */
.selector {
}
【強(qiáng)制】?>、+、~?選擇器的兩邊各保留一個(gè)空格;
示例:
/* Not so great */
main>nav {
??? padding: 10px;
}
label+input {
??? margin-left: 5px;
}
input:checked~button {
??? background-color: #69C;
}
?
/* Better */
main > nav {
??? padding: 10px;
}
label + input {
??? margin-left: 5px;
}
input:checked ~ button {
??? background-color: #69C;
}
【強(qiáng)制】?屬性名 與之后的?:?之間不允許包含空格,?:與 屬性值 之間必須包含空格;
示例:
/* Not so great */
margin :0;
?
/* Better */
margin: 0;
【強(qiáng)制】?列表型屬性值 書寫在單行時(shí),,后必須跟一個(gè)空格;
示例:
/* Not so great */
font-family: Arial,sans-serif;
box-shadow: 0 0 2px rgba(0,128,0,.3);
?
/* Better */
font-family: Arial, sans-serif;
box-shadow: 0 0 2px rgba(0, 128, 0, .3);
2.3 選擇器
【強(qiáng)制】?當(dāng)一個(gè) rule 包含多個(gè) selector 時(shí),每個(gè)選擇器聲明必須獨(dú)占一行;
示例:
/* Not so great */
.post, .page, .comment {
??? line-height: 1.5;
}
?
/* Better */
.post,
.page,
.comment {
??? line-height: 1.5;
}
2.4 屬性
【強(qiáng)制】?屬性定義必須另起一行;
示例:
/* Not so great */
.selector { margin: 0; padding: 0;}
?
/* Better */
.selector {
??? margin: 0;
??? padding: 0;
}
【強(qiáng)制】?屬性定義后必須以分號結(jié)尾;
示例:
/* Not so great */
.selector {
??? margin: 0
}
?
/* Better */
.selector {
??? margin: 0;
}
[?]
3. 通用
3.1 選擇器
【強(qiáng)制】?如無必要,不得為id、class選擇器添加?類型選擇器?進(jìn)行限定;
在性能和維護(hù)性上,都有一定的影響。
示例:
/* Not so great */
dialog#error,
p.danger-message {
??? font-color: #c00;
}
?
/* Better */
#error,
.danger-message {
??? font-color: #c00;
}
【建議】?選擇器的嵌套層級應(yīng)該不大于?3?級,位置靠后的限定條件應(yīng)可能精確;
在性能和維護(hù)性上,都有一定的影響。
示例:
/* Not so great */
.comment ul li a span {}
#top-hero .hero-avatar li.avatar .pic em {}
?
/* Better */
.comment .date {}
#top-hero .pic em {}
3.2 屬性
3.2.1 屬性書寫順序
【建議】?同一 rule set 下的屬性在書寫時(shí),應(yīng)按功能進(jìn)行分組,并以 Formatting Model > Box Model > Typographic > Visual 的順序書寫,以提高代碼的可讀性。
Positioning 處在第一位,因?yàn)樗梢允挂粋€(gè)元素脫離正常文本流,并且覆蓋盒模型相關(guān)的樣式。盒模型緊跟其后,因?yàn)樗麤Q定了一個(gè)組件的大小和位置。其他屬性只在組件 內(nèi)部 起作用或者不會對前面兩種情況的結(jié)果產(chǎn)生影響,所以他們排在后面。
詳情資料?Twitter的strictPropertyOrder
3.2.2 屬性引號
【強(qiáng)制】?屬性選擇器中的值必須用雙引號包圍。不允許使用單引號,不允許不使用引號。
示例:
/* Not so great */
article[character='juliet'] {
??? voice-family: "Vivien Leigh", victoria, female
}
?
/* Better */
article[character="juliet"] {
??? voice-family: "Vivien Leigh", victoria, female
}
3.2.3 屬性簡寫
簡寫形式可以在一定程度上壓縮樣式,但并不意味著你可以對所有可以簡寫的屬性聲明都使用簡寫。過度使用簡寫形式的屬性聲明會導(dǎo)致代碼混亂,會對屬性值帶來不必要的覆蓋從而引起意外的副作用,并且不能充分利用CSS的繼承。常見的濫用簡寫屬性聲明的情況如下:
- padding
- margin
- font
- background
- border
- border-radius
如果你只需定義其中的一兩個(gè)屬性,而不是全部,盡量分開來寫:
/* Better */
.selector {
??? margin-bottom: 10px;
??? background-color: red;
??? background-image: url(image.jpg);
??? border-top-left-radius: 3px;
??? border-top-right-radius: 3px;
}
?
/* Not so great */
.selector {
??? margin: 0 0 10px;
??? background: red;
??? background: url(image.jpg);
??? border-radius: 3px 3px 0 0;
}
[?]
4 值與單位
4.1 文本
【強(qiáng)制】?文本內(nèi)容必須用雙引號包圍,不允許使用單引號;
文本類型的內(nèi)容可能在選擇器、屬性值等內(nèi)容中。
示例:
/* Not so great */
html[lang|=zh] q:before {
??? font-family: 'Microsoft YaHei', sans-serif;
??? content: '“';
}
?
/* Better */
html[lang|="zh"] q:after {
??? font-family: "Microsoft YaHei", sans-serif;
??? content: "“";
}
4.2 數(shù)值
【強(qiáng)制】?當(dāng)數(shù)值為?0 - 1?之間的小數(shù)時(shí),省略整數(shù)部分的?0;
示例:
/* Not so great */
.selector {
??? opacity: 0.8;
}
?
/* Better */
.selector {
??? opacity: .8;
}
4.3 長度
【強(qiáng)制】?長度為?0?時(shí)須省略單位 (也只有長度單位可省);
示例:
/* Not so great */
.selector {
??? margin: 0px 10px;
}
?
/* Better */
.selector {
??? margin: 0 10px;
}
4.4 url()
【強(qiáng)制】?url() 函數(shù)中的路徑不加引號;
示例:
/* Not so great */
.selector {
??? background: url("bg.png");
}
?
/* Better */
.selector {
??? background: url(bg.png);
}
4.5 顏色
【強(qiáng)制】?RGB顏色值必須使用十六進(jìn)制記號形式?#rrggbb,不允許使用?rgb(),帶有alpha的顏色信息可以使用?rgba();顏色值不允許使用命名色值;
示例:
/* Not so great */
.selector {
??? box-shadow: 0 0 2px rgba(0,128,0,.3);
??? border-color: rgb(0, 128, 0);
??? color: gray;
}
?
/* Better */
.selector {
??? box-shadow: 0 0 2px rgba(0, 128, 0, .3);
??? border-color: #008000;
??? color: #999;
}
【建議】?顏色值中的英文字符采用小寫,至少要保證同一項(xiàng)目內(nèi)一致;
示例:
/* Not so great */
.selector {
??? color: #0073AA;
}
?
/* Better */
.selector {
??? color: #0073aa;
}
4.6 2D位置
【強(qiáng)制】?必須同時(shí)給出水平和垂直方向的位置;
2D 位置初始值為 0% 0%,但在只有一個(gè)方向的值時(shí),另一個(gè)方向的值會被解析為 center。為避免理解上的困擾,應(yīng)同時(shí)給出兩個(gè)方向的值。?background-position屬性值的定義
示例:
/* Not so great */
.selector {
??? background-position: top; /* 50% 0% */
}
?
/* Better */
.selector {
??? background-position: center top; /* 50% 0% */
}
[?]
5. 文本排版
5.1 字體族
【強(qiáng)制】?font-family?屬性中的字體族名稱應(yīng)使用字體的英文?Family Name,其中如有空格,須放置在引號中;
常見的字體族名稱如下:
| 字體 | 操作系統(tǒng) | Family Name |
| 宋體 (中易宋體) | Windows | SimSun |
| 黑體 (中易黑體) | Windows | SimHei |
| 微軟雅黑 | Windows | Microsoft YaHei |
| 微軟正黑 | Windows | Microsoft JhengHei |
| 華文黑體 | Mac/iOS | STHeiti |
| 冬青黑體 | Mac/iOS | Hiragino Sans GB |
| 文泉驛正黑 | Linux | WenQuanYi Zen Hei |
| 文泉驛微米黑 | Linux | WenQuanYi Micro Hei |
【強(qiáng)制】?font-family?應(yīng)當(dāng)遵循以下順序:
詳細(xì)說明可參考?如何保證網(wǎng)頁的字體在各平臺都盡量顯示為最高質(zhì)量的黑體?
【強(qiáng)制】?font-family?不區(qū)分大小寫,但在同一個(gè)項(xiàng)目中,同樣的 Family Name 大小寫必須統(tǒng)一;
示例:
/* Not so great */
body {
??? font-family: arial, sans-serif;
}
?
h1 {
??? font-family: Arial, "Microsoft YaHei", sans-serif;
}
?
/* Better */
body {
??? font-family: Arial, sans-serif;
}
?
h1 {
??? font-family: Arial, "Microsoft YaHei", sans-serif;
}
5.2 字重
【強(qiáng)制】?font-weight?屬性必須使用數(shù)值方式描述;
CSS 的字重分 100 – 900 共九檔,但目前受字體本身質(zhì)量和瀏覽器的限制,實(shí)際上支持 400 和 700 兩檔,分別等價(jià)于關(guān)鍵詞 normal 和 bold。
瀏覽器本身使用一系列啟發(fā)式規(guī)則來進(jìn)行匹配,在 >700 時(shí)一般匹配字體的 Regular 字重,>=700 時(shí)匹配 Bold 字重。
但已有瀏覽器開始支持 =600 時(shí)匹配 Semibold 字重 (見此表),故使用數(shù)值描述增加了靈活性,也更簡短。
示例:
/* Not so great */
.selector {
??? font-weight: bold;
}
?
/* Better */
.selector {
??? font-weight: 700;
}
[?]
6 變換與動畫
【強(qiáng)制】?使用?transition?定義屬性時(shí)應(yīng)遵循以下順序:
transition:[ transition-property ] || [ transition-duration ] || [ transition-timing-function ] || [ transition-delay ]
如果順序錯(cuò)亂,在某些安卓瀏覽器上會讓動畫失效。
示例:
/* Not so great */
.selector {
??? transition: color .2s 0 ease-in;
}
?
/* Better */
.selector {
??? transition: color .2s ease-in 0;
}
【建議】?盡可能在瀏覽器能高效實(shí)現(xiàn)的屬性上添加過渡和動畫:
在可能的情況下應(yīng)選擇這樣四種變換:
- transform: translate(npx, npx);
- transform: scale(n);
- transform: rotate(ndeg);
- opacity: 0..1;
詳見?High Performance Animations
[?]
7 媒體查詢
【強(qiáng)制】?Media Query?不得單獨(dú)編排,必須與相關(guān)的規(guī)則一起定義;
不要將他們一起放到一個(gè)獨(dú)立的樣式文件中,或者丟在文檔的最底部,這樣做只會讓大家以后更容易忘記他們。
示例:
/* Not so great */
/* header styles */
/* main styles */
/* footer styles */
?
@media (...) {
??? /* header styles */
??? /* main styles */
??? /* footer styles */
}
?
/* Better */
/* header styles */
@media (...) {
??? /* header styles */
}
?
/* main styles */
@media (...) {
??? /* main styles */
}
?
/* footer styles */
@media (...) {
??? /* footer styles */
}
8 兼容性
8.1 屬性前綴
【強(qiáng)制】?帶私有前綴的屬性由長到短排列,按冒號位置對齊;
標(biāo)準(zhǔn)屬性放在最后,按冒號對齊方便閱讀與編輯。
示例:
/* Not so great */
.selector {
??? transition: color .2s ease-in 0;
??? -webkit-transition: color .2s ease-in 0;
??? -moz-transition: color .2s ease-in 0;
}
?
/* Better */
.selector {
??? -webkit-transition: color .2s ease-in 0;
?????? -moz-transition: color .2s ease-in 0;
??????????? transition: color .2s ease-in 0;
}
8.2 hack
【建議】?如果有其他解決方案,請不要使用hack;
[?]
9 代碼注釋
代碼是由人編寫并維護(hù)的。請確保你的代碼能夠自描述、注釋良好并且易于他人理解。好的代碼注釋能夠傳達(dá)上下文關(guān)系和代碼目的。不要簡單地重申組件或 class 名稱。
9.1 單行注釋
【強(qiáng)制】?星號與內(nèi)容之間必須保留一個(gè)空格;
示例:
/* 新聞中心表格隔行變色 */
9.2 多行注釋
【強(qiáng)制】?星號要一列對齊,星號與內(nèi)容之間必須保留一個(gè)空格;
示例:
/**
?* Sometimes you need to include optional context for the entire component. Do that up here if it's important enough.
?*/
9.3 文件注釋
【強(qiáng)制】?文件頂部必須包含文件注釋,用?@file?標(biāo)識文件說明。星號要一列對齊,星號與內(nèi)容之間必須保留一個(gè)空格,標(biāo)識符冒號與內(nèi)容之間必須保留一個(gè)空格;
/**
?* @file: 文件概要描述
?* @author: author-name(mail-name@domain.com)
?*????????? author-name2(mail-name2@domain.com)
?* @update: 2015-04-29 00:02:45
?*/
- @update為可選項(xiàng),建議每次改動都更新一下;
- 當(dāng)該業(yè)務(wù)項(xiàng)目主要由固定的一個(gè)或多個(gè)人負(fù)責(zé)時(shí),需要添加@author標(biāo)識,一方面是尊重勞動成果,另一方面方便在需要時(shí)快速定位責(zé)任人;
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
Js規(guī)范
1 前言
本文檔的目標(biāo)是使JavaScript代碼風(fēng)格保持一致,容易被理解和被維護(hù)。雖然本文檔是針對JavaScript設(shè)計(jì)的,但是在使用各種JavaScript的預(yù)編譯語言時(shí)(如TypeScript等)時(shí),適用的部分也應(yīng)盡量遵循本文檔的約定。
2 代碼風(fēng)格
2.1 文件
【建議】?JavaScript?文件使用無?BOM?的?UTF-8?編碼。
解釋:
UTF-8 編碼具有更廣泛的適應(yīng)性。BOM 在使用程序或工具處理文件時(shí)可能造成不必要的干擾。
【建議】?在文件結(jié)尾處,保留一個(gè)空行。
2.2 結(jié)構(gòu)**【強(qiáng)制】**
2.2.1 縮進(jìn)
【強(qiáng)制】?使用?4?個(gè)空格做為一個(gè)縮進(jìn)層級,不允許使用?2?個(gè)空格 或?tab?字符。
【強(qiáng)制】?switch?下的?case?和?default?必須增加一個(gè)縮進(jìn)層級。
示例:
// 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)算符與操作對象之間不允許有空格。
示例:
var a = !arr.length; a++; a = b + c;【強(qiáng)制】?用作代碼塊起始的左花括號?{?前必須有一個(gè)空格。
示例:
// 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è)空格。
示例:
// good if (condition) { } ? while (condition) { } ? (function () { })(); ? // bad if(condition) { } ? while(condition) { } ? (function() { })();【強(qiáng)制】?在對象創(chuàng)建時(shí),屬性中的?:?之后必須有空格,:?之前不允許有空格。
示例:
// 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ù)名和?(?之間不允許有空格。
示例:
// good function funcName() { } ? var funcName = function funcName() { }; ? funcName(); ? // bad function funcName () { } ? var funcName = function funcName () { }; ? funcName ();【強(qiáng)制】?,?和?;?前不允許有空格。
示例:
// good callFunc(a, b); ? // bad callFunc(a , b) ;【強(qiáng)制】?在函數(shù)調(diào)用、函數(shù)聲明、括號表達(dá)式、屬性訪問、if / for / while / switch / catch?等語句中,()?和?[]內(nèi)緊貼括號部分不允許有空格。
示例:
// 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ù)組與對象,如果包含元素,{}?和?[]?內(nèi)緊貼括號部分不允許包含空格。
解釋:
聲明包含元素的數(shù)組與對象,只有當(dāng)內(nèi)部元素的形式較為簡單時(shí),才允許寫在一行。元素復(fù)雜的情況,還是應(yīng)該換行書寫。
示例:
// 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ú)立語句結(jié)束后必須換行。
【強(qiáng)制】?每行不得超過?120?個(gè)字符。
解釋:
超長的不可分割的代碼允許例外,比如復(fù)雜的正則表達(dá)式。長字符串不在例外之列。
【強(qiáng)制】?運(yùn)算符處換行時(shí),運(yùn)算符必須在新行的行首。
示例:
// 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)用、對象創(chuàng)建、數(shù)組創(chuàng)建、for語句等場景中,不允許在?,?或?;?前換行。
示例:
// 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 );【建議】?不同行為或邏輯的語句集,使用空行隔開,更易閱讀。
示例:
// 僅為按邏輯換行的示例,不代表setStyle的最優(yōu)實(shí)現(xiàn) function setStyle(element, property, value) { ??? if (element == null) { ??????? return; ??? } ? ??? element.style[property] = value; }【建議】?在語句的行長度超過?120?時(shí),根據(jù)邏輯條件合理縮進(jìn)。
示例:
// 較復(fù)雜的邏輯條件組合,將每個(gè)條件獨(dú)立一行,邏輯運(yùn)算符放置在行首進(jìn)行分隔,或?qū)⒉糠诌壿嫲催壿嫿M合進(jìn)行分隔。 // 建議最終將右括號 ) 與左大括號 { 放在獨(dú)立一行,保證與 if 內(nèi)語句塊能容易視覺辨識。 if (user.isAuthenticated() ??? && user.isInRole('admin') ??? && user.hasAuthority('add-admin') ??? || user.hasAuthority('delete-admin') ) { ??? // Code } ? // 按一定長度截?cái)嘧址?#xff0c;并使用 + 運(yùn)算符進(jìn)行連接。 // 分隔字符串盡量按語義進(jìn)行,如不要在一個(gè)完整的名詞中間斷開。 // 特別的,對于HTML片段的拼接,通過縮進(jìn),保持和HTML相同的結(jié)構(gòu)。 var html = '' // 此處用一個(gè)空字符串,以便整個(gè)HTML片段都在新行嚴(yán)格對齊 ??? + '<article>' ??? +???? '<h1>Title here</h1>' ??? +???? '<p>This is a paragraph</p>' ??? +???? '<footer>Complete</footer>' ??? + '</article>'; ? // 也可使用數(shù)組來進(jìn)行拼接,相對 + 更容易調(diào)整縮進(jìn)。 var html = [ ??? '<article>', ??????? '<h1>Title here</h1>', ??????? '<p>This is a paragraph</p>', ??????? '<footer>Complete</footer>', ??? '</article>' ]; html = html.join(''); ? // 當(dāng)參數(shù)過多時(shí),將每個(gè)參數(shù)獨(dú)立寫在一行上,并將結(jié)束的右括號 ) 獨(dú)立一行。 // 所有參數(shù)必須增加一個(gè)縮進(jìn)。 foo( ??? aVeryVeryLongArgument, ??? anotherVeryLongArgument, ??? callback ); ? // 也可以按邏輯對參數(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ù)或者對象初始化等作為參數(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)用較長時(shí)采用縮進(jìn)進(jìn)行調(diào)整。 $('#items') ??? .find('.selected') ??? .highlight() ??? .end(); ? // 三元運(yùn)算符由3部分組成,因此其換行應(yīng)當(dāng)根據(jù)每個(gè)部分的長度不同,形成不同的情況。 var result = thisIsAVeryVeryLongCondition ??? ? resultA : resultB; ? var result = condition ??? ? thisIsAVeryVeryLongResult ??? : resultB; ? // 數(shù)組和對象初始化的混用,嚴(yán)格按照每個(gè)對象的 { 和結(jié)束 } 在獨(dú)立一行的風(fēng)格書寫。 var array = [ ??? { ??????? // ... ??? }, ??? { ??????? // ... ??? } ];【建議】?對于?if...else...、try...catch...finally?等語句,推薦使用在?}?號后添加一個(gè)換行 的風(fēng)格,使代碼層次結(jié)構(gòu)更清晰,閱讀性更好。
示例:
if (condition) { ??? // some statements; } else { ??? // some statements; } ? try { ??? // some statements; } catch (ex) { ??? // some statements; }2.2.4 語句
【強(qiáng)制】?不得省略語句結(jié)束的分號。
【強(qiáng)制】?在?if / else / for / do / while?語句中,即使只有一行,也不得省略塊?{...}。
示例:
// good if (condition) { ??? callFunc(); } ? // bad if (condition) callFunc(); if (condition) ??? callFunc();【強(qiáng)制】?函數(shù)定義結(jié)束不允許添加分號。
示例:
// good function funcName() { } ? // bad function funcName() { }; ? // 如果是函數(shù)表達(dá)式,分號是不允許省略的。 var funcName = function () { };【強(qiáng)制】?IIFE?必須在函數(shù)表達(dá)式外添加?(,非?IIFE?不得在函數(shù)表達(dá)式外添加?(。
解釋:
IIFE = Immediately-Invoked Function Expression.
額外的 ( 能夠讓代碼在閱讀的一開始就能判斷函數(shù)是否立即被調(diào)用,進(jìn)而明白接下來代碼的用途。而不是一直拖到底部才恍然大悟。
示例:
// 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命名法。
示例:
var loadingModules = {};【強(qiáng)制】?常量?使用?全部字母大寫,單詞間下劃線分隔?的命名方式。
示例:
var HTML_ENTITY = {};【強(qiáng)制】?函數(shù)?使用?Camel命名法。
示例:
function stringFormat(source) { }【強(qiáng)制】?函數(shù)的?參數(shù)?使用?Camel命名法。
示例:
function hear(theBells) { }【強(qiáng)制】?類?使用?Pascal命名法。
示例:
function TextNode(options) { }【強(qiáng)制】?類的?方法 / 屬性?使用?Camel命名法。
示例:
function TextNode(value, engine) { ??? this.value = value; ??? this.engine = engine; } ? TextNode.prototype.clone = function () { ??? return this; };【強(qiáng)制】?枚舉變量?使用?Pascal命名法,枚舉的屬性?使用?全部字母大寫,單詞間下劃線分隔?的命名方式。
示例:
var TargetState = { ??? READING: 1, ??? READED: 2, ??? APPLIED: 3, ??? READY: 4 };【強(qiáng)制】?命名空間?使用?Camel命名法。
示例:
equipments.heavyWeapons = {};【強(qiáng)制】?由多個(gè)單詞組成的縮寫詞,在命名中,根據(jù)當(dāng)前命名法和出現(xiàn)的位置,所有字母的大小寫與首字母的大小寫保持一致。
示例:
function XMLParser() { } ? function insertHTML(element, html) { } ? var httpRequest = new HTTPRequest();【強(qiáng)制】?類名?使用?名詞。
示例:
function Engine(options) { }【建議】?函數(shù)名?使用?動賓短語。
示例:
function getStyle(element) { }【建議】?boolean?類型的變量使用?is?或?has?開頭。
示例:
var isReady = false; var hasMoreCommands = false;【建議】?Promise對象?用?動賓短語的進(jìn)行時(shí)?表達(dá)。
示例:
var loadingData = ajax.get('url'); loadingData.then(callback);2.4 注釋
2.4.1 單行注釋
【強(qiáng)制】?必須獨(dú)占一行。//?后跟一個(gè)空格,縮進(jìn)與下一行被注釋說明的代碼一致。
2.4.2 多行注釋
【建議】?避免使用?/*...*/?這樣的多行注釋。有多行注釋內(nèi)容時(shí),使用多個(gè)單行注釋。
2.4.3 文檔化注釋
【強(qiáng)制】?為了便于代碼閱讀和自文檔化,以下內(nèi)容必須包含以?/**...*/?形式的塊注釋中。
解釋:
【強(qiáng)制】?文檔注釋前必須空一行。
【建議】?自文檔化的文檔說明 what,而不是 how。
2.4.4 類型定義
【強(qiáng)制】?類型定義都是以{開始, 以}結(jié)束。
解釋:
常用類型如:{string}, {number}, {boolean}, {Object}, {Function}, {RegExp}, {Array}, {Date}。
類型不僅局限于內(nèi)置的類型,也可以是自定義的類型。比如定義了一個(gè)類 Developer,就可以使用它來定義一個(gè)參數(shù)和返回值的類型。
【強(qiáng)制】?對于基本類型 {string}, {number}, {boolean},首字母必須小寫。
| 類型定義 | 語法示例 | 解釋 |
| String | {string} | -- |
| Number | {number} | -- |
| Boolean | {boolean} | -- |
| Object | {Object} | -- |
| Function | {Function} | -- |
| RegExp | {RegExp} | -- |
| Array | {Array} | -- |
| Date | {Date} | -- |
| 單一類型集合 | {Array.<string>} | 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 | 變長參數(shù), ...為類型前綴 |
| 任意類型 | {*} | 任意類型 |
| 可選任意類型 | @param {*=} name | 可選參數(shù),類型不限 |
| 可變?nèi)我忸愋?/p> | @param {...*} args | 變長參數(shù),類型不限 |
2.4.5 文件注釋
【強(qiáng)制】?文件頂部必須包含文件注釋,用?@file?標(biāo)識文件說明。
示例:
/** * @file Describe the file */【建議】?文件注釋中可以用?@author?標(biāo)識開發(fā)者信息。
解釋:
開發(fā)者信息能夠體現(xiàn)開發(fā)人員對文件的貢獻(xiàn),并且能夠讓遇到問題或希望了解相關(guān)信息的人找到維護(hù)人。通常情況文件在被創(chuàng)建時(shí)標(biāo)識的是創(chuàng)建者。隨著項(xiàng)目的進(jìn)展,越來越多的人加入,參與這個(gè)文件的開發(fā),新的作者應(yīng)該被加入?@author?標(biāo)識。
@author?標(biāo)識具有多人時(shí),原則是按照?責(zé)任?進(jìn)行排序。通常的說就是如果有問題,就是找第一個(gè)人應(yīng)該比找第二個(gè)人有效。比如文件的創(chuàng)建者由于各種原因,模塊移交給了其他人或其他團(tuán)隊(duì),后來因?yàn)樾略鲂枨?#xff0c;其他人在新增代碼時(shí),添加?@author標(biāo)識應(yīng)該把自己的名字添加在創(chuàng)建人的前面。
@author?中的名字不允許被刪除。任何勞動成果都應(yīng)該被尊重。
業(yè)務(wù)項(xiàng)目中,一個(gè)文件可能被多人頻繁修改,并且每個(gè)人的維護(hù)時(shí)間都可能不會很長,不建議為文件增加?@author?標(biāo)識。通過版本控制系統(tǒng)追蹤變更,按業(yè)務(wù)邏輯單元確定模塊的維護(hù)責(zé)任人,通過文檔與wiki跟蹤和查詢,是更好的責(zé)任管理方式。
對于業(yè)務(wù)邏輯無關(guān)的技術(shù)型基礎(chǔ)項(xiàng)目,特別是開源的公共項(xiàng)目,應(yīng)使用?@author?標(biāo)識。
示例:
/** * @file Describe the file * @author author-name(mail-name@domain.com) *???????? author-name2(mail-name2@domain.com) */2.4.6 命名空間注釋
【建議】?命名空間使用?@namespace?標(biāo)識。
示例:
/** * @namespace */ var util = {};2.4.7 類注釋
【建議】?使用?@class?標(biāo)記類或構(gòu)造函數(shù)。
解釋:
對于使用對象?constructor?屬性來定義的構(gòu)造函數(shù),可以使用?@constructor?來標(biāo)記。
示例:
/** * 描述 * * @class */ function Developer() { ??? // constructor body }【建議】?使用?@extends?標(biāo)記類的繼承信息。
示例:
/** * 描述 * * @class * @extends Developer */ function Fronteer() { ??? Developer.call(this); ??? // constructor body } util.inherits(Fronteer, Developer);【強(qiáng)制】?使用包裝方式擴(kuò)展類成員時(shí), 必須通過?@lends?進(jìn)行重新指向。
解釋:
沒有?@lends?標(biāo)記將無法為該類生成包含擴(kuò)展類成員的文檔。
示例:
/** * 類描述 * * @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è),指明可訪問性。
解釋:
生成的文檔中將有可訪問性的標(biāo)記,避免用戶直接使用非?public?的屬性或方法。
示例:
/** * 類描述 * * @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ù)說明,有參數(shù)和返回值時(shí)必須使用注釋標(biāo)識。
【強(qiáng)制】?參數(shù)和返回值注釋必須包含類型信息和說明。
【建議】?當(dāng)函數(shù)是內(nèi)部函數(shù),外部不可訪問時(shí),可以使用?@inner?標(biāo)識。
示例:
/** * 函數(shù)描述 * * @param {string} p1 參數(shù)1的說明 * @param {string} p2 參數(shù)2的說明,比較長 *???? 那就換行了. * @param {number=} p3 參數(shù)3的說明(可選) * @return {Object} 返回值描述 */ function foo(p1, p2, p3) { ??? var p3 = p3 || 10; ??? return { ??????? p1: p1, ??????? p2: p2, ??????? p3: p3 ??? }; }【強(qiáng)制】?對 Object 中各項(xiàng)的描述, 必須使用?@param?標(biāo)識。
示例:
/** * 函數(shù)描述 * * @param {Object} option 參數(shù)描述 * @param {string} option.url option項(xiàng)描述 * @param {string=} option.method option項(xiàng)描述,可選參數(shù) */ function foo(option) { ??? // TODO }【建議】?重寫父類方法時(shí), 應(yīng)當(dāng)添加?@override?標(biāo)識。如果重寫的形參個(gè)數(shù)、類型、順序和返回值類型均未發(fā)生變化,可省略@param、@return,僅用?@override?標(biāo)識,否則仍應(yīng)作完整注釋。
解釋:
簡而言之,當(dāng)子類重寫的方法能直接套用父類的方法注釋時(shí)可省略對參數(shù)與返回值的注釋。
2.4.9 事件注釋
【強(qiáng)制】?必須使用?@event?標(biāo)識事件,事件參數(shù)的標(biāo)識與方法描述的參數(shù)標(biāo)識相同。
示例:
/** * 值變更時(shí)觸發(fā) * * @event * @param {Object} e e描述 * @param {string} e.before before描述 * @param {string} e.after after描述 */ onchange: function (e) { }【強(qiáng)制】?在會廣播事件的函數(shù)前使用?@fires?標(biāo)識廣播的事件,在廣播事件代碼前使用?@event?標(biāo)識事件。
【建議】?對于事件對象的注釋,使用?@param?標(biāo)識,生成文檔時(shí)可讀性更好。
示例:
/** * 點(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)記,并包含說明和類型信息。
示例:
/** * 常量說明 * * @const * @type {string} */ var REQUEST_URL = 'myurl.do';2.4.11 復(fù)雜類型注釋
【建議】?對于類型未定義的復(fù)雜結(jié)構(gòu)的注釋,可以使用?@typedef?標(biāo)識來定義。
示例:
// `namespaceA~` 可以換成其它 namepaths 前綴,目的是為了生成文檔中能顯示 `@typedef` 定義的類型和鏈接。 /** * 服務(wù)器 * * @typedef {Object} namespaceA~Server * @property {string} host 主機(jī) * @property {number} port 端口 */ ? /** * 服務(wù)器列表 * * @type {Array.<namespaceA~Server>} */ var servers = [ ??? { ??????? host: '1.2.3.4', ??????? port: 8080 ??? }, ??? { ??????? host: '1.2.3.5', ??????? port: 8081 ??? } ];2.4.12 細(xì)節(jié)注釋
對于內(nèi)部實(shí)現(xiàn)、不容易理解的邏輯說明、摘要信息等,我們可能需要編寫細(xì)節(jié)注釋。
【建議】?細(xì)節(jié)注釋遵循單行注釋的格式。說明必須換行時(shí),每行是一個(gè)單行注釋的起始。
示例:
function foo(p1, p2) { ??? // 這里對具體內(nèi)部邏輯進(jìn)行說明 ??? // 說明太長需要換行 ??? for (...) { ??????? .... ??? } }【強(qiáng)制】?有時(shí)我們會使用一些特殊標(biāo)記進(jìn)行說明。特殊標(biāo)記必須使用單行注釋的形式。下面列舉了一些常用標(biāo)記:
解釋:
3 語言特性
3.1 變量
【強(qiáng)制】?變量在使用前必須通過?var?定義。
解釋:
不通過 var 定義變量將導(dǎo)致變量污染全局環(huán)境。
示例:
// good var name = 'MyName'; ? // bad name = 'MyName';【強(qiáng)制】?每個(gè)?var?只能聲明一個(gè)變量。
解釋:
一個(gè) var 聲明多個(gè)變量,容易導(dǎo)致較長的行長度,并且在修改時(shí)容易造成逗號和分號的混淆。
示例:
// 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)的距離空間。
示例:
// 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)換。
示例:
// good if (age === 30) { ??? // ...... } ? // bad if (age == 30) { ??? // ...... }【建議】?盡可能使用簡潔的表達(dá)式。
示例:
// 字符串為空 ? // good if (!name) { ??? // ...... } ? // bad if (name === '') { ??? // ...... } // 字符串非空 ? // good if (name) { ??? // ...... } ? // bad if (name !== '') { ??? // ...... } // 數(shù)組非空 ? // good if (collection.length) { ??? // ...... } ? // bad if (collection.length > 0) { ??? // ...... } // 布爾不成立 ? // good if (!notTrue) { ??? // ...... } ? // bad if (notTrue === false) { ??? // ...... } // null 或 undefined ? // good if (noValue == null) { ? // ...... } ? // bad if (noValue === null || typeof noValue === 'undefined') { ? // ...... }【建議】?按執(zhí)行頻率排列分支的順序。
解釋:
按執(zhí)行頻率排列分支的順序好處是:
【建議】?對于相同變量或表達(dá)式的多值條件,用?switch?代替?if。
示例:
// 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?塊后沒有任何語句,可以刪除?else。
示例:
// 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)行過程中會生成循環(huán)次數(shù)個(gè)函數(shù)對象。
示例:
// 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 () {}); }【建議】?對循環(huán)內(nèi)多次使用的不變值,在循環(huán)外用變量緩存。
示例:
// 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'; ??? // ...... }【建議】?對有序集合進(jìn)行遍歷時(shí),緩存?length。
解釋:
雖然現(xiàn)代瀏覽器都對數(shù)組長度進(jìn)行了緩存,但對于一些宿主對象和老舊瀏覽器的數(shù)組對象,在每次 length 訪問時(shí)會動態(tài)計(jì)算元素個(gè)數(shù),此時(shí)緩存 length 能有效提高程序性能。
示例:
for (var i = 0, len = elements.length; i < len; i++) { ??? var element = elements[i]; ??? // ...... }【建議】?對有序集合進(jìn)行順序無關(guān)的遍歷時(shí),使用逆序遍歷。
解釋:
逆序遍歷可以節(jié)省變量,代碼比較優(yōu)化。
示例:
var len = elements.length; while (len--) { ??? var element = elements[len]; ??? // ...... }3.4 類型
3.4.1 類型檢測
【建議】?類型檢測優(yōu)先使用?typeof。對象類型檢測使用?instanceof。null?或?undefined?的檢測使用?== null。
示例:
// 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í),使用?+ ''。
示例:
// good num + ''; ? // bad new String(num); num.toString(); String(num);【建議】?轉(zhuǎn)換成?number?時(shí),通常使用?+。
示例:
// good +str; ? // bad Number(str);【建議】?string?轉(zhuǎn)換成?number,要轉(zhuǎn)換的字符串結(jié)尾包含非數(shù)字并期望忽略時(shí),使用?parseInt。
示例:
var width = '200px'; parseInt(width, 10);【強(qiáng)制】?使用?parseInt?時(shí),必須指定進(jìn)制。
示例:
// good parseInt(str, 10); ? // bad parseInt(str);【建議】?轉(zhuǎn)換成?boolean?時(shí),使用?!!。
示例:
var num = 3.14; !!num;【建議】?number?去除小數(shù)點(diǎn),使用?Math.floor / Math.round / Math.ceil,不使用?parseInt。
示例:
// good var num = 3.14; Math.ceil(num); ? // bad var num = 3.14; parseInt(num, 10);3.5 字符串
【強(qiáng)制】?字符串開頭和結(jié)束使用單引號?'。
解釋:
示例:
var str = '我是一個(gè)字符串'; var html = '<div class="cls">拼接HTML可以省去雙引號轉(zhuǎn)義</div>';【建議】?使用?數(shù)組?或?+?拼接字符串。
解釋:
示例:
// 使用數(shù)組拼接字符串 var str = [ ??? // 推薦換行開始并縮進(jìn)開始第一個(gè)字符串, 對齊代碼, 方便閱讀. ??? '<ul>', ??????? '<li>第一項(xiàng)</li>', ??????? '<li>第二項(xiàng)</li>', ??? '</ul>' ].join(''); ? // 使用 + 拼接字符串 var str2 = '' // 建議第一個(gè)為空字符串, 第二個(gè)換行開始并縮進(jìn)開始, 對齊代碼, 方便閱讀 ??? + '<ul>', ??? +??? '<li>第一項(xiàng)</li>', ??? +??? '<li>第二項(xiàng)</li>', ??? + '</ul>';【建議】?復(fù)雜的數(shù)據(jù)到視圖字符串的轉(zhuǎn)換過程,選用一種模板引擎。
解釋:
使用模板引擎有如下好處:
- artTemplate: 體積較小,在所有環(huán)境下性能高,語法靈活。
- dot.js: 體積小,在現(xiàn)代瀏覽器下性能高,語法靈活。
- etpl: 體積較小,在所有環(huán)境下性能高,模板復(fù)用性高,語法靈活。
- handlebars: 體積大,在所有環(huán)境下性能高,擴(kuò)展性高。
- hogon: 體積小,在現(xiàn)代瀏覽器下性能高。
- nunjucks: 體積較大,性能一般,模板復(fù)用性高。
3.6 對象
【強(qiáng)制】?使用對象字面量?{}?創(chuàng)建新?Object。
示例:
// good var obj = {}; ? // bad var obj = new Object();【強(qiáng)制】?對象創(chuàng)建時(shí),如果一個(gè)對象的所有?屬性?均可以不添加引號,則所有?屬性?不得添加引號。
示例:
var info = { ??? name: 'someone', ??? age: 28 };【強(qiáng)制】?對象創(chuàng)建時(shí),如果任何一個(gè)?屬性?需要添加引號,則所有?屬性?必須添加?'。
解釋:
如果屬性不符合 Identifier 和 NumberLiteral 的形式,就需要以 StringLiteral 的形式提供。
示例:
// good var info = { ??? 'name': 'someone', ??? 'age': 28, ??? 'more-info': '...' }; ? // bad var info = { ??? name: 'someone', ??? age: 28, ??? 'more-info': '...' };【強(qiáng)制】?不允許修改和擴(kuò)展任何原生對象和宿主對象的原型。
示例:
// 以下行為絕對禁止 String.prototype.trim = function () { };【建議】?屬性訪問時(shí),盡量使用?.。
解釋:
屬性名符合 Identifier 的要求,就可以通過?.?來訪問,否則就只能通過?[expr]?方式訪問。
通常在 JavaScript 中聲明的對象,屬性命名是使用 Camel 命名法,用?.?來訪問更清晰簡潔。部分特殊的屬性(比如來自后端的JSON),可能采用不尋常的命名方式,可以通過?[expr]?方式訪問。
示例:
info.age; info['more-info'];【建議】?for in?遍歷對象時(shí), 使用?hasOwnProperty?過濾掉原型中的屬性。
示例:
var 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)建的是指定長度的數(shù)組。
示例:
// good var arr = []; ? // bad var arr = new Array();【強(qiáng)制】?遍歷數(shù)組不使用?for in。
解釋:
數(shù)組對象可能存在數(shù)字以外的屬性, 這種情況下 for in 不會得到正確結(jié)果.
示例:
var 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 方法。以下兩種場景可以自己實(shí)現(xiàn)排序:
【建議】?清空數(shù)組使用?.length = 0。
3.8 函數(shù)
3.8.1 函數(shù)長度
【建議】?一個(gè)函數(shù)的長度控制在?50?行以內(nèi)。
解釋:
將過多的邏輯單元混在一個(gè)大函數(shù)中,易導(dǎo)致難以維護(hù)。一個(gè)清晰易懂的函數(shù)應(yīng)該完成單一的邏輯單元。復(fù)雜的操作應(yīng)進(jìn)一步抽取,通過函數(shù)的調(diào)用來體現(xiàn)流程。
特定算法等不可分割的邏輯允許例外。
示例:
function 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ù)會難以明確其主線邏輯,因此下方是一種更合理的表達(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)。
解釋:
除去不定長參數(shù)以外,函數(shù)具備不同邏輯意義的參數(shù)建議控制在 6 個(gè)以內(nèi),過多參數(shù)會導(dǎo)致維護(hù)難度增大。
【建議】?通過?options?參數(shù)傳遞非數(shù)據(jù)輸入型參數(shù)。
解釋:
有些函數(shù)的參數(shù)并不是作為算法的輸入,而是對算法的某些分支條件判斷之用,此類參數(shù)建議通過一個(gè) options 參數(shù)傳遞。
如下函數(shù):
/** * 移除某個(gè)元素 * * @param {Node} element 需要移除的元素 * @param {boolean} removeEventListeners 是否同時(shí)將所有注冊在元素上的事件移除 */ function removeElement(element, removeEventListeners) { ??? element.parent.removeChild(element); ??? if (removeEventListeners) { ??????? element.clearEventListeners(); ??? } }可以轉(zhuǎn)換為下面的簽名:
/** * 移除某個(gè)元素 * * @param {Node} element 需要移除的元素 * @param {Object} options 相關(guān)的邏輯配置 * @param {boolean} options.removeEventListeners 是否同時(shí)將所有注冊在元素上的事件移除 */ function removeElement(element, options) { ??? element.parent.removeChild(element); ??? if (options.removeEventListeners) { ??????? element.clearEventListeners(); ??? } }這種模式有幾個(gè)顯著的優(yōu)勢:
- boolean 型的配置項(xiàng)具備名稱,從調(diào)用的代碼上更易理解其表達(dá)的邏輯意義。
- 當(dāng)配置項(xiàng)有增長時(shí),無需無休止地增加參數(shù)個(gè)數(shù),不會出現(xiàn) removeElement(element, true, false, false, 3) 這樣難以理解的調(diào)用代碼。
- 當(dāng)部分配置參數(shù)可選時(shí),多個(gè)參數(shù)的形式非常難處理重載邏輯,而使用一個(gè) options 對象只需判斷屬性是否存在,實(shí)現(xiàn)得以簡化。
3.8.3 閉包
【建議】?在適當(dāng)?shù)臅r(shí)候?qū)㈤]包內(nèi)大對象置為?null。
解釋:
在 JavaScript 中,無需特別的關(guān)鍵詞就可以使用閉包,一個(gè)函數(shù)可以任意訪問在其定義的作用域外的變量。需要注意的是,函數(shù)的作用域是靜態(tài)的,即在定義時(shí)決定,與調(diào)用的時(shí)機(jī)和方式?jīng)]有任何關(guān)系。
閉包會阻止一些變量的垃圾回收,對于較老舊的JavaScript引擎,可能導(dǎo)致外部所有變量均無法回收。
首先一個(gè)較為明確的結(jié)論是,以下內(nèi)容會影響到閉包內(nèi)變量的回收:
- 嵌套的函數(shù)中是否有使用該變量。
- 嵌套的函數(shù)中是否有?直接調(diào)用eval。
- 是否使用了 with 表達(dá)式。
Chakra、V8 和 SpiderMonkey 將受以上因素的影響,表現(xiàn)出不盡相同又較為相似的回收策略,而JScript.dll和Carakan則完全沒有這方面的優(yōu)化,會完整保留整個(gè) LexicalEnvironment 中的所有變量綁定,造成一定的內(nèi)存消耗。
由于對閉包內(nèi)變量有回收優(yōu)化策略的 Chakra、V8 和 SpiderMonkey 引擎的行為較為相似,因此可以總結(jié)如下,當(dāng)返回一個(gè)函數(shù) fn 時(shí):
對于Chakra引擎,暫無法得知是按 V8 的模式還是按 SpiderMonkey 的模式進(jìn)行。
如果有?非常龐大?的對象,且預(yù)計(jì)會在?老舊的引擎?中執(zhí)行,則使用閉包時(shí),注意將閉包不需要的對象置為空引用。
【建議】?使用?IIFE?避免?Lift 效應(yīng)。
解釋:
在引用函數(shù)外部變量時(shí),函數(shù)執(zhí)行時(shí)外部變量的值由運(yùn)行時(shí)決定而非定義時(shí),最典型的場景如下:
var 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](); }以上代碼對 tasks 中的函數(shù)的執(zhí)行均會輸出?Current cursor is at 5,往往不符合預(yù)期。
此現(xiàn)象稱為?Lift 效應(yīng)?。解決的方式是通過額外加上一層閉包函數(shù),將需要的外部變量作為參數(shù)傳遞來解除變量的綁定關(guān)系:
var 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()?的形式。
示例:
var emptyFunction = function () {};【建議】?對于性能有高要求的場合,建議存在一個(gè)空函數(shù)的常量,供多處使用共享。
示例:
var 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ū)ο?/h3> 【強(qiáng)制】?類的繼承方案,實(shí)現(xiàn)時(shí)需要修正?constructor。
解釋:
通常使用其他 library 的類繼承方案都會進(jìn)行 constructor 修正。如果是自己實(shí)現(xiàn)的類繼承方案,需要進(jìn)行 constructor 修正。
示例:
/** * 構(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?的正確性。
示例:
function Animal(name) { ??? this.name = name; } ? // 直接prototype等于對象時(shí),需要修正constructor Animal.prototype = { ??? constructor: Animal, ? ??? jump: function () { ??????? alert('animal ' + this.name + ' jump'); ??? } }; ? // 這種方式擴(kuò)展prototype則無需理會constructor Animal.prototype.jump = function () { ??? alert('animal ' + this.name + ' jump'); };【建議】?屬性在構(gòu)造函數(shù)中聲明,方法在原型中聲明。
解釋:
原型對象的成員被所有實(shí)例共享,能節(jié)約內(nèi)存占用。所以編碼時(shí)我們應(yīng)該遵守這樣的原則:原型對象包含程序不會修改的成員,如方法函數(shù)或配置項(xiàng)。
function TextNode(value, engine) { ??? this.value = value; ??? this.engine = engine; } ? TextNode.prototype.clone = function () { ??? return this; };【強(qiáng)制】?自定義事件的?事件名?必須全小寫。
解釋:
在 JavaScript 廣泛應(yīng)用的瀏覽器環(huán)境,絕大多數(shù) DOM 事件名稱都是全小寫的。為了遵循大多數(shù) JavaScript 開發(fā)者的習(xí)慣,在設(shè)計(jì)自定義事件時(shí),事件名也應(yīng)該全小寫。
【強(qiáng)制】?自定義事件只能有一個(gè)?event?參數(shù)。如果事件需要傳遞較多信息,應(yīng)仔細(xì)設(shè)計(jì)事件對象。
解釋:
一個(gè)事件對象的好處有:
【建議】?設(shè)計(jì)自定義事件時(shí),應(yīng)考慮禁止默認(rèn)行為。
解釋:
常見禁止默認(rèn)行為的方式有兩種:
3.10 動態(tài)特性
3.10.1 eval
【強(qiáng)制】?避免使用直接?eval?函數(shù)。
解釋:
直接 eval,指的是以函數(shù)方式調(diào)用 eval 的調(diào)用方法。直接 eval 調(diào)用執(zhí)行代碼的作用域?yàn)楸镜刈饔糜?#xff0c;應(yīng)當(dāng)避免。
如果有特殊情況需要使用直接 eval,需在代碼中用詳細(xì)的注釋說明為何必須使用直接 eval,不能使用其它動態(tài)執(zhí)行代碼的方式,同時(shí)需要其他資深工程師進(jìn)行 Code Review。
【建議】?盡量避免使用?eval?函數(shù)。
3.10.2 動態(tài)執(zhí)行代碼
【建議】?使用?new Function?執(zhí)行動態(tài)代碼。
解釋:
通過 new Function 生成的函數(shù)作用域是全局使用域,不會影響當(dāng)當(dāng)前的本地作用域。如果有動態(tài)代碼執(zhí)行的需求,建議使用 new Function。
示例:
var handler = new Function('x', 'y', 'return x + y;'); var result = handler($('#x').val(), $('#y').val());3.10.3 with
【建議】?盡量不要使用?with。
解釋:
使用 with 可能會增加代碼的復(fù)雜度,不利于閱讀和管理;也會對性能有影響。大多數(shù)使用 with 的場景都能使用其他方式較好的替代。所以,盡量不要使用 with。
3.10.4 delete
【建議】?減少?delete?的使用。
解釋:
如果沒有特別的需求,減少或避免使用delete。delete的使用會破壞部分 JavaScript 引擎的性能優(yōu)化。
【建議】?處理?delete?可能產(chǎn)生的異常。
解釋:
對于有被遍歷需求,且值 null 被認(rèn)為具有業(yè)務(wù)邏輯意義的值的對象,移除某個(gè)屬性必須使用 delete 操作。
在嚴(yán)格模式或IE下使用 delete 時(shí),不能被刪除的屬性會拋出異常,因此在不確定屬性是否可以刪除的情況下,建議添加 try-catch 塊。
示例:
try { ??? delete o.x; } catch (deleteError) { ??? o.x = null; }3.10.5 對象屬性
【建議】?避免修改外部傳入的對象。
解釋:
JavaScript 因其腳本語言的動態(tài)特性,當(dāng)一個(gè)對象未被 seal 或 freeze 時(shí),可以任意添加、刪除、修改屬性值。
但是隨意地對 非自身控制的對象 進(jìn)行修改,很容易造成代碼在不可預(yù)知的情況下出現(xiàn)問題。因此,設(shè)計(jì)良好的組件、函數(shù)應(yīng)該避免對外部傳入的對象的修改。
下面代碼的 selectNode 方法修改了由外部傳入的 datasource 對象。如果 datasource 用在其它場合(如另一個(gè) Tree 實(shí)例)下,會造成狀態(tài)的混亂。
function Tree(datasource) { ??? this.datasource = datasource; } ? Tree.prototype.selectNode = function (id) { ??? // 從datasource中找出節(jié)點(diǎn)對象 ??? var node = this.findNode(id); ??? if (node) { ??????? node.selected = true; ??????? this.flushView(); ??? } };對于此類場景,需要使用額外的對象來維護(hù),使用由自身控制,不與外部產(chǎn)生任何交互的 selectedNodeIndex 對象來維護(hù)節(jié)點(diǎn)的選中狀態(tài),不對 datasource 作任何修改。
function Tree(datasource) { ??? this.datasource = datasource; ??? this.selectedNodeIndex = {}; } ? Tree.prototype.selectNode = function (id) { ??? // 從datasource中找出節(jié)點(diǎn)對象 ??? var node = this.findNode(id); ??? if (node) { ??????? this.selectedNodeIndex[id] = true; ??????? this.flushView(); ??? } };除此之外,也可以通過 deepClone 等手段將自身維護(hù)的對象與外部傳入的分離,保證不會相互影響。
【建議】?具備強(qiáng)類型的設(shè)計(jì)。
解釋:
- 如果一個(gè)屬性被設(shè)計(jì)為 boolean 類型,則不要使用 1 / 0 作為其值。對于標(biāo)識性的屬性,如對代碼體積有嚴(yán)格要求,可以從一開始就設(shè)計(jì)為 number 類型且將 0 作為否定值。
- 從 DOM 中取出的值通常為 string 類型,如果有對象或函數(shù)的接收類型為 number 類型,提前作好轉(zhuǎn)換,而不是期望對象、函數(shù)可以處理多類型的值。
4 瀏覽器環(huán)境
4.1 DOM
4.1.1 元素獲取
【建議】?對于單個(gè)元素,盡可能使用?document.getElementById?獲取,避免使用document.all。
【建議】?對于多個(gè)元素的集合,盡可能使用?context.getElementsByTagName?獲取。其中?context?可以為?document?或其他元素。指定?tagName?參數(shù)為?*?可以獲得所有子元素。
【建議】?遍歷元素集合時(shí),盡量緩存集合長度。如需多次操作同一集合,則應(yīng)將集合轉(zhuǎn)為數(shù)組。
解釋:
原生獲取元素集合的結(jié)果并不直接引用 DOM 元素,而是對索引進(jìn)行讀取,所以 DOM 結(jié)構(gòu)的改變會實(shí)時(shí)反映到結(jié)果中。
示例:
<div></div> <span></span> ? <script> var elements = document.getElementsByTagName('*'); ? // 顯示為 DIV alert(elements[0].tagName); ? var div = elements[0]; var p = document.createElement('p'); docpment.body.insertBefore(p, div); ? // 顯示為 P alert(elements[0].tagName); </script>【建議】?獲取元素的直接子元素時(shí)使用?children。避免使用childNodes,除非預(yù)期是需要包含文本、注釋和屬性類型的節(jié)點(diǎn)。
4.1.2 樣式獲取
【建議】?獲取元素實(shí)際樣式信息時(shí),應(yīng)使用?getComputedStyle?或?currentStyle。
解釋:
通過 style 只能獲得內(nèi)聯(lián)定義或通過 JavaScript 直接設(shè)置的樣式。通過 CSS class 設(shè)置的元素樣式無法直接通過 style 獲取。
4.1.3 樣式設(shè)置
【建議】?盡可能通過為元素添加預(yù)定義的 className 來改變元素樣式,避免直接操作 style 設(shè)置。
【強(qiáng)制】?通過 style 對象設(shè)置元素樣式時(shí),對于帶單位非 0 值的屬性,不允許省略單位。
解釋:
除了 IE,標(biāo)準(zhǔn)瀏覽器會忽略不規(guī)范的屬性值,導(dǎo)致兼容性問題。
4.1.4 DOM 操作
【建議】?操作?DOM?時(shí),盡量減少頁面?reflow。
解釋:
頁面 reflow 是非常耗時(shí)的行為,非常容易導(dǎo)致性能瓶頸。下面一些場景會觸發(fā)瀏覽器的reflow:
- DOM元素的添加、修改(內(nèi)容)、刪除。
- 應(yīng)用新的樣式或者修改任何影響元素布局的屬性。
- Resize瀏覽器窗口、滾動頁面。
- 讀取元素的某些屬性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE)) 。
【建議】?盡量減少?DOM?操作。
解釋:
DOM 操作也是非常耗時(shí)的一種操作,減少 DOM 操作有助于提高性能。舉一個(gè)簡單的例子,構(gòu)建一個(gè)列表。我們可以用兩種方式:
第一種方法看起來比較標(biāo)準(zhǔn),但是每次循環(huán)都會對 DOM 進(jìn)行操作,性能極低。在這里推薦使用第二種方法。
4.1.5 DOM 事件
【建議】?優(yōu)先使用?addEventListener / attachEvent?綁定事件,避免直接在 HTML 屬性中或 DOM 的?expando?屬性綁定事件處理。
解釋:
expando 屬性綁定事件容易導(dǎo)致互相覆蓋。
【建議】?使用?addEventListener?時(shí)第三個(gè)參數(shù)使用?false。
解釋:
標(biāo)準(zhǔn)瀏覽器中的 addEventListener 可以通過第三個(gè)參數(shù)指定兩種時(shí)間觸發(fā)模型:冒泡和捕獲。而 IE 的 attachEvent 僅支持冒泡的事件觸發(fā)。所以為了保持一致性,通常 addEventListener 的第三個(gè)參數(shù)都為 false。
【建議】?在沒有事件自動管理的框架支持下,應(yīng)持有監(jiān)聽器函數(shù)的引用,在適當(dāng)時(shí)候(元素釋放、頁面卸載等)移除添加的監(jiān)聽器。
?
轉(zhuǎn)載于:https://www.cnblogs.com/z-e-r-o/p/6726855.html
總結(jié)
以上是生活随笔為你收集整理的前端开发规范文档(html,css,js)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 查看Chome浏览器中已保存的密码
- 下一篇: 原生js 修改html,原生JS改变HT