除錯 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
嘗試將一個值(value)當作函式使用,但該值並不是一個函式。例如:
1 2 |
var foo = undefined; foo(); |
這個錯誤很常見,當呼叫物件中的一個方法,但寫錯了方法名:
1 |
var x = document.getElementByID('foo'); |
訪問物件中不存在的屬性時將返回 undefined
,上面程式碼就將出現該錯誤。
其他類似的錯誤,比如“number is not a function”發生在嘗試將一個 Number
當作函式使用時。
如何修復:確保函式名正確。對於該錯誤,行號通常準確地指向了錯誤發生的位置。
Uncaught ReferenceError: Invalid left-hand side in assignment
同類錯誤:
- Uncaught exception: ReferenceError: Cannot assign to ‘functionCall()’
- Uncaught exception: ReferenceError: Cannot assign to ‘this’
當嘗試給一個不能被賦值的變數賦值時將發生該錯誤。看下面的典型例子:
1 |
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
序列化一個存在迴圈引用的物件時。
1 2 3 4 |
var a = { }; var b = { a: a }; a.b = b; JSON.stringify(a); |
由於上面 a
和 b
兩個物件都彼此相互引用,結果導致物件不能被轉換為 JSON 字串。
如何修復:移除將要被轉換為 JSON 字串物件內部的迴圈引用。
Unexpected token ;
同類錯誤:
- Expected )
- missing ) after argument list
通常發生在缺少括號或分號時。
該錯誤中所謂的符號(token)可以多種多樣,如“Unexpected token ]”或“Expected {”等等。
如何修復:該錯誤提示的行號有時並不能指向正確的位置,這增加了修復難度。
- 錯誤資訊中包含“[ ] { } ( )”時,通常是因為缺少配對的部分,檢查所有括號,保證都是配對的。這種情況下,行號通常指向了其他位置,問不是錯誤的位置。
- 異常的
/
和正規表示式有關,行號指向了正確的位置。 - 異常的
;
通常發生在物件、陣列或函式呼叫時引數列表內部包含;
,行號也指向了正確的位置。
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
作為一個物件使用,例如:
1 2 |
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
的物件的屬性賦值。
1 2 |
var someVal = null; someVal.foo = 1; |
如何修復:這也通常是由於書寫錯誤導致,檢查錯誤提示的行號附近的變數名是否正確。
Uncaught RangeError: Maximum call stack size exceeded
同類錯誤:
- Uncaught exception: RangeError: Maximum recursion depth exceeded
- too much recursion
- Stack overflow
通常是由程式邏輯問題,導致了無限遞迴的函式呼叫。
如何修復:檢查函式的遞迴呼叫,確保函式不是無限遞迴的。
Uncaught URIError: URI malformed
同類錯誤:URIError: malformed URI sequence
無效的 decodeURIComponent
呼叫將導致該錯誤。
如何修復:確保行號所指位置的 decodeURIComponent
呼叫的引數正確。
XMLHttpRequest cannot load 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/
該錯誤總是由使用 XMLHttpRequest
時導致。
如何修復:確保請求的 url 滿足同源策略。
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
同類錯誤:
- InvalidStateError
- DOMException code 11
該錯誤表示呼叫物件的方法時,物件的狀態不對。在使用 XMLHttpRequest
時,在其準備好之前嘗試呼叫其中的方法將導致該錯誤。
1 2 |
var xhr = new XMLHttpRequest(); xhr.setRequestHeader('Some-Header', 'val'); |
上例中將導致錯誤,因為 setRequestHeader
方法只能在 xhr.open
之後呼叫。
如何修復:檢查行號指示的位置,確保程式碼執行在合適的時間,或在這之前新增必要的函式呼叫(比如xhr.open
)。