出了什麼問題?JavaScript 故障排除

在上一篇文章中,你構建了“猜數字”遊戲,你可能發現它無法正常工作。不用擔心——本文旨在透過提供一些關於如何在 JavaScript 程式中查詢和修復錯誤的技巧,幫助你避免因這些問題而抓狂。

先決條件 對 HTML 和 CSS 的基本瞭解,瞭解 JavaScript 是什麼。
目標 獲得開始修復自己程式碼中問題的能力和信心。

錯誤型別

一般來說,當你犯程式碼錯誤時,你會遇到兩種主要型別的錯誤

  • 語法錯誤:這些是程式碼中的拼寫錯誤,實際上會導致程式根本無法執行,或在執行過程中停止工作——你通常也會收到一些錯誤訊息。只要你熟悉正確的工具並瞭解錯誤訊息的含義,這些錯誤通常很容易修復!
  • 邏輯錯誤:這些錯誤是指語法實際上是正確的,但程式碼並非你想要的那樣,這意味著程式成功執行,但結果不正確。這些錯誤通常比語法錯誤更難修復,因為通常沒有錯誤訊息可以引導你找到錯誤的來源。

好的,所以情況並非完全那麼簡單——當你深入研究時,還有一些其他差異。但在你職業生涯的早期階段,上述分類就足夠了。我們將在後續內容中探討這兩種型別的錯誤。

一個錯誤示例

首先,讓我們回到我們的猜數字遊戲——但這次我們將探索一個引入了某些故意錯誤的版本。訪問 GitHub 併為自己建立一個本地副本 number-game-errors.html線上檢視)。

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

注意:你可能擁有自己版本的無法正常工作的遊戲示例,你可能希望修復它!我們仍然希望你使用我們的版本完成本文,以便學習我們在這裡教授的技術。然後你可以返回並嘗試修復你的示例。

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

修復語法錯誤

在課程的早期,我們讓你在開發者工具 JavaScript 控制檯中輸入一些簡單的 JavaScript 命令(如果你不記得如何在瀏覽器中開啟它,請按照前面的連結瞭解如何操作)。更有用的是,只要在傳送到瀏覽器 JavaScript 引擎的 JavaScript 中存在語法錯誤,控制檯就會向你顯示錯誤訊息。現在讓我們開始搜尋吧。

  1. 轉到你在其中開啟number-game-errors.html的選項卡,並開啟你的 JavaScript 控制檯。你應該會看到一條類似於以下內容的錯誤訊息:"Number guessing game" demo page in Firefox. One error is visible in the JavaScript console: "X TypeError: guessSubmit.addeventListener is not a function [Learn More] (number-game-errors.html:86:3)".
  2. 錯誤訊息的第一行是
    Uncaught TypeError: guessSubmit.addeventListener is not a function
    number-game-errors.html:86:15
    
    • 第一部分,Uncaught TypeError: guessSubmit.addeventListener is not a function,告訴我們出了什麼問題。
    • 第二部分,number-game-errors.html:86:15,告訴我們程式碼中錯誤的來源:檔案“number-game-errors.html”的第 86 行,第 15 個字元。
  3. 如果我們在程式碼編輯器中檢視第 86 行,我們會找到以下程式碼行

    警告:錯誤訊息可能不在第 86 行。

    如果你使用任何帶有擴充套件程式的程式碼編輯器,該擴充套件程式會在你的本地機器上啟動一個即時伺服器,這將導致注入額外的程式碼。因此,開發者工具會將錯誤列為發生在非 86 行的位置。

    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. 現在,如果你嘗試輸入猜測並按下“提交猜測”按鈕,你將看到另一個錯誤!Screenshot of the same "Number guessing game" demo. This time, a different error is visible in the console, reading "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() { }塊內)。正如你將在我們後面的函式文章中更詳細地瞭解的那樣,函式內部的程式碼與函式外部的程式碼位於不同的作用域中。在這種情況下,程式碼沒有執行,並且錯誤直到第 86 行執行checkGuess()函式時才被丟擲。

  4. 錯誤中給出的行號是 80。檢視第 80 行,你會看到以下程式碼
    js
    lowOrHi.textContent = "Last guess was too high!";
    
  5. 此行試圖將lowOrHi變數的textContent屬性設定為文字字串,但它不起作用,因為lowOrHi不包含它應該包含的內容。讓我們看看為什麼會出現這種情況——嘗試在程式碼中搜索其他lowOrHi例項。你將找到的最早的例項在第 49 行
    js
    const lowOrHi = document.querySelector("lowOrHi");
    
  6. 此時,我們試圖使變數包含對文件 HTML 中元素的引用。讓我們看看在執行此行程式碼後變數包含什麼。在第 50 行新增以下程式碼
    js
    console.log(lowOrHi);
    
    此程式碼將在我們嘗試在第 49 行設定lowOrHi後將其值列印到控制檯。有關更多資訊,請參閱console.log()
  7. 儲存並重新整理,你應該現在可以在控制檯中看到console.log()結果。Screenshot of the same demo. One log statement is visible in the console, reading simply "null". 的確,此時lowOrHi的值為null,這與 Firefox 錯誤訊息lowOrHi is null一致。因此第 49 行肯定存在問題。null值表示“無”或“無值”。因此,我們設定lowOrHi為元素的程式碼出錯了。
  8. 讓我們考慮一下可能是什麼問題。第 49 行使用document.querySelector()方法透過使用 CSS 選擇器來獲取對元素的引用。進一步檢視我們的檔案,我們可以找到相關段落
    html
    <p class="lowOrHi"></p>
    
  9. 因此,我們這裡需要一個類選擇器,它以點 (.) 開頭,但傳遞給第 49 行中querySelector()方法的選擇器沒有點。這可能是問題所在!嘗試在第 49 行將lowOrHi更改為.lowOrHi
  10. 嘗試再次儲存並重新整理,你的console.log()語句應該會返回我們想要的<p>元素。呼!另一個錯誤已修復!你現在可以刪除你的console.log()行,或者保留它以供以後參考——由你決定。

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

語法錯誤第三輪

  1. 現在,如果你再次嘗試玩遊戲,你應該會取得更多成功——遊戲應該可以正常進行,直到你結束遊戲,無論是猜對了數字還是用完了猜測次數。
  2. 在這一點上,遊戲再次失敗,並且輸出了與我們一開始相同的錯誤——“TypeError: resetButton.addeventListener is not a function”!但是,這次它被列為來自第 94 行。
  3. 檢視第 94 行,很容易看出我們在這裡犯了同樣的錯誤。我們再次只需要將addeventListener更改為addEventListener。立即執行此操作。

邏輯錯誤

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

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

  1. 搜尋randomNumber變數以及首次設定隨機數的行。在遊戲開始時儲存我們要猜的隨機數的例項應該在第 45 行左右
    js
    let randomNumber = Math.floor(Math.random()) + 1;
    
  2. 而在每次後續遊戲中生成隨機數的例項應該在第 113 行左右
    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.random()的結果傳遞給Math.floor(),它將傳遞給它的數字向下舍入到最接近的整數。然後我們將 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
if (userGuess === randomNumber) {

js
if (userGuess = randomNumber) {

則測試將始終返回 true,導致程式報告遊戲已獲勝。小心!

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 錯誤參考
  • 如果你在程式碼中遇到任何不確定如何修復的錯誤,請在閱讀本文後尋求幫助!在 溝通渠道 上尋求幫助。告訴我們你的錯誤是什麼,我們會盡力幫助你。列出你的程式碼也很有用。