欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入分析javascript中的錯誤處理機制

 更新時間:2016年07月17日 21:36:09   投稿:hebedich  
這篇文章主要介紹了深入分析javascript中的錯誤處理機制的相關(guān)資料,需要的朋友可以參考下

前面的話

  錯誤處理對于web應用程序開發(fā)至關(guān)重要,不能提前預測到可能發(fā)生的錯誤,不能提前采取恢復策略,可能導致較差的用戶體驗。由于任何javascript錯誤都可能導致網(wǎng)頁無法使用,因此作為開發(fā)人員,必須要知道何時可能出錯,為什么會出錯,以及會出什么錯。本文將詳細介紹javascript中的錯誤處理機制

error對象

  error對象是包含錯誤信息的對象,是javascript的原生對象。當代碼解析或運行時發(fā)生錯誤,javascript引擎就會自動產(chǎn)生并拋出一個error對象的實例,然后整個程序就中斷在發(fā)生錯誤的地方

console.log(t);//Uncaught ReferenceError: t is not defined

  ECMA-262規(guī)定了error對象包括兩個屬性:message和name。message屬性保存著錯誤信息,而name屬性保存錯誤類型

復制代碼 代碼如下:

//一般地,使用try-catch語句來捕獲錯誤
try{
    t;
}catch(ex){
    console.log(ex.message);//t is not defined
    console.log(ex.name);//ReferenceError
}

  瀏覽器還對error對象的屬性做了擴展,添加了其他相關(guān)信息。其中各瀏覽器廠商實現(xiàn)最多的是stack屬性,它表示棧跟蹤信息(safari不支持)

復制代碼 代碼如下:

try{
    t;
}catch(ex){
    console.log(ex.stack);//@file:///D:/wamp/www/form.html:12:2
}

  當然,可以使用error()構(gòu)造函數(shù)來創(chuàng)建錯誤對象。如果指定message參數(shù),則該error對象將把它用做它的message屬性;若不指定,它將使用一個預定義的默認字符串作為該屬性的值

復制代碼 代碼如下:

new Error();
new Error(message);   
//一般地,使用throw語句來拋出錯誤
throw new Error('test');//Uncaught Error: test
throw new Error();//Uncaught Error

復制代碼 代碼如下:

function UserError(message) {
   this.message = message;
   this.name = "UserError";
}
UserError.prototype = new Error();
UserError.prototype.constructor = UserError;
throw new UserError("errorMessage");//Uncaught UserError: errorMessage

  當不使用new操作符,直接將Error()構(gòu)造函數(shù)像一個函數(shù)一樣調(diào)用時,它的行為和帶new操作符調(diào)用時一樣

復制代碼 代碼如下:

Error();
Error(message);   
throw Error('test');//Uncaught Error: test
throw Error();//Uncaught Error

  error對象有一個toString()方法,返回'Error:'+ error對象的message屬性

復制代碼 代碼如下:

var test = new Error('testError');
console.log(test.toString());//'Error: testError'

error類型

  執(zhí)行代碼期間可能會發(fā)生的錯誤有多種類型。每種錯誤都有對應的錯誤類型,而當錯誤發(fā)生時,就會拋出相應類型的錯誤對象。ECMA-262定義了下列7種錯誤類型:

復制代碼 代碼如下:

Error
EvalError(eval錯誤)
RangeError(范圍錯誤)
ReferenceError(引用錯誤)
SyntaxError(語法錯誤)
TypeError(類型錯誤)
URIError(URI錯誤)

  其中,Error是基類型,其他錯誤類型都繼承自該類型。因此,所有錯誤類型共享了一組相同的屬性。Error類型的錯誤很少見,如果有也是瀏覽器拋出的;這個基類型的主要目的是供開發(fā)人員拋出自定義錯誤

【EvalError(eval錯誤)】

  eval函數(shù)沒有被正確執(zhí)行時,會拋出EvalError錯誤。該錯誤類型已經(jīng)不再在ES5中出現(xiàn)了,只是為了保證與以前代碼兼容,才繼續(xù)保留

【RangeError(范圍錯誤)】

  RangeError類型的錯誤會在一個值超出相應范圍時觸發(fā),主要包括超出數(shù)組長度范圍以及超出數(shù)字取值范圍等

復制代碼 代碼如下:

new Array(-1);//Uncaught RangeError: Invalid array length
new Array(Number.MAX_VALUE);//Uncaught RangeError: Invalid array length

(1234).toExponential(21);//Uncaught RangeError: toExponential() argument must be between 0 and 20
(1234).toExponential(-1);////Uncaught RangeError: toExponential() argument must be between 0 and 20


【ReferenceError(引用錯誤)】

  引用一個不存在的變量或左值(lvalue)類型錯誤時,會觸發(fā)ReferenceError(引用錯誤)

a;//Uncaught ReferenceError: a is not defined
1++;//Uncaught ReferenceError: Invalid left-hand side expression in postfix operation
【SyntaxError(語法錯誤)】

  當不符合語法規(guī)則時,會拋出SyntaxError(語法錯誤)

復制代碼 代碼如下:

//變量名錯誤
var 1a;//Uncaught SyntaxError: Unexpected number
// 缺少括號
console.log 'hello');//Uncaught SyntaxError: Unexpected string

【TypeError(類型錯誤)】

  在變量中保存著意外的類型時,或者在訪問不存在的方法時,都會導致TypeError類型錯誤。錯誤的原因雖然多種多樣,但歸根結(jié)底還是由于在執(zhí)行特定類型的操作時,變量的類型并不符合要求所致

復制代碼 代碼如下:

var o = new 10;//Uncaught TypeError: 10 is not a constructor
alert('name' in true);//Uncaught TypeError: Cannot use 'in' operator to search for 'name' in true
Function.prototype.toString.call('name');//Uncaught TypeError: Function.prototype.toString is not generic

【URIError(URI錯誤)】

  URIError是URI相關(guān)函數(shù)的參數(shù)不正確時拋出的錯誤,主要涉及encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()這六個函數(shù)

decodeURI('%2');// URIError: URI malformed

error事件

  任何沒有通過try-catch處理的錯誤都會觸發(fā)window對象的error事件

  error事件可以接收三個參數(shù):錯誤消息、錯誤所在的URL和行號。多數(shù)情況下,只有錯誤消息有用,因為URL只是給出了文檔的位置,而行號所指的代碼行既可能出自嵌入的JavaScript代碼,也可能出自外部的文件

  要指定onerror事件處理程序,可以使用DOM0級技術(shù),也可以使用DOM2級事件的標準格式

復制代碼 代碼如下:

//DOM0級
window.onerror = function(message,url,line){
    alert(message);
}
//DOM2級
window.addEventListener("error",function(message,url,line){
    alert(message);
});

  瀏覽器是否顯示標準的錯誤消息,取決于onerror的返回值。如果返回值為false,則在控制臺中顯示錯誤消息;如果返回值為true,則不顯示

復制代碼 代碼如下:

//控制臺顯示錯誤消息
window.onerror = function(message,url,line){
    alert(message);
    return false;
}
a;
//控制臺不顯示錯誤消息
window.onerror = function(message,url,line){
    alert(message);
    return true;
}
a;

  這個事件處理程序是避免瀏覽器報告錯誤的最后一道防線。理想情況下,只要可能就不應該使用它。只要能夠適當?shù)厥褂胻ry-catch語句,就不會有錯誤交給瀏覽器,也就不會觸發(fā)error事件

  圖像也支持error事件。只要圖像的src特性中的URL不能返回可以被識別的圖像格式,就會觸發(fā)error事件。此時的error事件遵循DOM格式,會返回一個以圖像為目標的event對象

  加載圖像失敗時會顯示一個警告框。發(fā)生error事件時,圖像下載過程已經(jīng)結(jié)束,也就是不能再重新下載了

復制代碼 代碼如下:

var image = new Image();
image.src = 'smilex.gif';
image.onerror = function(e){
    console.log(e);
}

throw語句與拋出錯誤

  throw語句用于拋出錯誤。拋出錯誤時,必須要給throw語句指定一個值,這個值是什么類型,沒有要求

  [注意]拋出錯誤的過程是阻塞的,后續(xù)代碼將不會執(zhí)行

復制代碼 代碼如下:

throw 12345;
throw 'hello world';
throw true;
throw {name: 'javascript'};

  可以使用throw語句手動拋出一個Error對象

復制代碼 代碼如下:

throw new Error('something bad happened');
throw new SyntaxError('I don\'t like your syntax.');
throw new TypeError('what type of variable do you take me for?');
throw new RangeError('sorry,you just don\'t have the range.');
throw new EvalError('That doesn\'t evaluate.');
throw new URIError('URI, is that you?');
throw new ReferenceError('you didn\'t cite your references properly');

  利用原型鏈還可以通過繼承Error來創(chuàng)建自定義錯誤類型(原型鏈在第6章中介紹)。此時,需要為新創(chuàng)建的錯誤類型指定name和message屬性

  瀏覽器對待繼承自Error的自定義錯誤類型,就像對待其他錯誤類型一樣。如果要捕獲自己拋出的錯誤并且把它與瀏覽器錯誤區(qū)別對待的話,創(chuàng)建自定義錯誤是很有用的

復制代碼 代碼如下:

function CustomError(message){
    this.name = 'CustomError';
    this.message = message;
}
CustomError.prototype = new Error();
throw new CustomError('my message');

  在遇到throw語句時,代碼會立即停止執(zhí)行。僅當有try-catch語句捕獲到被拋出的值時,代碼才會繼續(xù)執(zhí)行

  更詳細的解釋為:當拋出異常時,javascript解釋器會立即停止當前正在執(zhí)行的邏輯,并跳轉(zhuǎn)到就近的異常處理程序。異常處理程序是用try-catch語句的catch從句編寫的。如果拋出異常的代碼塊沒有一條相關(guān)聯(lián)的catch從句,解釋器會檢查更高層的閉合代碼塊,看它是否有相關(guān)聯(lián)的異常處理程序。以此類推,直到找到一個異常處理程序為止。如果拋出異常的函數(shù)沒有處理它的try-catch語句,異常將向上傳播到調(diào)用該函數(shù)的代碼。這樣的話,異常就會沿著javascript方法的詞法結(jié)構(gòu)和調(diào)用棧向上傳播。如果沒有找到任何異常處理程序,javascript將把異常當成程序錯誤來處理,并報告給用戶

try catch語句與捕獲錯誤

  ECMA-262第3版引入了try-catch語句,作為JavaScript中處理異常的一種標準方式,用于捕獲和處理錯誤

  其中,try從句定義了需要處理的異常所在的代碼塊。catch從句跟隨在try從句之后,當try塊內(nèi)某處發(fā)生了異常時,調(diào)用catch內(nèi)的代碼邏輯。catch從句后跟隨finally塊,后者中放置清理代碼,不管try塊中是否產(chǎn)生異常,finally塊內(nèi)的邏輯總是會執(zhí)行。盡管catch和finally都是可選的,但try從句需要至少二者之一與之組成完整的語句

  try/catch/finally語句塊都需要使用花括號括起來,這里的花括號是必需的,即使從句中只有一條語句也不能省略花括號

try{
    //通常來講,這里的代碼會從頭到尾而不會產(chǎn)生任何問題
    //但有時會拋出一個異常,要么是由throw語句直接拋出,要么通過調(diào)用一個方法間接拋出
}catch(e){
    //當且僅當try語句塊拋出了異常,才會執(zhí)行這里的代碼
    //這里可以通過局部變量e來獲得對Error對象或者拋出的其他值的引用
    //這里的代碼塊可以基于某種原因處理這個異常,也可以忽略這個異常,還可以通過throw語句重新拋出異常
}finally{
    //不管try語句是否拋出了異常,finally里的邏輯總是會執(zhí)行,終止try語句塊的方式有:
    //1、正常終止,執(zhí)行完語句塊的最后一條語句
    //2、通過break、continue或return語句終止
    //3、拋出一個異常,異常被catch從句捕獲
    //4、拋出一個異常,異常未被捕獲,繼續(xù)向上傳播
}

  一般地,把所有可能會拋出錯誤的代碼都放在try語句塊中,而把那些用于錯誤處理的代碼放在catch塊中

  如果try塊中的任何代碼發(fā)生了錯誤,就會立即退出代碼執(zhí)行過程,然后接著執(zhí)行catch塊。此時,catch塊會接收到一個錯誤信息的對象,這個對象中包含的實際信息會因瀏覽器而異,但共同的是有一個保存著錯誤消息的message屬性

  [注意]一定要給error對象起個名字,置空會報語法錯誤

復制代碼 代碼如下:

try{
    q;
}catch(error){
    alert(error.message);//q is not defined
}
//Uncaught SyntaxError: Unexpected token )
try{
    q;
}catch(){
    alert(error.message);
}

  catch接受一個參數(shù),表示try代碼塊拋出的值

復制代碼 代碼如下:

function throwIt(exception) {
  try {
    throw exception;
  } catch (e) {
    console.log('Caught: '+ e);
  }
}
throwIt(3);// Caught: 3
throwIt('hello');// Caught: hello
throwIt(new Error('An error happened'));// Caught: Error: An error happened

  catch代碼塊捕獲錯誤之后,程序不會中斷,會按照正常流程繼續(xù)執(zhí)行下去

復制代碼 代碼如下:

try{
  throw "出錯了";
} catch (e) {
  console.log(111);
}
console.log(222);
// 111
// 222

  為了捕捉不同類型的錯誤,catch代碼塊之中可以加入判斷語句

復制代碼 代碼如下:

try {
  foo.bar();
} catch (e) {
  if (e instanceof EvalError) {
    console.log(e.name + ": " + e.message);
  } else if (e instanceof RangeError) {
    console.log(e.name + ": " + e.message);
  }
  // ...
}

  雖然finally子句在try-catch語句中是可選的,但finally子句一經(jīng)使用,其代碼無論如何都會執(zhí)行。換句話說,try語句塊中的代碼全部正常執(zhí)行,finally子句會執(zhí)行;如果因為出錯而執(zhí)行了catch語句塊,finally子句照樣還會執(zhí)行。只要代碼中包含finally子句,則無論try或catch語句塊中包含什么代碼——甚至return語句,都不會阻止finally子句的執(zhí)行

復制代碼 代碼如下:

//由于沒有catch語句塊,所以錯誤沒有捕獲。執(zhí)行finally代碼塊以后,程序就中斷在錯誤拋出的地方
function cleansUp() {
  try {
    throw new Error('出錯了……');
    console.log('此行不會執(zhí)行');
  } finally {
    console.log('完成清理工作');
  }
}
cleansUp();
// 完成清理工作
// Error: 出錯了……

復制代碼 代碼如下:

function testFinnally(){
    try{
        return 2;
    }catch(error){
        return 1;
    }finally{
        return 0;
    }
}
testFinnally();//0

  [注意]return語句的count的值,是在finally代碼塊運行之前,就獲取完成了

復制代碼 代碼如下:

var count = 0;
function countUp() {
  try {
    return count;
  } finally {
    count++;
  }
}
countUp();// 0
console.log(count);// 1

復制代碼 代碼如下:

function f() {
  try {
    console.log(0);
    throw "bug";
  } catch(e) {
    console.log(1);
    return true; // 這句原本會延遲到finally代碼塊結(jié)束再執(zhí)行
    console.log(2); // 不會運行
  } finally {
    console.log(3);
    return false; // 這句會覆蓋掉前面那句return
    console.log(4); // 不會運行
  }
  console.log(5); // 不會運行
}
var result = f();
// 0
// 1
// 3
console.log(result);// false

【tips】塊級作用域

  try-catch語句的一個常見用途是創(chuàng)建塊級作用域,其中聲明的變量僅僅在catch內(nèi)部有效

  ES6引入了let關(guān)鍵字,為其聲明的變量創(chuàng)建塊級作用域。但是,在目前ES3和ES5的情況下,常常使用try-catch語句來實現(xiàn)類似的效果

  由下面代碼可知,e僅存在于catch分句內(nèi)部,當試圖從別處引用它時會拋出錯誤

復制代碼 代碼如下:

try{
    throw new Error();//拋出錯誤
}catch(e){
    console.log(e);//Error(…)
}
console.log(e);//Uncaught ReferenceError: e is not defined

常見錯誤

  錯誤處理的核心是首先要知道代碼里會發(fā)生什么錯誤。由于javaScript是松散類型的,而且也不會驗證函數(shù)的參數(shù),因此錯誤只會在代碼期間出現(xiàn)。一般來說,需要關(guān)注三種錯誤:類型轉(zhuǎn)換錯誤、數(shù)據(jù)類型錯誤、通信錯誤

【類型轉(zhuǎn)換錯誤】

  類型轉(zhuǎn)換錯誤發(fā)生在使用某個操作符,或者使用其他可能自動轉(zhuǎn)換值的數(shù)據(jù)類型的語言結(jié)構(gòu)時

  容易發(fā)生類型轉(zhuǎn)換錯誤的地方是流控制語句。像if之類的語句在確定下一步操作之前,會自動把任何值轉(zhuǎn)換成布爾值。尤其是if語句,如果使用不當,最容易出錯

  未使用過的命名變量會自動被賦予undefined值。而undefined值可以被轉(zhuǎn)換成布爾值false,因此下面這個函數(shù)中的if語句實際上只適用于提供了第三個參數(shù)的情況。問題在于,并不是只有undefined才會被轉(zhuǎn)換成false,也不是只有字符串值才可以轉(zhuǎn)換為true。例如,假設(shè)第三個參數(shù)是數(shù)值0,那么if語句的測試就會失敗,而對數(shù)值1的測試則會通過

復制代碼 代碼如下:

function concat(str1,str2,str3){
    var result = str1 + str2;
    if(str3){ //絕對不要這樣
        result += str3;
    }
    return result;
}

  在流控制語句中使用非布爾值,是極為常見的一個錯誤來源。為避免此類錯誤,就要做到在條件比較時切實傳入布爾值。實際上,執(zhí)行某種形式的比較就可以達到這個目的

復制代碼 代碼如下:

function concat(str1,str2,str3){
    var result = str1 + str2;
    if(typeof str3 == 'string'){ //更合適
        result += str3;
    }
    return result;
}

【數(shù)據(jù)類型錯誤】

  javascript是松散類型的,在使用變量和函數(shù)參數(shù)之前,不會對它們進行比較以確保它們的數(shù)據(jù)類型正確。為了保證不會發(fā)生數(shù)據(jù)類型錯誤,只能編寫適當?shù)臄?shù)據(jù)類型檢測代碼。在將預料之外的值傳遞繪函數(shù)的情況下,最容易發(fā)生數(shù)據(jù)類型錯誤

復制代碼 代碼如下:

//不安全的函數(shù),任何非數(shù)組值都會導致錯誤
function reverseSort(values){
    if(values){
        values.sort();
        values.reverse();
    }
}

  另一個常見的錯誤就是將參數(shù)與null值進行比較。與null進行比較只能確保相應的值不是null和undefined。要確保傳入的值有效,僅檢測null值是不夠的

復制代碼 代碼如下:

//不安全的函數(shù),任何非數(shù)組值都會導致錯誤
function reverseSort(values){
    if(values != null){
        values.sort();
        values.reverse();
    }
}

  如果傳入一個包含sort()方法的對象(而不是數(shù)組)會通過檢測,但調(diào)用reverse()函數(shù)時可能會出錯

復制代碼 代碼如下:

//不安全的函數(shù),任何非數(shù)組值都會導致錯誤
function reverseSort(values){
    if(typeof values.sort == 'function'){
        values.sort();
        values.reverse();
    }
}

  在確切知道應該傳入什么類型的情況下,最好是使用instanceof來檢測其數(shù)據(jù)類型

復制代碼 代碼如下:

//安全,非數(shù)組值被忽略
function reverseSort(values){
    if(values instanceof Array){
        values.sort();
        values.reverse();
    }
}

【通信錯誤】

  隨著Ajax編程的興起,Web應用程序在其生命周期內(nèi)動態(tài)加載信息或功能,已經(jīng)成為一件司空見慣的事。不過,javascript與服務器之間的任何一次通信,都有可能會產(chǎn)生錯誤

  最常見的問題是在將數(shù)據(jù)發(fā)送給服務器之前,沒有使用encodeURIComponent()對數(shù)據(jù)進行編碼

復制代碼 代碼如下:

//錯誤
http://www.yourdomain.com/?redir=http://www.sometherdomain.com?a=b&c=d
//針對'redir='后面的所有字符串調(diào)用encodeURIComponent()就可以解決這個問題
http://www.yourdomain.com/?redir=http:%3A%2F%2Fwww.sometherdomain.com%3Fa%3Db%26c%3Dd

相關(guān)文章

  • javascript利用控件對windows的操作實現(xiàn)原理與應用

    javascript利用控件對windows的操作實現(xiàn)原理與應用

    假如要發(fā)送漢字的聊天框的內(nèi)容的話,我們也要從windows消息機制下手,先找到聊天消息的句柄(可以利用findwindow函數(shù)或者用spy工具哈),然后在找到上面的聊天框的句柄,接著我們就可以想這個句柄發(fā)送WM_SETTEXT的消息了
    2012-12-12
  • 小程序自定義模板實現(xiàn)吸頂功能

    小程序自定義模板實現(xiàn)吸頂功能

    這篇文章主要為大家詳細介紹了小程序自定義模板實現(xiàn)吸頂功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • 常見的JavaScript內(nèi)存錯誤及解決方法

    常見的JavaScript內(nèi)存錯誤及解決方法

    這篇文章主要介紹了常見的JavaScript內(nèi)存錯誤,JavaScript?不提供任何內(nèi)存管理操作。相反,內(nèi)存由?JavaScript?VM?通過內(nèi)存回收過程管理,該過程稱為垃圾收集。下面我們就來看看下面文章對JavaScript內(nèi)存錯誤的各種舉例說明吧
    2021-12-12
  • checkbox勾選判斷代碼分析

    checkbox勾選判斷代碼分析

    我們在做項目的時候,特別是注冊用戶的時候,基本上都需要有注冊協(xié)議之類的東西,那么我們?nèi)绾闻袛嘤脩羰欠窆催x了同意了此協(xié)議呢?
    2014-06-06
  • Javascript的匿名函數(shù)小結(jié)

    Javascript的匿名函數(shù)小結(jié)

    Javascript的匿名函數(shù)小結(jié),需要的朋友可以參考下。
    2009-12-12
  • JavaScript之AOP編程實例

    JavaScript之AOP編程實例

    這篇文章主要介紹了JavaScript的AOP編程,以實例形式分析了javascript面向切面編程的實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • javascript簡寫效果“神秘的眼睛”

    javascript簡寫效果“神秘的眼睛”

    “眼睛跟隨鼠標轉(zhuǎn)動效果”—— 265.com 把它放在網(wǎng)頁的LOGO里,用javascript來實現(xiàn),這個創(chuàng)意不錯! 以前剛做FLASH的時候,用AS1實現(xiàn)過,今天下班早,在家簡寫了個:
    2008-02-02
  • JS高級調(diào)試技巧:捕獲和分析 JavaScript Error詳解

    JS高級調(diào)試技巧:捕獲和分析 JavaScript Error詳解

    前端工程師都知道 JavaScript 有基本的異常處理能力。我們可以 throw new Error(),瀏覽器也會在我們調(diào)用 API 出錯時拋出異常。但估計絕大多數(shù)前端工程師都沒考慮過收集這些異常信息
    2014-03-03
  • javascript延時加載之defer測試

    javascript延時加載之defer測試

    偶爾發(fā)現(xiàn) js 中有個延時加載的標簽 defer,還在疑惑這么好用的東西為什么沒有流行起來,本人今天把它拾起來用了一下,發(fā)現(xiàn)只在ie7,8,9和360安全濟覽器下可以,知道為什么不用它了吧
    2012-12-12
  • 鍵盤元素的控制小方塊的移動效果

    鍵盤元素的控制小方塊的移動效果

    鍵盤元素的控制小方塊的移動效果...
    2007-01-01

最新評論