web移动开发最佳实践之js篇
一、js概述
js即JavaScript,是被設(shè)計(jì)用來(lái)驗(yàn)證表單、檢測(cè)瀏覽器、創(chuàng)建cookies、改進(jìn)設(shè)計(jì)以及更多應(yīng)用的網(wǎng)絡(luò)腳本語(yǔ)言,它非常容易使用。在web應(yīng)用中,它是主要的編程語(yǔ)言,主要用途是進(jìn)行各種邏輯控制、行為展現(xiàn)等。對(duì)于js的優(yōu)化,對(duì)于整個(gè)應(yīng)用的提升都是非常顯著的。
二、使用字面量(literal notation)來(lái)聲明對(duì)象和數(shù)組
創(chuàng)建對(duì)象和數(shù)組的方法有很多,但是使用字面量是最簡(jiǎn)單最快的。傳統(tǒng)的方法是使用內(nèi)建的構(gòu)造器聲明:
//create an object var obj = new Object(); obj.debug = false; obj.lang = "en";//create an array var arr = new Array("one", "two", "three");這種方式在技術(shù)上是沒(méi)問(wèn)題的,但是使用字面量聲明會(huì)更快而且代碼更少:
//create an object var obj = {debug: false, lang: "en"};//create an array var arr = ["one", "two", "three"];三、避免使用全局變量和函數(shù)
即把屬性和方法都綁定到一個(gè)命名空間對(duì)象里,這樣不僅可以減少命名沖突,而且可以提升程序性能。
當(dāng)兩個(gè)區(qū)域的代碼使用同一個(gè)全局變量名作不同用途時(shí),就會(huì)產(chǎn)生命名沖突。在JavaScript里,函數(shù)外定義的變量或?qū)ο蠖际?strong>全局的,隨著程序代碼和庫(kù)的增加,命名沖突的概率就越大。如果函數(shù)內(nèi)或其他區(qū)域的代碼引用了一個(gè)特定的全局變量,腳本引擎就必須遍歷一遍作用域直到找到這個(gè)變量,局部變量則更容易找到。全局變量會(huì)在整個(gè)腳本的生命周期中存在,但是局部變量會(huì)及時(shí)被垃圾收集器回收。
例如以下使用全局的聲明(不高效):
//define global variables var lang = "en"; var debug = true;//define global function function setLang (arg) {lang = arg; }使用如下聲明則更好:
var myApp = {lang: "en",debug: true, };myApp.setLang = function (arg) {this.lang = arg; }四、高效的使用try catch語(yǔ)句
你可以使用try-catch語(yǔ)句來(lái)攔截程序拋出的錯(cuò)誤(在瀏覽器處理之前),這對(duì)于向用戶隱藏錯(cuò)誤或者為用戶定制錯(cuò)誤信息是很有用的。
當(dāng)try結(jié)構(gòu)中發(fā)生錯(cuò)誤時(shí),程序會(huì)立即停止并跳到catch結(jié)構(gòu)(會(huì)提供錯(cuò)誤對(duì)象)中。在catch結(jié)構(gòu)中,錯(cuò)誤對(duì)象會(huì)賦給一個(gè)新的變量,新的變量在catch結(jié)構(gòu)中一直存在,直到catch語(yǔ)句結(jié)束。創(chuàng)建并處理這個(gè)新的運(yùn)行時(shí)變量會(huì)影響到程序的性能,在關(guān)鍵功能和循環(huán)中應(yīng)避免使用try-catch結(jié)構(gòu)。例如:
var object = ['foo', 'bar'], i; for (i = 0; i < object.length; i++) {try {// do something} catch (e) {// handle exception } }以上這段代碼可能會(huì)拋出多個(gè)錯(cuò)誤,這樣寫(xiě)可能會(huì)更好:
var object = ['foo', 'bar'], i; try {for (i = 0; i < object.length; i++) {// do something } } catch (e) {// handle exception }五、使用賦值運(yùn)算來(lái)連接字符串
字符串連接是很常用的操作,也有很多種方式,比如:
//Using the concatenation (+) operator str = "h" + "e"; //Using the shorthand assigment (+=) operator str += "l"; //Using string.concat() str = str.concat("l", "o"); //Using array.join() str = ["h", "e", "l", "l", "o"].join("");如果你執(zhí)行的連接操作次數(shù)較少,那么以上任何一種方式都可以。但是,當(dāng)執(zhí)行大量的連接操作時(shí),就需要優(yōu)化一下了:
//Slower: Concatenating strings with + operator str += "x" + "y";以上連接操作比較慢,它會(huì)按以下步驟執(zhí)行(參見(jiàn)‘編譯原理’):
你可以使用如下的方式避免使用臨時(shí)變量(減少內(nèi)存的使用):
str += "x"; str += "y";六、優(yōu)化你的循環(huán)
當(dāng)你使用循環(huán)的時(shí)候,你可以通過(guò)減少每次迭代時(shí)工作量來(lái)優(yōu)化循環(huán)的整體性能。例如:
for (var i = 0; i < arr.length; i++) {// length of arr is recalculated every time }在以上代碼中,arr.length在每次循環(huán)中都被計(jì)算了一次,這是不必要的,可以聲明一個(gè)局部變量len來(lái)緩存這個(gè)值,就會(huì)提高運(yùn)行速度:
for (var i = 0, len = arr.length; i < len; i++) {// cache the length of the array }或者為了進(jìn)一步優(yōu)化,考慮反向的執(zhí)行循環(huán)(如果不關(guān)心數(shù)組成員的順序的話):
for (var i = arr.length; i--;) {// in reverse }七、避免使用eval()方法
eval()方法可以執(zhí)行一段JavaScript代碼,應(yīng)該避免使用的原因:
- 性能較差,它必須調(diào)用編譯器來(lái)傳遞其參數(shù),然后執(zhí)行
- 安全問(wèn)題,因?yàn)樗鼤?huì)執(zhí)行傳遞給它的任何代碼,所以容易受各種注入攻擊,特別是在來(lái)源未知的時(shí)候
- 不利于調(diào)試,eval的參數(shù)是動(dòng)態(tài)產(chǎn)生的,調(diào)試起來(lái)不方便,可讀性也較差
另外timeout函數(shù)中的setTimeout()和setInterval()也可以接受字符串參數(shù),然后執(zhí)行,因此表現(xiàn)跟eval()一樣。應(yīng)該避免傳遞字符串,如下:
// Incorrect usage: Passing a string to setInterval() var oElement = null; setInterval('oElement = document.getElementById("pepe");', 0);// Correct usage: Passing a function to setInterval() var oElement = null; setInterval(function() {oElement = document.getElementById("pepe"); }, 0);八、使用事件委托
在處理DOM事件的時(shí)候,你可以僅對(duì)一個(gè)父元素綁定一個(gè)事件而不是每一個(gè)子元素。這種技術(shù)即事件委托,它利用事件冒泡來(lái)分配事件處理程序,可以提高腳本的性能。比如,一個(gè)div元素下面有10個(gè)按鈕,你可以給div綁定一個(gè)監(jiān)聽(tīng)事件,而不是給10個(gè)按鈕分別綁定一個(gè)事件。傳統(tǒng)的聲明方式:
<a href="javascript:handleClick();">Click</a> <button id="btn1" onclick="handleClick();">One</button> <button id="btn2" onclick="handleClick();">Two</button>為了提高代碼的性能,我們可以加一個(gè)div父元素,事件會(huì)向上冒泡,直到被處理。事件對(duì)象是觸發(fā)事件的元素,我們可以根據(jù)它的id屬性來(lái)判斷是哪一個(gè)元素觸發(fā)了事件:
<div id="btngroup"><button id="btn1">One</button><button id="btn2">Two</button> </div> document.getElementById("btngroup").addEventListener("click", function (event) {switch (event.srcElement.id) { //firefox 下為 event.target.idcase "btn1":handleClick();break;default:handleClick();} }, false); // type, listener, useCapture (true=beginning, false=end)九、盡量減少DOM操作
DOM是一個(gè)包含了很多信息的復(fù)雜的API,因此即使是很小的操作可能會(huì)花費(fèi)較長(zhǎng)的時(shí)間執(zhí)行(如果要重繪頁(yè)面的話)。為了提高程序性能,應(yīng)盡量減少DOM操作,這里有一些建議:
1.減少DOM的數(shù)目
DOM節(jié)點(diǎn)的數(shù)目會(huì)影響與它相關(guān)的所有操作,要盡量使DOM樹(shù)小一些:
- 避免多余的標(biāo)記和嵌套的表格
- 元素?cái)?shù)盡量控制在500個(gè)以內(nèi)(document.getElementsByTagName('*').length)
2.緩存已經(jīng)訪問(wèn)過(guò)的節(jié)點(diǎn)
當(dāng)訪問(wèn)過(guò)一個(gè)DOM元素后,就應(yīng)該把它緩存起來(lái),因?yàn)槟愕某绦蛲?strong>重復(fù)訪問(wèn)某個(gè)對(duì)象的,例如:
for (var i = 0; i < document.images.length; i++) {document.images[i].src = "blank.gif"; }以上例子中,docum.images對(duì)象被訪問(wèn)了多次,這并不高效,因?yàn)槊恳淮窝h(huán)中,瀏覽器都要查找這個(gè)元素兩次:第一次讀取它的長(zhǎng)度,第二次改變相應(yīng)的src值。更好的做法是先把這個(gè)對(duì)象存儲(chǔ)起來(lái):
var imgs = document.images; for (var i = 0; i < imgs.length; i++) { //當(dāng)然也可以把 imgs.length 提前算出來(lái),這里不是重點(diǎn)imgs[i].src = "blank.gif"; }十、減少頁(yè)面重繪
在控制DOM元素?cái)?shù)目的同時(shí),你還可以通過(guò)減少修改元素(減少頁(yè)面的重繪)的方法來(lái)提高性能。重繪有兩種方式:repaint、reflow。
1.repaint,也叫redraw,即改變了元素的視覺(jué)效果,但是不影響它的排版(比如改變背景顏色)
2.reflow,會(huì)影響部分或者全部頁(yè)面的排版,瀏覽器不僅要計(jì)算該元素的位置,還要計(jì)算它影響到的周圍的元素位置
當(dāng)你要改變頁(yè)面布局的時(shí)候,reflow就發(fā)生了,主要有如下情況:
- 增加或刪除DOM節(jié)點(diǎn)
- 改變?cè)氐奈恢?/span>
- 改變?cè)氐某叽?#xff08;如margin,padding,border,font,width,height等)
- 調(diào)整瀏覽器窗口的尺寸
- 增加或刪除css
- 改變內(nèi)容(如用戶輸入表單)
- 命中css選擇器(如hover)
- 更改了class屬性
- 利用腳本更改了DOM
- 檢索一個(gè)必須被計(jì)算的尺寸(如offsetWidth,offsetHeight)
- 設(shè)置了一個(gè)css屬性
這里有一些減少頁(yè)面重繪的建議:
css的建議:
- 改變class屬性時(shí)應(yīng)盡量少的影響到周圍的元素節(jié)點(diǎn)
- 避免聲明多個(gè)內(nèi)聯(lián)的樣式(把多個(gè)樣式放在一個(gè)外部文件里)
- 有動(dòng)畫(huà)的元素使用絕對(duì)定位,這樣不會(huì)影響其他元素
- 避免使用table來(lái)排版,如果需要使用保存數(shù)據(jù),那么要固定排版(table-layout:fixed)
js的建議:
- 緩存計(jì)算過(guò)的樣式
- 對(duì)于固定的樣式,改變class的名詞而不是樣式;對(duì)于動(dòng)態(tài)的樣式,改變cssText屬性: // bad - changing the stle - accessing DOM multiple times var myElement = document.getElementById('mydiv'); myElement.style.borderLeft = '2px'; myElement.style.borderRight = '3px'; myElement.style.padding = '5px';// good - use cssText and modify DOM once var myElement = document.getElementById('mydiv'); myElement.style.cssText = 'border-left: 2px; border-right: 3px; padding: 5px;';
- 當(dāng)你要對(duì)一個(gè)DOM元素做出很多修改時(shí),可以先進(jìn)行一些‘預(yù)處理’,批量修改后再替換原始的元素
- 創(chuàng)建一個(gè)副本(cloneNode()),對(duì)這個(gè)副本進(jìn)行更新,然后替代原來(lái)的節(jié)點(diǎn) // slower - multiple reflows var list = ['foo', 'bar', 'baz'], elem, contents; for (var i = 0; i < list.length; i++) {elem = document.createElement('div');content = document.createTextNode(list[i]);elem.appendChild(content);document.body.appendChild(elem); // multiple reflows }// faster - create a copy var orig = document.getElementById('container'),clone = orig.cloneNode(true), // create a copylist = ['foo', 'bar', 'baz'], elem, contents; clone.setAttribute('width', '50%');
- 修改一個(gè)不可見(jiàn)的元素,可以先讓其不可見(jiàn)(display:none),修改完成后,再恢復(fù)其可見(jiàn)(display:block),這樣就會(huì)減少reflow的次數(shù) // slower var subElem = document.createElement('div'),elem = document.getElementById('animated'); elem.appendChild(subElem); elem.style.width = '320px';// faster var subElem = document.createElement('div'),elem = document.getElementById('animated'); elem.style.display = 'none'; // will not be repainted elem.appendChild(subElem); elem.style.width = '320px'; elem.style.display = 'block';
- 創(chuàng)建一個(gè)文檔片段(使用DocumentFragment()),修改完成后,再把它追加到原始文檔中 // slower var list = ['foo', 'bar', 'baz'], elem, contents; for (var i = 0; i < list.length; i++) {elem = document.createElement('div');content = document.createTextNode(list[i]);elem.appendChild(content);document.body.appendChild(elem); // multiple reflows }// faster var fragment = document.createDocumentFragment(),list = ['foo', 'bar', 'baz'], elem, contents; for (var i = 0; i < list.length; i++) {elem = document.createElement('div');content = document.createTextNode(list[i]);fragment.appendChild(content); } document.body.appendChild(fragment); // one reflow
?
轉(zhuǎn)載于:https://www.cnblogs.com/xiangzi888/archive/2013/01/19/2867630.html
總結(jié)
以上是生活随笔為你收集整理的web移动开发最佳实践之js篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: tnsnames.ora无法保存的问题
- 下一篇: 雷鸣----总结下男人30岁之前要知道的