摘要:常出現的錯誤前十位為了可讀性,錯誤名稱進行了一定的簡寫。讓我們深入了解每個錯誤發生的原因以及解決方法。這個問題很容易解決。當未捕獲的錯誤跨越違法跨域策略的域邊界時,會發生腳本錯誤。這是當你在中試圖調用的方法時出現的錯誤。
JavaScript常出現的錯誤前十位
為了可讀性,錯誤名稱進行了一定的簡寫。讓我們深入了解每個錯誤發生的原因以及解決方法。
1. Uncaught TypeError: Cannot Read Property如果你是一名JavaScript開發人員,你可能已經記不清楚多少次看到這個錯誤了。當你讀取一個undefined對象的屬性或是調用其上的方法時,就會出現這個錯誤。你可以再Chrome Console中進行測試。
導致這個問題的原因有許多,最常見的是渲染UI組件時對state不恰當的初始化。讓我們看一個真實APP中可能出現該情況的例子。我們選擇了React,但是這樣的不良初始化也適用于Angular,Vue或是其它的框架。
class Quiz extends Component { componentWillMount() { axios.get("/thedata").then(res => { this.setState({items: res.data}); }); } render() { return (
這里要注意兩件重要的事情:
組件的state(比如 this.state)在生命周期開始時為undefined。
當你異步獲取數據的時候,component會在數據加載之前至少渲染一次 - 無論是否在constructor中獲取數據,都會運行componentWillMount或是componentDidMount。當Quiz第一次渲染的時候,this.state.items為undefined。因此,item列表獲得的值為undefined,因此會報錯"Uncaught TypeError: Cannot read property ‘map’ of undefined"。
這個問題很容易解決。最簡單的方法是,在構造器里面將state初始化為一個合理的默認值。
class Quiz extends Component { // Added this: constructor(props) { super(props); // Assign state itself, and a default value for items this.state = { items: [] }; } componentWillMount() { axios.get("/thedata").then(res => { this.setState({items: res.data}); }); } render() { return (
這和你的項目中的代碼不一定完全相同,但是我們希望給你提供一個解決或是避免該問題的思路。
2. TypeError: ‘undefined’ Is Not an Object (evaluating...)這是一個在Safari中在undefined對象上訪問屬性或方法時報的錯。你可以在Safari的控制臺上進行測試。這個錯誤和之前在Chrome中出現的錯誤是相同,只是報錯信息不同。
這是在Safari中在訪問null對象上的屬性或方法時報的錯。
有趣的是,在JavaScript中,null和undefined是不同的,所以我們看到了兩個不同的報錯信息。Undefined通常是指一個尚未賦值的變量,而null是指該變量的值為空。要想判斷二者不等,應當使用嚴格的相等操作符:
在真實世界中,這種錯誤可能出現的原因之一是你試圖在元素加載完成之前訪問DOM元素。對于空白的對象引用,DOM API會返回null。
任何對DOM元素進行處理的JS代碼都應該都在DOM元素創建完成之后進行。JS代碼按照HTML中的規定按從上到下的順序進行解釋。所以,如果在DOM元素之前存在標簽,則腳本標簽內的JS代碼將在瀏覽器解析HTML頁面時執行。如果在加載腳本之前尚未創建相關的DOM元素,就會出現此錯誤。
在這個例子中,我們通過添加一個事件監聽器通知我們頁面已經完成加載,來解決這個問題。一旦addEventListener被觸發,init()方法就能夠使用DOM元素。
4. (unknown): Script Error
當未捕獲的JavaScript錯誤跨越違法跨域策略的域邊界時,會發生腳本錯誤。比如,如果你將你的JavaScript代碼托管到CDN上,任何未被捕捉的錯誤(沒有被try-catch塊捕獲,被冒泡至window.onerror處理器的錯誤)將會被簡單的報告為Script Error,不包含任何有用的信息。這是瀏覽器的一種安全措施,旨在防止跨域傳遞數據。
要想獲得真正的報錯信息,做以下幾步:
1. 發送Access-Control-Allow-Origin頭將Access-Control-Allow-Origin設置為.來標記該資源從任何域都可以正常訪問。如果需要的話,也可以將其設置為自己的域名:比如,Access-Control-Allow-Origin: www.example.com。但是,處理多個域會變的棘手,而且如果你是出于緩存的問題而使用CDN,那么這樣子的代價可能不值得。詳情參考這里
這里給出一些在不同的環境中設置header的例子:
Apache
在你存放JavaScript的文件夾中添加一個.htacess文件,包含以下內容:
Header add Access-Control-Allow-Origin "*"
Nginx
將add_header指令添加到為JavaScript文件提供服務的位置塊:
location ~ ^/assets/ { add_header Access-Control-Allow-Origin *; }
HAProxy
將以下內容添加到提供JavaScript的asset backend
rspadd Access-Control-Allow-Origin: *2. 在script標簽上設置crossorigin="annonymous"屬性
在HTML中,對于每一個設置了Access-Control-Allow-Origin頭的腳本,在腳本的標簽上添加crossorigin="anonymous"屬性。在將crossorigin屬性添加到腳本之前,請確保驗證是否為腳本文件設置了header。在火狐瀏覽器中,如果設置了crossorigin屬性但是沒有設置Access-Control-Allow-Origin頭,該腳本不會執行。
5. TypeError: Object Doesn’t Support Property這是在IE瀏覽器中報的錯,當你試圖調用一個undefined對象的方法時:
這等價于Chrome中的TypeError: ‘undefined’ is not a function錯誤。是的,不同的瀏覽器對相同的錯誤會產生不同的報錯信息。
對于使用JavaScript命名空間的Web程序,在IE上運行時經常會遇到這個錯誤。當這個錯誤出現時,99.9%的情況是因為IE不能將當前的命名空間的方法綁定到this關鍵字上。比如,假設你有一個JS命名空間Rollbar,其下有一個方法isAwesome()。通常在Rollbar命名空間下你會用如下的語法調用isAwesome方法:
this.isAwesome();
Chrome,Firfox和Opera都會愉快的接受這個語法。但是,IE并不會。因此,使用JS命名空間時最安全的選擇是始終以實際的命名空間作為前綴。
Rollbar.isAwesome();6. TypeError: ‘undefined’ Is Not a Function
這是當你在Chrome中試圖調用undefined的方法時出現的錯誤。
隨著JavaScript的編程技巧和設計模式在這幾年來越來越復雜,在回調和閉包中自我引用范圍的擴散也相應的增加,導致對this出現困惑。
看下面這段代碼:
function testFunction() { this.clearLocalStorage(); this.timer = setTimeout(function() { this.clearBoard(); // what is "this"? }, 0); };
運行上面的代碼會出現"Uncaught TypeError: undefined is not a function."報錯。原因是當你試圖調用setTimeout()方法時,你實際上在調用window.setTimeout()方法。因此,一個匿名的函數傳入到setTimeout()方法中,該函數的上下文實際上是window對象,而window對象沒有clearBoard()方法。
一個傳統的,瀏覽器兼容的方案是將引用this存儲到一個變量中,該引用能夠被閉包繼承,如下:
function testFunction () { this.clearLocalStorage(); var self = this; // save reference to "this", while it"s still this! this.timer = setTimeout(function(){ self.clearBoard(); }, 0); };
在新版本的瀏覽器中,你可以使用bind()方法來傳遞引用:
function testFunction () { this.clearLocalStorage(); this.timer = setTimeout(this.reset.bind(this), 0); // bind to "this" }; function reset(){ this.clearBoard(); //back in the context of the right "this"! };7. Uncaught RangeError: Maximum Call Stack
這是在Chrome中出現的一種錯誤。情況之一是當你調用了一個沒有終止的遞歸方法:
當你向方法傳了一個超越規定范圍的值也可能會出現這個報錯。很多方法只接受特定范圍的值作為輸入。比如,Number.toExponential(digits)和Number.toFixed(digits)只接受從0到20的數字,而Number.toPrecision(digits)則接受1到21的數字。
var a = new Array(4294967295); //OK var b = new Array(-1); //range error var num = 2.555555; document.writeln(num.toExponential(4)); //OK document.writeln(num.toExponential(-2)); //range error! num = 2.9999; document.writeln(num.toFixed(2)); //OK document.writeln(num.toFixed(25)); //range error! num = 2.3456; document.writeln(num.toPrecision(1)); //OK document.writeln(num.toPrecision(22)); //range error!8. TypeError: Cannot Read Property ‘length’
這是在Chrome中讀取一個undefined對象的length屬性時報的錯。
你通常可以在array中找到length屬性,但是你也可能在array還沒有初始化或是變量名被隱藏在另一個上下文中時遇到這個錯誤。讓我們用下面這個例子理解一下這個報錯:
var testArray= ["Test"]; function testFunction(testArray) { for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction();
當你在方法中聲明參數時,這些參數成為了局部變量。這意味著即使你有名為testArray的全局變量,方法中相同名稱的參數還是會被當做局部變量。
你有兩種方法來結局這個問題:
刪去方法聲明中的參數(如果你想要訪問方法外的變量,就不需要在方法參數中聲明)
var testArray = ["Test"]; /* Precondition: defined testArray outside of a function */ function testFunction(/* No params */) { for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction();
向方法傳入聲明的參數
var testArray = ["Test"]; function testFunction(testArray) { for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction(testArray);9. Uncaught TypeError: Cannot Set Property
當我們試圖訪問一個undefined的變量時,通常會返回undefined,而我們不能獲取或是設置undefined的屬性。這時候,應用就會拋出“Uncaught TypeError cannot set property of undefined.”報錯。
如果test對象不存在,也會拋出“Uncaught TypeError cannot set property of undefined.”。
10. ReferenceError: Event Is Not Defined當你試圖訪問的變量為undifined或是不在當前作用域范圍內時,會拋出這個錯誤:
如果你在使用事件處理系統時遇到這個報錯,請確保你將事件對象作為參數傳入了處理方法中。老的瀏覽器器如IE會提供一個全局的事件變量,而Chrome會自動將事件變量附屬到handler上。Firfox不會自動添加它。而類似jQuery之類的庫則試圖規范化這個行為。總之,你最好將event作為采納數傳入事件處理方法中:
document.addEventListener("mousemove", function (event) { console.log(event); })總結
看來大多數的錯誤都是null或是undefined相關的錯誤。如果你在使用編譯器的嚴格模式選項,一個良好的類型檢查系統如Typescript能夠幫助你避免這些問題。它會在一個預期類型沒有被定義時警告你。即便沒有Typescript, 它也能幫助我們使用防御性編程,在調用對象之前檢查對象是否是undefined。
我們希望你能夠學到一些新的內容,并且在未來能夠避免這些錯誤,也可能這個指南幫你解決了一些頭疼的問題。無論如何,即便是最佳實踐,在編碼過程中還是會出現意料之外的錯誤。了解影響用戶使用的錯誤并且擁有可以快速解決問題的工具是很重要的。
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注我的微信公眾號!將會不定期的發放福利哦~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107532.html
摘要:無需檢查的異常也是的子類。從低層拋出的需檢查異常強制要求調用方捕獲或是拋出該異常。當前執行的線程將會停止并報告該異常。單元測試允許我在使用中查看異常,并且作為一個可以被執行的文檔來使用。不要捕獲最高層異常繼承的異常同樣是的子類。 前言 異常處理的問題之一是知道何時以及如何去使用它。我會討論一些異常處理的最佳實踐,也會總結最近在異常處理上的一些爭論。 作為程序員,我們想要寫高質量的能夠解...
摘要:如果我們的容器使用,文件如下在這個例子中,我們可以重復創建和銷毀,同一個持久存儲會被提供給新的,無論容器位于哪個節點上。 前言 臨時性存儲是容器的一個很大的買點。根據一個鏡像啟動容器,隨意變更,然后停止變更重啟一個容器。你看,一個全新的文件系統又誕生了。 在docker的語境下: # docker run -it centos [root@d42876f95c6a /]# echo H...
摘要:如果我們的容器使用,文件如下在這個例子中,我們可以重復創建和銷毀,同一個持久存儲會被提供給新的,無論容器位于哪個節點上。 前言 臨時性存儲是容器的一個很大的買點。根據一個鏡像啟動容器,隨意變更,然后停止變更重啟一個容器。你看,一個全新的文件系統又誕生了。 在docker的語境下: # docker run -it centos [root@d42876f95c6a /]# echo H...
摘要:有可能一個線程中的動作相對于另一個線程出現亂序。當實際輸出取決于線程交錯的結果時,這種情況被稱為競爭條件。這里的問題在于代碼塊不是原子性的,而且實例的變化對別的線程不可見。這種不能同時在多個線程上執行的部分被稱為關鍵部分。 為什么要額外寫一篇文章來研究volatile呢?是因為這可能是并發中最令人困惑以及最被誤解的結構。我看過不少解釋volatile的博客,但是大多數要么不完整,要么難...
閱讀 3206·2021-11-19 09:40
閱讀 3005·2021-09-09 09:32
閱讀 791·2021-09-02 09:55
閱讀 1392·2019-08-26 13:23
閱讀 2403·2019-08-26 11:46
閱讀 1229·2019-08-26 10:19
閱讀 2054·2019-08-23 16:53
閱讀 1071·2019-08-23 12:44