這次帶給大家關於JS拋出錯誤使用匯總,JS拋出錯誤的注意事項有哪些,下面就是實戰案例,一起來看一下。
在JS中拋出錯誤是一門藝術。摸清楚程式碼中哪裡合適拋出錯誤是需要時間的。因此,一旦搞清楚了這一點,調試程式碼的事件將大大縮短,對程式碼的滿意度將急劇提升。
錯誤的本質
當某些非期望的事情發生時程式就引發一個錯誤。也許是給函數傳遞了一個不正確的值,或是數學運算碰到了一個無效的運算元。 程式語言定義了一組基本的規則,當偏離了這些規則時將導致錯誤,然後開發者能修復程式碼。如果錯誤沒有被拋出或報告給你的話,調試是非常困難的。如果所有的失敗都是悄無聲息的,首要的問題是那必將消耗你大量的時間才能發現它,更不要說單獨隔離並修復它了。所以,錯誤是開發者的朋友,而不是敵人。
錯誤常常在非期望的地點、不恬當的時機跳出來,這很麻煩。更糟的是,預設的錯誤訊息通常太簡潔而無法解釋到底是什麼東西出錯了。 JS錯誤訊息以資訊稀少、隱晦含糊而臭名昭著(特別是在舊版的IE中),這只會讓問題更加複雜。想像一下,如果跳出一個錯誤能這樣描述:「由於發生這些情況,該函數呼叫失敗」。那麼,調試任務馬上就會變得更簡單,這正是拋出自己的錯誤的好處。
像內建的失敗案例一樣來考慮錯誤是非常有幫助的。在程式碼某個特殊之處規劃一個失敗總比要在所有的地方都預期失敗簡單的多。在產品設計上,這是非常普遍的實踐經驗,而不僅僅是在程式碼編寫方面。汽車仍有碰撞力吸收區域,這些區域框架的設計旨在撞擊發生時以可預測的方式崩塌。知道一個碰撞到來時這些框架將如何反應——特別是,哪些部分將失敗——製造商將能確保乘客的安全。你的程式碼也可以用這種方法來創建。
在JS中拋出錯誤
毫無疑問,在JS中拋出錯誤要比在任何其他語言中做同樣的事情更加有價值,這歸咎於Web端調試的複雜性。可以使用throw操作符,將提供的一個物件作為錯誤拋出。任何類型的物件都可以作為錯誤拋出,然而,Error物件是最常用的。
throw new Error('Something bad happened.');
內建的Error類型在所有的JS實作中都是有效的,它的建構器只接受一個參數,指稱錯誤訊息(message)。以這種方式拋出錯誤時,如果沒有透過try-catch語句來捕獲的話,瀏覽器通常直接顯示該訊息(message字串)。當今大多數瀏覽器都有一個控制台(console),一旦發生錯誤都會在這裡輸出錯誤訊息。換言之,任何你拋出的和沒拋出的錯誤都被以相同的方式來對待。
缺乏經驗的開發者有時直接將一個字串作為錯誤拋出,如:
// 不好的写法throw 'message';
這樣做確實能夠拋出一個錯誤,但不是所有的瀏覽器做出的回應都會按照你的預期。 Firefox、Opera和Chrome都會顯示一則「uncaught exception」訊息,同時它們包含上述訊息字串。 Safari和IE只是簡陋地拋出一個「uncaught exception」錯誤,完全不提供上述訊息字串,這種方式對偵錯無益。
顯然,如果你願意,你可以拋出任何類型的資料。沒有任何規則約束不能是特定的資料型別。
throw { name: 'Nicholas' };throw true;throw 12345;throw new Date();
就一件事情需要牢記,如果沒有透過try-catch語句捕獲,拋出任何值都會引發一個錯誤。 Firefox、Opera和Chrome都會在該拋出的值上呼叫String()函數,來完成錯誤訊息的顯示邏輯,但Safari和IE不是這樣的。針對所有的瀏覽器,唯一不出差錯的顯示自訂的錯誤訊息的方式就是用一個Error物件。
拋出錯誤的好處
拋出自己的錯誤可以使用確切的文字供瀏覽器顯示。除了行和列的號碼,還可以包含任何你需要的有助於調試問題的資訊。我推薦總是在錯誤訊息中包含函數名稱,以及函數失敗的原因。考察下面的函數:
function getDivs (element) { return element.getElementsByTagName('div'); }
這個函數旨在獲取element元素下所有後代元素中的div元素。傳遞給函數要操作的DOM元素為null值可能是件很常見的事情,但實際需要的是DOM元素。如果給這個函數傳遞null會發生什麼情況呢?你會看到一個類似「object expected」的含糊的錯誤訊息。然後,你要去看執行棧,再實際定位到原始檔中的問題。透過拋出一個錯誤,調試會更簡單:
function getDivs (element) { if (element && element.getElementsByTagName) { return element.getElementsByTagName('div'); } else { throw new Error('getDivs(): Argument must be a DOM element.'); } }
现在给getDivs()函数抛出一个错误,任何时候只要element不满足继续执行的条件,就会抛出一个错误明确地陈述发生的问题。如果在浏览器控制台中输出该错误,你马上能开始调试,并知道最有可能导致该错误的原因是调用函数试图用一个值为null的DOM元素去做进一步的事情。
我倾向于认为抛出错误就像给自己留下告诉自己为什么失败的标签。
何时抛出错误
理解了如何抛出错误只是等式的一个部分,另外一部分就是要理解什么时候抛出错误。由于JS没有类型和参数检查,大量的开发者错误地假设他们自己应该实现每个函数的类型检查。这种做法并不实际,并且会对脚本的整体性能造成影响。考察下面的函数,它试图实现充分的类型检查。
// 不好的做法:检查了太多的错误function addClass (element, className) { if (!element || typeof element.className !== 'string') { throw new Error('addClass(): First argument must be a DOM element.'); } if (typeof className !== 'string') { throw new Error('addClass(): Second argument must be a string.'); } element.className += '' + className; }
这个函数本来只是简单地给一个给定的元素增加一个CSS类名(className),因此,函数的大部分工作变成了错误检查。纵然它能在每个函数中检查每个参数(模仿静态语言),在JS中这么做也会引起过度的杀伤。辨识代码中哪些部分在特定的情况下最有可能导致失败,并只在那些地方抛出错误才是关键所在。
在上例中,最有可能引发错误的是给函数传递一个null引用值。如果第二个参数是null或者一个数字或者一个布尔值是不会抛出错误的,因为JS会将其强制转换为字符串。那意味着导致DOM元素的显示不符合期望,但这并不至于提高到严重错误的程度。所以,我只会检查DOM元素。
// 好的写法function addClass (element, className) { if (!element || typeof element.className !== 'string') { throw new Error('addClass(): First argument must be a DOM element.'); } element.className += '' + className; }
如果一个函数只被已知的实体调用,错误检查很可能没有必要(这个案例是私有函数);如果不能提前确定函数会被调用的所有地方,你很可能需要一些错误检查。这就更有可能从抛出自己的错误中获益。抛出错误最佳的地方是在工具函数中,如addClass()函数,它是通用脚本环境中的一部分,会在很多地方使用,更准确的案例是JS类库。
针对已知条件引发的错误,所有的JS类库都应该从它们的公共接口里抛出错误。如jQuery、YUI和Dojo等大型的库,不可能预料你在何时何地调用了它们的函数。当你做错事的时候通知你是它们的责任,因为你不可能进入库代码中去调试错误的原因。函数调用栈应该在进入库代码接口时就终止,不应该更深了。没有比看到由一打库代码中函数调用时发生一个错误更加糟糕的事情了吧,库的开发者应该承担起防止类似情况发生的责任。
私有JS库也类似。许多Web应用程序都有自己专用的内置的JS库或“拿来”一些有名的开源类库(类似jQuery)。类库提供了对脏的实现细节的抽象,目的是让开发者用得更爽。抛出错误有助于对开发者安全地隐藏这些脏的实现细节。
这里有一些关于抛出错误很好的经验法则:
一旦修复了一个很难调试的错误,尝试增加一两个自定义错误。当再次发生错误时,这将有助于更容易地解决问题。
如果正在编写代码,思考一下:“我希望[某些事情]不会发生,如果发生,我的代码会一团糟糕”。这时,如果“某些事情”发生,就抛出一个错误。
如果正在编写的代码别人(不知道是谁)也会使用,思考一下他们使用的方式,在特定的情况下抛出错误。
请牢记,我们目的不是防止错误,而是在错误发生时能更加容易地调试。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上是關於JS拋出錯誤使用匯總的詳細內容。更多資訊請關注PHP中文網其他相關文章!