哪裡出了問題?JavaScript 故障排除
在上一篇文章中構建“猜數字”遊戲時,您可能會發現它無法正常工作。不用擔心——本文旨在透過提供一些查詢和修復 JavaScript 程式錯誤的方法,讓您免於為這些問題而抓狂。
錯誤型別
一般來說,當您在程式碼中做錯事時,會遇到兩種主要型別的錯誤:
- 語法錯誤:這些是程式碼中的拼寫錯誤,實際上會導致程式根本無法執行,或者在執行過程中停止工作——通常還會提供一些錯誤訊息。只要您熟悉正確的工具並知道錯誤訊息的含義,這些錯誤通常不難修復!
- 邏輯錯誤:這些是語法實際上正確但程式碼並非您預期的情況,這意味著程式成功執行但給出不正確的結果。這些錯誤通常比語法錯誤更難修復,因為通常沒有錯誤訊息可以引導您找到錯誤的根源。
好的,事情並非那麼簡單——當您深入研究時,還有其他一些區別。但是,在您職業生涯的這個早期階段,上述分類就足夠了。我們將在接下來探討這兩種型別。
一個錯誤示例
首先,讓我們回到我們的猜數字遊戲——只不過這次我們將探索一個引入了一些故意錯誤的版本。前往 GitHub 並下載一份 number-game-errors.html 的本地副本(在此處檢視即時執行)。
- 首先,在您喜歡的文字編輯器和瀏覽器中開啟本地副本。
- 嘗試玩遊戲——您會注意到,當您按下“提交猜測”按鈕時,它不起作用!
注意: 您可能也有一個無法正常工作的遊戲示例版本,您可能想修復它!我們仍然希望您使用我們的版本來完成本文,以便您學習我們在此處教授的技術。然後您可以回去嘗試修復您的示例。
此時,讓我們檢視開發者控制檯,看看它是否報告了任何語法錯誤,然後嘗試修復它們。您將在下面學習如何操作。
修復語法錯誤
在本課程的早期,我們讓您在 開發者工具 JavaScript 控制檯 中輸入一些簡單的 JavaScript 命令(如果您不記得如何在瀏覽器中開啟它,請點選上一個連結瞭解如何操作)。更有用的是,每當提供給瀏覽器 JavaScript 引擎的 JavaScript 中存在語法錯誤時,控制檯都會為您提供錯誤訊息。現在讓我們開始查詢錯誤。
-
轉到您開啟
number-game-errors.html的選項卡,然後開啟您的 JavaScript 控制檯。您應該會看到一條類似以下內容的錯誤訊息:![Firefox 中的“猜數字遊戲”演示頁面。JavaScript 控制檯中可見一個錯誤:“X TypeError: guessSubmit.addeventListener is not a function [瞭解更多] (number-game-errors.html:87:19)”。](/en-US/docs/Learn_web_development/Core/Scripting/What_went_wrong/not-a-function.png)
-
錯誤訊息的第一行是
Uncaught TypeError: guessSubmit.addeventListener is not a function number-game-errors.html:87:19
- 第一部分
Uncaught TypeError: guessSubmit.addeventListener is not a function告訴我們出了什麼問題。 - 第二部分
number-game-errors.html:87:19告訴我們錯誤來自程式碼的哪個位置:檔案 "number-game-errors.html" 的第 87 行第 19 個字元。
- 第一部分
-
如果我們在程式碼編輯器中檢視第 87 行,我們會找到這一行
jsguessSubmit.addeventListener("click", checkGuess); -
錯誤訊息說“guessSubmit.addeventListener is not a function”,這意味著我們呼叫的函式未被 JavaScript 直譯器識別。通常,此錯誤訊息實際上意味著我們拼錯了什麼。如果您不確定某個語法片段的正確拼寫,最好在 MDN 上查詢該功能。目前最好的方法是使用您喜歡的搜尋引擎搜尋“mdn 功能名稱”。為了在此例項中節省您的時間,這裡有一個快捷方式:
addEventListener()。 -
所以,檢視此頁面,錯誤似乎是我們拼錯了函式名!請記住 JavaScript 是區分大小寫的,因此拼寫或大小寫上的任何細微差異都會導致錯誤。將
addeventListener更改為addEventListener應該可以解決此問題。現在就執行此操作。
注意: 有關此錯誤的更多詳細資訊,請參閱我們的 TypeError: "x" is not a function 參考頁面。
語法錯誤第二輪
-
儲存並重新整理您的頁面,您應該會看到錯誤消失了。
-
現在,如果您嘗試輸入一個猜測並按下“提交猜測”按鈕,您會看到另一個錯誤!

-
這次報告的錯誤是
Uncaught TypeError: can't access property "textContent", lowOrHi is null
根據您使用的瀏覽器,您可能會在此處看到不同的訊息。上面顯示的訊息是 Firefox 會顯示的,但例如 Chrome 會顯示這個
Uncaught TypeError: Cannot set properties of null (setting 'textContent')
這是相同的錯誤,但不同的瀏覽器以不同的方式描述它。
注意: 此錯誤在頁面載入時沒有立即出現,因為此錯誤發生在函式內部(在
checkGuess() { }塊內部)。正如您將在我們稍後的 函式文章 中更詳細地瞭解到的,函式內部的程式碼在與函式外部程式碼不同的作用域中執行。在這種情況下,程式碼直到第 87 行執行checkGuess()函式時才執行並丟擲錯誤。 -
錯誤中給出的行號是 79。檢視第 79 行,您會看到以下程式碼
jslowOrHi.textContent = "Last guess was too high!"; -
這一行試圖將
lowOrHi變數的textContent屬性設定為文字字串,但它不起作用,因為lowOrHi沒有包含它應該包含的內容。讓我們看看這是為什麼——嘗試在程式碼中搜索其他lowOrHi例項。您會找到的最早的例項在第 51 行jsconst lowOrHi = document.querySelector("lowOrHi"); -
此時我們正試圖讓變數包含對文件 HTML 中元素的引用。讓我們看看執行此行後變數包含什麼。在第 54 行新增以下程式碼
jsconsole.log(lowOrHi);此程式碼將在第 51 行嘗試設定
lowOrHi的值後將其列印到控制檯。有關更多資訊,請參閱console.log()。 -
儲存並重新整理,您現在應該會在控制檯中看到
console.log()的結果。
果然,此時 lowOrHi的值為null,這與 Firefox 錯誤訊息lowOrHi is null相匹配。所以第 51 行肯定有問題。null值表示“無”或“沒有值”。因此,我們將lowOrHi設定為元素的程式碼出錯了。 -
讓我們思考一下問題可能是什麼。第 51 行正在使用
document.querySelector()方法,透過 CSS 選擇器獲取對元素的引用。進一步向上檢視我們的檔案,我們可以找到有問題的段落html<p class="lowOrHi"></p> -
所以我們需要一個類選擇器,它以一個點(
.)開頭,但是傳入第 51 行querySelector()方法的選擇器沒有點。這可能就是問題所在!嘗試將第 51 行的lowOrHi更改為.lowOrHi。 -
嘗試再次儲存並重新整理,您的
console.log()語句應該會返回我們想要的<p>元素。哦!又一個錯誤修復了!您現在可以刪除您的console.log()行,或者保留它以供以後參考——由您選擇。
注意: 有關此錯誤的更多詳細資訊,請參閱我們的 TypeError: "x" is (not) "y" 參考頁面。
語法錯誤第三輪
- 現在,如果您再次嘗試玩遊戲,您應該會更成功——遊戲應該可以完全正常進行,直到您結束遊戲,無論是透過猜對數字,還是用完猜測次數。
- 此時,遊戲再次失敗,並吐出了我們一開始就遇到的相同錯誤——“TypeError: resetButton.addeventListener is not a function”!然而,這次它被列為來自第 95 行。
- 檢視第 95 行,很容易看出我們在這裡犯了同樣的錯誤。我們仍然只需要將
addeventListener更改為addEventListener。現在就執行此操作。
一個邏輯錯誤
此時,遊戲應該會順利進行,但是玩了幾次後,您無疑會注意到遊戲總是選擇 1 作為您必須猜的“隨機”數字。這絕對不是我們希望遊戲進行的模式!
遊戲邏輯中肯定存在問題——遊戲沒有返回錯誤;它只是沒有正常執行。
-
搜尋
randomNumber變數,以及首次設定隨機數的行。在遊戲開始時儲存我們想要猜測的隨機數的例項應該在第 47 行左右jslet randomNumber = Math.floor(Math.random()) + 1; -
每次後續遊戲之前生成隨機數的例項在第 114 行左右
jsrandomNumber = Math.floor(Math.random()) + 1; -
為了檢查這些行是否確實是問題所在,讓我們再次求助於我們的朋友
console.log()——在上面兩行之後直接插入以下行jsconsole.log(randomNumber); -
儲存並重新整理,然後玩幾局遊戲——您會看到在每次記錄到控制檯時,
randomNumber都等於 1。
理清邏輯
要解決此問題,讓我們考慮一下這一行是如何工作的。首先,我們呼叫 Math.random(),它生成一個介於 0 和 1 之間的隨機小數,例如 0.5675493843。
Math.random();
接下來,我們透過 Math.floor() 傳遞呼叫 Math.random() 的結果,它將傳遞給它的數字向下舍入到最接近的整數。然後我們給那個結果加 1
Math.floor(Math.random()) + 1;
將 0 到 1 之間的隨機小數向下舍入將始終返回 0,因此將其加 1 將始終返回 1。我們需要在將其向下舍入之前將隨機數乘以 100。以下將給我們一個 0 到 99 之間的隨機數
Math.floor(Math.random() * 100);
因此,我們希望加 1,以給我們一個 1 到 100 之間的隨機數
Math.floor(Math.random() * 100) + 1;
嘗試像這樣更新這兩行,然後儲存並重新整理——遊戲現在應該按我們預期的那樣運行了!
其他常見錯誤
在您的程式碼中還會遇到其他常見錯誤。本節重點介紹了其中大部分。
第一次猜錯後遊戲結束
這可能是將賦值運算子和嚴格相等運算子混淆的另一個症狀。例如,如果我們要更改 checkGuess() 中的這一行
} else if (guessCount === 10) {
改為
} else if (guessCount = 10) {
測試將始終返回 true,導致程式在第一次猜錯後執行 setGameOver()。要小心!
SyntaxError: missing ) after argument list
這個非常簡單——它通常意味著您在函式/方法呼叫的末尾遺漏了右括號。
注意: 有關此錯誤的更多詳細資訊,請參閱我們的 SyntaxError: missing ) after argument list 參考頁面。
SyntaxError: missing : after property id
此錯誤通常與格式不正確的 JavaScript 物件有關,但在這種情況下,我們透過更改以下內容來獲得它
function checkGuess() {
改為
function checkGuess( {
這導致瀏覽器認為我們正試圖將函式的內容作為引數傳遞給函式。小心那些括號!
SyntaxError: missing } after function body
這很容易——它通常意味著您在函式或條件結構中遺漏了其中一個大括號。我們透過刪除 checkGuess() 函式底部附近的一個右大括號來獲得此錯誤。
SyntaxError: expected expression, got 'string' 或 SyntaxError: string literal contains an unescaped line break
這些錯誤通常意味著您遺漏了字串值的起始或結束引號。在上面的第一個錯誤中,string 將被替換為瀏覽器找到的意外字元(而不是字串開頭的引號)。第二個錯誤意味著字串沒有以引號結束。
對於所有這些錯誤,請思考我們如何處理我們在演練中看到的示例。當出現錯誤時,檢視給定的行號,轉到該行,看看您是否能發現問題所在。請記住,錯誤不一定在該行,並且錯誤可能不是由我們上面提到的完全相同的問題引起的!
注意: 有關這些錯誤的更多詳細資訊,請參閱我們的 SyntaxError: Unexpected token 和 SyntaxError: string literal contains an unescaped line break 參考頁面。
總結
所以我們已經掌握了,這是找出簡單 JavaScript 程式中錯誤的基礎知識。在您的程式碼中找出錯誤並非總是那麼簡單,但至少這可以為您節省幾個小時的睡眠,並讓您在事情沒有順利進行時更快地取得進展,尤其是在學習旅程的早期階段。
另見
- 還有許多其他型別的錯誤未在此處列出;我們正在編寫一個詳細解釋其含義的參考資料——請參閱 JavaScript 錯誤參考。
- 如果您在閱讀本文後遇到任何不確定如何修復的程式碼錯誤,您可以獲得幫助!在 交流渠道 上尋求幫助。告訴我們您的錯誤是什麼,我們將盡力幫助您。提供您的程式碼列表也會很有用。