前端開發規范總結 總結前端開發模式和規范


1、前端開發規范

WEB客戶端開發自成體系, 主要用於智能終端(iPhone、Android手機、iPad、Android Pad)和傳統PC的開發。JS規范、HTML規范和CSS規范對客戶端開發進行全方位指導,統一編碼規范、提高可讀性、降低維護成本。

1.1一般規范

應用在 HTML, JavaScript 和 CSS上的通用規則。

1.1.1文件/資源命名

1)     以可讀性而言,減號(-)用來分隔文件名;

2)     使用駝峰方式命名文件名與文件所在的文件夾,便於統一配置;

3)     確保文件命名總是以字母開頭而不是數字;

4)     特殊含義的文件,需要對文件增加前后綴或特定的擴展名(比如 .min.js, .min.css),抑或一串前綴(比如 all.main.min.css)。使用點分隔符來區分這些在文件名中帶有清晰意義的元數據。

 

 

 

 

1.1.1.2 文本縮進

一次縮進4個空格

 

 

 

1.1.1.3 代碼檢查

對於前端JavaScript這種比較寬松自由的編程語言來說,嚴格遵循編碼規范和格式化風格指南極為重要。前端開發人員需嚴格遵循開發規范,並且使用自動代碼檢查工具(如JSHint)降低語法錯誤,確保代碼正確執行。

JSHint是一款檢查JS代碼規范與否的工具,用來檢查JS代碼的規范性。它提供了配置的方法,來檢查不符合開發規范的錯誤。

1.1.2 HTML開發規范

1.1.2.1 文檔類型

使用 HTML5的文檔類型申明: <!DOCTYPE html>。

1.1.2.2 腳本加載

出於性能考慮,腳本應該異步加載。不允許將腳本放置在 <head> 內,比如 <scriptsrc="main.js"></script>,其加載會一直阻塞 DOM解析,直至它完全地加載和執行完畢。這會造成頁面顯示的延遲,特別是一些重量級的腳本,不利於提高用戶體驗度。

異步加載腳本可緩解這種性能影響,有如下幾種解決方案。

1、如果只需兼容 IE10+,可將 HTML5 的async 屬性加至腳本中,它可防止阻塞 DOM 的解析,也可以將腳本引用寫在 <head> 里也沒有影響。

2、如需兼容老舊的瀏覽器,實踐表明可使用用來動態注入腳本的腳本加載器。可以考慮 yepnope 或 labjs。注入腳本的一個問題是:一直要等到 CSS 對象文檔已就緒,它們才開始加載(短暫地在 CSS 加載完畢之后),這就對需要及時觸發的 JS 造成了一定的延遲,也影響了用戶體驗。

終上所述,兼容老舊瀏覽器(IE9-)時,應該遵循以下最佳實踐。

腳本引用寫在body 結束標簽之前,並帶上 async 屬性。這雖然在老舊瀏覽器中不會異步加載腳本,但它只阻塞了 body 結束標簽之前的 DOM 解析,這就大大降低了其阻塞影響。而在現代瀏覽器中,腳本將在 DOM 解析器發現 body 尾部的script 標簽才進行加載,此時加載屬於異步加載,不會阻塞 CSSOM(但其執行仍發生在 CSSOM 之后)。

在所有瀏覽器中,推薦

 

在現代瀏覽器中,推薦

 

1.1.2.3 語義化

根據元素(有時稱作“標簽”)其被創造出來時的初始意義來使用它。打個比方,用 heading 元素來定義頭部標題,p 元素來定義文字段落,用 a 元素來定義鏈接錨點。

有根據有目的地使用 HTML 元素,對於可訪問性、代碼重用、代碼效率來說意義重大。

以下示例列出了一些的語義化 HTML 主要情況:

 

不推薦

 

推薦

 

 

 

1.1.2.4 多媒體回溯

對頁面上的媒體而言,像圖片、視頻、canvas 動畫等,要確保其有可替代的接入接口。圖片文件我們可采用有意義的備選文本(alt),視頻和音頻文件我們可以為其加上說明文字或字幕。

提供可替代內容,提高可用性。圖片的 alt 屬性可不填寫內容,純裝飾性的圖片可以使用alt=""。

不推薦

 

推薦

 

盡量用 alt 標簽去描述圖片。

不推薦

 

推薦

 

1.1.2.5 關注點分離

 web 中的關注點包括信息(HTML 結構)、外觀(CSS)和行為(JavaScript)。為了使它們成為可維護的干凈整潔的代碼,必須將它們分離開。嚴格地保證結構、表現、行為三者分離,並使三者之間沒有太多的交互和聯系。

就是說,盡量在文檔和模板中只包含結構性的 HTML;而將所有表現代碼,移入樣式表中;將所有動作行為,移入腳本中。

在此之外,為使得它們之間的聯系盡可能的小,在文檔和模板中也盡量少地引入樣式和腳本文件。

清晰的分層意味着:

1)     合並樣式,不引用過多樣式表

2)     合並腳本,不使用過多腳本

3)     不使用行內樣式(<style>.no-good{}</style>)

4)     不在元素上使用style 屬性(<hr style="border-top: 5px solidblack">)

5)     不使用行內腳本(<script>alert(‘nogood’)</script>)

6)     不使用表象元素(<b>, <u>, <center>, <font>, <b>)

7)     不使用表象 class 名(red, left, center)

 

不推薦

 

推薦

 

 

1.1.2.6 Type屬性

省略樣式表與腳本上的 type 屬性。鑒於 HTML5 中以上兩者默認的 type 值就是 text/css 和text/javascript,所以 type 屬性一般是可以忽略掉的。在老舊版本的瀏覽器中這么做也是安全可靠的。

 

不推薦

 

推薦

 

1.1.2.7 ID和錨點

在利用錨點提高用戶體驗方面,一個比較好的做法是將頁面內所有的頭部標題元素都加上 ID。頁面 URL 的 hash 中帶上對應的 ID 名稱,即形成描點,方便跳轉至對應元素所處位置。

例如,在瀏覽器中輸入URL(帶有錨點)時,瀏覽器將定位至錨點對應元素位置。

1.1.2.8 格式化規則

在每一個塊狀元素,列表元素和表格元素后,對其子孫元素進行縮進。內聯元素寫在一行內,塊狀元素還有列表和表格要另起一行。

 

推薦

 

1.1.2.9 HTML引號

使用雙引號(“”)而不是單引號(‘’)

 

不推薦

 

推薦

 

1.1.3 CSS開發規范

1.1.3.1 ID andclass 命名

ID和class(類)名使用可以反應元素目的和用途的名稱,或其他通用名稱。使用具體且反映元素目的的名稱,這些是最容易理解的,而且發生變化的可能性最小。

通用名稱只是多個元素的備用名,他們兄弟元素之間是一樣的,沒有特別意義。

ID命名要注意明確性及唯一性;class命名要注意通用性及復用性。

1.1.3.2 合理的避免使用ID

ID不應該被應用於樣式。因為ID的樣式不能被復用並且每個頁面中你只能使用一次ID。只有為了確定網頁或整個站點中的唯一有效位置時才使用ID。

 

不推薦

 

推薦

 

 

1.1.3.3 CSS選擇器中避免標簽名

當構建選擇器時應該使用清晰, 准確和有語義的class(類)名。不要使用標簽選擇器。使用class(類)名,而不是代碼元素,這樣會更容易維護。從分離的角度考慮,在表現層中不應該分配html標記/語義。

 

不推薦

 

推薦

 

 

1.1.3.4 盡可能的精確

很多前端開發人員寫選擇器鏈的時候不使用直接子選擇器,導致疼痛的設計問題並且有時候可能會很耗性能。

如果不是需要匹配到DOM末端的選擇器, 應該使用直接子選擇器。

考慮下面的DOM:

 

下面的CSS應用於有title類的全部三個元素。賦予content類下的title類 和 teaser類下的title類下不同的樣式,需要精確的選擇器編寫他們的樣式。

 

不推薦

 

推薦

 

1.1.3.5 縮寫屬性

CSS提供了各種縮寫屬性(如 font 字體)應該盡可能使用,即使在只設置一個值的情況下。使用縮寫屬性對於代碼效率和可讀性是有很有用的。

 

不推薦

 

推薦

 

1.1.3.6 0和單位

省略“0”值后面的單位。不要在0值后面使用單位,除非有值。

 

不推薦

 

推薦

 

1.1.3.7 十六進制表示法

在可能的情況下,使用3個字符的十六進制表示法。
例如,顏色值允許這樣表示,3個字符的小寫的十六進制表示法更簡短。

 

不推薦

 

推薦

 

1.1.3.8 ID 和 Class(類) 名的分隔符

使用連字符(中划線)分隔ID和Class(類)名中的單詞。為了增強課理解性,在選擇器中不要使用除了連字符(中划線)以為的任何字符(包括沒有)來連接單詞和縮寫。

另外,作為該標准,預設屬性選擇器能識別連字符(中划線)作為單詞[attribute|=value]的分隔符。

 

不推薦

 

推薦

 

 

1.1.3.9 聲明順序

為了保證更好的可讀性和可掃描性,樣式聲明應該遵循以下順序:

1)  結構性屬性:

a)  display

b)  position, left, top, right 等.

c)  overflow, float, clear 等.

d)  margin, padding

2)  表現性屬性:

a)  background, border 等.

b)  font, text

 

不推薦

 

推薦

 

1.1.3.10 聲明結束

為了保證一致性和可擴展性,每個聲明應該用分號“;”結束,每個聲明換行。

 

不推薦

 

推薦

 

1.1.3.11 屬性名結束

出於一致性的原因,屬性名的冒號后使用一個空格,屬性和值(但屬性和冒號之間沒有空格)的之間使用一個空格。

 

不推薦

 

推薦

 

1.1.3.12 CSS引用

屬性選擇器或屬性值用雙引號(“”),而不是單引號(“)括起來。

URI值(url())不要使用引號。

 

不推薦

 

推薦

 

 

1.1.4 JS開發規范

1.1.4.1嚴格模式

ECMAScript 5 嚴格模式(‘usestrict’)可在整個腳本或獨個方法內被激活。嚴格模式對應不同的javascript 語境會做更加嚴格的錯誤檢查。嚴格模式也確保了 javascript 代碼更加的健壯,運行的也更加快速。

嚴格模式會阻止使用在未來很可能被引入的預留關鍵字。

你應該在你的腳本中啟用嚴格模式,最好是在獨立的 IIFE 中應用它。避免在你的腳本第一行使用它而導致你的所有腳本都啟動了嚴格模式,這有可能會引發一些第三方類庫的問題。

 

不推薦

 

推薦

 

1.1.4.2 明智地使用真假判斷

在一個 if 條件語句中使用變量或表達式時,會做真假判斷。if(a == true) 是不同於 if(a) 的。后者的判斷比較特殊,我們稱其為真假判斷。這種判斷會通過特殊的操作將其轉換為 true 或 false,下列表達式統統返回 false:

false, 0, undefined, null, NaN, ''(空字符串)。

以下示例展示了真假判斷是如何工作的:

 

 

1.1.4.3 類型

1)     原始值: 相當於傳值(包括string、number、boolean、null、undefined)

var foo = 1,

bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9

2)     復雜類型: 相當於傳引(包括object、array、function)

var foo = [1, 2],

    bar = foo;

 

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

1.1.4.4  對象

1)     使用字面值創建對象

// bad

var item = new Object();

 

// good

var item = {};

2)     不要使用保留字 reservedwords作為鍵

// bad

var superman = {

  class: 'superhero',

  default: { clark: 'kent' },

  private: true

};

 

// good

var superman = {

  klass: 'superhero',

  defaults: { clark: 'kent' },

  hidden: true

};

1.1.4.5  數組

1)     使用字面值創建數組

// bad

var items = new Array();

 

// good

var items = [];

2)     如果你不知道數組的長度,使用push

var someStack = [];

 

// bad

someStack[someStack.length] = 'abracadabra';

 

// good

someStack.push('abracadabra');

3)     當你需要拷貝數組時使用slice

var len =items.length,

    itemsCopy = [],

    i;

 

// bad

for (i =0; i < len; i++) {

  itemsCopy[i] = items[i];

}

 

// good

itemsCopy= items.slice();

4)     使用slice將類數組的對象轉成數組.

function trigger() {

var args = Array.prototype.slice.call(arguments);

...

}

1.1.4.6  字符串

1)     對字符串使用單引號 ''

// bad

var name = "Bob Parr";

 

// good

var name = 'Bob Parr';

 

// bad

var fullName = "Bob " + this.lastName;

 

// good

var fullName = 'Bob ' + this.lastName;

2)     超過80個字符的字符串應該使用字符串連接換行

注: 如果過度使用,長字符串連接可能會對性能有影響.

// bad

var errorMessage = 'This is a super long error thatwas thrown because of Batman. When you stop to think about how Batman hadanything to do with this, you would get nowhere fast.';

 

// bad

var errorMessage = 'This is a super long error that \

was thrown because of Batman. \

When you stop to think about \

how Batman had anything to do \

with this, you would get nowhere \

fast.';

 

 

// good

var errorMessage = 'This is a super long error that '+

  'was thrownbecause of Batman.' +

  'When you stopto think about ' +

  'how Batmanhad anything to do ' +

  'with this,you would get nowhere ' +

'fast.';

3)     編程時使用join而不是字符串連接來構建字符串,特別是IE:

var items,

    messages,

    length, i;

 

messages = [{

    state:'success',

    message:'This one worked.'

},{

    state:'success',

    message:'This one worked as well.'

},{

    state:'error',

    message:'This one did not work.'

}];

 

length = messages.length;

 

// bad

function inbox(messages) {

  items ='<ul>';

 

  for (i = 0; i< length; i++) {

    items +='<li>' + messages[i].message + '</li>';

  }

 

  return items +'</ul>';

}

 

// good

function inbox(messages) {

  items = [];

 

  for (i = 0; i< length; i++) {

    items[i] =messages[i].message;

  }

 

  return '<ul><li>'+ items.join('</li><li>') + '</li></ul>';

}

1.1.4.7  函數

1)   函數表達式:

// 匿名函數表達式

var anonymous = function() {

  return true;

};

 

// 有名函數表達式

var named = function named() {

  return true;

};

 

// 立即調用函數表達式

(function() {

 console.log('Welcome to the Internet. Please follow me.');

})();

 

2)   絕對不要在一個非函數塊里聲明一個函數,把那個函數賦給一個變量。瀏覽器允許你這么做,但是它們解析不同。

3)   注: ECMA-262定義把塊定義為一組語句,函數聲明不是一個語句。閱讀ECMA-262對這個問題的說明.

// bad

if (currentUser) {

  functiontest() {

   console.log('Nope.');

  }

}

 

// good

if (currentUser) {

  var test =function test() {

   console.log('Yup.');

  };

}

4)   絕對不要把參數命名為arguments, 這將會逾越函數作用域內傳過來的 arguments 對象.

// bad

function nope(name, options, arguments) {

  // ...stuff...

}

 

// good

function yup(name, options, args) {

  // ...stuff...

}

1.1.4.8  屬性

1)     當使用變量訪問屬性時使用中括號.

var luke= {

  jedi: true,

  age: 28

};

 

functiongetProp(prop) {

  return luke[prop];

}

 

varisJedi = getProp('jedi');

 

1.1.4.9變量

1)   總是使用 var 來聲明變量,如果不這么做將導致產生全局變量,我們要避免污染全局命名空間。

// bad

superPower = new SuperPower();

 

// good

var superPower = new SuperPower();

2)   使用一個 var 以及新行聲明多個變量,縮進4個空格。

// bad

var items = getItems();

var goSportsTeam = true;

var dragonball = 'z';

 

// good

var items = getItems(),

    goSportsTeam= true,

    dragonball ='z';

3)   最后再聲明未賦值的變量,當你想引用之前已賦值變量的時候很有用。

// bad

var i, len, dragonball,

    items =getItems(),

    goSportsTeam= true;

 

// bad

var i, items = getItems(),

    dragonball,

    goSportsTeam= true,

    len;

 

// good

var items = getItems(),

    goSportsTeam= true,

    dragonball,

    length,

    i;

4)   在作用域頂部聲明變量,避免變量聲明和賦值引起的相關問題。

// bad

function() {

  test();

 console.log('doing stuff..');

 

  //..otherstuff..

 

  var name =getName();

 

  if (name ==='test') {

    returnfalse;

  }

 

  return name;

}

 

// good

function() {

  var name =getName();

 

  test();

 console.log('doing stuff..');

 

  //..otherstuff..

 

  if (name ==='test') {

    returnfalse;

  }

 

  return name;

}

 

// bad

function() {

  var name =getName();

 

  if(!arguments.length) {

    returnfalse;

  }

 

  return true;

}

 

// good

function() {

  if(!arguments.length) {

    returnfalse;

  }

 

  var name =getName();

 

  return true;

}

1.1.4.10 變量賦值時的邏輯操作

邏輯操作符“||”和“&&”也可被用來返回布爾值。如果操作對象為非布爾對象,那每個表達式將會被自左向右地做真假判斷。基於此操作,最終總有一個表達式被返回。這在變量賦值時,是可以用來簡化你的代碼的。

不推薦

 

推薦

 

這一小技巧經常用來給方法設定默認的參數。

 

1.1.4.11 總是使用帶類型判斷的比較判斷

總是使用 ===精確的比較操作符,避免在判斷的過程中,由 JavaScript 的強制類型轉換所造成的困擾。

如果你使用=== 操作符,那比較的雙方必須是同一類型為前提的條件下才會有效。

在只使用 == 的情況下,JavaScript 所帶來的強制類型轉換使得判斷結果跟蹤變得復雜,下面的例子可以看出這樣的結果有多怪了:

 

1.1.4.12  條件表達式和等號

1)   適當使用 === 和 !== 以及 == 和 !=.

2)   條件表達式的強制類型轉換遵循以下規則:

if ([0]) {

  // true

  // An array isan object, objects evaluate to true

}

a)  對象 被計算為 true

b)  Undefined 被計算為 false

c)  Null 被計算為 false

d)  布爾值 被計算為 布爾的值

e)  數字 如果是 +0,-0, or NaN 被計算為 false , 否則為true

f)  字符串 如果是空字符串'' 則被計算為 false, 否則為 true

3)   使用快捷方式.

// bad

if (name !== '') {

  // ...stuff...

}

 

// good

if (name) {

  // ...stuff...

}

 

// bad

if (collection.length > 0) {

  // ...stuff...

}

 

// good

if (collection.length) {

  // ...stuff...

}

1.1.4.13  

1)   給所有多行的塊使用大括號

// bad

if (test)

  return false;

 

// good

if (test) return false;

 

// good

if (test) {

  return false;

}

 

// bad

function() { return false; }

 

// good

function() {

  return false;

}

1.1.4.14  空白

1)     將tab設為4個空格

// bad

function() {

∙∙var name;

}

 

// bad

function() {

∙var name;

}

 

// good

function() {

∙∙∙∙var name;

}

2)     大括號前放一個空格

// bad

function test(){

 console.log('test');

}

 

// good

function test() {

 console.log('test');

}

 

// bad

dog.set('attr',{

  age: '1 year',

  breed:'Bernese Mountain Dog'

});

 

// good

dog.set('attr', {

  age: '1 year',

  breed:'Bernese Mountain Dog'

});

3)     在做長方法鏈時使用縮進.

// bad

$('#items').find('.selected').highlight().end().find('.open').updateCount();

 

// good

$('#items')

 .find('.selected')

    .highlight()

    .end()

  .find('.open')

   .updateCount();

 

// bad

var leds =stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)

   .attr('width',  (radius + margin)* 2).append('svg:g')

   .attr('transform', 'translate(' + (radius + margin) + ',' + (radius +margin) + ')')

   .call(tron.led);

 

// good

var leds = stage.selectAll('.led')

    .data(data)

 .enter().append('svg:svg')

   .class('led', true)

   .attr('width',  (radius + margin)* 2)

 .append('svg:g')

   .attr('transform', 'translate(' + (radius + margin) + ',' + (radius +margin) + ')')

   .call(tron.led);

1.1.4.15  逗號

1)   不要將逗號放前面

// bad

var once

  , upon

  , aTime;

 

// good

var once,

    upon,

    aTime;

 

// bad

var hero = {

    firstName: 'Bob'

  , lastName: 'Parr'

  , heroName: 'Mr. Incredible'

  , superPower: 'strength'

};

 

// good

var hero = {

  firstName: 'Bob',

  lastName: 'Parr',

  heroName: 'Mr. Incredible',

  superPower: 'strength'

};

2)   不要加多余的逗號,這可能會在IE下引起錯誤,同時如果多一個逗號某些ES3的實現會計算多數組的長度。

// bad

var hero = {

  firstName: 'Kevin',

  lastName: 'Flynn',

};

 

var heroes = [

  'Batman',

  'Superman',

];

 

// good

var hero = {

  firstName: 'Kevin',

  lastName: 'Flynn'

};

 

var heroes = [

  'Batman',

  'Superman'

];

1.1.4.16  分號

1)   語句結束一定要加分號

// bad

(function() {

  var name = 'Skywalker'

  return name

})()

 

// good

(function() {

  var name = 'Skywalker';

  return name;

})();

 

// good

;(function() {

  var name = 'Skywalker';

  return name;

})();

 

2)   澄清:分號與函數

分號需要用在表達式的結尾,而並非函數聲明的結尾。區分它們最好的例子是:

 

1.1.4.17  語句塊內的函數聲明

切勿在語句塊內聲明函數,在 ECMAScript 5 的嚴格模式下,這是不合法的。函數聲明應該在定義域的頂層。但在語句塊內可將函數申明轉化為函數表達式賦值給變量。

不推薦

 

推薦

 

1.1.4.18 類型轉換

1)     在語句的開始執行類型轉換.

2)     字符串:

//  =>this.reviewScore = 9;

 

// bad

var totalScore = this.reviewScore + '';

 

// good

var totalScore = '' + this.reviewScore;

 

// bad

var totalScore = '' + this.reviewScore + ' totalscore';

 

// good

var totalScore = this.reviewScore + ' total score';

3)     對數字使用parseInt 並且總是帶上類型轉換的基數.

var inputValue = '4';

 

// bad

var val = new Number(inputValue);

 

// bad

var val = +inputValue;

 

// bad

var val = inputValue >> 0;

 

// bad

var val = parseInt(inputValue);

 

// good

var val = Number(inputValue);

 

// good

var val = parseInt(inputValue, 10);

 

// good

/**

 * parseInt wasthe reason my code was slow.

 * Bitshiftingthe String to coerce it to a

 * Number madeit a lot faster.

 */

var val = inputValue >> 0;

4)     布爾值:

var age = 0;

 

// bad

var hasAge = new Boolean(age);

 

// good

var hasAge = Boolean(age);

 

// good

var hasAge = !!age;

1.1.4.19  存取器

1)   屬性的存取器函數不是必需的

2)   如果你確實有存取器函數的話使用getVal() 和 setVal('hello')

// bad

dragon.age();

 

// good

dragon.getAge();

 

// bad

dragon.age(25);

 

// good

dragon.setAge(25);

3)   如果屬性是布爾值,使用isVal()或 hasVal()

// bad

if (!dragon.age()) {

  return false;

}

 

// good

if (!dragon.hasAge()) {

  return false;

}

4)   可以創建get()和set()函數,但是要保持一致

function Jedi(options) {

  options ||(options = {});

  var lightsaber= options.lightsaber || 'blue';

 this.set('lightsaber', lightsaber);

}

 

Jedi.prototype.set = function(key, val) {

  this[key] =val;

};

 

Jedi.prototype.get = function(key) {

  returnthis[key];

};

1.1.4.20  構造器

1)     給對象原型分配方法,而不是用一個新的對象覆蓋原型,覆蓋原型會使繼承出現問題。

function Jedi() {

 console.log('new jedi');

}

 

// bad

Jedi.prototype = {

  fight:function fight() {

   console.log('fighting');

  },

 

  block:function block() {

   console.log('blocking');

  }

};

 

// good

Jedi.prototype.fight = function fight() {

 console.log('fighting');

};

 

Jedi.prototype.block = function block() {

 console.log('blocking');

};

2)     方法可以返回 this 幫助方法可鏈。

// bad

Jedi.prototype.jump = function() {

  this.jumping =true;

  return true;

};

 

Jedi.prototype.setHeight = function(height) {

  this.height =height;

};

 

var luke = new Jedi();

luke.jump(); // => true

luke.setHeight(20) // => undefined

 

// good

Jedi.prototype.jump = function() {

  this.jumping =true;

  return this;

};

 

Jedi.prototype.setHeight = function(height) {

  this.height =height;

  return this;

};

 

var luke = new Jedi();

 

luke.jump()

 .setHeight(20);

3)     可以寫一個自定義的toString()方法,但是確保它工作正常並且不會有副作用。

function Jedi(options) {

  options ||(options = {});

  this.name =options.name || 'no name';

}

 

Jedi.prototype.getName = function getName() {

  returnthis.name;

};

 

Jedi.prototype.toString = function toString() {

  return 'Jedi -' + this.getName();

};

1.1.4.21  事件

1)     當給事件附加數據時,傳入一個哈希而不是原始值,這可以讓后面的貢獻者加入更多數據到事件數據里而不用找出並更新那個事件的事件處理器

// bad

$(this).trigger('listingUpdated', listing.id);

 

...

 

$(this).on('listingUpdated', function(e, listingId) {

  // dosomething with listingId

});

// good

$(this).trigger('listingUpdated', { listingId :listing.id });

 

...

 

$(this).on('listingUpdated', function(e, data) {

  // dosomething with data.listingId

});

1.1.4.22  模塊

1)     模塊應該以 ! 開始,這保證了如果一個有問題的模塊忘記包含最后的分號在合並后不會出現錯誤

2)     這個文件應該以駝峰命名,並在同名文件夾下,同時導出的時候名字一致

3)     加入一個名為noConflict()的方法來設置導出的模塊為之前的版本並返回它

4)     總是在模塊頂部聲明'use strict';

// fancyInput/fancyInput.js

 

!function(global) {

  'use strict';

 

  varpreviousFancyInput = global.FancyInput;

 

  functionFancyInput(options) {

    this.options= options || {};

  }

 

 FancyInput.noConflict = function noConflict() {

   global.FancyInput = previousFancyInput;

    returnFancyInput;

  };

 

 global.FancyInput = FancyInput;

}(this);

1.1.4.23  使用jQuery規范

1)     緩存jQuery查詢

// bad

function setSidebar() {

 $('.sidebar').hide();

 

  // ...stuff...

 

 $('.sidebar').css({

   'background-color': 'pink'

  });

}

 

// good

function setSidebar() {

  var $sidebar =$('.sidebar');

 $sidebar.hide();

 

  // ...stuff...

 

  $sidebar.css({

   'background-color': 'pink'

  });

}

2)     對DOM查詢使用級聯的 $('.sidebar ul') 或 $('.sidebar ul'),

3)     對有作用域的jQuery對象查詢使用 find

// bad

$('.sidebar', 'ul').hide();

 

// bad

$('.sidebar').find('ul').hide();

 

// good

$('.sidebar ul').hide();

 

// good

$('.sidebar > ul').hide();

 

// good (slower)

$sidebar.find('ul');

 

// good (faster)

$($sidebar[0]).find('ul');

1.1.4.24標准特性

總是優先考慮使用標准特性。為了最大限度地保證擴展性與兼容性,總是首選標准的特性,而不是非標准的特性(例如:首選 string.charAt(3) 而不是 string[3];首選 DOM 的操作方法來獲得元素引用,而不是某一應用特定的快捷方法)。

1.1.4.25 簡易的原型繼承

在 JavaScript 中繼承對象時,遵循使用一個簡易的模式來創建此繼承。如果遇上復雜對象的繼承,那考慮采用一個繼承庫。

簡易繼承請用以下方式:

 

 

1.1.4.26 使用閉包

由於在Javascript語言中,只有函數內部的子函數才能讀取局部變量,因此可以把閉包簡單理解成“定義在一個函數內部的函數”。 使用閉包的兩個場景:一個是讀取函數內部的變量,另一個是讓函數內變量的值始終保持在內存中。

1.1.4.27 切勿在循環中創建函數

在簡單的循環語句中加入函數是非常容易形成閉包而帶來隱患的。下面的例子就是一個典型的陷阱:

 

不推薦

 

接下來的改進雖然已經解決了上述例子中的問題或 bug,但還是違反了不在循環中創建函數或閉包的原則。

 

不推薦

 

接下來的改進已解決問題,而且也遵循了規范。可是,你會發現看上去似乎過於復雜繁冗了,應該會有更好的解決方案吧。

 

不完全推薦

 

將循環語句轉換為函數執行的方式問題能得到立馬解決,每一次循環都會對應地創建一次閉包。函數式的風格更加值得推薦,而且看上去也更加地自然和可預料。

 

推薦

 

1.1.4.28 eval函數

盡量不要使用 evil 函數。eval()不但混淆語境還很危險,總會有比這更好、更清晰、更安全的另一種方案來寫你的代碼。

1.1.4.29 this關鍵字

只在對象構造器、方法和在設定的閉包中使用 this 關鍵字。this 的語義容易有誤導,它時而指向全局對象(大多數時),時而指向調用者的定義域(在eval 中),時而指向 DOM 樹中的某一節點(當用事件處理綁定到 HTML 屬性上時),時而指向一個新創建的對象(在構造器中),還時而指向其它的一些對象。

正因為它是如此容易地被搞錯,請限制它的使用場景:

1)    在構造函數中

2)    在對象的方法中(包括由此創建出的閉包內)

1.1.4.30 函數式編程

函數式編程可以簡化代碼並縮減維護成本,容易復用、解耦、更少的依賴。

例外:往往在“重代碼性能,輕代碼維護”的情況之下,要選擇最優性能的解決方案而非維護性高的方案(比如用簡單的循環語句代替 forEach)。

 

1.1.4.31 注釋

注釋是了解代碼寫法和目的的唯一途徑。注釋用於描述“代碼都做了什么,代碼為什么要這么寫”。可以加入所思考問題或解決方案的鏈接地址。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM