JavaScript 除錯常見報錯以及修復方法
JavaScript 除錯是一場噩夢:首先給出的錯誤非常難以理解,其次給出的行號不總有幫助。有個查詢錯誤含義,及修復措施的列表,是不是很有用?
以下是奇怪的 JavaScript 錯誤列表。同樣的錯誤,不同的瀏覽器會給出不同的訊息,因此有一些不同的例子。
如何讀懂錯誤?
首先,讓我們快速看下錯誤資訊的結構。理解結構有助於理解錯誤,如果遇到列表之外的錯誤會減少麻煩。
Chrome 中典型的錯誤像這樣:
Uncaught TypeError: undefined is not a function
錯誤的結構如下:
Uncaught TypeError:
這部分資訊通常不是很有用。Uncaught
catch
語句捕獲,TypeError
是錯誤的名字。undefined is not a function:
這部分資訊,你必須逐字閱讀。比如這裡表示程式碼嘗試使用undefined
,把它當做一個函式。
其它基於 webkit 的瀏覽器,比如 Safari ,給出的錯誤格式跟 Chrome 很類似。Firefox 也類似,但是不總包含第一部分,最新版本的 IE 也給出比 Chrome 簡單的錯誤 - 但是在這裡,簡單並不總代表好。
以下是真正的錯誤。
Uncaught TypeError: undefined is not a function
相關錯誤:
number is not a function, object is not a function, string is not a function, Unhandled Error: ‘foo’ is not a function, Function Expected
當嘗試呼叫一個像方法的值時,這個值並不是一個方法。比如:
var foo = undefined;
foo();
如果你嘗試呼叫一個物件的方法時,你輸錯了名字,這個典型的錯誤很容易發生。
var x = document.getElementByID('foo');
由於物件的屬性不存在,預設是 undefined
如何修復錯誤:確保方法名正確。這個錯誤的行號將指出正確的位置。
Uncaught ReferenceError: Invalid left-hand side in assignment
相關錯誤:
Uncaught exception: ReferenceError: Cannot assign to ‘functionCall()’, Uncaught exception: ReferenceError: Cannot assign to ‘this’
嘗試給不能賦值的東西賦值,引起這個錯誤。
這個錯誤最常見的例子出現在 if 語句使用:
if(doSomething() = 'somevalue')
此例中,程式設計師意外地使用了單個等號,而不是雙等號。“left-hand side in assignment” 提及了等號左手邊的部分,因此你可以看到以上例子,左手邊包含不能賦值的東西,導致這個錯誤。
如何修復錯誤:確保沒有給函式結果賦值,或者給 this
關鍵字賦值。
Uncaught TypeError: Converting circular structure to JSON
相關錯誤:
Uncaught exception: TypeError: JSON.stringify: Not an acyclic Object, TypeError: cyclic object value, Circular reference in value argument not supported
把迴圈引用的物件,傳給 JSON.stringify
總會引起錯誤。
var a = { };
var b = { a: a };
a.b = b;
JSON.stringify(a);
由於以上的 a
和 b
迴圈引用彼此,結果物件無法轉換成 JSON。
如何修復錯誤: 移除任何想轉換成 JSON 的物件中的迴圈引用。
Unexpected token ;
相關錯誤:
Expected ), missing ) after argument list
JavaScript 直譯器預期的東西沒有被包含。不匹配的圓括號或方括號通常引起這個錯誤,錯誤資訊可能有所不同 - “Unexpected token ]”
或者
“Expected {”
等。
如何修復錯誤: 有時錯誤出現的行號並不準確,因此很難修復。
[ ]
{ }
( )
這幾個符號不配對常常導致出錯。檢查所有的圓括號和方括號是否配對。行號指出的不僅是問題字元。Unexpected /
跟正則表示式有關。此時行號通常是正確的。Unexpected ;
物件或者陣列字面量裡面有個;通常引起這個錯誤,或者函式呼叫的引數列表裡有個分號。此時的行號通常也是正確的。
Uncaught SyntaxError: Unexpected token ILLEGAL
相關錯誤:
Unterminated String Literal, Invalid Line Terminator
一個字串字面量少了結尾的引號。
如何修復錯誤: 確保所有的字串都有結束的引號。
Uncaught TypeError: Cannot read property ‘foo’ of null, Uncaught TypeError: Cannot read property ‘foo’ of undefined
相關錯誤:
TypeError: someVal is null, Unable to get property ‘foo’ of undefined or null reference
嘗試讀取 null
或者 undefined
,把它當成了物件。例如:
var someVal = null;
console.log(someVal.foo);
如何修復錯誤: 通常由於拼寫錯誤導致。檢查錯誤指出的行號附近使用的變數名是否正確。
Uncaught TypeError: Cannot set property ‘foo’ of null, Uncaught TypeError: Cannot set property ‘foo’ of undefined
相關錯誤:
TypeError: someVal is undefined, Unable to set property ‘foo’ of undefined or null reference
嘗試寫入 null 或者 undefined ,把它當成了一個物件。例如:
var someVal = null;
someVal.foo = 1;
如何修復錯誤: 也是由於拼寫錯誤所致。檢查錯誤指出的行號附近的變數名。
Uncaught RangeError: Maximum call stack size exceeded
相關錯誤:
Related errors: Uncaught exception: RangeError: Maximum recursion depth exceeded, too much recursion, Stack overflow
通常由程式邏輯 bug 引起,導致函式的無限遞迴呼叫。
如何修復錯誤: 檢查遞迴函式中可能導致無限迴圈 的 bug 。
Uncaught URIError: URI malformed
相關錯誤:
URIError: malformed URI sequence
無效的 decodeURIComponent 呼叫所致。
如何修復錯誤: 按照錯誤指出的行號,檢查 decodeURIComponent
呼叫,它是正確的。
XMLHttpRequest cannot load [http://some/url/](http://some/url/). No ‘Access-Control-Allow-Origin’ header is present on the requested resource
相關錯誤:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at
[http://some/url/](http://some/url/)
錯誤肯定是使用 XMLHttpRequest 引起的。
如何修復: 確保請求的 URL 是正確的,它遵循同源策略 。最好的方法是從程式碼中找到錯誤資訊指出的 URL 。
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
相關錯誤:
InvalidStateError, DOMException code 11
程式碼呼叫的方法在當前狀態無法呼叫。通常由 XMLHttpRequest
引起,在方法準備完畢之前呼叫它會引起錯誤。
var xhr = new XMLHttpRequest();
xhr.setRequestHeader('Some-Header', 'val');
這時就會出錯,因為 setRequestHeader
方法只能在 xhr.open
方法之後呼叫。
如何修復: 檢視錯誤指出的行號,確保程式碼執行的時機正確,或者在它(例如 xhr.open
)之前添加了不必要的呼叫
結論
我看過不少無用的 JavaScript 錯誤,比如 PHP 中聲名狼藉的異常 Expected T_PAAMAYIM_NEKUDOTAYIM
。丟擲更熟悉的錯誤才更有意義。現代瀏覽器不再丟擲完全無用的錯誤,才會更有幫助。