javascript編碼規範

一. 一些致使js性能緩慢的例子

DOM訪問執行DOM交互的代碼比i通常的js代碼要慢。DOM交互是不可避免的,可是儘可能的減小。javascript

例如:php

  • 動態的使用innerHTML插入HTML語句比建立DOM節點更快。
  •  eval不管何時,避免使用eval方法,由於執行這一方法會形成很大的開銷。
  •  with儘可能不要使用with
  •  for-in 循環

二. js陷阱

  • 避免使用evalFunction constructor使用eval或者function constructor會加大開銷由於每一次腳本引擎調用他們是必須將源碼轉換成可執行代碼;另外,使用eval時,字符串會在執行時被打斷
  • 避免使用with
  • 不要在對性能影響很大的地方使用:try-catch-finally
  • 避免使用全局變量 
  • 避免在對性能影響較大的地方使用for-in,for in循環須要腳本引擎構建一個枚舉屬性列表,並且每次都要從頭重複檢查
  • 使用字符串累加模式
  • 原生的操做比函數更快
  • 將函數而不是字符串傳到setTimeout()setInterval()
  • 避免對象裏不必的DOM引用 
  • 最大化對象解析速度,最小化做用域鏈
  • 儘可能讓腳本聲明的變量短一點,不要太長,特別是循環裏面的變量
  • 將自身引用存儲在做用域外的變量中。當一個funciton被執行時,一個執行的上下文(context)會被建立,被激活的對象將全部自身變量push到上下文(context)的做用域鏈以前。離做用域鏈越遠,解析的越慢,這也意味着做用域本地的變量時解析的最快的。 將自身引用用做用域以外的變量存儲,讀寫都會變的更快,這在全局變量和一些深度查找的資源解析中特別明顯。固然,做用域內定義的變量比使用對象自身訪問的速度更快。假如你須要在一個大循環中訪問一個dom,這樣子會更快:

三. 加載性能一些能夠提升的點

  • 更快的加載和展示頁面可讓js加載沒有阻塞(採用異步加載js方法)
  • 添加Experes或者Cache-Control HTTPheader
  • Gzip javascriptcss資源
  • 利用YUI或者JSMin壓縮代碼
  • 儘可能減小資源的數目和大小
  • 讓腳本無阻賽並行下載
  • 合併異步加載的腳本
  • 將行內腳本放到樣式表之上?有待考證,不科學
  • 少用iframe

四. 不爲人知的DOM

dom性能緩慢能夠歸結爲一下3個緣由:

  • 大規模的DOM操做
  • 腳本觸發太多的重構和重繪
  • 定位節點在DOM中的路徑慢

解決方案

  • 儘量減少DOM的大小
  • 使用文檔的組件模板來進行復用動態的在dom中插入或者更新元素是代價很大的。一個有效的方法來解決這個問題是利用HTML模板來插入一些對話框或者UI組件。
  • 最小化重繪和重構的次數重繪發生在一些元素可見或者隱藏的時候,可是沒有改變document的佈局重構發生在DOM的操做方式影響到佈局。重構的代價比重繪大的多得多。重構表格比重構塊狀元素代價大絕對定位的元素不會對document的佈局產生影響DOM的修改會觸發重繪
  • 參考資料:
  • Repaint and reflow at Opera Developer Network
  • Notes on HTML Reflow more detailed information on the reflow process (archived)
  • Reflows & Repaints: CSS Performance making your JavaScript slow
  • Go With The Reflow
  • Rendering: repaint, reflow/relayout, restyle
  • 利用cloneNode()
  • 利用HTML模板和innerHTML
  • 設定元素不可見再進行改變(質疑,appendChild不會重發重繪,js執行完成之後纔會)
  • 儘可能少的使用改變元素尺寸或位置的操做
  • 使用className來完成多個預約義樣式的的改變
  • 利用設定屬性來動態完成多個樣式的設定
  • css class name vs. style屬性
  • 不要遍歷大量的節點,避免在遍歷時改變dom結構
  • DOM元素緩存在變量中使用
  • dom元素使用完之後移除引用

五. 面向對象的Javascript

考慮使用繼承機制css

六. client-server對話

XMLHttpRequest設定超時時間html

考慮使用約定的數據來作大數據的處理,好比選擇xml或者jsonjava

七. 動畫

  • 選擇性的使用動畫
  • 使用scrollTo()方法來實現滾動動畫
  • 將動畫元素的position設置爲absolute或者fix
  • 在同一時間使用一個timer來服務多個動畫元素
  • 讓動畫的速度更平滑

八. 事件

  • 利用事件冒泡
  • 不要對一些常常觸發的event使用代理
  • Javascript調用棧使用setTimeout不會溢出緣由是setTimeout是僞異步的,把函數交給setTimeout處理後,原來的函數不會等待,會繼續執行,函數會結束,資源也就能夠釋放。而不用setTimeout的時候,函數必須等待調用的函數返回後才能繼續執行,但調用的函數又必須等待下一級函數,這樣全部函數都不能結束,資源也就釋放不出。換句話說,就是死鎖。

九. 命名規範

目的:提升代碼可預測性和可維護性的方法是使用命名約定,這就意味着採用一致的方法來對變量和函數進行命名。ajax

變量名json

變量名包括全局變量,局部變量,類變量,函數參數小程序

構造函數(類)命名數組

首字母大寫,駝峯式命名。緩存

JS中沒有類,可是能夠用new調用構造函數:var man = new Person();

普通變量命名

首字母小寫,駝峯式命名,匈牙利命名

如:nCheckCount 表示整形的數值

匈牙利命名法

匈牙利命名法語法:變量名=類型+對象描述

類型指變量的類型

對象描述指對象名字全稱或名字的一部分,要求有明確含義,命名要容易記憶容易理解。

提示: 雖然JavaScript變量表面上沒有類型,可是JavaScript內部仍是會爲變量賦予相應的類型

JavaScript變量起名類型

變量命名前綴

舉例

Array 數組

a

aListaGroup

Boolean 邏輯

b

bCheckedbHasLogin

Function 函數

f

fGetHtmlfInit

Integer 數字

n

nPagenTotal

Object 對象

o

oButtonoDate

Regular Expression 正則

r

rDomainrEmail

String 字符

s

sNamesHtml

 

 

其餘前綴規範

可根據團隊及項目須要增長

$:表示Jquery對象

例如:$Content$Module,一種比較普遍的Jquery對象變量命名規範。

fn:表示函數

例如:fnGetNamefnSetAge;和上面函數的前綴略有不一樣,改用fn來代替,我的認爲fn可以更好的區分普通變量和函數變量。 

例外狀況

以根據項目及團隊須要,設計出針對項目須要的前綴規範,從而達到團隊開發協做便利的目的。

做用域不大臨時變量能夠簡寫,好比:strnumbolobjfunarr

循環變量能夠簡寫,好比:ijk等。

某些做爲不容許修改值的變量認爲是常量,所有字母都大寫。例如:COPYRIGHTPI。常量能夠存在於函數中,也能夠存在於全局。必須採用全大寫的命名,且單詞以_分割,常量一般用於ajax請求url,和一些不會改變的數據。

函數命名

普通函數:首字母小寫,駝峯式命名,統一使用動詞或者動詞+名詞形式

例如:fnGetVersion()fnSubmitForm()fnInit();涉及返回邏輯值的函數可使用ishascontains等表示邏輯的詞語代替動詞,例如:fnIsObject()fnHasClass()fnContainsElment()

內部函數:使用_fn+動詞+名詞形式,內部函數必需在函數最後定義。

例如:

function fnGetNumber(nTotal) {    if (nTotal < 100) {        nTotal = 100;    }    return _fnAdd(nTotal);     function _fnAdd(nNumber) {        nNumber++;        return nNumber;    }}alert(fGetNumber(10)); //alert 101

對象方法與事件響應函數:對象方法命名使用fn+對象類名+動詞+名詞形式;

例如: fnAddressGetEmail()

事件響應函數:fn+觸發事件對象名+事件名或者模塊名

例如:fnDivClick()fnAddressSubmitButtonClick()

函數方法經常使用的動詞:

get 獲取/set 設置,        

add 增長/remove 刪除create 建立/destory 移除        

start 啓動/stop 中止open 打開/close 關閉,        

read 讀取/write 寫入load 載入/save 保存,        

create 建立/destroy 銷燬begin 開始/end 結束,       

 backup 備份/restore 恢復import 導入/export 導出,        

split 分割/merge 合併inject 注入/extract 提取,        

attach 附着/detach 脫離bind 綁定/separate 分離,       

 view 查看/browse 瀏覽edit 編輯/modify 修改,        

select 選取/mark 標記copy 複製/paste 粘貼,        

undo 撤銷/redo 重作insert 插入/delete 移除,        

add 加入/append 添加clean 清理/clear 清除,        

index 索引/sort 排序find 查找/search 搜索,        

increase 增長/decrease 減小play 播放/pause 暫停,       

 launch 啓動/run 運行compile 編譯/execute 執行,        

debug 調試/trace 跟蹤observe 觀察/listen 監聽,       

 build 構建/publish 發佈input 輸入/output 輸出,       

 encode 編碼/decode 解碼encrypt 加密/decrypt 解密,        

compress 壓縮/decompress 解壓縮pack 打包/unpack 解包,        

parse 解析/emit 生成connect 鏈接/disconnect 斷開,        

send 發送/receive 接收download 下載/upload 上傳,        

refresh 刷新/synchronize 同步update 更新/revert 復原,       

 lock 鎖定/unlock 解鎖check out 簽出/check in 簽入,        

submit 提交/commit 交付push /pull ,       

 expand 展開/collapse 摺疊begin 起始/end 結束,       

 start 開始/finish 完成enter 進入/exit 退出,        

abort 放棄/quit 離開obsolete 廢棄/depreciate 廢舊,        

collect 收集/aggregate 彙集

變量命名例子

爲何須要這樣強制定義變量前綴?正式由於javascript是弱語言形成的。在定義大量變量的時候,咱們須要很明確的知道當前變量是什麼屬性,若是隻經過普通單詞,是很難區分的。

普通代碼

var checked = false;

var check = function() {  

   return true;

}

/**some code**/

 if(check) {

//已經沒法很確切知道這裏是要用checked仍是check()從而致使邏輯錯誤    

//do some thing

}

規範後代碼

var bChecked = false;

var fnCheck = function() {   

   return true;

}

/**some code**/ 

if(bChecked) {   

   // do some thing

}

if(fnCheck()) {   

 // do other thing

}

如何標明私有方法或私有屬性?

var person = {    

  getName: function () {

          return this._getFirst() + ' ' + this._getLast();    

  },    

  _getFirst: function () {       

     //...    

  },   

   _getLast: function (){    

        //...   

   }

};

在這個例子中,getName()覺得這這是API的一個公開的方法,而_getFirst()_getLast()意味着這是一個私有函數。儘管他們都是普通的公開方法,可是使用下劃線前綴的表示方法能夠提醒使用person對象的用戶,告訴他們這些方法在其餘地方不能確保必定可以正常工做,不能直接調用。

總結:下面是一些使用下劃線約定的變量

使用下劃線結尾來代表是私有變量,例如name_getElements_()

使用一個下劃線前綴來表示受保護屬性,使用兩個下劃線前綴來表示私有屬性。

十. 編寫註釋

爲代碼編寫註釋是很是重要的。一般人們在深刻思考一個問題時,會很是清楚這段代碼的工做原理。可是當過一週後再次回到該代碼時,可能會花上很長時間來回想起那段代碼究竟是幹什麼的。

公共組件維護者和各欄目WD都須要在文件頭部加上註釋說明:

/** *文件用途說明*做者姓名、聯繫方式(旺旺)*製做日期**/

大的模塊註釋方法: 

//================// 代碼用途//================

 小的註釋;

//代碼說明 

註釋單獨一行,不要在代碼後的同一行內加註釋。例如:

//姓名var name = abc;   Vvar name =abc; //姓名 X

十一. 使用空格

使用空格有助於改善代碼的可讀性和一致性。在撰寫英文文章時在逗號和區間範圍後面使用空格。

javascript採用一樣的邏輯,可在列表表達式(等價於逗號)和語句結束(等價於完成一次「思考」)後面添加空格。

用處一:

  • 在分開for循環的各個部分的分號以後:例如,for (var i = 0; i < 10; i +=1){}
  • for循環中初始化多個變量(i和最大值等):for (var i = 0, max = 10; i < max; i += 1){}
  • 在限定數組項的逗號後面:var a = [1, 2, 3];
  • 對象屬性的逗號以後和將屬性名和屬性值分開的冒號以後:var o = {a: 1, b: 2};
  • 分隔開函數中各個參數的逗號以後:myFunc(a, b, c)
  • 在函數聲明的大括號以前:function myFunc() {}
  • 在匿名函數表達式以後:var myFunc = function () {};

用處二:

空格的另一個很好的用途是用來分隔全部的操做符和操做,這也就是意味着在 +, -, *, =, <, >, <=, >=, ===, !==, &&, ||, += 等以後使用空格:

例子:

//大量空格,而且使用一致,是的代碼可讀性更好

//容許在閱讀的時候不用一口氣讀下去

var d = 0,    a = b +1;if ( a && b && c) {    d = a % c;    a += d;} 

//反模式//缺乏空格或空格使用不一致,使得代碼比較混亂

var d= 0;    a =b+1;if (a&& b&& c) {d=a %c;    a+= d;}

十二. 編寫API文檔

 生成API文檔的步驟:

  • 編寫特殊格式的代碼塊(即一些註釋塊)
  • 運行工具來解析代碼和註釋(工具如:JSDoc ToolkitYUIDoc
  • 發佈工具解析的結果,大多數狀況是採用HTML格式發佈(如網頁版的API文檔就是利用工具生成的)

簡單舉例:

/*** 翻轉一個字符串** @param  {String} 輸入須要翻轉的字符串* @return {String} 翻轉後的字符串**/ var reverse = function (input) {    //...    return output;};

YUIDoc範例:

完整範例:本程序由一個文件(app.js)組成,該文件僅有一個模塊(myapp)

app.js:

/*** 個人javascript應用程序* * @module myapp*/ //使用命名空間來定義一個空對象var MYAPP = {}; //定義一個包含兩個方法(sum()multi())math_stuff對象/*** @namespace MYAPP* class math_stuff*/ MYAPP.math_stuff = {    /**    * Sums two numbers    *     * @method sum    * param     {Number}    是第一個數    * param     {Number}    是第二個數    * return    {Number}    兩個輸入的總和    */    sum: function (a, b) {        return a + b;    },    /**    * Multiplies two numbers    * param     {Number}    是第一個數    * param     {Number}    是第二個數    * return    {Number}    兩個輸入相乘後結果    */    multi: function (a, b) {        return a * b;    }};

@namespace:這裏用於命名包含以上對象的全局引用的名稱

@class:這裏有些命名不當,他實際意思是指對象或者構造函數

@method:定義對象中的方法和方法名

@param:列舉函數所使用的參數。其中將參數類型用大括號括起來,並在其後註釋參數名及描述。

@return:相似於@param,這裏用於描述返回值的,而且該方法沒有名稱。

@constructor:代表這個「類」其實是一個構造函數

@property@type描述了對象的屬性。

2. 編寫API目的:

API編寫註釋不只僅是一中提供參考文檔的簡便方法,並且還有其餘用途——經過再次審查代碼,提升代碼質量。

在解決問題時寫出的解決方案僅僅是一個初稿。該解決方案能夠給出使人期待的輸出,可是該方案是不是最佳方案呢?改代碼是否可讀、易於理解、維護和升級呢?當您再次審視代碼時您將更加肯定代碼哪些部分能夠改進——如何使得代碼更容易繼續更新,移除一些不足之處等。它能夠極大地幫助您建立高質量的代碼。

十三. 推薦寫法

除了三目運算,if,else等禁止簡寫

 // 正確的書寫

 if (true) {    

   alert(name);

 } 

console.log(name); 

// 不推薦的書寫 if (true)     alert(name); console.log(name); 

// 不推薦的書寫 if (true) alert(name); console.log(name)

在須要以{}閉合的代碼段前增長換行,如:for if

 

 // 沒有換行,小的代碼段沒法區分 if (wl && wl.length) {     for (i = 0, l = wl.length; i < l; ++i) {         p = wl[i];         type = Y.Lang.type(r[p]);         if (s.hasOwnProperty(p)) {             if (merge && type == 'object') {                 Y.mix(r[p], s[p]);             } else if (ov || !(p in r)) {                 r[p] = s[p];             }         }     } }

 // 有了換行,邏輯清楚多了 if (wl && wl.length) {      for (i = 0, l = wl.length; i < l; ++i) {         p = wl[i];         type = Y.Lang.type(r[p]);          if (s.hasOwnProperty(p)) {             // 處理merge邏輯             if (merge && type == 'object') {                 Y.mix(r[p], s[p]);             } else if (ov || !(p in r)) {                 r[p] = s[p];             }         }     } }

 換行能夠是空行,也能夠是註釋

使用Function進行類的定義,不推薦繼承,如需繼承採用成熟的類庫實現繼承

// 類的實現 function Person(name) {     this.name = name; }  Person.prototype.sayName = function() {     alert(this.name); };  var me = new Person("Nicholas");  // this放到局部變量self function Persion(name, sex) {     var self = this;      self.name = name;     self.sex = sex; }

平時我們寫代碼,基本都是小程序,真心用不上什麼繼承,並且繼承並非JS的擅長的語言特性,儘可能少用。若是非要使用的話,注意一點:

function A(){    //...}function B(){    //...}B.prototype = new A();B.prototype.constructor = B; //原則上,記得把這句話加上

繼承從原則上來說,別改變他的構造函數,不然這個繼承就顯得很彆扭了~

使用局部變量緩存反覆查找的對象(包括但不限於全局變量、dom查詢結果、做用域鏈較深的對象)

// 緩存對象

var getComment = function() {   

   var dom = $("#common-container"),// 緩存dom               

   appendTo = $.appendTo, // 緩存全局變量       

   data = this.json.data;   // 緩存做用域鏈較深的對象

}

//當須要緩存this時必須使用self變量進行緩存// 緩存

thisfunction Row(name) {   

   var self = this;     

  self.name = name;   

   $(".row").click(function() {        

    self.getName();   

   });

} 

self是一個保留字,不過用它也不要緊。在這裏,看我的愛好吧,能夠用_this, that, me等這些詞,都行,可是團隊開發的時候統一下比較好。

十四. 不規範寫法

  • 句尾沒有分號

    var isHotel = json.type == "hotel" ? true : false

    這個是要引發注意的,好比:

    a = b        // 賦值(function(){    //....})()         // 自執行函數

    未加分號,結果被解析成 

    a = b(function(){//...})()  //b()()返回的結果賦值給a

  • 變量命名各類各樣

    var is_hotel;var isHotel;var ishotel;

  • if 縮寫

    if (isHotel)    console.log(true)else    console.log(false)

  • 使用 eval

    var json = eval(jsonText);

  • 變量未定義處處都是

    function() {    var isHotel = 'true';    .......     var html = isHotel ? '<p>hotel</p>' : "";}

  • 超長函數

    function() {    var isHotel = 'true';    //....... 此處省略500    return false;}

相關文章
相關標籤/搜索