Javascript基礎系列之(八)Javascript的調試與優化

Javascript的錯誤主要是語法錯誤和運行時的錯誤,前者在代碼解析時就會出錯,影響程序的運行。後者稱爲異常,影響它所運行的線程。下面就Javascript常見錯誤進行分析javascript

1.常見的錯誤和異常java

i.拼寫錯誤node

任何開發者在編寫javascript程序時都犯過拼寫錯誤,例如將document.getElementsByTagName()寫成document.getElementByTagName(),將getElementByid()拼寫成getElementByID()等。還有一些大小寫的問題。例如:web

If(photo.href){
    var url= photo.href;
}

以上將關鍵字if拼寫成If,致使語法錯誤,這種拼寫錯誤一般能夠經過編寫軟件高亮顯示出來。
而另一些變量上的錯誤拼寫錯誤則稍微馬軒寫,須要開發的人耐心檢查,例如:瀏覽器

var PhotoAlbum = "isaac";
        var PhotoAlbumWife = "fresheggs";
        alert("the photo:\n"+
        PhotoAbulm + "and" + PhotoAlbumWife);

會提示 PhotoAbulm is not defined(變量未定義。)經過檢查咱們發現,定義了「PhotoAlbum」而未定義PhotoAbulm。服務器

ii.訪問未存在的變量。app

最規範的變量定義都是經過var,可是javascript容許不使用關鍵字而直接定義變量。好比如下代碼都是合法的dom

  var isaac = "husband of fresheggs";
        fresheggs = "wife of isaac";

這就無形中給檢查代碼增長了麻煩,像下面幾行代碼是比較容易發現的,瀏覽器也會相應的給出變量不存在的位置。ide

var isaac = "husband of fresheggs";
        alert(fresheggs);
        fresheggs = "wife of isaac";

可是不少時候,錯誤是十分隱蔽的函數

複製代碼
<script language="javascript">
            var oInputField;
            var oPopDiv;
            var oColorsUl;
            var aColors = ["red", "green", "blue", "magenta", "yellow", "cornfloewrblue"];

            function clearColors() {
                for (var i = oColorsUl.childNodes.length - 1; i >= 0; i--)
                    oColorsUl.removeChild(oColorsUl.childNodes[i]);
                oPopDiv.className = "hide";
            }

            function setColors(the_clors) {
                oInputField = document.forms["myForm1"].colors;
                oPopDiv = document.getElementById("popup");
                oColorsUl = document.getElementById("colors_ul");
                clearColors();
                oPopDiv.className = "show";
                var oLi;
                for (var i = 0; i < aColors.length; i++) {
                    oLi = document.createElement("li");
                    oColorsUl.appendChild(oLi);
                    oLi.appendChild(document.createTextNode(the_colors[i]));

                    oLi.onmouseover = function() {
                        this.className = "mouseOver";
                    }
                    oLi.onmouseout = function() {
                        this.className = "mouseOut";
                    }
                    oLi.onclick = function() {
                        oInputField.value = this.firstChild.nodeValue;
                        clearColors();
                    }
                }
            }
        </script>
<form method="post" name="myForm1">
            Color:
            <input type="text" name="colors" id="colors" onkeyup="setColors(aColors);" />
        </form>
        <div id="popup">
            <ul id="colors_ul"></ul>
        </div>
複製代碼

瀏覽器告知:Uncaught ReferenceError: the_colors is not defined the_colors變量未定義,仔細檢查32行

oLi.appendChild(document.createTextNode(the_colors[i]));

確沒有錯誤,其實錯誤在第22行拼寫錯誤。這樣提示和錯誤不符大大增長了檢查的難度。

function setColors(the_clors) 

iii.括號不匹配

編寫較長的邏輯關係代碼時,經常須要反覆的使用花括弧和小括弧,不少時候由於刪除某些代碼致使括號和括號後的個數不匹配。

複製代碼
function testPic(x, start, end) {
                    if (x <= end && x >= start) {
                        if (x == start) {
                            alert(x + " is the start of the range");
                        }
                        if (x == end) {
                            alert(x + " is the end of the range");
                        }
                        if (x != start && x != end) {
                            alert(x + " is in the range");
                        } else {
                            alert(x + " is not in the range");
                        }
                    }
                    testPic(7, 5, 8);
複製代碼

錯誤報告10行缺乏},但行數不必定在10行。

正確代碼

複製代碼
function testPic(x, start, end) {
                if (x <= end && x >= start) {
                    if (x == start) {
                        alert(x + " is the start of the range");
                    }
                    if (x == end) {
                        alert(x + " is the end of the range");
                    }
                    if (x != start && x != end) {
                        alert(x + " is in the range");
                    }
                } else {
                    alert(x + " is not in the range");
                }
            }
            testPic(7, 5, 8);
複製代碼

從正確的代碼能夠看到,要避免括號遺漏的最有效辦法是養成規範的編碼習慣,適當應用tab 空行等

iiii.字符串和變量鏈接錯誤

javascript在輸出結果時經常須要將字符串和變量鏈接,所以加號和引號都不少,容易錯漏

father = "isaac";
mother = "fresheggs";
child = "none";
family = father+" "+mother+" "child;

如上面的代碼,在child前邊漏掉了+號,致使程序錯誤

還有一種典型的鏈接錯誤就是javascript的類型轉化。以下代碼

a = 10;
b = 20;
c = 30;
alert("a+b+c="+a+b+c);

執行結果102030顯然不是咱們所想要的結果,解決上述問題的辦法就是利用括號把數值部分和文字串部門分別作處理,而後加起來。

a = 10;
b = 20;
c = 30;
alert("a+b+c="+(a+b+c));

iiiii.等號與賦值混淆。

在條件判斷中,經常會把等號==誤寫成賦值符號= ,這樣的語法沒有任何問題,javascript會把它處理成賦值是否成功來判斷真假

if (isaac = "talking"){
    fresheggs.hear();
}

以上代碼的執行結果是將變量isaac賦值爲"talking",若是賦值成功,則執行花括弧中的fresheggs,但開發者的本意是

if (isaac == "talking"){
    fresheggs.hear();
}

即當isaac的變量值爲"talking"時,執行fresheggs.hear();這樣的問題在程序檢查中是很難發現的

2.錯誤處理

i.用alert()和document.write()來監視變量值

在平常開發中,alert()和document.write()來監視變量值,恐怕是最經常使用和有些的解決的方法。

alert()在開發中會跳出目前的變量值,並停止程序的運行,直到點擊肯定後繼續執行。document.write()方法則是輸出變量值後繼續執行程序,由於二者的執行方法不一樣,因此給開發者帶來了選擇上的技巧。

for(var i=0;i<aColors.length;i++)
if(aColors[i].indexOf(oInputField.value)==0)
aResult.push(aColors[i]);

爲了檢測傳入aResult的值,常給if加入alert()方法來檢測,若是值不少,最好使用document.write()方法來檢測傳入值,避免反覆的進行肯定

ii.使用onerro方法

當頁面出現錯誤時,onerro事件使用window對象觸發,告訴開發者哪出了錯誤。

複製代碼
<script language="javascript">
window.onerror = function(){
    alert("出錯啦!");
}
</script>
</head>
<body onload="nonExistent()">
</body>
複製代碼

利用window.onload引用一個不存在的函數引起異常,瀏覽器自己也出現了調試錯誤,要屏蔽錯誤信息,只須要在onerror函數後面加return true便可。

複製代碼
    <script type="text/javascript">
window.onerror = function(){
    alert("出錯啦!");
    return true;    //屏蔽系統事件
}
</script>
</head>
<body onload="nonExistent()">
</body>
複製代碼

可是這樣對處理錯誤沒有任何幫助,其實onerror提供了三個參數肯定錯誤性質

<script type="text/javascript">
window.onerror = function(sMessage,sUrl,sLine){
    alert("出錯了:\n"+sMessage+"\n 地址:"+ sUrl +"\n行號:"+sLine);
    return true;    //屏蔽系統事件
}
</script>

iii.使用try...catch語句找到錯誤

js中借鑑了java的try...catch方法,該語句會先運行try裏邊的方法,若是出現錯誤則跳轉運行catch()裏面的代碼,若是有finnally,則不管是否錯誤都運行其後的代碼

try...catch的語法以下:

複製代碼
try...catch的代碼語法以下:
try{
    //代碼
}catch([exception]){
    //若是try裏面的代碼有錯,則運行
}[finally{
    //最後運行,不管是否出錯
}]
複製代碼

例子:使用try...catch語法找錯誤

複製代碼
<script type="text/javascript">
try{
    alert("this is an example");
    alert(fresheggs);
} catch(exception){
    var sError = "";
    for(var i in exception)
        sError += i + ":" + exception[i] + "\n";
    alert(sError);
}
</script>
複製代碼

在以上語法中特地輸出一個未定義的變量fresheggs,致使了異常,由此運行catch裏面的代碼,此時瀏覽器會跳出錯誤

經過try...catch能輕鬆的找到錯誤,但惋惜的是該語句並不能很好的處理語法錯誤。

以下:try語句中出現了語法錯誤,而這個代碼並無運行catch中的代碼。

複製代碼
<script type="text/javascript">
try{
    alert("this is an example") );
} catch(exception){
    var sError = "";
    for(var i in exception)
        sError += i + ":" + exception[i] + "\n";
    alert(sError);
}
</script>
複製代碼

3.使用調試器

儘管javascript不具備調試功能,可是咱們藉助ie或者firefox瀏覽器的控制檯或者調試插件能起到調試做用。

i.使用firefox錯誤控制檯進行調試

使用firefox錯誤控制檯,咱們在頁面中右鍵鼠標,審查元素,調到控制檯,js選項就能夠看到瀏覽器把頁面運行的全部js錯誤信息都傳到錯誤控制檯上,單擊每條信息就會打開對於的代碼。

firefox錯誤調試平臺比ie準確的多,在沒有特殊需求的調試要求下,是個不錯的選擇。

ii.使用Microsoft Script debugger進行調試

http://www.microsoft.com/zh-cn/download/details.aspx?id=23992

iii.使用Venkman

在火狐瀏覽器中直接安裝便可。

關於vankman 請參看http://jiangzhengjun.iteye.com/blog/481500一文。

 4.javascript的優化

i.減緩代碼的下載時間。
web瀏覽器下載的是javascript的源碼,其中包含的長變量名、註釋、空格換行等內容減緩了代碼的下載時間。這些字符對於團隊編寫代碼十分有效但在工程上傳到服務器時應當刪除。
如如下代碼

複製代碼
<script type="text/javascript">
function showMeTheMoney(money){
    if(!money){
        return false;
    }else{
        ...
    }
}
</script>
複製代碼

能夠優化成

function showMeTheMoney(money){if(!money){return false;}else{...}}

這樣優化後節省了20個字符,若這個項目是一個很大的工程,將節省很大的服務器空間,不但提升了下載速度,也減小了服務器的壓力。另外對於布爾型的值,true和false,true均可以用1來替換,false能夠用0來替換,對於true來講節省了3個字符,對於false來講節省了4個字符,例如

var bSearch = false;
for(var i = 0;i<aChoices.length&&!bSearch;i++){
    if(aChoices[i]==vValue)
    bSearch=true;
}

替換成

var bSearch = 0;
for(var i = 0;i<aChoices.length&&!bSearch;i++){
    if(aChoices[i]==vValue)
    bSearch=1;
}

代碼的執行效率,結果都相同,但節省了7個字符。

代碼中經常會出現檢測某個值是否爲有效值的語句,而不少條件非的判斷就是判斷某個變量是否爲"undefined"、"null"、"false"

複製代碼
if(myValue !=undefined){
    ...//
}
if(myValue !=null){
    ...//
}
if(myValue !=false){
    ..///
}
複製代碼

儘管這些操做符都正確,但使用「邏輯非」操做符「!」也能達到一樣的效果。

if(!myValue){
    ...//
}

並且不影響代碼的可讀性。相似的替換還有

var myTalk = new Array myTalk();
var myTalk =[];
var myTack = new Array myTack{};
var myTack ={};

另外,在編寫代碼時爲了提升可讀性,函數名稱,變量名儘可能使用簡單明瞭的代碼

function AddThreeVarsRogether(first Var,second Var,Third Var){
    return(firstVar+secondVar+thirdVar)
}

能夠縮寫成

function A(a,b,c){return(a+b+c)}

ii.合理聲明變量

合理的聲明全局變量和局部變量,一個原則,儘可能使用局部變量,即用即銷。

iii.使用內置函數縮短編譯時間

由於儘可能的使用內置函數,由於這些函數相似C,Java都是經過編譯好的,比起實時編譯的javascript效率高不少。

複製代碼
function myPower(iNum, n){
    var iResult = iNum;
    for(var i=1;i<n;i++)
        iResult *= iNum;
    return iResult;
}
document.write(myPower(5,3));
複製代碼

例如計算指數,以上的代碼邏輯沒有問題,可是比內置的函數Math.pow(5,3);執行起來效率低不少

如如下代碼

複製代碼
function myPower(iNum, n){
    var iResult = iNum;
    for(var i=1;i<n;i++)
        iResult *= iNum;
    return iResult;
}
var myDate1 = new Date();
for(var i=0;i<150000;i++){
    myPower(7,8);        //自定義方法
}
var myDate2 = new Date();
document.write(myDate2-myDate1);
document.write("<br>");
myDate1 = new Date();
for(var i=0;i<150000;i++){
    Math.pow(7,8);        //採用系統內置方法
}
myDate2 = new Date();
document.write(myDate2-myDate1);
複製代碼

讓指數函數各運算15萬次,而後分別計算運行時間,發現內置方法要比myPower方法快不少。

iiii.合理書寫if語句。

if多是代碼中使用頻率最多的,然而惋惜他的執行效率不高,所以,在多個if else時,儘可能把可能性最高的放在第一個,把可能性第二高的放在第二個,以此類推。

複製代碼
    var iNum = 1111;
            if(iNum>0&&iNum<100){
                alert("在0-100之間!")
            }else
            if(iNum>100&&iNum<200){
                alert("在100-200之間")
            }else
            if(iNum>200&&iNum<300){
                alert("200-300之間")
            }else
            {alert("小於0或大於300!")}
複製代碼

另外,以上代碼還能夠優化成

複製代碼
if (iNum > 0) {
                if (iNum < 100) {
                    alert("在0-100之間");
                } else {
                    if (iNum < 200) {
                        alert("在100-200之間!");
                    } else {
                        if (iNum < 300) {
                            alert("200-300之間!");
                        } else {
                            alert("大於300!");
                        }
                    }

                }
            }else{
                alert("小於0!")
            }
複製代碼

以上代碼看上去比較複雜,但考慮了多個因素,執行起來要比原來的代碼效率高。

另外 ,在超過兩種狀況下,最好使用switch語句,常用switch代替if語句,可以使代碼效率執行高10倍。因爲case能夠適合多種類型,大大提升了執行效率。

iiiii.最小化語句數量

var myNumber = 365;
var myString = "yellows";
var aMyNum = [8,8,4,5,6];
var oData = new Date();

以上代碼能夠用var一次性定義

var myNumber = 365,myString = "yellows",aMyNum = [8,8,4,5,6],oData = new Date();

一樣在不少迭代運算時,也儘量少的減小代碼,代碼中的語句越少

例如:

var sCar = aCars[i];
i++;

能夠寫成

var sCar = aCars[i++]

iiiiii.合理使用DOM

javascript對dom的操做多是最耗時的操做之一,每次javascript對dom操做都要重新渲染頁面一次。有比較明顯的時間消耗,儘量的方法就是不在頁面上進行dom操做。

複製代碼
    <ul id="parentUl">
            <li> 原li </li>
        </ul>
        <script type="text/javascript">
            function addElementLi(obj) {    
                var ul = document.getElementById(obj);  
                for (var i = 0; i < 10; i++) {
                    var li = document.createElement("li");    
                    li.setAttribute("id", "newli" + i);    
                    li.innerHTML = "動態添加li";    
                    ul.appendChild(li); 
                }   
            }
            addElementLi("parentUl");
        </script>
複製代碼

(本文結束,歡迎你們點評)

相關文章
相關標籤/搜索