先自我介紹下,Sonia,女,資深前端開發一枚,現就任於某魚技術部,負責主站性能優化和重構工做。掐指一算,從事前端開發整整12個年頭了,不少朋友常常問到代碼優化及性能調試,這裏給你們總結了一下JS開發中的一些代碼規範及優化的技巧和經驗,此文談不上精品之做,但絕對是匠心之做,誠心之做,但願給前端開發路上的你一點幫助。javascript
在一個函數中會用到全局對象存儲爲局部變量來減小全局查找,由於訪問局部變量的速度要比訪問全局變量的速度更快些。前端
若是針對的是不斷運行的代碼,不該該使用setTimeout,而應該是用setInterval,由於setTimeout每一次都會初始化一個定時器,而setInterval只會在開始的時候初始化一個定時器。java
若是要鏈接多個字符串,應該少使用+=,如:編程
x+=a; x+=b; x+=c; 應該寫成 x+= a + b + c; 而若是是收集字符串,好比屢次對同一個字符串進行+=操做的話,最好使用一個緩存,使用JavaScript數組來收集,最後使用join方法鏈接起來。數組
和函數相似 ,with語句會建立本身的做用域,所以會增長其中執行的代碼的做用域鏈的長度,因爲額外的做用域鏈的查找,在with語句中執行的代碼確定比外面執行的代碼要慢,在能不使用with語句的時候儘可能不要使用with語句。瀏覽器
通常最好用"" + 1來將數字轉換成字符串,雖然看起來比較醜一點,但事實上這個效率是最高的,性能上來講:("" +) > String() > .toString() > new String()緩存
不少人喜歡使用parseInt(),其實parseInt()是用於將字符串轉換成數字,而不是浮點數和整型之間的轉換,咱們應該使用Math.floor()或者Math.round()。安全
若是定義了toString()方法來進行類型轉換的話,推薦顯式調用toString(),由於內部的操做在嘗試全部可能性以後,會嘗試對象的toString()方法嘗試可否轉化爲String,因此直接調用這個方法效率會更高性能優化
在JavaScript中全部變量均可以使用單個var語句來聲明,這樣就是組合在一塊兒的語句,以減小整個腳本的執行時間,就如上面代碼同樣,上面代碼格式也挺規範,讓人一看就明瞭。微信
如var a=arr[i]; i++;前面兩條語句能夠寫成var a=arr[i++]
一旦須要更新DOM,請考慮使用文檔碎片來構建DOM結構,而後再將其添加到現存的文檔中。
對於大的DOM更改,使用innerHTML要比使用標準的DOM方法建立一樣的DOM結構快得多。
不少人喜歡在JavaScript中使用document.write來給頁面生成內容。事實上這樣的效率較低,若是須要直接插入HTML,能夠找一個容器元素,好比指定一個div或者span,並設置他們的innerHTML來將本身的HTML代碼插入到頁面中。一般咱們可能會使用字符串直接寫HTML來建立節點,其實這樣作,1沒法保證代碼的有效性2字符串操做效率低,因此應該是用document.createElement()方法,而若是文檔中存在現成的樣板節點,應該是用cloneNode()方法,由於使用createElement()方法以後,你須要設置屢次元素的屬性,使用cloneNode()則能夠減小屬性的設置次數——一樣若是須要建立不少元素,應該先準備一個樣板節點。
刪除dom節點以前,必定要刪除註冊在該節點上的事件,無論是用observe方式仍是用attachEvent方式註冊的事件,不然將會產生沒法回收的內存。另外,在removeChild和innerHTML=’’兩者之間,儘可能選擇後者. 由於在sIEve(內存泄露監測工具)中監測的結果是用removeChild沒法有效地釋放dom節點。
任何能夠冒泡的事件都不只僅能夠在事件目標上進行處理,目標的任何祖先節點上也能處理,使用這個知識就能夠將事件處理程序附加到更高的地方負責多個目標的事件處理,一樣,對於內容動態增長而且子節點都須要相同的事件處理函數的狀況,能夠把事件註冊提到父節點上,這樣就不須要爲每一個子節點註冊事件監聽了。另外,現有的js庫都採用observe方式來建立事件監聽,其實現上隔離了dom對象和事件處理函數之間的循環引用,因此應該儘可能採用這種方式來建立事件監聽。
最小化訪問NodeList的次數能夠極大的改進腳本的性能。
編寫JavaScript的時候必定要知道什麼時候返回NodeList對象,這樣能夠最小化對它們的訪問,進行了對getElementsByTagName()的調用,獲取了元素的childNodes屬性,獲取了元素的attributes屬性,訪問了特殊的集合,如document.forms、document.images等等,要了解了當使用NodeList對象時,合理使用會極大的提高代碼執行速度。
可使用下面幾種方式來優化循環。
大多數循環使用一個從0開始、增長到某個特定值的迭代器,在不少狀況下,從最大值開始,在循環中不斷減值的迭代器更加高效。
因爲每次循環過程都會計算終止條件,因此必須保證它儘量快,也就是說避免屬性查找或者其它的操做,最好是將循環控制量保存到局部變量中,也就是說對數組或列表對象的遍歷時,提早將length保存到局部變量中,避免在循環的每一步重複取值。
循環體是執行最多的,因此要確保其被最大限度的優化
在JavaScript中,咱們可使用for(;;),while(),for(in)三種循環,事實上,這三種循環中for(in)的效率極差,由於他須要查詢散列鍵,只要能夠,就應該儘可能少用。for(;;)和while循環,while循環的效率要優於for(;;),多是由於for(;;)結構的問題,須要常常跳轉回去。
最經常使用的for循環和while循環都是前測試循環,而如do-while這種後測試循環,能夠避免最初終止條件的計算,所以運行更快。
當循環次數是肯定的,消除循環並使用屢次函數調用每每會更快。
若是要提升代碼性能,儘量避免出現須要按照JavaScript解釋的字符串,也就是儘可能少使用eval函數, 使用eval至關於在運行時再次調用解釋引擎對內容進行運行,須要消耗大量時間,並且使用Eval帶來的安全性問題也是不容忽視的。
不要給setTimeout或者setInterval傳遞字符串參數
將條件分支,按可能性順序從高到低排列:能夠減小解釋器對條件的探測次數,在同一條件子的多(>2)條件分支時,使用switch優於if:switch分支選擇的效率高於if,在IE下尤其明顯。4分支的測試,IE下switch的執行時間約爲if的一半,使用三目運算符替代條件分支。
重複值:任何在多處用到的值都應該抽取爲一個常量,用戶界面字符串:任何用於顯示給用戶的字符串,都應該抽取出來以方便國際化,URLs:在Web應用中,資源位置很容易變動,因此推薦用一個公共地方存放全部的URL,任意可能會更改的值:每當你用到字面量值的時候,你都要問一下本身這個值在將來是否是會變化,若是答案是「是」,那麼這個值就應該被提取出來做爲一個常量。
因爲JavaScript是弱類型的,因此它不會作任何的自動類型檢查,因此若是看到與null進行比較的代碼,嘗試使用如下技術替換,若是值應爲一個引用類型,使用instanceof操做符檢查其構造函數,若是值應爲一個基本類型,做用typeof檢查其類型,若是是但願對象包含某個特定的方法名,則使用typeof操做符確保指定名字的方法存在於對象上。
全局變量應該所有字母大寫,各單詞之間用_下劃線來鏈接。儘量避免全局變量和函數,儘可能減小全局變量的使用,由於在一個頁面中包含的全部JavaScript都在同一個域中運行。因此若是你的代碼中聲明瞭全局變量或者全局函數的話,後面的代碼中載入的腳本文件中的同名變量和函數會覆蓋掉(overwrite)你的。
由於JavaScript能夠在任什麼時候候修改任意對象,這樣就能夠以不可預計的方式覆寫默認的行爲,因此若是你不負責維護某個對象,它的對象或者它的方法,那麼你就不要對它進行修改,具體一點就是說:
不要爲實例或原型添加屬性
不要爲實例或者原型添加方法
不要重定義已經存在的方法
不要重複定義其它團隊成員已經實現的方法,永遠不要修改不是由你全部的對象,你能夠經過如下方式爲對象建立新的功能。
建立包含所需功能的新對象,並用它與相關對象進行交互
建立自定義類型,繼承須要進行修改的類型,而後能夠爲自定義類型添加額外功能
若是循環引用中包含DOM對象或者ActiveX對象,那麼就會發生內存泄露。內存泄露的後果是在瀏覽器關閉前,即便是刷新頁面,這部份內存不會被瀏覽器釋放。簡單的循環引用:
可是一般不會出現這種狀況。一般循環引用發生在爲dom元素添加閉包做爲expendo的時候。
init在執行的時候,當前上下文咱們叫作context。這個時候,context引用了el,el引用了function,function引用了context。這時候造成了一個循環引用。
下面2種方法能夠解決循環引用:
將el置空,context中不包含對dom對象的引用,從而打斷循環應用。若是咱們須要將dom對象返回,能夠用以下方法:
把function抽到新的context中,這樣,function的context就不包含對el的引用,從而打斷循環引用。
IE下,腳本建立的dom對象,若是沒有append到頁面中,刷新頁面,這部份內存是不會回收的!
將dom元素的innerHTML設置爲空字符串,能夠釋放其子元素佔用的內存。在rich應用中,用戶也許會在一個頁面上停留很長時間,可使用該方法釋放積累得愈來愈多的dom元素使用的內存。
在rich應用中,隨着實例化對象數量的增長,內存消耗會愈來愈大。因此應當及時釋放對對象的引用,讓GC可以回收這些內存控件。 對象:obj = null 對象屬性:delete obj.myproperty 數組item:使用數組的splice方法釋放數組中不用的item
對string的方法調用,好比'xxx'.length,瀏覽器會進行一個隱式的裝箱操做,將字符串先轉換成一個String對象。推薦對聲明有可能使用String實例方法的字符串時,採用以下寫法:
var myString = new String('Hello World');
經過將case語句按照最可能到最不可能的順序進行組織
當進行數字運算時,位運算操做要比任何布爾運算或者算數運算快
在if語句中,即便條件表達式只有一條語句也要用{}把它括起來,以避免後續若是添加了語句以後形成邏輯錯誤。
JavaScript 和其餘編程語言不一樣的是,在 JavaScript 中,'+'除了表示數字值相加,字符串相鏈接之外,還能夠做一元運算符用,把字符串轉換爲數字。於是若是使用不當,則可能與自增符'++'混淆而引發計算錯誤。
一條有返回值的return語句不要用()括號來括住返回值,若是返回表達式,則表達式應與return關鍵字在同一行,以免壓縮時,壓縮工具自動加分號而形成返回與開發人員不一致的結果。
避免在if和while語句的條件部分進行賦值,如if (a = b),應該寫成if (a == b),可是在比較是否相等的狀況下,最好使用全等運行符,也就是使用===和!==操做符會相對於==和!=會好點。==和!=操做符會進行類型強制轉換。
不要使用生偏語法,寫讓人迷惑的代碼,雖然計算機可以正確識別並運行,可是晦澀難懂的代碼不方便之後維護。
雖然JavaScript是弱類型的,對於函數來講,前面返回整數型數據,後面返回布爾值在編譯和運行均可以正常經過,但爲了規範和之後維護時容易理解,應保證函數應返回統一的數據類型。
雖然在JavaScript當中,雙引號和單引號均可以表示字符串, 爲了不混亂,咱們建議在HTML中使用雙引號,在JavaScript中使用單引號,但爲了兼容各個瀏覽器,也爲了解析時不會出錯,定義JSON對象時,最好使用雙引號。
要檢查你的方法輸入的全部數據,一方面是爲了安全性,另外一方面也是爲了可用性。用戶隨時隨地都會輸入錯誤的數據。這不是由於他們蠢,而是由於他們很忙,而且思考的方式跟你不一樣。用typeof方法來檢測你的function接受的輸入是否合法。
最近加班加點錄製了一套JS系列視頻,涵蓋了JS基礎、JQ基礎、JS高級、JS實戰四個部分,你們能夠報名學習下,都是免費的,後續我還會錄製一套MVVM系列的視頻,報名下面的課程後,你們也能夠加我微信,有什麼前端技術問題,均可以隨時跟我討論的。
JS系列視頻教程地址:點擊學習>>>
個人微信(消息備註"掘金",謝謝!):