常見JavaScript報錯分析
1. Uncaught TypeError: Cannot read property
如果你是一個JavaScript開發者,這種錯誤大概你已經見怪不怪了。在Chrome下,當你從一個不存在的物件(undefined)獲取屬性或則進行函式呼叫,就會報這樣的錯。你可以在Chrome瀏覽器控制檯測試:
有很多種原因可以導致這種情況的出現,一個常見的情況是在渲染UI部件的時候,沒有正確地初始化狀態(state)。我們來看一個真實的例子。在這裡我選用React,不過內在的原理同樣適用於Angular、Vue或則其它框架。
2. TypeError: ‘undefined’ is not an object (evaluating
在Safari下,如果在一個未定義(undefined)的物件上讀取屬性或則呼叫函式,就會觸發這樣的錯誤。你可以在Safari控制檯測試。這個錯誤根本上來說和第一個在Chrome下的錯誤是一樣的,只是錯誤的訊息不同。
備註:Fundebug早已機智地將這兩種情況聚合為一個錯誤了,更加方便分析,歡迎各位老鐵試用!
3. TypeError: null is not an object (evaluating
在Safari下,如果你嘗試從null讀取屬性或則呼叫方法,就會報錯。如下:
有趣的是,在JavaScript中,null和undefined是不同的,所以我們看到兩個不同的錯誤訊息。Undefined指的是一個變數沒有被賦值,而null指的是值為空。我們可以用===
一種現實中可能的情況就是:如果你嘗試在一個DOM元素載入之前使用它。那麼DOM API就會返回null。任何處理DOM元素的JS程式碼都應當在DOM載入完畢之後呼叫。JS程式碼是按照程式碼的順序從上往下依次解釋執行。如果在DOM元素前有指令碼,那麼在瀏覽器分析HTML頁面的時候,JS程式碼也在執行了。如果JS程式碼執行的時候,DOM還沒有建立好,那麼你會遇到這個錯誤。
4. (unknown): Script error
當未捕獲的 JavaScript 錯誤(通過window.onerror處理程式引發的錯誤,而不是捕獲在try-catch中)被瀏覽器的跨域策略限制時,會產生這類的指令碼錯誤。 例如,如果您將您的 JavaScript 程式碼託管在 CDN 上,則任何未被捕獲的錯誤將被報告為“指令碼錯誤” 而不是包含有用的堆疊資訊。這是一種瀏覽器安全措施,旨在防止跨域傳遞資料,否則將不允許進行通訊。
5. TypeError: Object doesn’t support property
在IE中,如果呼叫未定義的方法就會發生這種錯誤。您可以在IE開發者控制檯中進行測試。
相當於 Chrome 中的 “TypeError:”undefined“ is not a function” 錯誤。 對於相同的錯誤,不同的瀏覽器具有不同的錯誤訊息。
在IE裡使用JavaScript的名稱空間時,就很容易碰到這個錯誤。發生這個錯誤十有八九是因為IE無法將當前名稱空間裡的方法繫結到this關鍵字上。例如,假設有個名稱空間Rollbar,它有一個方法叫isAwesome()。在Rollbar名稱空間中,可以直接使用this關鍵字來呼叫這個方法:
6. TypeError: ‘undefined’ is not a function
在Chrome下,呼叫一個未定義的函式時就會發生這個錯誤,可以在Chrome/Mozilla開發者控制檯測試:
隨著js程式碼的編碼技巧和設計模式越來越複雜,在回撥函式、閉包等各種作用域中this的指向的層級也隨之增加,這就是js程式碼中this/that指向容易混淆的原因。
比如下面這段程式碼:
執行上面的程式碼會報錯:“Uncaught TypeError: undefined is not a function”。因為在呼叫setTimeout()方法時,實際上是在呼叫window.setTimeout()。傳給setTimeout()的匿名函式的this實際上是window,而window並不包含clearBoard()方法。
7. Uncaught RangeError: Maximum call stack
在Chrome裡,有幾種情況會發生這個錯誤,其中一個就是函式的遞迴呼叫,並且不能終止。這個錯誤可以在Chrome開發者控制檯重現。
還有,如果傳給函式的值超出可接受的範圍時,也會出現這個錯誤。很多函式只接受指定範圍的數值,例如,Number.toExponential(digits)和Number.toFixed(digits)方法,只接受0到20的數值,而Number.toPrecision(digits)只接受1到21的數值。
8. TypeError: Cannot read property ‘length’
在Chrome中,如果讀取未定義變數的長度屬性,會報錯。
如果陣列未初始化,或者因為作用域的問題而沒有正確地獲取到,則可能會遇到此錯誤。讓我們用下面的例子來理解這個錯誤。
函式的引數名會覆蓋全域性的變數名。也就是說,全域性的testArray被函式的引數名覆蓋了,所以在函式體裡訪問到的是本地的testArray,但本地並沒有定義testArray,所以出現了這個錯誤。
9. Uncaught TypeError: Cannot set property
如果對undefined變數進行賦值或讀取操作,會丟擲“Uncaught TypeError: cannot set property of undefined”異常。
因為test物件不存在,就會丟擲“Uncaught TypeError: cannot set property of undefined”異常。
10. ReferenceError: event is not defined
當訪問一個未定義的物件或超出當前作用域的物件,就會發生這個錯誤。
結論
看到這裡,你會發現這十大錯誤幾乎都是null/undefined錯誤。如果有一個好的靜態型別檢查系統,比如使用TypeScript可以幫助你在編譯的時候就發現問題。如果沒有使用TypeScript,那麼請多多使用條件語句做判斷,防止這種情況出現。
在生產環境中會出現各種不可預期的錯誤。關鍵是要及時發現那些影響使用者體驗的錯誤,並使用適當的工具快速發現和解決這些問題。Fundebug提供JavaScript的bug監控,助你實時發現bug。通過獨創的使用者行為記錄技術,方便開發者更好地理解為什麼出錯,如下所示: