一直在學習javascript,也有看過《犀利開發Jquery內核詳解與實踐》,對這本書的評價只有兩個字犀利,多是對javascript理解的還不夠透徹異或是本身太笨,更多的是本身不擅於思考懶得思考以致於裏面說的一些精髓都沒有太深刻的理解。javascript
鑑於想讓本身有一個提高,進不了一個更加廣闊的天地,總得找一個屬於本身的居所好好生存,因此平時會有意無心的去積累一些使用jQuerry的經常使用知識,特別是對於性能要求這一塊,老是會想是否是有更好的方式來實現。html
下面是我總結的一些小技巧,僅供參考。(我先會說一個總標題,而後用一小段話來講明這個意思 再最後用一個demo來簡單言明)java
一、避免全局查找node
在一個函數中會用到全局對象存儲爲局部變量來減小全局查找,由於訪問局部變量的速度要比訪問全局變量的速度更快些數組
function search() { //當我要使用當前頁面地址和主機域名 alert(window.location.href + window.location.host); } //最好的方式是以下這樣 先用一個簡單變量保存起來 function search() { var location = window.location; alert(location.href + location.host); }
二、定時器緩存
若是針對的是不斷運行的代碼,不該該使用setTimeout,而應該是用setInterval,由於setTimeout每一次都會初始化一個定時器,而setInterval只會在開始的時候初始化一個定時器安全
var timeoutTimes = 0; function timeout() { timeoutTimes++; if (timeoutTimes < 10) { setTimeout(timeout, 10); } } timeout(); //能夠替換爲: var intervalTimes = 0; function interval() { intervalTimes++; if (intervalTimes >= 10) { clearInterval(interv); } } var interv = setInterval(interval, 10);
三、字符串鏈接app
若是要鏈接多個字符串,應該少使用+=,如dom
s+=a;函數
s+=b;
s+=c;
應該寫成s+=a + b + c;
而若是是收集字符串,好比屢次對同一個字符串進行+=操做的話,最好使用一個緩存,使用JavaScript數組來收集,最後使用join方法鏈接起來
var buf = []; for (var i = 0; i < 100; i++) { buf.push(i.toString()); } var all = buf.join("");
四、避免with語句
和函數相似 ,with語句會建立本身的做用域,所以會增長其中執行的代碼的做用域鏈的長度,因爲額外的做用域鏈的查找,在with語句中執行的代碼確定會比外面執行的代碼要慢,在能不使用with語句的時候儘可能不要使用with語句。
with (a.b.c.d) { property1 = 1; property2 = 2; } //能夠替換爲: var obj = a.b.c.d; obj.property1 = 1; obj.property2 = 2;
五、數字轉換成字符串
般最好用"" + 1來將數字轉換成字符串,雖然看起來比較醜一點,但事實上這個效率是最高的,性能上來講:
("" +) > String() > .toString() > new String()
六、浮點數轉換成整型
不少人喜歡使用parseInt(),其實parseInt()是用於將字符串轉換成數字,而不是浮點數和整型之間的轉換,咱們應該使用Math.floor()或者Math.round()
七、各類類型轉換
var myVar = "3.14159", str = "" + myVar, // to string i_int = ~ ~myVar, // to integer f_float = 1 * myVar, // to float b_bool = !!myVar, /* to boolean - any string with length and any number except 0 are true */ array = [myVar]; // to array
若是定義了toString()方法來進行類型轉換的話,推薦顯式調用toString(),由於內部的操做在嘗試全部可能性以後,會嘗試對象的toString()方法嘗試可否轉化爲String,因此直接調用這個方法效率會更高
八、多個類型聲明
在JavaScript中全部變量均可以使用單個var語句來聲明,這樣就是組合在一塊兒的語句,以減小整個腳本的執行時間,就如上面代碼同樣,上面代碼格式也挺規範,讓人一看就明瞭。
九、插入迭代器
如var name=values[i]; i++;前面兩條語句能夠寫成var name=values[i++]
十、使用直接量
var aTest = new Array(); //替換爲 var aTest = []; var aTest = new Object; //替換爲 var aTest = {}; var reg = new RegExp(); //替換爲 var reg = /../; //若是要建立具備一些特性的通常對象,也可使用字面量,以下: var oFruit = new O; oFruit.color = "red"; oFruit.name = "apple"; //前面的代碼可用對象字面量來改寫成這樣: var oFruit = { color: "red", name: "apple" };
十一、使用DocumentFragment優化屢次append
一旦須要更新DOM,請考慮使用文檔碎片來構建DOM結構,而後再將其添加到現存的文檔中。
for (var i = 0; i < 1000; i++) { var el = document.createElement('p'); el.innerHTML = i; document.body.appendChild(el); } //能夠替換爲: var frag = document.createDocumentFragment(); for (var i = 0; i < 1000; i++) { var el = document.createElement('p'); el.innerHTML = i; frag.appendChild(el); } document.body.appendChild(frag);
十二、使用一次innerHTML賦值代替構建dom元素
對於大的DOM更改,使用innerHTML要比使用標準的DOM方法建立一樣的DOM結構快得多。
var frag = document.createDocumentFragment(); for (var i = 0; i < 1000; i++) { var el = document.createElement('p'); el.innerHTML = i; frag.appendChild(el); } document.body.appendChild(frag); //能夠替換爲: var html = []; for (var i = 0; i < 1000; i++) { html.push('<p>' + i + '</p>'); } document.body.innerHTML = html.join('');
1三、經過模板元素clone,替代createElement
不少人喜歡在JavaScript中使用document.write來給頁面生成內容。事實上這樣的效率較低,若是須要直接插入HTML,能夠找一個容器元素,好比指定一個div或者span,並設置他們的innerHTML來將本身的HTML代碼插入到頁面中。一般咱們可能會使用字符串直接寫HTML來建立節點,其實這樣作,1沒法保證代碼的有效性2字符串操做效率低,因此應該是用document.createElement()方法,而若是文檔中存在現成的樣板節點,應該是用cloneNode()方法,由於使用createElement()方法以後,你須要設置屢次元素的屬性,使用cloneNode()則能夠減小屬性的設置次數——一樣若是須要建立不少元素,應該先準備一個樣板節點
var frag = document.createDocumentFragment(); for (var i = 0; i < 1000; i++) { var el = document.createElement('p'); el.innerHTML = i; frag.appendChild(el); } document.body.appendChild(frag); //替換爲: var frag = document.createDocumentFragment(); var pEl = document.getElementsByTagName('p')[0]; for (var i = 0; i < 1000; i++) { var el = pEl.cloneNode(false); el.innerHTML = i; frag.appendChild(el); } document.body.appendChild(frag);
1四、 使用firstChild和nextSibling代替childNodes遍歷dom元素
var nodes = element.childNodes; for (var i = 0, l = nodes.length; i < l; i++) { var node = nodes[i]; //…… } //能夠替換爲: var node = element.firstChild; while (node) { //…… node = node.nextSibling; }
1五、刪除DOM節點
刪除dom節點以前,必定要刪除註冊在該節點上的事件,無論是用observe方式仍是用attachEvent方式註冊的事件,不然將會產生沒法回收的內存。另外,在removeChild和innerHTML=’’兩者之間,儘可能選擇後者. 由於在sIEve(內存泄露監測工具)中監測的結果是用removeChild沒法有效地釋放dom節點
1六、使用事件代理
任何能夠冒泡的事件都不只僅能夠在事件目標上進行處理,目標的任何祖先節點上也能處理,使用這個知識就能夠將事件處理程序附加到更高的地方負責多個目標的事件處理,一樣,對於內容動態增長而且子節點都須要相同的事件處理函數的狀況,能夠把事件註冊提到父節點上,這樣就不須要爲每一個子節點註冊事件監聽了。另外,現有的js庫都採用observe方式來建立事件監聽,其實現上隔離了dom對象和事件處理函數之間的循環引用,因此應該儘可能採用這種方式來建立事件監聽
1七、重複使用的調用結果,事先保存到局部變量
//避免屢次取值的調用開銷 var h1 = element1.clientHeight + num1; var h2 = element1.clientHeight + num2; //能夠替換爲: var eleHeight = element1.clientHeight; var h1 = eleHeight + num1; var h2 = eleHeight + num2;
1八、注意NodeList
最小化訪問NodeList的次數能夠極大的改進腳本的性能
var images = document.getElementsByTagName('img'); for (var i = 0, len = images.length; i < len; i++) { }
編寫JavaScript的時候必定要知道什麼時候返回NodeList對象,這樣能夠最小化對它們的訪問
要了解了當使用NodeList對象時,合理使用會極大的提高代碼執行速度
1九、優化循環
可使用下面幾種方式來優化循環
大多數循環使用一個從0開始、增長到某個特定值的迭代器,在不少狀況下,從最大值開始,在循環中不斷減值的迭代器更加高效
因爲每次循環過程都會計算終止條件,因此必須保證它儘量快,也就是說避免屬性查找或者其它的操做,最好是將循環控制量保存到局部變量中,也就是說對數組或列表對象的遍歷時,提早將length保存到局部變量中,避免在循環的每一步重複取值。
var list = document.getElementsByTagName('p'); for (var i = 0; i < list.length; i++) { //…… } //替換爲: var list = document.getElementsByTagName('p'); for (var i = 0, l = list.length; i < l; i++) { //…… }
循環體是執行最多的,因此要確保其被最大限度的優化
在JavaScript中,咱們可使用for(;;),while(),for(in)三種循環,事實上,這三種循環中for(in)的效率極差,由於他須要查詢散列鍵,只要能夠,就應該儘可能少用。for(;;)和while循環,while循環的效率要優於for(;;),多是由於for(;;)結構的問題,須要常常跳轉回去。
var arr = [1, 2, 3, 4, 5, 6, 7]; var sum = 0; for (var i = 0, l = arr.length; i < l; i++) { sum += arr[i]; } //能夠考慮替換爲: var arr = [1, 2, 3, 4, 5, 6, 7]; var sum = 0, l = arr.length; while (l--) { sum += arr[l]; }
最經常使用的for循環和while循環都是前測試循環,而如do-while這種後測試循環,能夠避免最初終止條件的計算,所以運行更快。
20、展開循環
當循環次數是肯定的,消除循環並使用屢次函數調用每每會更快。
2一、避免雙重解釋
若是要提升代碼性能,儘量避免出現須要按照JavaScript解釋的字符串,也就是
使用eval至關於在運行時再次調用解釋引擎對內容進行運行,須要消耗大量時間,並且使用Eval帶來的安全性問題也是不容忽視的。
不要給setTimeout或者setInterval傳遞字符串參數
var num = 0; setTimeout('num++', 10); //能夠替換爲: var num = 0; function addNum() { num++; } setTimeout(addNum, 10);
2二、縮短否認檢測
if (oTest != '#ff0000') { //do something } if (oTest != null) { //do something } if (oTest != false) { //do something } //雖然這些都正確,但用邏輯非操做符來操做也有一樣的效果: if (!oTest) { //do something }
2三、條件分支
if (a > b) { num = a; } else { num = b; } //能夠替換爲: num = a > b ? a : b;
2四、使用常量
2五、避免與null進行比較
因爲JavaScript是弱類型的,因此它不會作任何的自動類型檢查,因此若是看到與null進行比較的代碼,嘗試使用如下技術替換
2六、避免全局量
全局變量應該所有字母大寫,各單詞之間用_下劃線來鏈接。儘量避免全局變量和函數, 儘可能減小全局變量的使用,由於在一個頁面中包含的全部JavaScript都在同一個域中運行。因此若是你的代碼中聲明瞭全局變量或者全局函數的話,後面的代碼中載入的腳本文件中的同名變量和函數會覆蓋掉(overwrite)你的。
//糟糕的全局變量和全局函數 var current = null; function init(){ //... } function change() { //... } function verify() { //... } //解決辦法有不少,Christian Heilmann建議的方法是: //若是變量和函數不須要在「外面」引用,那麼就可使用一個沒有名字的方法將他們全都包起來。 (function(){ var current = null; function init() { //... } function change() { //... } function verify() { //... } })(); //若是變量和函數須要在「外面」引用,須要把你的變量和函數放在一個「命名空間」中 //咱們這裏用一個function作命名空間而不是一個var,由於在前者中聲明function更簡單,並且能保護隱私數據 myNameSpace = function() { var current = null; function init() { //... } function change() { //... } function verify() { //... } //全部須要在命名空間外調用的函數和屬性都要寫在return裏面 return { init: init, //甚至你能夠爲函數和屬性命名一個別名 set: change }; };
2七、尊重對象的全部權
由於JavaScript能夠在任什麼時候候修改任意對象,這樣就能夠以不可預計的方式覆寫默認的行爲,因此若是你不負責維護某個對象,它的對象或者它的方法,那麼你就不要對它進行修改,具體一點就是說: