前端開發規範

最佳原則

堅持制定好的代碼規範。

無論團隊人數多少,代碼應該同出一門。

命名規則

項目命名

全部採用小寫方式, 以短橫線分隔。

例:my-project-name

目錄命名

參照項目命名規則;

有複數結構時,要採用複數命名法。

例:scriptsstylesimagesdata-models

JS文件命名

參照項目命名規則。

例:account-model.js

CSS, SCSS文件命名

參照項目命名規則。

例:retina-sprites.scss

HTML文件命名

參照項目命名規則。

例:error-report.html


HTML

語法

  • 縮進使用soft tab(4個空格);
  • 嵌套的節點應該縮進;
  • 在屬性上,使用雙引號,不要使用單引號;
  • 屬性名全小寫,用中劃線做分隔符;
  • 不要在自動閉合標籤結尾處使用斜線(HTML5 規範 指出他們是可選的);
  • 不要忽略可選的關閉標籤,例:
<!DOCTYPE html>
<html>
    <head>
        <title>Page title</title>
    </head>
    <body>
        <img src="images/company_logo.png" alt="Company">

        <h1 class="hello-world">Hello, world!</h1>
    </body>
</html>

HTML5 doctype

在頁面開頭使用這個簡單地doctype來啓用標準模式,使其在每個瀏覽器中儘可能一致的展現;

雖然doctype不區分大小寫,但是按照慣例,doctype大寫 (關於html屬性,大寫還是小寫)。

<!DOCTYPE html>
<html>
	...
</html>

lang屬性

根據HTML5規範:

應在html標籤上加上lang屬性。這會給語音工具和翻譯工具幫助,告訴它們應當怎麼去發音和翻譯。

更多關於 lang 屬性的說明在這裏

在sitepoint上可以查到語言列表

但sitepoint只是給出了語言的大類,例如中文只給出了zh,但是沒有區分香港,臺灣,大陸。而微軟給出了一份更加詳細的語言列表,其中細分了zh-cn, zh-hk, zh-tw。

<!DOCTYPE html>
<html lang="en-us">
    ...
</html>

字符編碼

通過聲明一個明確的字符編碼,讓瀏覽器輕鬆、快速的確定適合網頁內容的渲染方式,通常指定爲'UTF-8'。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
    </head>
    ...
</html>

IE兼容模式

用 `` 標籤可以指定頁面應該用什麼版本的IE來渲染;

如果你想要了解更多,請點擊這裏

不同doctype在不同瀏覽器下會觸發不同的渲染模式(這篇文章總結的很到位)。

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    </head>
    ...
</html>

引入CSS, JS

根據HTML5規範, 通常在引入CSS和JS時不需要指明 type,因爲 text/css和 text/javascript 分別是他們的默認值。

HTML5 規範鏈接

<!-- External CSS -->
<link rel="stylesheet" href="code_guide.css">

<!-- In-document CSS -->
<style>
    ...
</style>

<!-- External JS -->
<script src="code_guide.js"></script>

<!-- In-document JS -->
<script>
    ...
</script>

屬性順序

屬性應該按照特定的順序出現以保證易讀性;

  • class
  • id
  • name
  • data-*
  • srcfortypehrefvalue , max-lengthmaxminpattern
  • placeholdertitlealt
  • aria-*role
  • requiredreadonlydisabled

class是爲高可複用組件設計的,所以應處在第一位;

id更加具體且應該儘量少使用,所以將它放在第二位。

<a class="..." id="..." data-modal="toggle" href="#">Example link</a>

<input class="form-control" type="text">

<img src="..." alt="...">

boolean屬性

boolean屬性指不需要聲明取值的屬性,XHTML需要每個屬性聲明取值,但是HTML5並不需要;

更多內容可以參考 WhatWG section on boolean attributes

boolean屬性的存在表示取值爲true,不存在則表示取值爲false。

<input type="text" disabled>

<input type="checkbox" value="1" checked>

<select>
    <option value="1" selected>1</option>
</select>

JS生成標籤

在JS文件中生成標籤讓內容變得更難查找,更難編輯,性能更差。應該儘量避免這種情況的出現。

減少標籤數量

在編寫HTML代碼時,需要儘量避免多餘的父節點;

很多時候,需要通過迭代和重構來使HTML變得更少。

<!-- Not well -->
<span class="avatar">
    <img src="...">
</span>

<!-- Better -->
<img class="avatar" src="...">

實用高於完美

儘量遵循HTML標準和語義,但是不應該以浪費實用性作爲代價;

任何時候都要用盡量小的複雜度和儘量少的標籤來解決問題。


CSS, SCSS

縮進

使用soft tab(4個空格)。

.element {
    position: absolute;
    top: 10px;
    left: 10px;

    border-radius: 10px;
    width: 50px;
    height: 50px;
}

分號

每個屬性聲明末尾都要加分號。

.element {
    width: 20px;
    height: 20px;

    background-color: red;
}

空格

以下幾種情況不需要空格:

  • 屬性名後
  • 多個規則的分隔符','前
  • !important '!'後
  • 屬性值中'('後和')'前
  • 行末不要有多餘的空格

以下幾種情況需要空格:

  • 屬性值前
  • 選擇器'>', '+', '~'前後
  • '{'前
  • !important '!'前
  • @else 前後
  • 屬性值中的','後
  • 註釋'/'後和'/'前
/* not good */
.element {
    color :red! important;
    background-color: rgba(0,0,0,.5);
}

/* good */
.element {
    color: red !important;
    background-color: rgba(0, 0, 0, .5);
}

/* not good */
.element ,
.dialog{
    ...
}

/* good */
.element,
.dialog {

}

/* not good */
.element>.dialog{
    ...
}

/* good */
.element > .dialog{
    ...
}

/* not good */
.element{
    ...
}

/* good */
.element {
    ...
}

/* not good */
@if{
    ...
}@else{
    ...
}

/* good */
@if {
    ...
} @else {
    ...
}

空行

以下幾種情況需要空行:

  • 文件最後保留一個空行
  • '}'後最好跟一個空行,包括scss中嵌套的規則
  • 屬性之間需要適當的空行,具體見屬性聲明順序
/* not good */
.element {
    ...
}
.dialog {
    color: red;
    &:after {
        ...
    }
}

/* good */
.element {
    ...
}

.dialog {
    color: red;

    &:after {
        ...
    }
}

換行

以下幾種情況不需要換行:

  • '{'前

以下幾種情況需要換行:

  • '{'後和'}'前
  • 每個屬性獨佔一行
  • 多個規則的分隔符','後
/* not good */
.element
{color: red; background-color: black;}

/* good */
.element {
    color: red;
    background-color: black;
}

/* not good */
.element, .dialog {
    ...
}

/* good */
.element,
.dialog {
    ...
}

註釋

註釋統一用'/* */'(scss中也不要用'//'),具體參照右邊的寫法;

縮進與下一行代碼保持一致;

可位於一個代碼行的末尾,與代碼間隔一個空格。

/* Modal header */
.modal-header {
    ...
}

/*
 * Modal header
 */
.modal-header {
    ...
}

.modal-header {
    /* 50px */
    width: 50px;

    color: red; /* color red */
}

引號

最外層統一使用雙引號;

url的內容要用引號;

屬性選擇器中的屬性值需要引號。

.element:after {
    content: "";
    background-image: url("logo.png");
}

li[data-type="single"] {
    ...
}

命名

  • 類名使用小寫字母,以中劃線分隔
  • id採用駝峯式命名
  • scss中的變量、函數、混合、placeholder採用駝峯式命名
/* class */
.element-content {
    ...
}

/* id */
#myDialog {
    ...
}

/* 變量 */
$colorBlack: #000;

/* 函數 */
@function pxToRem($px) {
    ...
}

/* 混合 */
@mixin centerBlock {
    ...
}

/* placeholder */
%myDialog {
    ...
}

屬性聲明順序

相關的屬性聲明按右邊的順序做分組處理,組之間需要有一個空行。

.declaration-order {
    display: block;
    float: right;

    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 100;

    border: 1px solid #e5e5e5;
    border-radius: 3px;
    width: 100px;
    height: 100px;

    font: normal 13px "Helvetica Neue", sans-serif;
    line-height: 1.5;
    text-align: center;

    color: #333;
    background-color: #f5f5f5;

    opacity: 1;
}
// 下面是推薦的屬性的順序
[
    [
        "display",
        "visibility",
        "float",
        "clear",
        "overflow",
        "overflow-x",
        "overflow-y",
        "clip",
        "zoom"
    ],
    [
        "table-layout",
        "empty-cells",
        "caption-side",
        "border-spacing",
        "border-collapse",
        "list-style",
        "list-style-position",
        "list-style-type",
        "list-style-image"
    ],
    [
        "-webkit-box-orient",
        "-webkit-box-direction",
        "-webkit-box-decoration-break",
        "-webkit-box-pack",
        "-webkit-box-align",
        "-webkit-box-flex"
    ],
    [
        "position",
        "top",
        "right",
        "bottom",
        "left",
        "z-index"
    ],
    [
        "margin",
        "margin-top",
        "margin-right",
        "margin-bottom",
        "margin-left",
        "-webkit-box-sizing",
        "-moz-box-sizing",
        "box-sizing",
        "border",
        "border-width",
        "border-style",
        "border-color",
        "border-top",
        "border-top-width",
        "border-top-style",
        "border-top-color",
        "border-right",
        "border-right-width",
        "border-right-style",
        "border-right-color",
        "border-bottom",
        "border-bottom-width",
        "border-bottom-style",
        "border-bottom-color",
        "border-left",
        "border-left-width",
        "border-left-style",
        "border-left-color",
        "-webkit-border-radius",
        "-moz-border-radius",
        "border-radius",
        "-webkit-border-top-left-radius",
        "-moz-border-radius-topleft",
        "border-top-left-radius",
        "-webkit-border-top-right-radius",
        "-moz-border-radius-topright",
        "border-top-right-radius",
        "-webkit-border-bottom-right-radius",
        "-moz-border-radius-bottomright",
        "border-bottom-right-radius",
        "-webkit-border-bottom-left-radius",
        "-moz-border-radius-bottomleft",
        "border-bottom-left-radius",
        "-webkit-border-image",
        "-moz-border-image",
        "-o-border-image",
        "border-image",
        "-webkit-border-image-source",
        "-moz-border-image-source",
        "-o-border-image-source",
        "border-image-source",
        "-webkit-border-image-slice",
        "-moz-border-image-slice",
        "-o-border-image-slice",
        "border-image-slice",
        "-webkit-border-image-width",
        "-moz-border-image-width",
        "-o-border-image-width",
        "border-image-width",
        "-webkit-border-image-outset",
        "-moz-border-image-outset",
        "-o-border-image-outset",
        "border-image-outset",
        "-webkit-border-image-repeat",
        "-moz-border-image-repeat",
        "-o-border-image-repeat",
        "border-image-repeat",
        "padding",
        "padding-top",
        "padding-right",
        "padding-bottom",
        "padding-left",
        "width",
        "min-width",
        "max-width",
        "height",
        "min-height",
        "max-height"
    ],
    [
        "font",
        "font-family",
        "font-size",
        "font-weight",
        "font-style",
        "font-variant",
        "font-size-adjust",
        "font-stretch",
        "font-effect",
        "font-emphasize",
        "font-emphasize-position",
        "font-emphasize-style",
        "font-smooth",
        "line-height",
        "text-align",
        "-webkit-text-align-last",
        "-moz-text-align-last",
        "-ms-text-align-last",
        "text-align-last",
        "vertical-align",
        "white-space",
        "text-decoration",
        "text-emphasis",
        "text-emphasis-color",
        "text-emphasis-style",
        "text-emphasis-position",
        "text-indent",
        "-ms-text-justify",
        "text-justify",
        "letter-spacing",
        "word-spacing",
        "-ms-writing-mode",
        "text-outline",
        "text-transform",
        "text-wrap",
        "-ms-text-overflow",
        "text-overflow",
        "text-overflow-ellipsis",
        "text-overflow-mode",
        "-ms-word-wrap",
        "word-wrap",
        "-ms-word-break",
        "word-break"
    ],
    [
        "color",
        "background",
        "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
        "background-color",
        "background-image",
        "background-repeat",
        "background-attachment",
        "background-position",
        "-ms-background-position-x",
        "background-position-x",
        "-ms-background-position-y",
        "background-position-y",
        "-webkit-background-clip",
        "-moz-background-clip",
        "background-clip",
        "background-origin",
        "-webkit-background-size",
        "-moz-background-size",
        "-o-background-size",
        "background-size"
    ],
    [
        "outline",
        "outline-width",
        "outline-style",
        "outline-color",
        "outline-offset",
        "opacity",
        "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
        "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
        "-ms-interpolation-mode",
        "-webkit-box-shadow",
        "-moz-box-shadow",
        "box-shadow",
        "filter:progid:DXImageTransform.Microsoft.gradient",
        "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
        "text-shadow"
    ],
    [
        "-webkit-transition",
        "-moz-transition",
        "-ms-transition",
        "-o-transition",
        "transition",
        "-webkit-transition-delay",
        "-moz-transition-delay",
        "-ms-transition-delay",
        "-o-transition-delay",
        "transition-delay",
        "-webkit-transition-timing-function",
        "-moz-transition-timing-function",
        "-ms-transition-timing-function",
        "-o-transition-timing-function",
        "transition-timing-function",
        "-webkit-transition-duration",
        "-moz-transition-duration",
        "-ms-transition-duration",
        "-o-transition-duration",
        "transition-duration",
        "-webkit-transition-property",
        "-moz-transition-property",
        "-ms-transition-property",
        "-o-transition-property",
        "transition-property",
        "-webkit-transform",
        "-moz-transform",
        "-ms-transform",
        "-o-transform",
        "transform",
        "-webkit-transform-origin",
        "-moz-transform-origin",
        "-ms-transform-origin",
        "-o-transform-origin",
        "transform-origin",
        "-webkit-animation",
        "-moz-animation",
        "-ms-animation",
        "-o-animation",
        "animation",
        "-webkit-animation-name",
        "-moz-animation-name",
        "-ms-animation-name",
        "-o-animation-name",
        "animation-name",
        "-webkit-animation-duration",
        "-moz-animation-duration",
        "-ms-animation-duration",
        "-o-animation-duration",
        "animation-duration",
        "-webkit-animation-play-state",
        "-moz-animation-play-state",
        "-ms-animation-play-state",
        "-o-animation-play-state",
        "animation-play-state",
        "-webkit-animation-timing-function",
        "-moz-animation-timing-function",
        "-ms-animation-timing-function",
        "-o-animation-timing-function",
        "animation-timing-function",
        "-webkit-animation-delay",
        "-moz-animation-delay",
        "-ms-animation-delay",
        "-o-animation-delay",
        "animation-delay",
        "-webkit-animation-iteration-count",
        "-moz-animation-iteration-count",
        "-ms-animation-iteration-count",
        "-o-animation-iteration-count",
        "animation-iteration-count",
        "-webkit-animation-direction",
        "-moz-animation-direction",
        "-ms-animation-direction",
        "-o-animation-direction",
        "animation-direction"
    ],
    [
        "content",
        "quotes",
        "counter-reset",
        "counter-increment",
        "resize",
        "cursor",
        "-webkit-user-select",
        "-moz-user-select",
        "-ms-user-select",
        "user-select",
        "nav-index",
        "nav-up",
        "nav-right",
        "nav-down",
        "nav-left",
        "-moz-tab-size",
        "-o-tab-size",
        "tab-size",
        "-webkit-hyphens",
        "-moz-hyphens",
        "hyphens",
        "pointer-events"
    ]
]

顏色

顏色16進制用小寫字母;

顏色16進制儘量用簡寫。

/* not good */
.element {
    color: #ABCDEF;
    background-color: #001122;
}

/* good */
.element {
    color: #abcdef;
    background-color: #012;
}

屬性簡寫

屬性簡寫需要你非常清楚屬性值的正確順序,而且在大多數情況下並不需要設置屬性簡寫中包含的所有值,所以建議儘量分開聲明會更加清晰;

margin 和 padding 相反,需要使用簡寫;

常見的屬性簡寫包括:

  • font
  • background
  • transition
  • animation
/* not good */
.element {
    transition: opacity 1s linear 2s;
}

/* good */
.element {
    transition-delay: 2s;
    transition-timing-function: linear;
    transition-duration: 1s;
    transition-property: opacity;
}

媒體查詢

儘量將媒體查詢的規則靠近與他們相關的規則,不要將他們一起放到一個獨立的樣式文件中,或者丟在文檔的最底部,這樣做只會讓大家以後更容易忘記他們。

.element {
    ...
}

.element-avatar{
    ...
}

@media (min-width: 480px) {
    .element {
        ...
    }

    .element-avatar {
        ...
    }
}

SCSS相關

提交的代碼中不要有 @debug

聲明順序:

  • @extend
  • 不包含 @content 的 @include
  • 包含 @content 的 @include
  • 自身屬性
  • 嵌套規則

@import 引入的文件不需要開頭的'_'和結尾的'.scss';

嵌套最多不能超過5層;

@extend 中使用placeholder選擇器;

去掉不必要的父級引用符號'&'。

/* not good */
@import "_dialog.scss";

/* good */
@import "dialog";

/* not good */
.fatal {
    @extend .error;
}

/* good */
.fatal {
    @extend %error;
}

/* not good */
.element {
    & > .dialog {
        ...
    }
}

/* good */
.element {
    > .dialog {
        ...
    }
}

雜項

不允許有空的規則;

元素選擇器用小寫字母;

去掉小數點前面的0;

去掉數字中不必要的小數點和末尾的0;

屬性值'0'後面不要加單位;

同個屬性不同前綴的寫法需要在垂直方向保持對齊,具體參照右邊的寫法;

無前綴的標準屬性應該寫在有前綴的屬性後面;

不要在同個規則裏出現重複的屬性,如果重複的屬性是連續的則沒關係;

不要在一個文件裏出現兩個相同的規則;

用 border: 0; 代替 border: none;

選擇器不要超過4層(在scss中如果超過4層應該考慮用嵌套的方式來寫);

發佈的代碼中不要有 @import

儘量少用'*'選擇器。

/* not good */
.element {
}

/* not good */
LI {
    ...
}

/* good */
li {
    ...
}

/* not good */
.element {
    color: rgba(0, 0, 0, 0.5);
}

/* good */
.element {
    color: rgba(0, 0, 0, .5);
}

/* not good */
.element {
    width: 50.0px;
}

/* good */
.element {
    width: 50px;
}

/* not good */
.element {
    width: 0px;
}

/* good */
.element {
    width: 0;
}

/* not good */
.element {
    border-radius: 3px;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;

    background: linear-gradient(to bottom, #fff 0, #eee 100%);
    background: -webkit-linear-gradient(top, #fff 0, #eee 100%);
    background: -moz-linear-gradient(top, #fff 0, #eee 100%);
}

/* good */
.element {
    -webkit-border-radius: 3px;
       -moz-border-radius: 3px;
            border-radius: 3px;

    background: -webkit-linear-gradient(top, #fff 0, #eee 100%);
    background:    -moz-linear-gradient(top, #fff 0, #eee 100%);
    background:         linear-gradient(to bottom, #fff 0, #eee 100%);
}

/* not good */
.element {
    color: rgb(0, 0, 0);
    width: 50px;
    color: rgba(0, 0, 0, .5);
}

/* good */
.element {
    color: rgb(0, 0, 0);
    color: rgba(0, 0, 0, .5);
}

JavaScript

縮進

使用soft tab(4個空格)。

var x = 1,
    y = 1;

if (x < y) {
    x += 10;
} else {
    x += 1;
}

單行長度

不要超過80,但如果編輯器開啓word wrap可以不考慮單行長度。

分號

以下幾種情況後需加分號:

  • 變量聲明
  • 表達式
  • return
  • throw
  • break
  • continue
  • do-while
/* var declaration */
var x = 1;

/* expression statement */
x++;

/* do-while */
do {
    x++;
} while (x < 10);

空格

以下幾種情況不需要空格:

  • 對象的屬性名後
  • 前綴一元運算符後
  • 後綴一元運算符前
  • 函數調用括號前
  • 無論是函數聲明還是函數表達式,'('前不要空格
  • 數組的'['後和']'前
  • 對象的'{'後和'}'前
  • 運算符'('後和')'前

以下幾種情況需要空格:

  • 二元運算符前後
  • 三元運算符'?:'前後
  • 代碼塊'{'前
  • 下列關鍵字前:elsewhilecatchfinally
  • 下列關鍵字後:ifelseforwhiledoswitchcasetry,catchfinallywithreturntypeof
  • 單行註釋'//'後(若單行註釋和代碼同行,則'//'前也需要),多行註釋'*'後
  • 對象的屬性值前
  • for循環,分號後留有一個空格,前置條件如果有多個,逗號後留一個空格
  • 無論是函數聲明還是函數表達式,'{'前一定要有空格
  • 函數的參數之間
// not good
var a = {
    b :1
};

// good
var a = {
    b: 1
};

// not good
++ x;
y ++;
z = x?1:2;

// good
++x;
y++;
z = x ? 1 : 2;

// not good
var a = [ 1, 2 ];

// good
var a = [1, 2];

// not good
var a = ( 1+2 )*3;

// good
var a = (1 + 2) * 3;

// no space before '(', one space before '{', one space between function parameters
var doSomething = function(a, b, c) {
    // do something
};

// no space before '('
doSomething(item);

// not good
for(i=0;i<6;i++){
    x++;
}

// good
for (i = 0; i < 6; i++) {
    x++;
}

空行

以下幾種情況需要空行:

  • 變量聲明後(當變量聲明在代碼塊的最後一行時,則無需空行)
  • 註釋前(當註釋在代碼塊的第一行時,則無需空行)
  • 代碼塊後(在函數調用、數組、對象中則無需空行)
  • 文件最後保留一個空行
// need blank line after variable declaration
var x = 1;

// not need blank line when variable declaration is last expression in the current block
if (x >= 1) {
    var y = x + 1;
}

var a = 2;

// need blank line before line comment
a++;

function b() {
    // not need blank line when comment is first line of block
    return a;
}

// need blank line after blocks
for (var i = 0; i < 2; i++) {
    if (true) {
        return false;
    }

    continue;
}

var obj = {
    foo: function() {
        return 1;
    },

    bar: function() {
        return 2;
    }
};

// not need blank line when in argument list, array, object
func(
    2,
    function() {
        a++;
    },
    3
);

var foo = [
    2,
    function() {
        a++;
    },
    3
];

var foo = {
    a: 2,
    b: function() {
        a++;
    },
    c: 3
};

換行

換行的地方,行末必須有','或者運算符;

以下幾種情況不需要換行:

  • 下列關鍵字後:elsecatchfinally
  • 代碼塊'{'前

以下幾種情況需要換行:

  • 代碼塊'{'後和'}'前
  • 變量賦值後
// not good
var a = {
    b: 1
    , c: 2
};

x = y
    ? 1 : 2;

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

x = y ? 1 : 2;
x = y ?
    1 : 2;

// no need line break with 'else', 'catch', 'finally'
if (condition) {
    ...
} else {
    ...
}

try {
    ...
} catch (e) {
    ...
} finally {
    ...
}

// not good
function test()
{
    ...
}

// good
function test() {
    ...
}

// not good
var a, foo = 7, b,
    c, bar = 8;

// good
var a,
    foo = 7,
    b, c, bar = 8;

換行

換行的地方,行末必須有','或者運算符;

以下幾種情況不需要換行:

  • 下列關鍵字後:elsecatchfinally
  • 代碼塊'{'前

以下幾種情況需要換行:

  • 代碼塊'{'後和'}'前
  • 變量賦值後
// not good
var a = {
    b: 1
    , c: 2
};

x = y
    ? 1 : 2;

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

x = y ? 1 : 2;
x = y ?
    1 : 2;

// no need line break with 'else', 'catch', 'finally'
if (condition) {
    ...
} else {
    ...
}

try {
    ...
} catch (e) {
    ...
} finally {
    ...
}

// not good
function test()
{
    ...
}

// good
function test() {
    ...
}

// not good
var a, foo = 7, b,
    c, bar = 8;

// good
var a,
    foo = 7,
    b, c, bar = 8;

單行註釋

雙斜線後,必須跟一個空格;

縮進與下一行代碼保持一致;

可位於一個代碼行的末尾,與代碼間隔一個空格。

if (condition) {
    // if you made it here, then all security checks passed
    allowed();
}

var zhangsan = 'zhangsan'; // one space after code

多行註釋

最少三行, '*'後跟一個空格,具體參照右邊的寫法;

建議在以下情況下使用:

  • 難於理解的代碼段
  • 可能存在錯誤的代碼段
  • 瀏覽器特殊的HACK代碼
  • 業務邏輯強相關的代碼
/*
 * one space after '*'
 */
var x = 1;

文檔註釋

各類標籤@param, @method等請參考usejsdocJSDoc Guide

建議在以下情況下使用:

  • 所有常量
  • 所有函數
  • 所有類
/**
 * @func
 * @desc 一個帶參數的函數
 * @param {string} a - 參數a
 * @param {number} b=1 - 參數b默認值爲1
 * @param {string} c=1 - 參數c有兩種支持的取值</br>1—表示x</br>2—表示xx
 * @param {object} d - 參數d爲一個對象
 * @param {string} d.e - 參數d的e屬性
 * @param {string} d.f - 參數d的f屬性
 * @param {object[]} g - 參數g爲一個對象數組
 * @param {string} g.h - 參數g數組中一項的h屬性
 * @param {string} g.i - 參數g數組中一項的i屬性
 * @param {string} [j] - 參數j是一個可選參數
 */
function foo(a, b, c, d, g, j) {
    ...
}

引號

最外層統一使用單引號。

// not good
var x = "test";

// good
var y = 'foo',
    z = '<div id="test"></div>';

變量命名

  • 標準變量採用駝峯式命名(除了對象的屬性外,主要是考慮到cgi返回的數據)
  • 'ID'在變量名中全大寫
  • 'URL'在變量名中全大寫
  • 'Android'在變量名中大寫第一個字母
  • 'iOS'在變量名中小寫第一個,大寫後兩個字母
  • 常量全大寫,用下劃線連接
  • 構造函數,大寫第一個字母
  • jquery對象必須以'$'開頭命名
var thisIsMyName;

var goodID;

var reportURL;

var AndroidVersion;

var iOSVersion;

var MAX_COUNT = 10;

function Person(name) {
    this.name = name;
}

// not good
var body = $('body');

// good
var $body = $('body');

變量聲明

一個函數作用域中所有的變量聲明儘量提到函數首部,用一個var聲明,不允許出現兩個連續的var聲明。

function doSomethingWithItems(items) {
    // use one var
    var value = 10,
        result = value + 10,
        i,
        len;

    for (i = 0, len = items.length; i < len; i++) {
        result += 10;
    }
}

函數

無論是函數聲明還是函數表達式,'('前不要空格,但'{'前一定要有空格;

函數調用括號前不需要空格;

立即執行函數外必須包一層括號;

不要給inline function命名;

參數之間用', '分隔,注意逗號後有一個空格。

// no space before '(', but one space before'{'
var doSomething = function(item) {
    // do something
};

function doSomething(item) {
    // do something
}

// not good
doSomething (item);

// good
doSomething(item);

// requires parentheses around immediately invoked function expressions
(function() {
    return 1;
})();

// not good
[1, 2].forEach(function x() {
    ...
});

// good
[1, 2].forEach(function() {
    ...
});

// not good
var a = [1, 2, function a() {
    ...
}];

// good
var a = [1, 2, function() {
    ...
}];

// use ', ' between function parameters
var doSomething = function(a, b, c) {
    // do something
};

數組、對象

對象屬性名不需要加引號;

對象以縮進的形式書寫,不要寫在一行;

數組、對象最後不要有逗號。

// not good
var a = {
    'b': 1
};

var a = {b: 1};

var a = {
    b: 1,
    c: 2,
};

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

括號

下列關鍵字後必須有大括號(即使代碼塊的內容只有一行):ifelse,forwhiledoswitchtrycatchfinallywith

// not good
if (condition)
    doSomething();

// good
if (condition) {
    doSomething();
}

null

適用場景:

  • 初始化一個將來可能被賦值爲對象的變量
  • 與已經初始化的變量做比較
  • 作爲一個參數爲對象的函數的調用傳參
  • 作爲一個返回對象的函數的返回值

不適用場景:

  • 不要用null來判斷函數調用時有無傳參
  • 不要與未初始化的變量做比較
// not good
function test(a, b) {
    if (b === null) {
        // not mean b is not supply
        ...
    }
}

var a;

if (a === null) {
    ...
}

// good
var a = null;

if (a === null) {
    ...
}

undefined

永遠不要直接使用undefined進行變量判斷;

使用typeof和字符串'undefined'對變量進行判斷。

// not good
if (person === undefined) {
    ...
}

// good
if (typeof person === 'undefined') {
    ...
}

jshint

用'===', '!=='代替'==', '!=';

for-in裏一定要有hasOwnProperty的判斷;

不要在內置對象的原型上添加方法,如Array, Date;

不要在內層作用域的代碼裏聲明瞭變量,之後卻訪問到了外層作用域的同名變量;

變量不要先使用後聲明;

不要在一句代碼中單單使用構造函數,記得將其賦值給某個變量;

不要在同個作用域下聲明同名變量;

不要在一些不需要的地方加括號,例:delete(a.b);

不要使用未聲明的變量(全局變量需要加到.jshintrc文件的globals屬性裏面);

不要聲明瞭變量卻不使用;

不要在應該做比較的地方做賦值;

debugger不要出現在提交的代碼裏;

數組中不要存在空元素;

不要在循環內部聲明函數;

不要像這樣使用構造函數,例:new function () { ... }new Object

// not good
if (a == 1) {
    a++;
}

// good
if (a === 1) {
    a++;
}

// good
for (key in obj) {
    if (obj.hasOwnProperty(key)) {
        // be sure that obj[key] belongs to the object and was not inherited
        console.log(obj[key]);
    }
}

// not good
Array.prototype.count = function(value) {
    return 4;
};

// not good
var x = 1;

function test() {
    if (true) {
        var x = 0;
    }

    x += 1;
}

// not good
function test() {
    console.log(x);

    var x = 1;
}

// not good
new Person();

// good
var person = new Person();

// not good
delete(obj.attr);

// good
delete obj.attr;

// not good
if (a = 10) {
    a++;
}

// not good
var a = [1, , , 2, 3];

// not good
var nums = [];

for (var i = 0; i < 10; i++) {
    (function(i) {
        nums[i] = function(j) {
            return i + j;
        };
    }(i));
}

// not good
var singleton = new function() {
    var privateVar;

    this.publicMethod = function() {
        privateVar = 1;
    };

    this.publicMethod2 = function() {
        privateVar = 2;
    };
};

雜項

不要混用tab和space;

不要在一處使用多個tab或space;

換行符統一用'LF';

對上下文this的引用只能使用'_this', 'that', 'self'其中一個來命名;

行尾不要有空白字符;

switch的falling through和no default的情況一定要有註釋特別說明;

不允許有空的代碼塊。

// not good
var a   = 1;

function Person() {
    // not good
    var me = this;

    // good
    var _this = this;

    // good
    var that = this;

    // good
    var self = this;
}

// good
switch (condition) {
    case 1:
    case 2:
        ...
        break;
    case 3:
        ...
    // why fall through
    case 4
        ...
        break;
    // why no default
}

// not good with empty block
if (condition) {

}

編輯器配置和構建檢查

sublime3插件

  1. 安裝node包

    • jscs npm install jscs -g
    • jshint npm install jshint -g
    • csscomb npm install csscomb -g
    • csslint npm install csslint -g
  2. 安裝gem包

    • scss-lint gem install scss_lint
  3. 安裝sublime3 Package Control

    • 按下 `ctrl+``
    • 複製粘貼以下代碼
import urllib.request,os,hashlib; h = 'eb2297e1a458f27d836c04bb0cbaf282' + 'd0e7a3098092775ccb37ca9d6b2e4b7d'; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); by = urllib.request.urlopen( 'http://packagecontrol.io/' + pf.replace(' ', '%20')).read(); dh = hashlib.sha256(by).hexdigest(); print('Error validating download (got %s instead of %s), please try manual install' % (dh, h)) if dh != h else open(os.path.join( ipp, pf), 'wb' ).write(by)
  1. 安裝sublime3插件

    • 按下 ctrl+shift+p,輸入'ip'(Install Package)

    • 輸入以下插件的名字,按順序逐個進行安裝:

      • EditorConfig
      • Sass
      • SublimeLinter
      • SublimeLinter-jscs
      • SublimeLinter-jshint
      • SublimeLinter-csslint
      • SublimeLinter-contrib-scss-lint
      • JSFormat
      • CSScomb
  2. 插件的配置文件

    將以下配置文件分別下載後放入項目根目錄下:

  3. 編輯器及插件設置

    • sublime3 自身

Preferences->Setting-User,增加下面兩個配置:

{
    "translate_tabs_to_spaces": true,
    "word_wrap": true
}

點擊右下角的Spaces->Convert Indentation to Spaces可以將文件中的所有tab轉換成空格

*   `JSFormat`

Preferences->Package Settings->JSFormat->Setting-User,下載配置文件覆蓋

配置好後格式化的默認快捷鍵是 ctrl+alt+f

*   `SublimeLinter`

右鍵->SublimeLinter->Lint Mode,有4種檢查模式,建議選擇 Load/save

右鍵->SublimeLinter->Mark Style,建議選擇 Outline

右鍵->SublimeLinter->Choose Gutter Theme,建議選擇 Blueberry-round

右鍵->SublimeLinter->Open User Settings,將linter裏面jscs的args改成 ["--verbose"],將linter裏面csslint的ignore改成

"box-model,adjoining-classes,box-sizing,compatible-vendor-prefixes,gradients,text-indent,fallback-colors,star-property-hack,underscore-property-hack,bulletproof-font-face,font-faces,import,regex-selectors,universal-selector,unqualified-attributes,overqualified-elements,duplicate-background-images,floats,font-sizes,ids,important,outline-none,qualified-headings,unique-headings"

當光標處於有錯誤的代碼行時,詳細的錯誤信息會顯示在下面的狀態欄中,右鍵->SublimeLinter 可以看到所有的快捷鍵,其中 ctrl+k, a 可以列出所有錯誤

*   `CSScomb`

Preferences->Package Settings->CSScomb->Setting-User,下載配置文件覆蓋

配置好後格式化的默認快捷鍵是 ctrl+shift+c

grunt插件

  1. 在項目中安裝grunt插件

    • jscs npm install grunt-jscs --save-dev
    • jshint npm install grunt-contrib-jshint --save-dev
    • csslint npm install grunt-contrib-csslint --save-dev
    • scss-lint npm install grunt-scss-lint --save-dev
  2. 插件的配置文件

    • JSCS

      {
          options: {
              config: true,
              verbose: true
          },
          files: {
              src: [...]
          }
      }
      
    • JSHint

      {
          options: {
              jshintrc: true
          },
          files: {
              src: [...]
          }
      }
      
    • CSSLint

      {
          options: {
              csslintrc: '.csslintrc'
          },
          files: {
              src: [...]
          }
      }
      
    • SCSS-Lint

      {
          options: {
              config: '.scss-lint.yml'
          },
          files: {
              src: [...]
          }
      }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章