<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Debug - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Debug - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 09 Jun 2026 20:19:52 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/tag/debugging/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 如何在浏览器中使用开发者工具调试 JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ console 对象是开发人员处理有问题的 JavaScript 代码时的第一选择。 但如果你仍然只是重度依赖于 console 对象来调试 JavaScript，你就错过了浏览器开发者工具的一些很棒的功能。 让我们来看看如何使用 Chrome 开发者工具调试 JavaScript。 我们要处理的问题代码 首先，我准备了一些有 bug 的代码，将四个数字相加并计算其平均值。 这是代码的 HTML 部分： <label for="num1">Number 1:</label> <input type="text" id="num1" placeholder="Enter a number" /> <label for="num2">Number 2:</label> <input type="text" id="num2" placeholder="Enter a number" /> <label for="num3">Number 3:</label> <input type="text" id="num3" placeholder="Enter a number" / ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-use-developer-tools-to-debug-javascript-in-the-browser/</link>
                <guid isPermaLink="false">6732d3dc7b243504ae537c9b</guid>
                
                    <category>
                        <![CDATA[ 调试 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Debug ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Miya Liu ]]>
                </dc:creator>
                <pubDate>Tue, 12 Nov 2024 11:19:29 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2024/11/f2ead89e25e967947691c8e4a1f8f862.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/how-to-use-developer-tools-to-debug-javascript-in-the-browser/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Use Developer Tools to Debug JavaScript in the Browser</a>
      </p><!--kg-card-begin: markdown--><p><code>console</code> 对象是开发人员处理有问题的 JavaScript 代码时的第一选择。</p>
<p>但如果你仍然只是重度依赖于 <code>console</code> 对象来调试 JavaScript，你就错过了浏览器开发者工具的一些很棒的功能。</p>
<p>让我们来看看如何使用 Chrome 开发者工具调试 JavaScript。</p>
<h2 id="">我们要处理的问题代码</h2>
<p>首先，我准备了一些有 bug 的代码，将四个数字相加并计算其平均值。</p>
<p>这是代码的 HTML 部分：</p>
<pre><code class="language-html">&lt;label for="num1"&gt;Number 1:&lt;/label&gt;
&lt;input type="text" id="num1" placeholder="Enter a number" /&gt;

&lt;label for="num2"&gt;Number 2:&lt;/label&gt;
&lt;input type="text" id="num2" placeholder="Enter a number" /&gt;

&lt;label for="num3"&gt;Number 3:&lt;/label&gt;
&lt;input type="text" id="num3" placeholder="Enter a number" /&gt;

&lt;label for="num4"&gt;Number 4:&lt;/label&gt;
&lt;input type="text" id="num4" placeholder="Enter a number" /&gt;

&lt;button id="calculateBtn"&gt;Calculate Sum and Average&lt;/button&gt;

&lt;p id="addition-result"&gt;&lt;/p&gt;
&lt;p id="average-result"&gt;&lt;/p&gt;

&lt;script src="script.js"&gt;&lt;/script&gt;
</code></pre>
<p>这是非常简单的 CSS，用来将标签推到各自的行，并稍微放大输入元素和按钮：</p>
<pre><code class="language-css">body {
  background: #d2d2d2;
}

label {
  display: block;
  margin-top: 0.5rem;
}

button {
  display: block;
  margin-top: 1rem;
}

input,
button {
  padding: 0.2rem;
}
</code></pre>
<p>这是 HTML 和 CSS 在浏览器中显示的样子：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729767323533/db4b903d-8cfe-4d6b-85b2-2233a2a2bcd0.png" alt="Sum and Average Calculator" width="538" height="410" loading="lazy"></p>
<p>以下是有 bug 的 JavaScript：</p>
<pre><code class="language-javascript">const calculateBtn = document.getElementById('calculateBtn');
const sumText = document.getElementById('sum');
const avgText = document.getElementById('average');

function calculateTotal(a, b, c, d) {
 return a + b + c + d;
}

function calculateAverage(total, count) {
 return total / count;
}

function handleButtonClick() {
 let num1 = document.getElementById('num1').value;
 let num2 = document.getElementById('num2').value;
 let num3 = document.getElementById('num3').value;
 let num4 = document.getElementById('num4').value;

 let total = calculateTotal(num1, num2, num3, num4);
 let average = calculateAverage(total, 4);

 sumText.textContent = `The sum is ${total}`;
 avgText.textContent = `The average is: ${average}`;
}

calculateBtn.addEventListener('click', handleButtonClick);
</code></pre>
<p>如果你输入四个数字，比如 <code>3</code>、<code>4</code>、<code>2</code>、<code>1</code>，然后点击 <code>Calculate Sum and Average</code> 按钮，会发生什么：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729767417791/6c5a49d1-dc6f-45db-9720-c3c6daedbeb3.png" alt="Wrong sum and average" width="688" height="395" loading="lazy"></p>
<p>不幸的是，数字只是被合并了，平均值是基于这个计算的，这意味着执行了拼接而不是加法。加法执行有问题也导致了平均值计算错误。</p>
<p>让我们用浏览器开发者工具检查一下发生了什么。</p>
<h2 id="chromejavascript">如何使用 Chrome 开发者工具调试 JavaScript 代码</h2>
<p>当出现这样的错误时，你可能会倾向于添加一堆控制台日志。</p>
<p>很多时候，控制台日志可以完成任务，但你必须花费大量时间来弄清楚事情。</p>
<p>浏览器开发者工具为你提供了更多选项，比如添加断点、监视特定表达式，甚至逐行执行代码以查看错误发生的位置。</p>
<h3 id="sources">如何打开开发者工具和源代码（Sources）标签</h3>
<p>首先，右键点击浏览器中并选择“检查”来打开 Chrome DevTools。</p>
<p>在 DevTools 中，打开源代码（Sources）标签查看程序中的文件。你也可以按下键盘上的 <code>F12</code> 键并选择源代码（Sources）标签。</p>
<p>以下是 Chrome DevTools 源代码（Sources）标签的简要结构：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729767628385/30310aa1-ddb0-41d5-a3ce-9ecc84b034e3.png" alt="Anatomy of the chrome developer tools source tab" width="1477" height="602" loading="lazy"></p>
<p>在调试器标签顶部有一些灰色的图标。激活它们，你可以逐步执行代码并添加或移除断点。</p>
<p>在调试器标签中还有：</p>
<ul>
<li>
<p>监视：你可以在此添加和查看监视表达式。</p>
</li>
<li>
<p>断点：你可以在此查看你添加断点的代码行。</p>
</li>
<li>
<p>作用域：包含本地和全局变量。</p>
</li>
<li>
<p>调用栈：显示导致当前位置代码执行的函数调用。</p>
</li>
</ul>
<p>要查看任何文件的内容，你可以点击它。然后，调试器标签中的一些图标将不再是灰色的。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729767971149/04f8e5c7-a08a-49b3-be7f-2854f820b94a.png" alt="Icons of the Chrome developer tools source tab" width="1474" height="597" loading="lazy"></p>
<h3 id="">如何通过添加断点调试代码</h3>
<p>要开始调试代码，你可以通过点击行号添加断点。</p>
<p>断点就像你可以在开发者工具中设置的行标记，它会在该行执行之前暂停你的代码执行。这样，你就可以检查变量的值，查看函数是否按预期被调用，或者观察代码的整体流程。</p>
<p>当你添加一个断点并执行代码时，该行会出现一个蓝色图标，表示执行会在该行之前暂停。</p>
<p>或者，你可以在你想暂停执行的行添加 <code>debugger</code> 语句。不过，还是让我们坚持使用断点。</p>
<p>例如，我们在第 14 行添加一个断点，然后输入四个数字并点击 <code>Calculate Sum and Average</code> 按钮，这样代码就会运行：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729768234921/8c1f0d4e-5fb2-4461-8e62-574d95a51672.png" alt="第 14 行的断点" width="1476" height="1015" loading="lazy"></p>
<p>此时，你会看到没有继续执行——这就是为什么在 “Local” 下所有变量显示 “value unavailable”。</p>
<p>从这里开始，你可以通过点击右上角的 step 图标逐行单步执行代码：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729768323163/45fb5c6b-682d-4b90-8bec-d4ef8596c4b7.png" alt="Chrome 开发者工具源标签的 step 图标" width="1477" height="607" loading="lazy"></p>
<p>一旦你点击 step 图标，你所退出的行被执行。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729768411765/f2670800-c8d8-490f-8dc9-1fdfa8c8da7b.png" alt="点击 step 图标" width="1477" height="970" loading="lazy"></p>
<p>你可以看到，<code>"3"</code> 是第<code>14</code>行的值。该值被一对双引号包围，这意味着它是一个字符串。你需要确保这一点，而这正是 watch 特性能让你做到的。你将很快了解这一特性。</p>
<p>如果你正处理多行代码，逐行单步执行可能会耗费时间。因此，你可能需要添加另一个断点。</p>
<p>我将继续在第 <code>23</code> 行设置一个断点并再次运行代码：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729768528136/478fc837-0c16-4990-9b70-19ff1695331e.png" alt="第 23 行的断点" width="1475" height="968" loading="lazy"></p>
<p>现在你可以看到，除了 <code>average</code> 外的所有变量结果似乎都是字符串。这引出了下一个 Chrome 开发者工具调试器特性——watcher。</p>
<h3 id="watch">如何使用开发者工具的监视（watch）特性</h3>
<p>开发者工具的监视特性可以让你在代码运行时监视（watch）特定的变量或表达式。</p>
<p>要确认变量的数据类型，你可以添加一个显示其值的监视（watch）表达式，或更合适地，显示其类型。</p>
<p>要添加监视（watch）表达式，点击 “监视（watch）” 旁边的加号（+）图标，并按键盘上的 <code>ENTER</code>。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729768780977/ef22ae71-068c-41a2-9a2e-509c7c6a8afb.png" alt="添加 watch 表达式" width="1549" height="1015" loading="lazy"></p>
<p>以下监视（watch）表达式是确认 <code>num1</code> 到 <code>num4</code> 和 <code>total</code> 为字符串——但它们应为整数：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729768808497/5d7352d6-37b3-490c-9ce2-f430c2d9a0e6.png" alt="watch 表达式" width="1479" height="609" loading="lazy"></p>
<p>你还可以在控制台标签中验证变量类型：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729768847227/3730a133-0a5b-4eb1-a5dd-257fa0ac2293.png" alt="控制台的变量类型" width="736" height="390" loading="lazy"></p>
<p>这意味着你输入的数字被解释为字符串。这是因为在 JavaScript 中，从 HTML 元素（如输入字段）获取的值总是字符串。</p>
<p>这是因为输入元素的 <code>value</code> 属性返回一个字符串，即使你输入的是数字——这就是 bug 出现的原因。</p>
<p>记住，JavaScript 只会连接字符串，即使它们是数字。这说明 <code>"3"</code> 是字符串类型而不是整型。</p>
<p>要修复这个 bug，你应将 <code>num1</code> 到 <code>num4</code> 的类型更改为整数，以便 JavaScript 能正确地将它们的值相加。</p>
<p>然后你可以继续在 DevTools 中修复此问题，并在 Windows 上按 <code>CTRL + S</code> 或在Mac上按 <code>CMD + S</code> 保存代码。你也可以在代码编辑器中，通过在数字的变量中使用 <code>parseInt()</code> 来修复它。</p>
<p>一旦你这么做并再次运行代码，watcher 中应该显示正确的数据类型，Local 下应该显示正确的变量值：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729768941146/964cabbd-2298-4303-ac0d-2b54af070d66.png" alt="watch 中的正确变量类型" width="1482" height="1011" loading="lazy"></p>
<p>你也可以在代码编辑器中实现这些更改，使一切正常工作。以下是正确的代码：</p>
<pre><code class="language-javascript">const calculateBtn = document.getElementById('calculateBtn');
const sumText = document.getElementById('sum');
const avgText = document.getElementById('average');

function calculateTotal(a, b, c, d) {
  return a + b + c + d;
}

function calculateAverage(total, count) {
  return total / count;
}

function handleButtonClick() {
  let num1 = parseInt(document.getElementById('num1').value);
  let num2 = parseInt(document.getElementById('num2').value);
  let num3 = parseInt(document.getElementById('num3').value);
  let num4 = parseInt(document.getElementById('num4').value);

  let total = calculateTotal(num1, num2, num3, num4);
  let average = calculateAverage(total, 4);

  sumText.textContent = `The sum is ${total}`;
  avgText.textContent = `The average is: ${average}`;
}

calculateBtn.addEventListener('click', handleButtonClick);
</code></pre>
<p>以下是在浏览器中的结果：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729769063113/b7e39538-e9fe-4ce5-a4de-e98f43263235.png" alt="求和并计算平均值正常执行" width="601" height="423" loading="lazy"></p>
<h2 id="">总结</h2>
<p>这就是如何使用 Chrome 的开发者工具调试 JavaScript。断点和监视器功能以及 step 按钮是对基本控制台日志的升级。</p>
<p>请注意，每个现代浏览器都内置了这个 JavaScript 调试工具，因此你可以使用相同的方法在 Firefox 或 Edge 中调试 JavaScript。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 小黄鸭调试法 ]]>
                </title>
                <description>
                    <![CDATA[ 原文：Rubber Duck Debugging [https://www.freecodecamp.org/news/rubber-duck-debugging/]，作者：Kolade Chris [https://www.freecodecamp.org/news/author/kolade/] 作为一个软件开发者，你可能遇到过你的代码不能按预期工作的情况。 这可能是因为你犯了一个错，你没有足够注意，或者你不确定某些东西是如何工作的。 当你的代码不能工作时，这很令人沮丧——但唯一要做的是找到使你的代码不能工作的bug。这些 bug 的出现是因为计算机需要你在说它的语言时尽可能的精确。 你可以用一种方法来寻找你的代码中的错误，那就是小黄鸭调试法。 那么，什么是小黄鸭调试法？它是如何工作的？这就是你将在这篇文章中理解的问题。 为什么程序员要使用小黄鸭？ 很多人看到程序员桌子上的橡皮小黄鸭，可能会认为它是一个玩具或一个无关紧要的装饰。 实际上，小黄鸭是一种帮助程序员解决问题的工具。程序员向小黄鸭解释他们代码中的问题——通常称为 bug，然后小黄鸭帮助他们找到解决 bug 的 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/rubber-duck-debugging/</link>
                <guid isPermaLink="false">62611c6e99ec7406219e729f</guid>
                
                    <category>
                        <![CDATA[ Debug ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Fri, 10 Jun 2022 03:50:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/04/duck-meet-gd27f1e256_1280.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>原文：<a href="https://www.freecodecamp.org/news/rubber-duck-debugging/">Rubber Duck Debugging</a>，作者：<a href="https://www.freecodecamp.org/news/author/kolade/">Kolade Chris</a></p><p>作为一个软件开发者，你可能遇到过你的代码不能按预期工作的情况。</p><p>这可能是因为你犯了一个错，你没有足够注意，或者你不确定某些东西是如何工作的。</p><p>当你的代码不能工作时，这很令人沮丧——但唯一要做的是找到使你的代码不能工作的bug。这些 bug 的出现是因为计算机需要你在说它的语言时尽可能的精确。</p><p>你可以用一种方法来寻找你的代码中的错误，那就是小黄鸭调试法。</p><p>那么，什么是小黄鸭调试法？它是如何工作的？这就是你将在这篇文章中理解的问题。</p><h2 id="-">为什么程序员要使用小黄鸭？</h2><p>很多人看到程序员桌子上的橡皮小黄鸭，可能会认为它是一个玩具或一个无关紧要的装饰。</p><p>实际上，小黄鸭是一种帮助程序员解决问题的工具。程序员向小黄鸭解释他们代码中的问题——通常称为 bug，然后小黄鸭帮助他们找到解决 bug 的方法。</p><p>这是因为向别人解释问题有助于你更好地理解问题，并找到解决问题的办法。它允许你从一个新的角度看问题，抓住你第一次可能错过的东西。</p><p>为了更好地理解小黄鸭调试法的概念和它背后的想法，请确保你将这篇文章读完。</p><h2 id="--1">什么是小黄鸭调试法？它是如何工作的？</h2><p>小黄鸭调试法最初是来自安德鲁-亨特和大卫-托马斯在 1999 年写的《务实的程序员》一书中的一个故事。</p><p>这个故事描述了一个程序员如何带着一只橡皮鸭子，在遇到错误的时候逐行向它解释他的代码。</p><p>跟一个没有生命的物体谈论你的代码中的错误可能听起来很傻，但它在程序员中非常流行，因为它很有效。</p><p>在小黄鸭调试法中，你不仅仅是逐行向橡皮鸭子解释代码，你还要告诉鸭子你到底想做什么，以及你对代码的目标。</p><p>当你向橡皮鸭子解释关于代码的一切时，你就更有可能发现隐藏在那里的错误。</p><p>我们中的一些人曾经遇到过这样的情况：我们遇到了一个问题，决定向一个朋友解释这个问题，甚至在我们没有向那个朋友解释完这个问题的时候，就得到了解决方案。</p><p>通过向一个无生命的物体如橡皮鸭子解释你代码中的错误，你不需要打扰任何人。你也可以用宠物或其他无生命的物体代替橡皮鸭。</p><h2 id="--2">什么是小黄鸭理论？</h2><p>小黄鸭调试法背后的想法是：当程序员被 bug 拖住时，将代码逐行向橡皮鸭子解释。</p><p>把这种方法想象成一个过程，即你打出一条要在社交媒体上发布的信息，在发布前大声读出来。这可以帮助你发现其中的排版和语法错误。同样的事情也适用于向橡皮鸭子解释你的代码。</p><p>当你遇到 bug 时，你向橡皮鸭子逐行解释代码，bug 的解决方案往往就会出现在那里。</p><h2 id="--3">最后的思考</h2><p>为了有效地解决问题和学习任何东西，你需要谈论它和教别人使用它。小黄鸭调试法可以帮助你修复错误，因为当你谈论一个问题并教授它时，往往可以找到解决方案。</p><p>多年来，小黄鸭调试法一直是软件开发人员解决问题的主要方式。据一些程序员说，当他们得到一份新工作时，他们甚至会得到橡皮小黄鸭作为欢迎礼的一部分。</p><p>当然，并不是橡皮鸭子告诉你如何修复这些错误。相反，你要通过逐行讨论你的代码所做的事情来弄清楚如何修复这些错误。</p><p>小黄鸭调试法不仅可以用于编程中，你也可以在生活的其他方面使用这种方法。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 什么是调试——如何调试代码？ ]]>
                </title>
                <description>
                    <![CDATA[ 原文：What is Debugging? How to Debug Your Code for Beginners [https://www.freecodecamp.org/news/what-is-debugging-how-to-debug-code/]，作者： Germán Cocca [https://www.freecodecamp.org/news/author/gercocca/] 在这篇文章中，我们将讨论什么是调试，如何调试你的代码，以及你如何能在这方面做得更好。 目录  * 如何调试 [./#how-debugging-started]  * 你为什么要学习调试知识 [./#why-should-you-learn-about-debugging]  * 如何调试你的代码 [./#how-to-debug-your-dode]  * 如何进入调试的思维模式 [./#how-to-get-in-a-gebugging-mindset] * 注意错误信息       [./#pay-attention-to-error-eessages]     * 用 Goog ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/what-is-debugging-how-to-debug-code/</link>
                <guid isPermaLink="false">6245847a7f18d1062895c42c</guid>
                
                    <category>
                        <![CDATA[ Debug ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ luojiyin ]]>
                </dc:creator>
                <pubDate>Thu, 31 Mar 2022 02:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/03/pexels-mike-198101.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>原文：<a href="https://www.freecodecamp.org/news/what-is-debugging-how-to-debug-code/">What is Debugging? How to Debug Your Code for Beginners</a>，作者：<a href="https://www.freecodecamp.org/news/author/gercocca/">Germán Cocca</a></p><!--kg-card-begin: markdown--><p>在这篇文章中，我们将讨论什么是调试，如何调试你的代码，以及你如何能在这方面做得更好。</p>
<h2 id="">目录</h2>
<ul>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#how-debugging-started">如何调试</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#why-should-you-learn-about-debugging">你为什么要学习调试知识</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#how-to-debug-your-dode">如何调试你的代码</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#how-to-get-in-a-gebugging-mindset">如何进入调试的思维模式</a>
<ul>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#pay-attention-to-error-eessages">注意错误信息</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#google-things">用 Google 搜索</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#explain-your-logic-to-another-person-or-a-duck">向另一个人或一只鸭子解释你的逻辑（小黄鸭调试法）</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#narrow-down-your-problem-and-understand-where-the-error-is-generated">缩小问题范围，了解错误产生的原因</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#take-a-break-and-think-about-something-else">休息一下，想想别的事情</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#look-for-help">寻找帮助</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#make-sure-the-bug-is-dead">确保bug已经解决</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#write-clean-code">编写简洁的代码</a>
<ul>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#write-dry-code">写 DRY 代码</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#write-simple-code-when-possible">尽可能写出简单的代码</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#use-the-solid-principles">使用 SOLID 原则</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#technical-debugging-tools">技术调试工具</a>
<ul>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#how-typeScript-helps-write-clean-code">TypeScript如何帮助编写简洁的代码</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#how-to-use-console.log-to-debug-dode">如何使用Console.log来调试代码</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#how-to-use-visual-studio-debugger">如何使用Visual Studio调试器</a></li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#chrome-debugger">Chrome 调试器</a></li>
</ul>
</li>
<li><a href="https://chinese.freecodecamp.org/news/what-is-debugging-how-to-debug-code/#conclusion">结语</a></li>
</ul>
<h2 id="how-debugging-started">如何调试</h2>
<p>软件中的 “<em>bug</em>” 和 “<em>debugging</em>” 这两个词被普遍认为是由 <a href="https://es.wikipedia.org/wiki/Grace_Murray_Hopper">Admiral Grace Hopper</a> 提出的。一个真正的传奇人物，她写了有史以来的第一个编译器。</p>
<p>20世纪40年代，当她在哈佛大学为美国海军开发的一台计算机工作时，她的同事发现一只飞蛾（一种真实的昆虫）卡在一个继电器中，使计算机崩溃。</p>
<p>在解决这个问题时，她说，他们正在 <code>debugging</code> 系统。</p>
<p>如果你是一个词源学爱好者，你可能会对这样一个事实感兴趣：在进入计算机世界之前，<code>debugging</code> 一词似乎已经作为一个术语在航空学中使用。</p>
<p>而且显然有某种证据表明，甚至托马斯-爱迪生在1878年也在 <code>technical error</code> 的意义上使用过这个词。</p>
<p>但这并不是本文的重点。重点是，调试是软件开发的一个核心部分。它一直都是，而且可能永远都是。</p>
<p>然而，值得庆幸的是，现在我们需要从计算机中移除真正的昆虫的情况相当罕见。</p>
<h2 id="why-should-you-learn-about-debugging?">你为什么要学习调试知识?</h2>
<p>漏洞和错误在软件开发中很容易发生，因为它是一种概念性和抽象的活动。</p>
<p>作为开发者，我们与信息打交道。我们组织它、移动它、更新它、编辑它、把它发送到各地，然后再次接收它。</p>
<p>我们一直在与信息打交道，但不是直接与它打交道。信息并不“实际”存在于计算机中，至少不是以用户认为的格式存在。</p>
<p>在计算机中只有电脉冲，然后被抽象为1和0，然后再次被抽象为我们正在处理的任何信息。</p>
<p>为了与计算机交互和使用计算机，我们使用编程语言。这些提供了计算机正在执行的实际任务的抽象，以及我们正在管理的信息的表示。</p>
<p>编程可以是一种非常抽象的活动，而且很容易很快就忽略了计算机正在执行的实际任务是什么，或者我们在某一行代码中根据什么信息行事。从那时起，我们就很容易给计算机发出错误的指令，从而错失我们所要寻找的目标。</p>
<p>在软件开发领域的一个内部笑话是，开发人员通常会花5分钟来写代码，花5个小时来理解为什么事情不能像它们应该的那样工作。</p>
<p>作为开发人员，无论我们做得多好，我们都要花无数个小时来调试我们的代码，所以我们应该努力在这方面做得更好、更快。</p>
<h2 id="how-to-debug-your-dode">如何调试你的代码</h2>
<p>调试可以被定义为在代码库中找到问题的根源并加以修复的过程。</p>
<p>通常我们会从思考所有可能的原因开始，然后测试每个假设（从最有可能的假设开始），直到找到最终的根本原因。然后我们纠正它，确保它不会再发生。</p>
<p>对于bug，没有神奇的解决方案。通常情况下，它需要结合搜索，记录我们的代码，并根据真正发生的情况检查我们的逻辑。</p>
<p>虽然有许多工具可以帮助你进行调试，但使用这些工具并不一定是困难的部分。难的是真正理解你得到的错误，并真正理解什么是解决这些错误的最佳方案。</p>
<p>因此，让我们先来谈谈“调试心态”，然后探索一些我们可以用来调试代码的有用工具。</p>
<h2 id="how-to-get-in-a-gebugging-mindset">如何进入调试的思维模式</h2>
<h3 id="pay-attention-to-error-eessages">注意错误信息</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/G-Wn7Seyn.gif" alt="G-Wn7Seyn" width="600" height="400" loading="lazy"></p>
<p>在几乎所有的开发环境中，如果你的代码失败了，很可能会显示一个错误信息，（在某种程度上）解释你的代码为什么会失败。</p>
<p>以这段代码为例：</p>
<pre><code class="language-js">mickTheBug('Im a scary bug!')

const mickTheBug = message =&gt; console.log(message)
</code></pre>
<p>这段代码出现了以下错误:</p>
<pre><code class="language-js">ReferenceError: Cannot access 'mickTheBug' before initialization
    at Object.&lt;anonymous&gt; (/home/German/Desktop/ger/code/projects/test.js:4:1)
</code></pre>
<p>正如你所看到的，错误信息明确指出了问题所在，甚至声明了问题发生在哪一行（<code>test.js:4:1</code>）。</p>
<p>这似乎是一个愚蠢的建议，但你可能会惊讶地看到有多少程序员不仔细阅读错误信息，而只是用他们脑海中的第一个想法来应对错误。</p>
<p>错误信息的存在是有原因的，这至少可以让我们对问题的来源有一个初步的了解。</p>
<h3 id="google-things">用 Google 搜索</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/ddqvW2927.png" alt="ddqvW2927" width="600" height="400" loading="lazy"></p>
<p>如果你得到的错误信息不清楚，或者你无法弄清楚为什么会得到它，那么好的第一步就是用谷歌搜索。</p>
<p>关于编码的许多令人惊奇的事情之一是，在线社区是巨大的。几乎可以肯定的是，已经有大量的人遇到了和你一样的问题，并且已经解决了它，解释了它，这样其他人就不必再纠结于它了。</p>
<p>当搜索时，一个好主意是在搜索中尽可能详细。按照前面的例子，我会使用 <code>javascript ReferenceError: Cannot access before initialization</code> 。我发现，在搜索中提到你所使用的技术会给你更准确的结果。</p>
<p>我还了解到，删除那些只针对我的代码而不是每个人都会遇到的错误的东西是很重要的。如我的函数的名字（<em>'mickTheBug'</em>）。</p>
<p>另一个好主意是尽量 <strong>使用可信的和最新的来源</strong>。可信的意思是官方文档或已经被其他人验证过的解决方案。最近的意思是指尽可能在最近实现的解决方案，因为五年前有效的东西可能不是现在解决问题的最好方法。</p>
<p>当你在学习新东西或处理错误时，官方文档总是应该是首先要检查的东西。</p>
<p>官方文档通常是任何特定工具的最完整和最新的信息来源。有时，翻阅这么多的技术信息可能会感到乏味或不知所措，但从长远来看，我认为这可以节省时间。</p>
<p>官方文档的问题是，有时它们包含如此多的信息，而且解释得如此详细，以至于它更令人困惑而不是解释。</p>
<p>正因为如此，我认为对于任何特定的主题，总是使用一个以上的来源，并“听取不同的声音”来解释同一件事是一个好主意。通常只有在阅读了文档、一些文章和观看了一些YouTube视频之后，我才觉得我对我正在使用的工具有了很好的理解。</p>
<h3 id="explain-your-logic-to-another-person-or-a-duck">向另一个人或一只鸭子解释你的逻辑（小黄鸭调试法）</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/lwjv2jUhM.png" alt="lwjv2jUhM" width="600" height="400" loading="lazy"></p>
<p>我之前提到过，编程可以是一种抽象的活动，这使得我们很容易忽视一些事情，做出错误的假设，并误解我们正在处理的信息</p>
<p>解决这个问题的一个好办法是逐行阅读你的代码，一边读一边大声解释。<a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging">小黄鸭调试法</a>是一种流行的方法，但你可以选择你最喜欢的宠物或想象中的朋友。=P</p>
<p>这样做的目的是强迫自己真正读懂你的代码，而不是仅仅假设你知道它是做什么的。通过这种方式，你可以检查你头脑中的逻辑与你的代码中实际发生的情况。</p>
<p>事实上，我们倾向于假设事情，而不是详细关注每一行代码，这只是人类的天性。这是一种帮助我们节省精力和更快做事的机制。</p>
<p>但在调试时，我们需要强制我们的大脑与我们一起工作，并尽可能地在每一行代码上出现。</p>
<h3 id="narrow-down-your-problem-and-understand-where-the-error-is-generated">缩小问题范围，了解错误产生的原因</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/aEKNV-Iju.gif" alt="aEKNV-Iju" width="600" height="400" loading="lazy"></p>
<p>随着你的代码库越来越大，你将很难分析每一行代码来寻找你的错误。因此，一个好主意是分而治之，从最有可能产生问题的地方开始搜索。</p>
<p>让我们看看这个例子。我有一个函数，它接收一个数字并返回它乘以2的结果，还有一个函数，它打印一个名字（firstName），一个姓氏（lastName），以及乘法函数的结果。</p>
<pre><code class="language-js">const multiply = num =&gt; num*2

const mickTheBug = async (firstName, lastName, age) =&gt; {
  console.log(`My name is ${firstName} ${lastName} and the double of my age is ${multiply(age)}`)
}

mickTheBug('Mick', 10)
</code></pre>
<p>这段代码是有意义的，运行时没有出现错误，但我得到的结果是 <code>My name is Mick 10 and the double of my age is NaN</code>，这不是我想要的。</p>
<p>这里我可以看到，<code>10</code> 被打印在 <code>lastName</code>的位置。而由于参数是在调用函数的那一行设置的。</p>
<p>这可能是一个很好的猜测，首先要检查参数的传递方式是否正确。事实上，我们可以看到，当我调用该函数时，我给它传递了两个参数，<code>Mick</code>和 <code>10</code>，而该函数希望有三个参数<code>firstName, lastName, age</code>。</p>
<blockquote>
<p>Typescript 可以轻松地防止我们犯这个错误。稍后再谈这个问题。;)</p>
</blockquote>
<p>同样，这是一个愚蠢的例子，但它说明了我们如何能够推断出问题的来源，即使我们没有错误信息来帮助我们。</p>
<p>在这些时候，试着问自己以下问题：</p>
<ul>
<li>我怎么知道我看到了一个错误？</li>
<li>我在提供什么输入？它是从哪里来的？这个输入与函数所期望的相同吗？</li>
<li>我得到了什么输出？输入是如何变化的？</li>
<li>是否有任何其他实体与这段代码互动？</li>
<li>我最近是否改变了什么，从而使代码中断？</li>
</ul>
<h3 id="take-a-break-and-think-about-something-else">休息一下，想想别的事情</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Ly_kXFJop.gif" alt="Ly_kXFJop" width="600" height="400" loading="lazy"></p>
<p>像我们到目前为止看到的例子那样的错误，解决起来小菜一碟。但许多其他的就不是这样了，在许多情况下，你不得不与bug斗争几个小时（或几天），直到你找到一个解决方案。</p>
<p>在这种情况下，我发现注意你的心理状态真的很重要。编程是一种非常消耗精力的活动。因此，你的大脑在某一时刻的工作方式或你的感觉将直接影响你的代码的外观和你以有效方式解决问题的能力。</p>
<p>如果你花了几个小时阅读，大声重复同样的代码行，上网搜索，翻阅Stack Overflow的问题，但你的代码仍然失败，你迟早会感到沮丧，并开始给自己施加压力。</p>
<p>当你尝试不同的解决方案并一次次失败时，你对细节的关注很可能会淡化，你会开始有不同的想法，并同时尝试很多东西。</p>
<p>一旦你到了这个地步，明智的做法是出去走走，或者干脆不去管它，直到第二天。</p>
<p>如果你在这种紧张和疲惫的精神状态下继续下去，你可能不会找到一个解决方案。更重要的是，你甚至可能因为触碰了与之无关的东西而使 bug 变得更糟。</p>
<p>当把事情搁置一段时间并思考其他事情时，我们的大脑会在默默地继续处理问题，并以 <code>潜意识</code> 和创造性的方式将想法联系起来。</p>
<p>在很多情况下，我在洗澡时或第二天早上一看到这个问题，我的脑海中就会出现一个新的解决方案。这就是那种 <code>啊哈!</code> 的时刻。它可能就在你的眼前，但因为你很累，压力很大，所以你没能看到它。</p>
<p>集中精力、充分休息和放松是写好代码和有效修复错误的关键。努力工作和烧坏头脑之间的界限并不远，但重要的是我们要注意它，并在我们需要时让自己休息一下。</p>
<p>通常当我没有想法了，是休息的好时机，或者开始失去焦点，以一种冲动的、非系统性的方式尝试不同的方法。</p>
<p>另外，在你的脑海中保持这样的想法：<code>bug</code> 只是软件开发的一部分。这并不意味着你作为一个开发者很糟糕。每个人都会有 bug，即使是最好的程序员。因此，冷静下来，利用这种情况来学习新的东西。</p>
<h3 id="look-for-help">寻找帮助</h3>
<p>我之前提到过在线社区的重要性，以及我们可以在几秒钟内轻松找到几乎任何主题的帮助是多么酷。</p>
<p>能够进入正确的社区，在那里你可以向对你所使用的工具有经验的人询问和交谈，这真的非常、非常、非常有帮助。</p>
<p>这取决于你工作的领域和你使用的工具，但对我来说，像 <a href="https://www.freecodecamp.org/">freecodecamp</a>、<a href="https://stackoverflow.com/">stackoverflow</a> 和 <a href="https://meetupjs.com.ar/">meetupjs</a> 这样的Sack或Dscord社区都起到了很大的作用。</p>
<p>在这些社区内提问时，我发现记住以下几点很重要：</p>
<ul>
<li>尽量做到 <code>详细</code>。仅仅通过阅读别人的代码并不容易理解，所以尽量解释你在做什么，你想实现什么，你面临的问题是什么。</li>
<li>显示你得到的 <code>确切的错误</code>。</li>
<li>显示你认为导致该错误的 <code>相关代码</code>。</li>
<li>提到到目前为止你已经尝试了哪些 <code>解决方案</code>，以及为什么它们不起作用。</li>
<li>调查并表明你已经对这个问题进行了 <code>探索</code>。尽管寻求帮助是完全可以的，但我认为在要求别人为你做思考之前，你必须首先排除比较明显和容易的路径。这意味着你已经分析了你的代码，在谷歌上搜索了这个问题，阅读了其他解决方案和官方文档，尝试了很多方法，但都没有成功。只有这样，才可以接受向别人寻求帮助。我认为这是一个能够独立学习和解决问题的问题，同时也要 <code>尊重别人的时间</code>。</li>
<li>提到你所查阅的关于这个主题的 <code>文档</code>，以及该文档对它的评价。</li>
<li>在网上提供你的 <code>完整的代码库</code>。</li>
</ul>
<p>这将使另一个人更容易理解你的问题，并希望为你提供解决思路。</p>
<p>如果你得到了回复，重要的是你要 <code>回复他们</code>，要么确认解决方案有效，要么确认它没有，并解释原因。</p>
<p>记住，你提出的问题可能会被储存起来，在下一次有人来搜索同样的错误时可以使用。这里的想法是要 <strong>构筑知识</strong>，并使其为 <strong>所有人所用</strong>，而不仅仅是为了解决这个特定的错误。</p>
<p>另外，如果你最终自己找到了解决方案，那么 <strong>回答你自己的问题</strong>，并与大家分享解决方案也是一个好主意。</p>
<p>按照同样的思路，如果你通过提问参与这些社区，你也应该参与回答问题。只要你有能力，并且发现你有知识，回馈一下也是好的。;)</p>
<p>我对这个问题的最后一个想法是，在这些类型的社区中，大多数人都很好，很开放，而且非常愿意帮助和分享知识。但是，就像在任何其他生活领域一样，偶尔你会遇到一些粗鲁、傲慢、甚至具有攻击性的人。</p>
<p>我在这里的建议是，你不要让别人吓到你，即使他们看起来比你有更多的知识。</p>
<p>没有人天生就知道所有的事情，如果你已经做了研究并致力于解决问题，你完全有权问任何你想要的东西。如果其他人傲慢或无礼，这说明他们不好，而不是你。</p>
<h3 id="make-sure-the-bug-is-dead">确保bug已经解决</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/xOmnh7_G7.gif" alt="xOmnh7_G7" width="600" height="400" loading="lazy"></p>
<p>唯一比与一个棘手的bug作斗争更令人沮丧的事情是，在修复它之后，却发现这个bug仍然在那里。甚至更糟糕的是，由于这个 "解决方案"，更多的bug被引入到你的代码中。</p>
<p>为了避免这种情况，关键是你要测试你的代码。如果你能用自动化单元测试来做，那就更好了。</p>
<p>理想情况下，你的代码库的每个部分或组件都应该有自己的测试。这些测试应该在每次对代码库做任何修改时运行。这样一来，如果测试写得正确，我们就可以在新的错误出现时注意到它。这当然会使我们更容易找到它的原因并解决它。</p>
<p>如果你没有自动化测试（如果你想创建高质量的软件，你真的应该这样做），至少要手动测试你的代码，重现用户可能与之发生的所有互动，并确保该bug被有效地杀死。</p>
<h3 id="write-clean-code">编写简洁的代码</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Y4PKO37NS.png" alt="Y4PKO37NS" width="600" height="400" loading="lazy"></p>
<p>对抗bug的最好方法是首先避免插入bug。对任何程序员来说，写出有保证的无缺陷的代码是不可能的，但有几件事你可以做，以减少缺陷被插入的机会。</p>
<p>一个好的开始是经典的DRY、KISS和SOLID原则。</p>
<p>关于这些主题有整整一本书，但长话短说，这些原则旨在使软件易于开发，易于理解和维护，并尽可能地接近于无缺陷。</p>
<h4 id="write-dry-code">写 DRY 代码</h4>
<p><strong>DRY</strong> 原则代表着 <strong>不要重复自己</strong>。它基本上意味着我们应该尽可能地避免重复相同的代码。</p>
<p>例如，如果你发现你在代码的不同部分反复执行相同的操作，那么更好的方法是将该逻辑抽象为一个函数，并调用该函数，而不是直接在代码的不同部分执行操作。</p>
<p>这样一来，如果在该操作中发生了一些错误或意外行为，我们就知道只有一段代码要负责，而不是许多分散在代码库中的代码。</p>
<h4 id="write-simple-code-when-possible">尽可能写出简单的代码</h4>
<p><strong>KISS</strong> 原则代表着 <strong>保持简单的愚蠢</strong>。随着一个软件项目的发展，它不可避免地开始变得越来越复杂。随着新的、计划外的功能被添加，不同的开发人员开始工作，不同的逻辑和执行任务的方式可能会在同一个项目中实现。</p>
<p>这使得代码更难理解、维护和工作。而当代码难以理解时，就很容易做出错误的假设和插入错误的代码。</p>
<p>我们的目标应该是使软件易于阅读和理解，有一个清晰的逻辑，对每个人都是明确的，而不仅仅是对我们。</p>
<p>请记住，将来有人可能要使用你写的代码，所以要让那个人容易理解你在做什么。甚至你在几个月后可能都不记得你想用那个函数做什么。</p>
<p>还要记住，没有软件是永远不变的。软件的本质是通过新的功能来改变和增强，所以你的代码应该在需要时易于修改。</p>
<p>再进一步说，只要你能找到一个更简单的方法来执行同样的任务，你就应该修改你的代码。</p>
<p>也许在加入了一些新的功能后，你一开始想到的设计并不是仍然是最好的选择。编码的另一个很酷的事情是，没有什么是一成不变的，当需要的时候，事情可以很容易地转过来。所以要利用这一点，习惯于不断重构你的代码，寻找更简单的方法。</p>
<p>一些有助于此的实用概念是使用明确的函数和变量名称，将关注点分离成不同的函数和代码模块，当你的任务不可避免地复杂时，写简短的注释来解释你的代码。</p>
<h4 id="use-the-solid-principles">使用 SOLID 原则</h4>
<p><strong>SOLID</strong> 是一套主要适用于 <a href="https://en.wikipedia.org/wiki/Object-oriented_programming">OOP</a> 的原则。它们是由<a href="https://en.wikipedia.org/wiki/Robert_C._Martin">Robert C. Martin</a> (他也是 <a href="https://en.wikipedia.org/wiki/Agile_software_development#The_Agile_Manifesto">agile manifesto</a> 的作者)，<a href="https://www.amazon.com/-/es/Robert-Martin/dp/0135974445">这本书中</a> 是面向对象设计的。</p>
<ul>
<li><strong>S</strong> 代表 <strong>单一责任</strong>，这意味着一个类应该有一个，而且只有一个工作。</li>
<li><strong>O</strong> 代表 <strong>开放封闭原则</strong>，这意味着你应该能够扩展一个类的行为，而不用修改它。</li>
<li><strong>L</strong> 代表 <strong>Liskov替代原则</strong>，这意味着派生类必须可以替代其基类。</li>
<li><strong>I</strong> 代表 <strong>接口隔离</strong>，这意味着不应该强迫客户实现它不使用的接口，也不应该强迫客户依赖他们不使用的方法。</li>
<li><strong>D</strong> 代表 <strong>依赖反转原则</strong>，这意味着实体必须依赖抽象，而不是依赖具体事物。它指出，高层模块不能依赖低层模块，但它们应该依赖抽象物。</li>
</ul>
<p>如前所述，SOLID更适用于OOP而不是一般的编程。我们不打算在本文中深入探讨OOP，但了解这些原则并将其牢记在心仍然是很好的。</p>
<p>现在让我们来了解一些你可以用来帮助你调试代码的工具。</p>
<h2 id="technical-debugging-tools">技术调试工具</h2>
<p>有许多工具我们可以用来减少在我们的代码中插入bug的机会，或者更有效地打击现有的bug。</p>
<p>在这方面，我们将看看<strong>TypeScript</strong>，流行的（非常有用的）<strong>console.log</strong>，以及<strong>VS Code</strong>和<strong>Chrome</strong>中内置的<strong>调试器</strong>。</p>
<p>这些工具和例子将以JavaScript为中心，但这些原则适用于任何编程语言。</p>
<p>你还应该知道，现在大多数代码编辑器和网络浏览器都有内置的调试器，但我们要审查的是VS代码和Chrome，因为它们是最流行的。</p>
<p>最后，你还应该知道有一些特定的调试工具，你可以用来调试特定类型的应用程序，比如 <a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=es">React</a> 和<a href="https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=es">Redux</a> 开发工具，这是你可以安装的浏览器扩展，以帮助你更有效地调试你的代码。</p>
<p>但我们将来会在另一篇关于如何调试React应用程序的文章中回顾这些。;)</p>
<h3 id="how-typeScript-helps-write-clean-code">TypeScript如何帮助编写简洁的代码</h3>
<p>我提到TypeScript是第一个工具，因为它与前面关于编写干净代码的部分密切相关。</p>
<p>TypeScript不只是为你提供了一个强大的JavaScript类型系统。它还增加了一个编译器，可以帮助你在运行代码之前识别代码中的错误和误区。它提供了惊人的自动完成功能，并且可以被认为是一个自动文档工具。</p>
<p>为了了解它的好处，让我们重温一下前面的例子，在这个例子中，我们没有为我们的函数调用提供正确的参数。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/TYPESCRIPT1.png" alt="TYPESCRIPT1" width="600" height="400" loading="lazy"></p>
<p>正如你在这里看到的，在运行程序之前，TypeScript立即检测到我们缺少一个参数，并给了我们以下错误:</p>
<pre><code class="language-js">Expected 3 arguments, but got 2.ts(2554)
index.ts(6, 64): An argument for 'age' was not provided.
</code></pre>
<p>这些类型的通知是非常有用的，特别是当你在大项目中工作时，你必须与许多API或不同的代码部分互动。</p>
<p>因此，如果你习惯于使用普通的JavaScript，TypeScript一开始可能会觉得是不必要的模板。但从长远来看，它肯定会节省你的时间，防止你在代码中插入愚蠢的错误。</p>
<h3 id="how-to-use-console.log-to-debug-dode">如何使用Console.log来调试代码</h3>
<p>在控制台中记录你的代码是最基本的调试方式，也是我们作为开发者最先学会使用的方式。</p>
<p>其目的是打印变量、函数、输入和输出的值，以检查我们头脑中的逻辑与我们代码中的真实情况。它还可以帮助我们看到我们正在做哪些错误的假设。</p>
<p>尽管它是一个基本的工具，但我们可以用它做一些很酷的事情。让我给你看看。</p>
<p>如果我们调用 "console.log"，我们将得到任何我们作为参数传递的对象打印在我们的控制台。</p>
<pre><code class="language-js">const arr = []
console.log(arr) // []

const populateArr = (elem1, elem2, elem3) =&gt; arr.push(elem1, elem2, elem3)
console.log(populateArr) // [Function: populateArr]

populateArr('John', 'Jake', 'Jill')
console.log(arr) // [ 'John', 'Jake', 'Jill' ]
</code></pre>
<p><code>console.table</code> is great when working with arrays or objects, as it sets the information within a table where your can easily see keys/indexes and properties/values.</p>
<pre><code class="language-js">const arr = ['John', 'Jake', 'Jill']
console.table(arr)

//┌─────────┬────────┐
//│ (index) │ Values │
//├─────────┼────────┤
//│    0    │ 'John' │
//│    1    │ 'Jake' │
//│    2    │ 'Jill' │
//└─────────┴────────┘

const obj1 = {
  name: 'John',
  age: 30,
  job: 'Programmer'
}

const obj2 = {
  name: 'Jason',
  age: 32,
  job: 'Designer',
  faveColor: 'Blue'
}

const arr2 = [obj1, obj2]

console.table( arr2 )
// ┌─────────┬─────────┬─────┬──────────────┬───────────┐
// │ (index) │  name   │ age │     job      │ faveColor │
// ├─────────┼─────────┼─────┼──────────────┼───────────┤
// │    0    │ 'John'  │ 30  │ 'Programmer' │           │
// │    1    │ 'Jason' │ 32  │  'Designer'  │  'Blue'   │
// └─────────┴─────────┴─────┴──────────────┴───────────┘
</code></pre>
<p>当同时记录许多事情时，<code>console.group</code> 给了我们一种有组织的方式来看待事情。</p>
<pre><code class="language-js">const arr1 = [22, 23, 24]
const arr2 = [25, 26, 27]

console.group('myArrays')
console.log(arr1)
console.log(arr2)
console.groupEnd()


const obj1 = {
  name: 'John',
  age: 30,
  job: 'Programmer'
}

const obj2 = {
  name: 'Jason',
  age: 32,
  job: 'Designer',
  faveColor: 'Blue'
}

console.group('myObjects')
console.log(obj1)
console.log(obj2)
console.groupEnd()

// myArrays
//   [ 22, 23, 24 ]
//   [ 25, 26, 27 ]
// myObjects
//  { name: 'John', age: 30, job: 'Programmer' }
//  { name: 'Jason', age: 32, job: 'Designer', faveColor: 'Blue' }
</code></pre>
<p><code>console.assert</code> 在测试我们代码中的条件时非常有用。它需要两个参数：第一个参数是条件，第二个参数是条件为假时记录的信息。</p>
<pre><code class="language-js">const arr1 = [22, 23, 24]

console.assert(arr1.indexOf(20) !== -1, '20 is not in my array')
// Assertion failed: 20 is not in my array
</code></pre>
<p><code>console.warning</code> 和 <code>console.error</code> 在调试我们代码中的错误时很有用。第一个将以黄色背景打印错误，第二个以红色背景打印。</p>
<pre><code class="language-js">console.warn('No biggie') // No biggie
console.error(new Error('Error detected'))

// Error: Error detected
//     at Object.&lt;anonymous&gt; (/home/German/Desktop/ger/code/projects/test.js:6:15)
//     at Module._compile (node:internal/modules/cjs/loader:1101:14)
//     at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
//     at Module.load (node:internal/modules/cjs/loader:981:32)
//     at Function.Module._load (node:internal/modules/cjs/loader:822:12)
//     at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12)
//     at node:internal/main/run_main_module:17:47
</code></pre>
<h3 id="how-to-use-visual-studio-debugger">如何使用Visual Studio调试器</h3>
<p>随着我们的应用程序的增长和开始变得更加复杂，控制台.记录的做法变得不是那么有效。</p>
<p>为了帮助我们与错误作斗争，我们开发了调试器。它们只不过是能够读取其他程序并逐行查看的程序，沿途检查我们想要的任何信息（例如，变量的值）。</p>
<p>我们要看到的第一个例子是 <strong>Visual Studio调试器</strong>。</p>
<p>为了调试一个Node.js应用程序，我们不需要安装任何额外的东西（假设我们的电脑中已经安装了VS代码和Node），因为VS代码中内置了node调试器。</p>
<p>如果你用其他语言调试，如Python或Java，你可能需要在运行调试器之前安装一个特定的VS扩展。</p>
<p>开始时，我们只需选择我们要调试的文件，然后按下 <code>bug</code> 图标。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/vsc1.png" alt="vsc1" width="600" height="400" loading="lazy"></p>
<p>之后，我们将看到以下画面:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/vsc2.png" alt="vsc2" width="600" height="400" loading="lazy"></p>
<p>我们将选择 <code>Run and debug</code>，这将只是为我们在编辑器中运行该程序。</p>
<p>考虑到你也可以创建一个<code>launch.json</code>文件，这是一个VS代码用来 <code>知道</code> 如何运行你的程序的文件。对于这个简单的例子来说，这不是必要的，但要知道这种方法。</p>
<p>点击 <code>Run and debug</code> 按钮后，我们的程序将运行，我们将进入以下屏幕:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/vsc3.png" alt="vsc3" width="600" height="400" loading="lazy"></p>
<p>在左上方，我们有程序中所有可用的变量，包括本地和全局的变量。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/vsc4.png" alt="vsc4" width="600" height="400" loading="lazy"></p>
<p>在下面，我们会有一个空间，可以声明我们想观察的特定表达式。表达式可以是任何东西，比如你想关注的特定变量或函数，以评估它们如何随着你的程序而变化。</p>
<p>例如，我添加了我的变量 <code>arr</code>，VS代码向我显示了该变量的值:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/vsc5.png" alt="vsc5" width="600" height="400" loading="lazy"></p>
<blockquote>
<p>在这下面，我们可以看到调用堆栈（如果你不知道那是什么，<a href="https://www.youtube.com/watch?v=8aGhZQkoFbQ">这里</a>有一个很好的视频来解释），正在加载的脚本，以及我们在代码中设置的断点（我们一会儿就会看到这些是什么）。</p>
</blockquote>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/vsc6.png" alt="vsc6" width="600" height="400" loading="lazy"></p>
<p><strong>断点</strong> 是使调试器有用的一个重要部分。正如它们的名字所示，它们是你可以在你的代码中声明的点，在这些点上调试器将停止运行程序。当程序停止时，你就可以检查我们之前提到的所有信息，因为它是在那个特定时刻。</p>
<p>所以断点允许我们看到程序正在运行的实际信息，而不需要在控制台中记录任何东西。相当酷啊!</p>
<p>你可以通过出现在代码中行号左边的小红点来识别断点（或者通过查看上面提到的部分）。</p>
<p>默认情况下，当你运行调试器时，断点会被插入到你代码的最后一行。要插入新的断点，只需在你希望调试器停止的行号左边点击即可。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/vsc7.png" alt="vsc7" width="600" height="400" loading="lazy"></p>
<p>现在，当你运行调试器时，你会看到在第一个断点的上方有一个小小的左箭头，表示程序的执行已经停止。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/vsc8.png" alt="vsc8" width="600" height="400" loading="lazy"></p>
<p>在屏幕的顶部，我们有 <strong>controls</strong>，这将使我们能够通过程序从断点到断点的步骤。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/vsc9.jpg" alt="vsc9" width="600" height="400" loading="lazy"></p>
<ul>
<li>The <strong>Continue</strong> 按钮运行程序，只在用户定义的断点上停止。</li>
<li>With <strong>Step Over</strong> 按键。如果有一个函数调用，它将执行该函数并返回结果。你不会踏入函数内部的行。你只是直接进入到函数的返回值。</li>
<li><strong>Step Into</strong> *会逐行进入函数，直到它返回，然后你会回到函数调用后的下一行。</li>
<li><strong>Step Out</strong> 按钮，如果你已经踏入了一个函数，你可以跳过该函数的剩余执行部分，直接进入返回值。</li>
<li><strong>Restart</strong> 从头开始重新运行调试器， <strong>Stop</strong> 退出调试器。、</li>
</ul>
<p>所以，你看，这就是一个内置于你的代码编辑器中的非常强大的调试器。正如你所看到的，有了这个工具，我们可以同时检查很多信息，只需在我们想要的地方设置断点，而且不需要任何console.logs。</p>
<h3 id="chrome-debugger">Chrome 调试器</h3>
<p>要在Chrome中进行调试，我们首先要在浏览器中打开我们的应用程序。在我的例子中，我创建了一个简单的HTML文件，其中链接了我的JS文件（与前面的例子相同）。</p>
<p>然后我们打开<strong>developer tools</strong>（ctrl+shit+i或右键-&gt;inspect），进入 "<strong>sources</strong>"标签。</p>
<p>我们应该看到像这样的东西:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/chrome1.png" alt="chrome1" width="600" height="400" loading="lazy"></p>
<p>在左边，我们可以看到我们的应用程序中可用的文件（在我的例子中，只有一个HTML文件和JS文件）。 在中间，我们可以看到我们选定的文件的代码，在右边，我们有一组信息，与我们在VS Code中的信息非常相似。</p>
<p>要设置断点，我们必须点击我们想要停止的那一行的顶部。在Chrome浏览器中，断点被识别为行号上方的蓝色箭头。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/chrome2.png" alt="chrome2" width="600" height="400" loading="lazy"></p>
<p>然后，如果我们刷新我们的页面，脚本将在第一个断点处停止，我们将被允许使用控件来浏览它，这与VS代码中的工作方式完全相同。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/chrome3.png" alt="chrome3" width="600" height="400" loading="lazy"></p>
<p>正如我们所看到的，Chrome和VS代码调试器的工作原理非常相似，你决定使用哪一个只是一个偏好的问题。</p>
<h2 id="conclusion">结语</h2>
<p>调试是我们作为开发者所做工作的一个核心部分。正因为如此，我认为以一种有效的方式来考虑它和做它是一个好主意，而不是在错误发生时才做出反应。</p>
<p>正如我们所看到的，我们有很多事情可以做，无论是从精神上还是从技术上，都可以成为更好的调试。</p>
<p>希望这对你有帮助，下一节课见!</p>
<p>你也可以在 <a href="https://twitter.com/CoccaGerman">Twitter</a> 和 <a href="https://www.linkedin.com/in/germancocca/">LinkedIn</a> 关注我。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
