哪裡出了問題?JavaScript 故障排除

在上一篇文章中構建“猜數字”遊戲時,您可能會發現它無法正常工作。不用擔心——本文旨在透過提供一些查詢和修復 JavaScript 程式錯誤的方法,讓您免於為這些問題而抓狂。

預備知識 瞭解 HTMLCSS 基礎知識,以及編寫 JavaScript 的基本經驗。
學習成果
  • 瞭解 JavaScript 中可能發生的錯誤型別。
  • 使用 console.log() 除錯錯誤。
  • 使用瀏覽器 DevTools JavaScript 控制檯的基本經驗。
  • 熟悉 JavaScript 錯誤訊息及其含義。

錯誤型別

一般來說,當您在程式碼中做錯事時,會遇到兩種主要型別的錯誤:

  • 語法錯誤:這些是程式碼中的拼寫錯誤,實際上會導致程式根本無法執行,或者在執行過程中停止工作——通常還會提供一些錯誤訊息。只要您熟悉正確的工具並知道錯誤訊息的含義,這些錯誤通常不難修復!
  • 邏輯錯誤:這些是語法實際上正確但程式碼並非您預期的情況,這意味著程式成功執行但給出不正確的結果。這些錯誤通常比語法錯誤更難修復,因為通常沒有錯誤訊息可以引導您找到錯誤的根源。

好的,事情並非那麼簡單——當您深入研究時,還有其他一些區別。但是,在您職業生涯的這個早期階段,上述分類就足夠了。我們將在接下來探討這兩種型別。

一個錯誤示例

首先,讓我們回到我們的猜數字遊戲——只不過這次我們將探索一個引入了一些故意錯誤的版本。前往 GitHub 並下載一份 number-game-errors.html 的本地副本(在此處檢視即時執行)。

  1. 首先,在您喜歡的文字編輯器和瀏覽器中開啟本地副本。
  2. 嘗試玩遊戲——您會注意到,當您按下“提交猜測”按鈕時,它不起作用!

注意: 您可能也有一個無法正常工作的遊戲示例版本,您可能想修復它!我們仍然希望您使用我們的版本來完成本文,以便您學習我們在此處教授的技術。然後您可以回去嘗試修復您的示例。

此時,讓我們檢視開發者控制檯,看看它是否報告了任何語法錯誤,然後嘗試修復它們。您將在下面學習如何操作。

修復語法錯誤

在本課程的早期,我們讓您在 開發者工具 JavaScript 控制檯 中輸入一些簡單的 JavaScript 命令(如果您不記得如何在瀏覽器中開啟它,請點選上一個連結瞭解如何操作)。更有用的是,每當提供給瀏覽器 JavaScript 引擎的 JavaScript 中存在語法錯誤時,控制檯都會為您提供錯誤訊息。現在讓我們開始查詢錯誤。

  1. 轉到您開啟 number-game-errors.html 的選項卡,然後開啟您的 JavaScript 控制檯。您應該會看到一條類似以下內容的錯誤訊息:Firefox 中的“猜數字遊戲”演示頁面。JavaScript 控制檯中可見一個錯誤:“X TypeError: guessSubmit.addeventListener is not a function [瞭解更多] (number-game-errors.html:87:19)”。

  2. 錯誤訊息的第一行是

    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 個字元。
  3. 如果我們在程式碼編輯器中檢視第 87 行,我們會找到這一行

    js
    guessSubmit.addeventListener("click", checkGuess);
    
  4. 錯誤訊息說“guessSubmit.addeventListener is not a function”,這意味著我們呼叫的函式未被 JavaScript 直譯器識別。通常,此錯誤訊息實際上意味著我們拼錯了什麼。如果您不確定某個語法片段的正確拼寫,最好在 MDN 上查詢該功能。目前最好的方法是使用您喜歡的搜尋引擎搜尋“mdn 功能名稱”。為了在此例項中節省您的時間,這裡有一個快捷方式:addEventListener()

  5. 所以,檢視此頁面,錯誤似乎是我們拼錯了函式名!請記住 JavaScript 是區分大小寫的,因此拼寫或大小寫上的任何細微差異都會導致錯誤。將 addeventListener 更改為 addEventListener 應該可以解決此問題。現在就執行此操作。

注意: 有關此錯誤的更多詳細資訊,請參閱我們的 TypeError: "x" is not a function 參考頁面。

語法錯誤第二輪

  1. 儲存並重新整理您的頁面,您應該會看到錯誤消失了。

  2. 現在,如果您嘗試輸入一個猜測並按下“提交猜測”按鈕,您會看到另一個錯誤!相同“猜數字遊戲”演示的截圖。這次,控制檯中可見一個不同的錯誤,顯示為“X TypeError: lowOrHi is null”。

  3. 這次報告的錯誤是

    Uncaught TypeError: can't access property "textContent", lowOrHi is null
    

    根據您使用的瀏覽器,您可能會在此處看到不同的訊息。上面顯示的訊息是 Firefox 會顯示的,但例如 Chrome 會顯示這個

    Uncaught TypeError: Cannot set properties of null (setting 'textContent')
    

    這是相同的錯誤,但不同的瀏覽器以不同的方式描述它。

    注意: 此錯誤在頁面載入時沒有立即出現,因為此錯誤發生在函式內部(在 checkGuess() { } 塊內部)。正如您將在我們稍後的 函式文章 中更詳細地瞭解到的,函式內部的程式碼在與函式外部程式碼不同的作用域中執行。在這種情況下,程式碼直到第 87 行執行 checkGuess() 函式時才執行並丟擲錯誤。

  4. 錯誤中給出的行號是 79。檢視第 79 行,您會看到以下程式碼

    js
    lowOrHi.textContent = "Last guess was too high!";
    
  5. 這一行試圖將 lowOrHi 變數的 textContent 屬性設定為文字字串,但它不起作用,因為 lowOrHi 沒有包含它應該包含的內容。讓我們看看這是為什麼——嘗試在程式碼中搜索其他 lowOrHi 例項。您會找到的最早的例項在第 51 行

    js
    const lowOrHi = document.querySelector("lowOrHi");
    
  6. 此時我們正試圖讓變數包含對文件 HTML 中元素的引用。讓我們看看執行此行後變數包含什麼。在第 54 行新增以下程式碼

    js
    console.log(lowOrHi);
    

    此程式碼將在第 51 行嘗試設定 lowOrHi 的值後將其列印到控制檯。有關更多資訊,請參閱 console.log()

  7. 儲存並重新整理,您現在應該會在控制檯中看到 console.log() 的結果。相同演示的截圖。控制檯中可見一條日誌語句,僅顯示“null”。 果然,此時 lowOrHi 的值為 null,這與 Firefox 錯誤訊息 lowOrHi is null 相匹配。所以第 51 行肯定有問題。 null 值表示“無”或“沒有值”。因此,我們將 lowOrHi 設定為元素的程式碼出錯了。

  8. 讓我們思考一下問題可能是什麼。第 51 行正在使用 document.querySelector() 方法,透過 CSS 選擇器獲取對元素的引用。進一步向上檢視我們的檔案,我們可以找到有問題的段落

    html
    <p class="lowOrHi"></p>
    
  9. 所以我們需要一個類選擇器,它以一個點(.)開頭,但是傳入第 51 行 querySelector() 方法的選擇器沒有點。這可能就是問題所在!嘗試將第 51 行的 lowOrHi 更改為 .lowOrHi

  10. 嘗試再次儲存並重新整理,您的 console.log() 語句應該會返回我們想要的 <p> 元素。哦!又一個錯誤修復了!您現在可以刪除您的 console.log() 行,或者保留它以供以後參考——由您選擇。

注意: 有關此錯誤的更多詳細資訊,請參閱我們的 TypeError: "x" is (not) "y" 參考頁面。

語法錯誤第三輪

  1. 現在,如果您再次嘗試玩遊戲,您應該會更成功——遊戲應該可以完全正常進行,直到您結束遊戲,無論是透過猜對數字,還是用完猜測次數。
  2. 此時,遊戲再次失敗,並吐出了我們一開始就遇到的相同錯誤——“TypeError: resetButton.addeventListener is not a function”!然而,這次它被列為來自第 95 行。
  3. 檢視第 95 行,很容易看出我們在這裡犯了同樣的錯誤。我們仍然只需要將 addeventListener 更改為 addEventListener。現在就執行此操作。

一個邏輯錯誤

此時,遊戲應該會順利進行,但是玩了幾次後,您無疑會注意到遊戲總是選擇 1 作為您必須猜的“隨機”數字。這絕對不是我們希望遊戲進行的模式!

遊戲邏輯中肯定存在問題——遊戲沒有返回錯誤;它只是沒有正常執行。

  1. 搜尋 randomNumber 變數,以及首次設定隨機數的行。在遊戲開始時儲存我們想要猜測的隨機數的例項應該在第 47 行左右

    js
    let randomNumber = Math.floor(Math.random()) + 1;
    
  2. 每次後續遊戲之前生成隨機數的例項在第 114 行左右

    js
    randomNumber = Math.floor(Math.random()) + 1;
    
  3. 為了檢查這些行是否確實是問題所在,讓我們再次求助於我們的朋友 console.log()——在上面兩行之後直接插入以下行

    js
    console.log(randomNumber);
    
  4. 儲存並重新整理,然後玩幾局遊戲——您會看到在每次記錄到控制檯時,randomNumber 都等於 1。

理清邏輯

要解決此問題,讓我們考慮一下這一行是如何工作的。首先,我們呼叫 Math.random(),它生成一個介於 0 和 1 之間的隨機小數,例如 0.5675493843。

js
Math.random();

接下來,我們透過 Math.floor() 傳遞呼叫 Math.random() 的結果,它將傳遞給它的數字向下舍入到最接近的整數。然後我們給那個結果加 1

js
Math.floor(Math.random()) + 1;

將 0 到 1 之間的隨機小數向下舍入將始終返回 0,因此將其加 1 將始終返回 1。我們需要在將其向下舍入之前將隨機數乘以 100。以下將給我們一個 0 到 99 之間的隨機數

js
Math.floor(Math.random() * 100);

因此,我們希望加 1,以給我們一個 1 到 100 之間的隨機數

js
Math.floor(Math.random() * 100) + 1;

嘗試像這樣更新這兩行,然後儲存並重新整理——遊戲現在應該按我們預期的那樣運行了!

其他常見錯誤

在您的程式碼中還會遇到其他常見錯誤。本節重點介紹了其中大部分。

第一次猜錯後遊戲結束

這可能是將賦值運算子和嚴格相等運算子混淆的另一個症狀。例如,如果我們要更改 checkGuess() 中的這一行

js
} else if (guessCount === 10) {

改為

js
} else if (guessCount = 10) {

測試將始終返回 true,導致程式在第一次猜錯後執行 setGameOver()。要小心!

SyntaxError: missing ) after argument list

這個非常簡單——它通常意味著您在函式/方法呼叫的末尾遺漏了右括號。

注意: 有關此錯誤的更多詳細資訊,請參閱我們的 SyntaxError: missing ) after argument list 參考頁面。

SyntaxError: missing : after property id

此錯誤通常與格式不正確的 JavaScript 物件有關,但在這種情況下,我們透過更改以下內容來獲得它

js
function checkGuess() {

改為

js
function checkGuess( {

這導致瀏覽器認為我們正試圖將函式的內容作為引數傳遞給函式。小心那些括號!

SyntaxError: missing } after function body

這很容易——它通常意味著您在函式或條件結構中遺漏了其中一個大括號。我們透過刪除 checkGuess() 函式底部附近的一個右大括號來獲得此錯誤。

SyntaxError: expected expression, got 'string' 或 SyntaxError: string literal contains an unescaped line break

這些錯誤通常意味著您遺漏了字串值的起始或結束引號。在上面的第一個錯誤中,string 將被替換為瀏覽器找到的意外字元(而不是字串開頭的引號)。第二個錯誤意味著字串沒有以引號結束。

對於所有這些錯誤,請思考我們如何處理我們在演練中看到的示例。當出現錯誤時,檢視給定的行號,轉到該行,看看您是否能發現問題所在。請記住,錯誤不一定在該行,並且錯誤可能不是由我們上面提到的完全相同的問題引起的!

注意: 有關這些錯誤的更多詳細資訊,請參閱我們的 SyntaxError: Unexpected tokenSyntaxError: string literal contains an unescaped line break 參考頁面。

總結

所以我們已經掌握了,這是找出簡單 JavaScript 程式中錯誤的基礎知識。在您的程式碼中找出錯誤並非總是那麼簡單,但至少這可以為您節省幾個小時的睡眠,並讓您在事情沒有順利進行時更快地取得進展,尤其是在學習旅程的早期階段。

另見

  • 還有許多其他型別的錯誤未在此處列出;我們正在編寫一個詳細解釋其含義的參考資料——請參閱 JavaScript 錯誤參考
  • 如果您在閱讀本文後遇到任何不確定如何修復的程式碼錯誤,您可以獲得幫助!在 交流渠道 上尋求幫助。告訴我們您的錯誤是什麼,我們將盡力幫助您。提供您的程式碼列表也會很有用。