最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript之異常處理過程

 更新時間:2026年03月25日 08:56:49   作者:吳聲子夜歌  
這篇文章主要介紹了JavaScript之異常處理過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

1、捕獲異常

在編寫代碼時,經常在控制臺看到TypeError、RangeError、ReferenceError等開頭的紅色錯誤信息,這些都是程序發(fā)出的警告,告知開發(fā)者出現(xiàn)了什么問題,并附加與代碼有關的信息,例如出錯的位置。這時可以在代碼出錯的地方使用try…catch語句塊對異常進行捕獲和處理。

try{}語句塊用于監(jiān)控內部的代碼,catch{}語句塊用于捕獲到異常后編寫異常處理語句。假設如果一個值應該為對象的變量,而實際上其值為undefined,則調用它的方法就會拋出TypeError異常,代碼如下:

     let obj=undefined;
     obj.method(); //Uncaught TypeError:Cannot read property 'method'of undefined
                     //未捕獲的類型異常:不能訪問undefined的method屬性
     console.log("這行代碼不會被執(zhí)行");

在異常拋出后,它后邊的代碼便不會被執(zhí)行了,如果obj.method()后邊還有其他代碼,則它們永遠不會被執(zhí)行,使用try…catch把異常捕獲之后就能解決這個問題了,代碼如下:

     try{
       let obj=undefined;
       obj.method();
     }catch(e){
       console.error(e.name);
       console.error("不能訪問undefined中的方法");
     }
     console.log("此行能正常執(zhí)行");
     TypeError
     不能訪問undefined中的方法
     此行能正常執(zhí)行

catch語句塊中的小括號接收一個可選的參數(shù)(如果不接收則不寫小括號)?,是try中代碼拋出來的Error對象,稍后再介紹有關Error的內容,這里訪問了它的name屬性,打印出了具體的Error對象名字,后面打印了自定義的異常信息,提示不能訪問undefined中的方法。這樣異常就被捕獲住了,并且后邊的代碼還會正常執(zhí)行。在catch語句塊打印日志時,可以使用console.error()以讓控制臺的顯示格式為錯誤信息。

如果只想捕獲異常但不處理,則也可以省略catch語句塊的參數(shù)和其中的內容,代碼如下:

     try{
       let obj=undefined;
       obj.method();
     }catch{}

2、throw拋出異常

有時候可能明確知道需要在什么地方拋出異常,而不是僅靠JavaScript運行時自動判斷,例如判斷函數(shù)參數(shù)是否符合規(guī)則,如果不符合就拋出異常,這時可以通過throw關鍵字自行拋出異常。

如果后續(xù)使用catch語句塊捕獲了該異常,則throw后邊的表達式會傳遞給catch的參數(shù),如果沒有捕獲異常,則會直接將異常打印到控制臺。另外,throw后邊的代碼不會被執(zhí)行。

throw關鍵字用法的代碼如下:

     function setName(name){
       if(!name)throw"name不能為空";
       console.log("這行代碼不會被執(zhí)行");
     }
     //未捕獲異常
     setName();                 //name不能為空

捕獲異常:

     try{
       setName();
     }catch(e){
       console.error(e);//name不能為空
     }

它會打印出"name不能為空",e參數(shù)的值就是throw后邊拋出的字符串。

throw關鍵字后邊可以是任何類型的值或表達式,例如下方的throw語句都是合法的:

     throw 10;   //拋出數(shù)字
     throw false;//拋出布爾值
     throw[];    //拋出數(shù)組
     throw{};    //拋出對象

throw語句幾乎可以用在任何地方??梢栽谌执a中、普通函數(shù)中、構造函數(shù)中、對象或類的方法中,但是不能用在需要表達式的地方,例如數(shù)組元素、函數(shù)參數(shù)、對象屬性值等當中。

如果throw語句嵌套的層次比較深,則可以在任何一層進行異常處理,例如當編寫后端Web應用程序時,一般會在處理請求和響應的控制器中統(tǒng)一處理用戶輸入錯誤、數(shù)據(jù)庫錯誤和業(yè)務邏輯錯誤等,這樣下層的代碼可以直接拋出異常,然后在最上層統(tǒng)一進行處理,代碼如下:

     function mapArr(arr){
       arr.map((v)=>{
          if(v===2){
            throw"error";
         }
         console.log(v);
       });
     }
     try{
       mapArr([1,2,3]);    //1 error
     }catch(error){
       console.log(error);
     }

mapArr使用數(shù)組的map()方法遍歷參數(shù)數(shù)組,在map()的回調函數(shù)中,判斷如果遍歷到的值為2就拋出異常,其他值則直接打印出來。代碼的輸出結果為1error,這是因為throw語句后邊的代碼不會被執(zhí)行,所以在遍歷數(shù)組元素2時,map()回調函數(shù)就停止執(zhí)行了。

這時throw語句在map()的回調函數(shù)中,后邊可以在調用mapArr()的時候再去捕獲異常,就像上方代碼一般。另外也可以在mapArr()函數(shù)中捕獲異常,代碼如下:

     function mapArr(arr){
       try{
         arr.map((v)=>{
            if(v===2){
              throw"error";
           }
            console.log(v);
         });
       }catch(error){
         console.log(error);
       }
     }

具體在何時處理異常,就要看具體的業(yè)務需求和對代碼的影響。

如果在一段代碼中使用了可能拋出異常的代碼,并且想做一些處理操作之后把相同的異常再次拋出,則可以直接在catch{}語句塊中使用throw語句把catch的參數(shù)拋出。

假設有一系列處理用戶請求的函數(shù),在收到查詢某個特定用戶信息的請求之后,由控制器交給業(yè)務邏輯層處理,再由業(yè)務邏輯層去查詢數(shù)據(jù)庫,當數(shù)據(jù)庫出錯時,在業(yè)務邏輯層做一些處理操作(例如記錄日志)?,然后直接把異常拋給控制器處理,這時就可以使用再拋出(Rethrow)來把異常原樣交給上層去處理,代碼如下:

     function queryDb(id){
       throw"未在數(shù)據(jù)庫中找到該條記錄";
     }
     function getUserByIdService(id){
       try{
         queryDb(id);
       }catch(error){
         //一些其他操作
         throw error;
       }
     }
     function getUserController(id){
       try{
         getUserByIdService(id);
       }catch(error){
         console.log(error);
       }
     }
     getUserController(1);

在getUserByIdService()函數(shù)中,當在catch里處理完其他操作之后,使用了throw把error參數(shù)拋出,之后在getUserController()中處理了這個異常。

throw后邊也可以拋出更具有實際意義的Error對象,11.3節(jié)來看一下它的用法。

3、Error對象

Error是JavaScript內置的對象,用于表示異常信息,它有name和message兩個屬性,分別為異常的名字和消息,它還有一個toString()方法,用于把異常信息轉換為字符串。這些屬性和方法是瀏覽器和Node.js都支持的,不過對于不同的瀏覽器,Error還會有更多的屬性,例如lineNumber異常出現(xiàn)的行號、columnNumber異常出現(xiàn)的列號和stack異常的堆棧信息。

不過,Error對象是基礎對象,一般需要通過繼承的方式來定義更明確的異常對象。JavaScript根據(jù)Error對象擴展出了如下幾種內置的異常對象。

  1. TypeError:表示變量或參數(shù)不是正確的類型,例如訪問undefined中的方法。
  2. RangeError:表示數(shù)字類型的變量或參數(shù)超出了指定范圍或無效。例如new Array(NaN)。
  3. ReferenceError:在引用不存在的變量時拋出,例如console.log(a)。
  4. SyntaxError:在使用錯誤的語法時拋出。例如let 32=5(使用了數(shù)字作為變量名)?。

這些異常的name屬性值就是各自的構造函數(shù)的名字,如TypeError、RangeError。

在使用throw語句時,可以在它后邊的表達式中直接創(chuàng)建Error對象,或創(chuàng)建上述內置的其他異常對象,這樣可以讓異常包含更豐富的信息,以便于開發(fā)者根據(jù)提示處理異常。要創(chuàng)建這些異常對象,可以直接使用它們的構造函數(shù),并傳遞一個message參數(shù)表示錯誤消息,代碼如下:

     function division(a,b){
       if(b===0)throw new Error("除數(shù)不能為0");
       return a/b;
     }
     division(5,0);           //Error:除數(shù)不能為0
                                //at division(<anonymous>:2:21)
                                //at<anonymous>:1:1

示例中的division()函數(shù)用于除法計算,如果除數(shù)為0就拋出異常。

當后邊給參數(shù)b傳遞值0時,該異常就會拋出,控制臺會打印出"Error:除數(shù)不能為0"的異常消息和堆棧信息。異常消息是通過調用Error中的toString()轉換成的字符串,其中冒號前邊為Error對象中name屬性的值,即異常的名字,后邊是message屬性的值。

上述throw語句也可以拋出一個更明確的RangeError:throw newRangeError("除數(shù)不能為0")?,這樣異常對象的name屬性就會變?yōu)镽angeError,打印出來的信息會變?yōu)椋angeError:除數(shù)不能為0"。

4、自定義異常

大部分情況下JavaScript內置的異常對象不能滿足業(yè)務的要求,一般的程序中都應該定義自己的異常對象來生成更具有業(yè)務意義上的異常對象,例如RESTful API請求異常、數(shù)據(jù)驗證異常等。通過繼承Error對象,然后修改其中默認的錯誤消息和處理方式,并添加自定義的異常信息和業(yè)務邏輯,就可以快速創(chuàng)建自定義的異常對象。

假設程序在接收到用戶輸入之后需要判斷數(shù)據(jù)是否符合驗證規(guī)則,如果不符合則拋出異常,那么這個異常可以定義為 ValidationError,它除了包括既有的name和message屬性之外,還包括用戶原始輸入信息,要創(chuàng)建它,可以通過原型方式或class方式,由于class方式比較直觀,所以本示例使用class實現(xiàn)繼承,代碼如下:

     class ValidationError extends Error{
       constructor(message,input){
          super(message+",用戶輸入:"+input);
         this.name=ValidationError.name;
         this.input=    input;
       }
     }
     function validatePassword(pwd){
       if(!pwd||pwd.length<8)
         throw new ValidationError("密碼不能小于8位",pwd);
       return true;
     }
     try{
       validatePassword("123456");
     }catch(e){
       console.log(e instanceof ValidationError);
       console.log(e.name);
       console.log(e.message);
       console.log(e.input);
     }

ValidationError繼承了Error對象,在構造函數(shù)中首先調用父類Error的構造函數(shù),使用super(message+",用戶輸入:"+input)?,初始化了message屬性,并在message屬性值的基礎上加上了用戶輸入的值。后邊給ValidationError類新添加了一個input屬性,用于保存用戶原始輸入信息,name屬性則設置為當前類的name屬性值,即ValidationError。

validatePassword()函數(shù)用于簡單地判斷密碼是否大于或等于8位,如果不是則拋出ValidationError,并分別設置異常消息和用戶原始輸入。在調用這種方法時,使用try…catch捕獲了這個異常,并打印了異常的信息,判斷它是不是ValidationError類的實例、異常的名字、消息和用戶輸入。

上述代碼的輸出結果如下:

     true
     ValidationError
     密碼不能小于8位,用戶輸入:123456
     123456

在日常開發(fā)中應盡量使用自定義的異常,這樣能夠使異常信息更具體,更符合實際的業(yè)務邏輯。

5、finally

在try…catch語句塊中,還可以添加可選的finally語句塊,一般用于在拋出異常后執(zhí)行一些收尾和清理操作,例如關閉數(shù)據(jù)庫或文件訪問句柄。finally語句塊的代碼里邊的語句必定會被執(zhí)行,無論try或catch是否執(zhí)行。如果有catch語句塊,則finally語句塊會在catch語句塊之后被執(zhí)行,如果沒有catch語句塊則會在try語句塊之后被執(zhí)行。

finally語句用法的代碼如下:

     try{
       console.log("獲取數(shù)據(jù)庫連接對象");
       throw"出現(xiàn)錯誤"
     }catch{
       console.log("不能獲取連接");
     }finally{
       console.log("關閉數(shù)據(jù)庫對象")
     }

上述代碼會輸出的結果如下:

     獲取數(shù)據(jù)庫連接對象
     不能獲取連接
     關閉數(shù)據(jù)庫對象

可以看到try、catch和finally的語句塊都按順序執(zhí)行了,這時如果把try中的throw注釋掉,則catch中的"不能獲取連接"就不會打印,但是finally中的"關閉數(shù)據(jù)庫對象"仍然會打印。

不過需要注意的是,如果try中有return語句,則finally語句仍然會被執(zhí)行,且在return語句后被執(zhí)行,例如把上方代碼稍做改動,放到函數(shù)中,并添加一個conn變量和return語句,來測試一下finally和return的執(zhí)行順序,代碼如下:

     function getConnection(){
       let conn=null;
       try{
         console.log("獲取數(shù)據(jù)庫連接對象");
         conn="連接對象";
         return conn;
       }catch{
         console.log("不能獲取連接");
       }finally{
         console.log("關閉數(shù)據(jù)庫對象");
         conn="連接已關閉";
       }
     }
     let conn=getConnection();
     console.log(conn);                 //"連接對象"

可以看到conn先于return被執(zhí)行出來了,console.log(conn)打印出了finally對conn進行修改前的值,為了進一步驗證可以在finally再加上一個return語句,代碼如下:

     finally{
       console.log("關閉數(shù)據(jù)庫對象");
       conn="連接已關閉";
       return conn;
     }

這次打印出來了"連接已關閉",因為finally語句塊最后被執(zhí)行,所以它里邊的return覆蓋掉了try中的return語句。當然這里只是為了演示它們的順序,在實際開發(fā)中不應該在同一函數(shù)中有兩個return語句。

在捕獲異常時,catch和finally語句塊至少需要存在一個,要么是try…catch,要么是try…finally,要么是try…catch…finally,如果只有一個try{}語句,則程序會拋出語法錯誤,提示try后邊缺少catch或finally語句,代碼如下:

     try{
       throw"異常"
     }
     //語法錯誤:try后邊缺少catch或finally語句

6、捕獲多個異常

有些程序代碼可能會同時拋出多個異常,在常見的后端開發(fā)中,數(shù)據(jù)庫的訪問、業(yè)務邏輯的處理、用戶請求的處理等都有可能拋出異常,然后在控制器(最上層處理用戶請求的地方)中統(tǒng)一進行異常處理,這時需要根據(jù)不同的異常類型來響應不同的HTTP狀態(tài)碼。

不過,JavaScript不像Java中可以用多個catch語句塊捕獲多種不同類型的異常,它只支持一個catch語句塊,在里邊可以通過if/else語句進行異常判斷。

例如下方示例在一個函數(shù)中返回了不同類型的異常,并且在catch語句塊中同時處理,代碼如下:

     function division(a,b){
       if(typeof a!=="number")throw new TypeError("a必須為數(shù)字");
       if(typeof b!=="number")throw new TypeError("b必須為數(shù)字");
       if(b===0)throw new RangeError("除數(shù)不能為0");
       return a/b;
     }
     try{
       division(1,"a");
       //division(1,0);
     }catch(e){
       if(e instanceof TypeError){
         console.log("類型不正確");
       }else if(e instanceof RangeError){
         console.log("取值不正確");
       }else{
         console.log(e);
       }
     }

上述代碼會輸出"類型不正確",如果把division(1,"a")注釋掉,并取消division(1,0)的注釋,則會打印出"取值不正確"。

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

最新評論

平原县| 璧山县| 泰州市| 尚义县| 高唐县| 霍邱县| 溆浦县| 竹北市| 厦门市| 沧州市| 河南省| 治县。| 黄大仙区| 尼木县| 长垣县| 佛冈县| 平山县| 芜湖市| 蓬溪县| 锦屏县| 天水市| 张家港市| 凤山市| 庄河市| 霍州市| 北海市| 巍山| 石柱| 丹巴县| 浪卡子县| 朔州市| 东乡族自治县| 永泰县| 新巴尔虎右旗| 苏尼特右旗| 台安县| 大姚县| 安化县| 阜阳市| 瑞丽市| 洛川县|