<?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[ Leo Zou - 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[ Leo Zou - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 08:28:41 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/author/leo/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 如何提高技术团队协作能力 ]]>
                </title>
                <description>
                    <![CDATA[ 这些技巧将助力你提升人际关系和团队工作效率。 当我作为初级开发人员获得第一份工作时，我觉得已经达到终极目标：通过做我最喜欢的事来获得报酬。 我的技能得到认可真是令人兴奋不已，特别是在经过多年的理论学习和学术研究之后。 我被媒体热炒过了头。 不久之后，我在这个新领域领受了难得的一课。事实证明，我在攻读计算机科学学位期间的所学与现实世界的所用之间存在巨大差异。 从“我知道很多”到“我还有更多要学”，这样的落差令人不悦。 从了解框架到理解模式与工作流程，我距离应该到达的境界的确相去甚远。 我意识到，如果我想提高编码能力并作为开发人员不断成长，我必须不断地学习。我领悟到学习的过程实际上永无止境。 快速前行十年之后，我每天仍然在不断学习新技术，感觉棒极了。 但我最大的教训是，仅凭技术技能本身还远远不够。 技术技能只是故事的一半 我们花了很多时间来磨练自己的技术技能，我们学习新的语言、框架、方法和模式。我们投入大量时间，有时甚至会忘记我们日常工作的另一个方面：我们团队的成员。 无论是作为开发人员、团队领导、质量保证工程师、设计师还是产品经理，我们大多数人都在团队中工作。我们一 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-be-a-team-player-in-the-tech-world/</link>
                <guid isPermaLink="false">5f61e948cd07b005bfb5b2df</guid>
                
                    <category>
                        <![CDATA[ 团队协作 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 自我提升 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 初级开发 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Leo Zou ]]>
                </dc:creator>
                <pubDate>Wed, 28 Apr 2021 09:30:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2020/09/jefferson-santos-9SoCnyQmkzI-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>这些技巧将助力你提升人际关系和团队工作效率。</p><p>当我作为初级开发人员获得第一份工作时，我觉得已经达到终极目标：通过做我最喜欢的事来获得报酬。</p><p>我的技能得到认可真是令人兴奋不已，特别是在经过多年的理论学习和学术研究之后。</p><p>我被媒体热炒过了头。</p><p>不久之后，我在这个新领域领受了难得的一课。事实证明，我在攻读计算机科学学位期间的所学与现实世界的所用之间存在巨大差异。</p><p>从“我知道很多”到“我还有更多要学”，这样的落差令人不悦。</p><p>从了解框架到理解模式与工作流程，我距离应该到达的境界的确相去甚远。</p><p>我意识到，如果我想提高编码能力并作为开发人员不断成长，我必须不断地学习。我领悟到学习的过程实际上永无止境。</p><p>快速前行十年之后，我每天仍然在不断学习新技术，感觉棒极了。</p><p>但我最大的教训是，仅凭技术技能本身还远远不够。</p><h2 id="-">技术技能只是故事的一半</h2><p>我们花了很多时间来磨练自己的技术技能，我们学习新的语言、框架、方法和模式。我们投入大量时间，有时甚至会忘记我们日常工作的另一个方面：我们团队的成员。</p><p>无论是作为开发人员、团队领导、质量保证工程师、设计师还是产品经理，我们大多数人都在团队中工作。我们一同分享史诗般故事发布的时刻，一同承受令人沮丧的一次次纠错调试。</p><p>对于一个由个人组成的集体，每个人都有自己的特点（经验、想法和专长），有效地工作和协作并不总是那么容易，每个人都必须采用特定的技能才能成为最有价值的团队成员。</p><p>“团队的力量在于每个成员，每个成员的力量就是团队。“ - 菲尔杰克逊</p><p>因此，尽管技术技能至关重要，但这只是等式的一部分，另一部分在于尽你所能成为最好的团队成员。</p><h2 id="--1">如何成为更好的团队成员</h2><p>说实话，这需要很多。但是，让我列出四个基本素质，你可以身体力行。</p><h3 id="1-">1.让自我留在门外</h3><p>我们生活在一个充满竞争的世界，因此，随着时间的推移，我们养成了我们自以为能使自己脱颖而出并生存下来的习惯。</p><p>我们想证明自己比其他人更聪明、更强大、更优秀。我们希望我们的实力得到队友和经理的认可。</p><p>我们的自我通常被当作一种生存技能来帮助我们脱颖而出，我们常常盲目地相信自己解决问题的方法是最好的。我们断然拒绝其他人的意见和建议。</p><p>在最糟糕的情况下，我们甚至会让同事觉得他们不知道自己在说什么。</p><p>这种行为，虽然可以供养我们的自我，让我们感觉更好，但却是破坏性的。它从每次谈话中吸取空气，并造成挫折感和令人窒息的工作环境。</p><p>“自我可以成为成功的一大障碍，它可以扼杀机会，进而扼杀成功。”-德韦恩约翰逊</p><p>为了使团队有效地工作和协作，其成员必须互相尊重，倾听他人的声音并接受他人的意见，即使我们不完全同意。</p><p>通过这样做，我们促成一个安全的环境。当我们感到安全时，我们的自我就变得无关紧要了。</p><h3 id="2-">2.乐于接受反馈</h3><p>持续的反馈，无论是积极的还是消极的，都是个人成长和团队合作的关键。没有它，我们就永远无法知道自己的弱点，也无法知道如何改进。</p><p>接受负面反馈很难。我们倾向于采取防御措施，可能会反击，试图为自己的行为或反应辩解。</p><p>给予负面反馈也同样困难，因为我们担心对方会做出怎样的反应，我们害怕它会给人居高临下的感觉，因此，我们往往会完全拒绝这样做。</p><p>“我们都需要有人给我们反馈意见，这样我们才能进步。” - 比尔盖茨</p><p>但是，反馈 -- 给予和接受反馈 -- 是我们理解需要什么以及如何改进的最有效的方法。</p><p>因此，我们应该学习如何给予建设性的反馈，同时也应该努力接受批评。这样，你就可以每天不断改进并成为更有价值的团队成员。</p><h3 id="3-">3.勇于承担责任</h3><p>当我们发布一个很棒的专题，修复一个难以搞定的错误，或者进行一段鼓舞人心的讲话时，我们期望我们努力得到认可。对我们所做的好事负责很容易。</p><p>但我们是人，是人就会犯错误。我们可能会在生产过程中导入某个关键性的错误，说出一些被误解的话，或者做出冒犯他人的行为。</p><p>对我们的错误负责并非易事，感觉就像我们举着“我错了”的牌子示众，身后跟着一位女士高喊“丢人，丢人，丢人。”</p><p>首先要明白的是犯错是可以的。与其沉溺于错误本身，不如将其视为一次成长的机会。</p><p>所以要勇于负责任，负责任意味着成熟，这是在团队中建立信任的关键因素。当你说的话被人曲解，或者你的编码导致错误的产生 - 勇敢地面对失败并承担责任。</p><p>“ 善于找借口的人对任何事都很难有所作为。” - 本杰明富兰克林</p><p>你将在团队成员之间建立信任，而且他们知道即使在最具挑战性的情况下，他们依然可以指望你在那里。</p><h3 id="4-">4.不要成为知识囤积者</h3><p>我们处在一个不断学习的过程中，无论是阅读StackOverflow上的答案、在线课程，还是自学一个新框架，您的大脑都在不停地消耗知识。</p><p>多年来，我们获得了大量知识，我们成为所在领域的专家，如果我们真的很出色，就会成为这个领域的万事通。</p><p>相信我们拥有的知识量使我们对公司如此宝贵，这种假想很容易愚弄我们，让我们自以为是不可替代的。为此，我们囤积这些知识，秘而不宣。</p><p>然而，知识囤积者对任何团队都具有破坏性。</p><p>当我们阻断我们在整个职业生涯中获取知识的通道时，我们不仅会损害团队的生产力和效率，而且还会形成一种“人人为自己”的文化。</p><p>这是有害的。</p><p><strong>当你分享知识时，你就会赋予他人权力。你积极参与他人的成长，鼓励对话和创造性思维。</strong></p><p>分享知识的最大好处是鼓励互惠互助：其他人更愿意与你分享他们的知识。你会惊喜地发现从坐在你身旁的人身上学到那么多东西。</p><p>“如果你有知识，让别人在里面点燃蜡烛。”——玛格丽特·富勒。</p><p>成为你所在领域的专家并不一定能让你成为一名出色的教育者; 在教与学中投入时间将使你成为一个更有价值的团队成员。</p><h2 id="--2">为团队合作腾出时间</h2><p>在你需要不断打磨自己的技术技能来提高自己的技术水平时，为你的团队合作技能的提升腾出空间。拥有一个技术精湛的团队成员而没有良好的团队合作，没有比这种情况更糟糕的了。</p><p>这不仅仅是为了创造一个积极的环境，由具备这四项素质的个人作为团队成员，组成完美的团队，将为你带来更好的技术成果和非凡的效率。</p><p>这对每个人都适用。</p><p>原文：<a href="https://www.freecodecamp.org/news/how-to-be-a-team-player-in-the-tech-world-c78aa9f4e898/">How to be a team player in the tech world</a>，作者：Ofer Vugman</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 通过一个开发实例掌握 Async/Await ]]>
                </title>
                <description>
                    <![CDATA[ 目录 1、介绍回调函数, promises, async/await 2、开发实例--货币转换器，从两个 API 异步获取数据 在开始正文之前 在写这篇文章的同时，我还录制了一个相关的视频，你可以边看视频边敲代码，我建议你先看下视频 [https://www.youtube.com/watch?v=mlb525FgU3k]，然后再以这篇文章为引导自己练习下代码。 简介 Async/Await 是一种建立在 promises 基础上的，书写异步代码的新方式，所以它也是非阻塞的。 与我们之前异步编程所使用到的回调函数和 promises 相比较，最大的区别就是 Async/Await 使我们的异步代码看起来就像同步代码一样，这也正是它的厉害之处。 使用回调函数 setTimeout(() => {  console.log('This runs after 1000 milliseconds.');}, 1000); 回调函数最典型的问题——回调地狱 在回调函数中嵌套回调函数，看起来就像这样： 回调地狱回调地狱 指的是回调函数被嵌套在另一个回调函数中，嵌套层级有多层，使我们 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-master-async-await-with-this-real-world-example/</link>
                <guid isPermaLink="false">5d5b819cfbfdee429dc5f82a</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 函数 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Promise ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Leo Zou ]]>
                </dc:creator>
                <pubDate>Wed, 10 Feb 2021 08:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/08/1_2Nco5zYP_Xv-5-FgL6kCuw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h3 id="-">目录</h3><p>1、介绍回调函数, promises, async/await</p><p>2、开发实例--货币转换器，从两个 API 异步获取数据</p><h3 id="--1">在开始正文之前</h3><p>在写这篇文章的同时，我还录制了一个相关的视频，你可以边看视频边敲代码，我建议你先看下<a href="https://www.youtube.com/watch?v=mlb525FgU3k">视频</a>，然后再以这篇文章为引导自己练习下代码。</p><h3 id="--2">简介</h3><p>Async/Await 是一种建立在 promises 基础上的，书写异步代码的新方式，所以它也是非阻塞的。</p><p>与我们之前异步编程所使用到的回调函数和 promises 相比较，最大的区别就是 Async/Await 使我们的异步代码看起来就像同步代码一样，这也正是它的厉害之处。</p><h3 id="--3">使用回调函数</h3><pre><code class="language-javascript">setTimeout(()&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;console.log('This&nbsp;runs&nbsp;after&nbsp;1000&nbsp;milliseconds.');},&nbsp;1000);</code></pre><h3 id="--4"><br>回调函数最典型的问题——回调地狱</h3><p>在回调函数中嵌套回调函数，看起来就像这样：</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/640.png" class="kg-image" alt="640" width="600" height="400" loading="lazy"><figcaption>回调地狱</figcaption></figure><h3 id="--5">回调地狱</h3><p>指的是回调函数被嵌套在另一个回调函数中，嵌套层级有多层，使我们的代码可读性和可维护性变得非常差。</p><h3 id="-promise">使用 Promise</h3><pre><code class="language-javascript">const&nbsp;promiseFunction&nbsp;=&nbsp;new&nbsp;Promise((resolve,&nbsp;reject)&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;const&nbsp;add&nbsp;=&nbsp;(a,&nbsp;b)&nbsp;=&gt;&nbsp;a&nbsp;+&nbsp;b;&nbsp;&nbsp;resolve(add(2,&nbsp;2));});promiseFunction.then((response)&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;console.log(response);}).catch((error)&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;console.log(error);});</code></pre><p>promiseFunction 这个函数返回一个表示函数运行过程的 Promise 对象， resolve 函数表示任务已经完成。</p><p>然后，我们就可以在 promiseFunction 函数的基础上调用 <code>then()</code> 和 <code>catch()</code> 方法。</p><p>then: Promise 成功后执行的回调函数。<br>catch: 当遇到了错误后执行的回调函数。</p><h3 id="async-">Async 函数</h3><p>Async 函数为我们提供了简洁的语法，我们可以通过它实现与 Promise 相同的效果，但是代码量会减少很多。其实底层原理上，async 不过是 promises 的语法糖而已。</p><p>在普通的函数声明前加上 async 关键字，我们就创建了一个 async 函数：</p><pre><code class="language-javascript">const&nbsp;asyncFunction&nbsp;=&nbsp;async&nbsp;()&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;//&nbsp;Code}</code></pre><p><br>异步函数使用 Await 表达式可以暂停函数的执行，Await 关键字只能在 Async 函数中使用，它会返回 Promise 对象的处理结果。</p><p>promises 和 Async/Await 的区别：</p><pre><code class="language-javascript">//&nbsp;Async/Awaitconst&nbsp;asyncGreeting&nbsp;=&nbsp;async&nbsp;()&nbsp;=&gt;&nbsp;'Greetings';//&nbsp;Promisesconst&nbsp;promiseGreeting&nbsp;=&nbsp;()&nbsp;=&gt;&nbsp;new&nbsp;Promise(((resolve)&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;resolve('Greetings');}));asyncGreeting().then(result&nbsp;=&gt;&nbsp;console.log(result));promiseGreeting().then(result&nbsp;=&gt;&nbsp;console.log(result));</code></pre><p>Async/Await 更易于我们理解，因为它看起来像同步代码。</p><p>前面我们已经介绍过这些基础知识了，现在我们来看看在现实开发中怎么使用！</p><h3 id="--6">货币转换器</h3><h3 id="--7">项目说明和初始化</h3><p>在下面的教程中，我们将创建一个简单实用，而且很有学习意义的应用程序，相信会加深你对 Async/Await 理解。</p><p>这个程序会接收到我们想要把什么货币转换成什么货币，以及货币金额，然后会调用相关的 API，显示正确的汇率。</p><p>在这个程序中，我们将从以下两个 API 异步获取数据：</p><ol><li>Currency Layer —— https://currencylayer.com - 你需要先免费注册账号，才能获取 API Access Key。这个 API 为我们提供了 计算货币间汇率所需的数据。</li><li>Rest Countries —— http://restcountries.eu/ - 这个 API 为我们提供了给定一种货币，返回该货币在哪些国家流通。</li></ol><p>首先，创建一个新目录并运行 <code>npm init</code> 初始化项目，接下里我们选择默认值，跳过所有步骤，然后再输入 <code>npm i——save axios</code> 安装 axios。在当前文件夹内创建一个 <code>currency-convert .js</code> 的文件。</p><p>在 <code>currency-convert .js</code> 文件中，我们先通过 <code>require</code> 语法引入 axios。</p><pre><code class="language-javascript">const&nbsp;axios&nbsp;=&nbsp;require(‘axios’);`</code></pre><h3 id="-async-await"><br>深入理解 Async/Await</h3><p>这个程序中，我们需要三个异步函数，第一个函数用来获取关于货币的数据；第二个函数用来获取关于国家的数据；第三个函数用来将所有信息集中起来并展示给用户看</p><h3 id="--8">第一个函数——异步获取有关货币的数据</h3><p>我们创建一个接收两个参数（fromCurrency 和 toCurrency）的异步函数：</p><pre><code class="language-javascript">const&nbsp;getExchangeRate&nbsp;=&nbsp;async&nbsp;(fromCurrency,&nbsp;toCurrency)&nbsp;=&gt;&nbsp;{}</code></pre><p>现在我们获取数据，然后通过使用 Async/Await，可以直接将我们想要的数据赋值给变量。调用接口之前别忘了要注册账号，才能获得 API access key。</p><pre><code class="language-javascript">const&nbsp;getExchangeRate&nbsp;=&nbsp;async&nbsp;(fromCurrency,&nbsp;toCurrency)&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;const&nbsp;response&nbsp;=&nbsp;await&nbsp;axios.get('http://data.fixer.io/api/latest?&nbsp;&nbsp;&nbsp;&nbsp;access_key=[yourAccessKey]&amp;format=1');}</code></pre><p>我们可以通过 <code>response.data.rates</code> 来提取我们想要的数据，然后我们将它赋值给一个变量 rate：</p><pre><code class="language-javascript">const&nbsp;rate&nbsp;=&nbsp;response.data.rates;</code></pre><p>因为所有的数据都是从欧元转换过来的，我们可以创建一个变量 <code>euro</code>，它的值等于：</p><pre><code class="language-javascript">const&nbsp;euro&nbsp;=&nbsp;1&nbsp;/&nbsp;rate[fromCurrency];</code></pre><p>最后，我们可以用欧元乘以我们要兑换的货币来得到汇率：</p><pre><code class="language-javascript">const&nbsp;exchangeRate&nbsp;=&nbsp;euro&nbsp;*&nbsp;rate[toCurrency];</code></pre><p>最终的函数看起来像这样：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/640-1.png" class="kg-image" alt="640-1" width="600" height="400" loading="lazy"></figure><h3 id="--9">第二个函数——异步获取国家数据</h3><p>创建一个异步函数，接收 currencyCode 作为参数：</p><pre><code class="language-javascript">const&nbsp;getCountries&nbsp;=&nbsp;async&nbsp;(currencyCode)&nbsp;=&gt;&nbsp;{}</code></pre><p>和之前一样，获取数据，然后将其赋值给一个变量：</p><pre><code class="language-javascript">const&nbsp;response&nbsp;=&nbsp;await&nbsp;axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);</code></pre><p>然后通过数组 map 方法将 <code>country.name</code> 提取出来，映射为一个新的数组：</p><pre><code class="language-javascript">return&nbsp;response.data.map(country&nbsp;=&gt;&nbsp;country.name);</code></pre><p>最终代码：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/640-2.png" class="kg-image" alt="640-2" width="600" height="400" loading="lazy"></figure><p>最后一个函数——将前面的函数组合起来</p><p>创建一个异步函数，接收 fromCurrency, toCurrency, amount 三个参数：</p><pre><code class="language-javascript">const&nbsp;convert&nbsp;=&nbsp;async&nbsp;(fromCurrency,&nbsp;toCurrency,&nbsp;amount)&nbsp;=&gt;&nbsp;{}</code></pre><p>第一步，获取货币数据：</p><pre><code class="language-javascript">const&nbsp;exchangeRate&nbsp;=&nbsp;await&nbsp;getExchangeRate(fromCurrency,&nbsp;toCurrency);</code></pre><p>第二步，获取国家数据：</p><pre><code class="language-javascript">const&nbsp;countries&nbsp;=&nbsp;await&nbsp;getCountries(toCurrency);</code></pre><p>第三步，将转换后的金额赋值给一个变量：</p><pre><code class="language-javascript">const&nbsp;convertedAmount&nbsp;=&nbsp;(amount&nbsp;*&nbsp;exchangeRate).toFixed(2);</code></pre><p>最后，将数据输出给用户</p><pre><code class="language-javascript">return&nbsp;`${amount}&nbsp;${fromCurrency}&nbsp;is&nbsp;worth&nbsp;${convertedAmount}&nbsp;${toCurrency}.&nbsp;You&nbsp;can&nbsp;spend&nbsp;these&nbsp;in&nbsp;the&nbsp;following&nbsp;countries:&nbsp;${countries}`;</code></pre><p>最后完整的代码：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/640-3.png" class="kg-image" alt="640-3" width="600" height="400" loading="lazy"></figure><h3 id="-try-catch-"><br>使用 try/catch 来处理错误</h3><p>我们将程序的逻辑用 try 语句包裹起来，如果出现错误，用 catch 语句捕捉：</p><pre><code class="language-javascript">const&nbsp;getExchangeRate&nbsp;=&nbsp;async&nbsp;(fromCurrency,&nbsp;toCurrency)&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;try&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;response&nbsp;=&nbsp;await&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;axios.get('http://data.fixer.io/api/latest?access_key=f68b13604ac8e570a00f7d8fe7f25e1b&amp;format=1');&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;rate&nbsp;=&nbsp;response.data.rates;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;euro&nbsp;=&nbsp;1&nbsp;/&nbsp;rate[fromCurrency];&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;exchangeRate&nbsp;=&nbsp;euro&nbsp;*&nbsp;rate[toCurrency];&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;exchangeRate;&nbsp;&nbsp;}&nbsp;catch&nbsp;(error)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(`Unable&nbsp;to&nbsp;get&nbsp;currency&nbsp;${fromCurrency}&nbsp;and&nbsp;&nbsp;${toCurrency}`);&nbsp;&nbsp;}};</code></pre><p>同样第二个函数也这样处理：</p><pre><code class="language-javascript">const&nbsp;getCountries&nbsp;=&nbsp;async&nbsp;(currencyCode)&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;try&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;response&nbsp;=&nbsp;await&nbsp;axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);return&nbsp;response.data.map(country&nbsp;=&gt;&nbsp;country.name);&nbsp;&nbsp;}&nbsp;catch&nbsp;(error)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(`Unable&nbsp;to&nbsp;get&nbsp;countries&nbsp;that&nbsp;use&nbsp;${currencyCode}`);&nbsp;&nbsp;}};</code></pre><p>因为第三个函数只是处理第一个和第二个函数的结果，所以我们不需要对它进行错误捕获。</p><p>最后，我们调用函数来接收数据：</p><pre><code class="language-javascript">convertCurrency('USD',&nbsp;'HRK',&nbsp;20)&nbsp;&nbsp;.then((message)&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;console.log(message);&nbsp;&nbsp;}).catch((error)&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;console.log(error.message);&nbsp;&nbsp;});</code></pre><p>你会看到下面的结果：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/640-4.png" class="kg-image" alt="640-4" width="600" height="400" loading="lazy"></figure><h3></h3><p>很不错，你坚持到了最后！如果在学习过程中遇到了困惑的地方，你可以参考这个<a href="https://github.com/adrianhajdin/tutorial_currency_converter">仓库</a>的代码。如果你有任何问题，可以在下面留言。</p><p>原文链接：<a href="https://medium.com/free-code-camp/how-to-master-async-await-with-this-real-world-example-19107e7558ad">How To Master Async/Await With This Real World Example</a>，作者：<a href="https://medium.com/@adrianhajdin00?source=post_page-----19107e7558ad--------------------------------" rel="noopener">Adrian Hajdin</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 我是如何自学编程找到第一份开发者工作的 ]]>
                </title>
                <description>
                    <![CDATA[ 对，你没看错标题！一家公司聘用了我，他们给我的职位是开发者，并且给我的待遇相当不错。 我感到既兴奋又震惊，坦白说还有点担心，不过还好啦。这事真的令人难以置信，不过我还是欣喜若狂地开始写代码了。 很多人建议我将自己的经历写成一篇文章分享出来，也许可以帮助别人。现在，就开始吧！ 开始 我一直都对计算机、技术等很感兴趣。和其他同龄人一样，刚开始学习的时候，我创建一个 GeoCities 网站，然后用一些基本的 CSS 样式来个性化修饰我的 MySpace 页面。 我当时并不知道，那就是开发，虽然很粗糙，但的确是在做开发。那时，我不知道这种工作还可以挣到钱，否则我可能会一直坚持下去。所以，我上了大学，并获得了一个与技术无关的学位 —— 心理学。这并不是一个完全无用的学位，只是在我之后的工作中我从来都没有用到过。 发现并追求内心最想做的 这样就到了 2016 年的夏天，那时候在工作之余我有很多空闲时间。其实我之前一直想自学编程，所以这对我来说是很好的时间点——别再拖了。于是我就利用网络上的很多免费资源，全身心地开始了我的编程之旅。 刚开始我在网上搜索学习资源，并发现了 CodeCad ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/landing-my-first-development-job-what-a-crazy-journey/</link>
                <guid isPermaLink="false">5db6bbd4ca1efa04e196a234</guid>
                
                <dc:creator>
                    <![CDATA[ Leo Zou ]]>
                </dc:creator>
                <pubDate>Mon, 17 Feb 2020 10:05:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/10/123-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>对，你没看错标题！一家公司聘用了我，他们给我的职位是开发者，并且给我的待遇相当不错。</p><p>我感到既兴奋又震惊，坦白说还有点担心，不过还好啦。这事真的令人难以置信，不过我还是欣喜若狂地开始写代码了。</p><p>很多人建议我将自己的经历写成一篇文章分享出来，也许可以帮助别人。现在，就开始吧！</p><h2 id="-">开始</h2><p>我一直都对计算机、技术等很感兴趣。和其他同龄人一样，刚开始学习的时候，我创建一个 GeoCities 网站，然后用一些基本的 CSS 样式来个性化修饰我的 MySpace 页面。</p><p>我当时并不知道，那就是开发，虽然很粗糙，但的确是在做开发。那时，我不知道这种工作还可以挣到钱，否则我可能会一直坚持下去。所以，我上了大学，并获得了一个与技术无关的学位 —— 心理学。这并不是一个完全无用的学位，只是在我之后的工作中我从来都没有用到过。</p><h2 id="--1">发现并追求内心最想做的</h2><p>这样就到了 2016 年的夏天，那时候在工作之余我有很多空闲时间。其实我之前一直想自学编程，所以这对我来说是很好的时间点——别再拖了。于是我就利用网络上的很多免费资源，全身心地开始了我的编程之旅。</p><p>刚开始我在网上搜索学习资源，并发现了 <a href="https://www.codecademy.com/" rel="nofollow">CodeCademy</a> 这个网站，我将上面的问题、解题思路还有结果全部手抄到笔记本上。我会将我认为重要的东西全部都用笔记下来，后面时不时地去复习。现在我再回过头来看这些东西，把我当时和现在觉得困难的内容对比一下，也挺有趣的。</p><p>一个朋友知道我在自学，就告诉了我 <a href="https://freecodecamp.org/" rel="nofollow">freeCodeCamp</a>，他说这个平台就是为像我这样的人设计的。我本来打算随便看看，上一两节课就够了，结果那天晚上我完成了 HTML 的整个学习章节，我完全被迷住了。</p><p>在学习的过程中我发现学得越多，问题就越多。总感觉有一种寻找这些问题答案的动力在推动着我。所以我继续学习接下来的课程和项目。在 freeCodeCamp 的课程更新之前（译者注：指的是 2016 年版课程更新至 2018 版课程），我在上面完成了两个项目。</p><p>平常我会抓住各种机会去学习或者做项目，比如排队时，我不会打开手机去浏览我的各种社交网络，而是看一些和 Web 开发相关的文章或者视频。</p><p>现在我对怎么合理安排休息时间有了很大的改变，不像以前一样把时间花费在一些“无脑消费”上（如果你喜欢社交媒体或看一些有趣的动物视频，我并不是说你是“无脑”，我只是说，这类行为通常不需要你的投入，你只需要打开手机，看着屏幕就可以了。其实，我也时不时这样）。</p><p>在这段时间里，我浏览了各种学习资源，一直在纠结哪种适合我，就像一个在糖果店里的孩子到处盯一盯。我曾经有一个文件夹，里面保存了大约300个链接，全是我计划要学习的东西。现在我知道了，找到适合自己的并坚持下去，远比选来选去，这看看、那看看要好得多。</p><p>我之前总是学习到很晚，妻子和女儿都睡着了。我经常熬夜到凌晨12点半，有时甚至是2点，然后不得不在早上6点起床去做我的日常工作。起初，当学习的东西很简单的时候，对我来说还可以适应。但是，当我开始学习 JavaScript，学习网络、服务器、无障碍等基础知识时，我发现越是熬夜我的大脑就越难以集中精力。</p><p>在坚持了几个月之后，我不得不开始改变我的学习计划。</p><p>当然，我并没有想停止我的学习和项目，只是将我的日程安排做了下调整。</p><p>每天早上，我4点起床，不再像以前一样熬夜。然后学习和做项目，再去健身房，一天就这样开始了。不得不说，在我的学习过程中，这是非常关键的，因为我记住了更多东西，做了更多项目，最终一步步在往前发展。</p><p>同时，在这期间我开始购买各种和 web 开发相关的学习资源(主要是 Udemy 的课程和书籍)。但这并不是一个明智的选择。如果你找到了一个你喜欢并适合你学习的资源，那么坚持下去，直到将它学完。不要像我这样从一个跳到另一个。</p><h2 id="-google-udacity-">成长 —— Google &amp; Udacity 奖学金</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chinese.freecodecamp.org/news/content/images/2021/10/--1.png" class="kg-image" alt="--1" width="704" height="704" loading="lazy"><figcaption>我收到的邮件中附带的图片</figcaption></figure><p>2018 年 1 月，我申请并获得了优达学城前端纳米学位项目的奖学金。这不仅是一个很棒的机会，驱使我朝着目标前进，同时也让我发现自己的不足之处。</p><p>刚参加这个项目，我只会 HTML、CSS 的基本知识，以及一小部分 JavaScript。在课程中，我知道了 <a href="https://jquery.com/" rel="nofollow">jQuery</a>、<a href="https://en.wikipedia.org/wiki/Functional_programming" rel="nofollow">函数式编程</a>、<a href="https://en.wikipedia.org/wiki/Object-oriented_programming" rel="nofollow">面向对象编程</a>（OOP）、<a href="https://en.wikipedia.org/wiki/Test-driven_development" rel="nofollow">测试驱动开发</a>（TDD）、<a href="https://en.wikipedia.org/wiki/Accessibility" rel="nofollow">无障碍</a>、服务器、API's、网络、<a href="https://reactjs.org/" rel="nofollow">React</a>、<a href="https://en.wikipedia.org/wiki/Ajax_%28programming%29" rel="nofollow">AJAX</a> 和其他我以前从未接触过的 web 开发技术。</p><p>老实说，学习的过程并不是总是轻松愉快，有时候我会很认真地想是不是该放弃。我觉得自己可能永远学不懂这些概念，我的脑子里一片迷茫。</p><p>我很庆幸自己没有半途而废，因为半途而废的人永远不会成功——这种老生常谈的话是第一次出现在这篇文章里，我保证后面不会有了。</p><p>在学习这些课程的时候，我开发了很多很棒的项目，比如<a href="https://github.com/JS-goose/card-matching-game">卡片匹配游戏</a>，<a href="https://github.com/JS-goose/frontend-nanodegree-arcade-game">街机游戏</a>，<a href="https://github.com/JS-goose/mws-restaurant-stage-1">餐厅点评 App</a>，<a href="https://github.com/JS-goose/neighborhood-map-react">邻里定位 App</a>。但除了这些项目，还认识了很多朋友，与其他开发者合作也是一份宝贵的经验。</p><p>可以这么说，没有这门课程，就不会有今天的我。在这9个月的课程中，我收获了很多宝贵的东西。</p><h2 id="--2">求职</h2><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2021/10/--2.jpeg" class="kg-image" alt="--2" width="1024" height="683" loading="lazy"></figure><p>在正式开始找工作之前，我已经努力学习了大约两年(有时也偷懒)。但还是觉得自己没有做好准备，一位后来成为我导师的朋友告诉我，你永远不会感觉到自己已经准备好。他说我应该去试一下，如果得到面试机会，就让面试官来告诉我，到底我有没有准备好，不要把任何一个机会挡在门外。</p><p>所以，带着极度的恐惧、焦虑和怀疑，我决定开始找工作。</p><p>起初，我只是投一些自己符合大多数条件的职位，但这并不是正确的做法。然而我又很害怕收到别人的面试电话。（后来我开始申请任何我感兴趣的工作。高级开发、前端 React 开发 、具有 SQL 经验的 API 开发，我全都申请过。这么做是因为你永远不知道你的申请会有什么结果。也许你没有得到某个高级职位的 offer，但他们可能喜欢你的个性，所以让你去面试他们的低级职位。）</p><p>在找工作投了三个月的简历之后。终于我接到了第一次面试的电话！我既高兴又害怕。压力非常大。</p><p>我阅读文章，学习面试技巧，阅读书籍，让我的妻子就问题对我进行测验，并尝想象各种我认为会在面试中出现的场景。我还为面试官准备了一些问题，因为我想知道在这家公司工作是什么样的。</p><p>结果最后我产生了这样的想法：这是一份完美的工作，是我从记事以来最想得到的东西，我必须得到它！</p><p>其实我不应该这么想的。</p><p>面试那天，已经不能用紧张来形容我自己了，我汗流浃背。在回答了所有的问题之后，我提问了我准备的问题。面试结束后，我感觉发挥得还可以。</p><p>最后，我没有得到这个职位，我很沮丧。我觉得一切都进行得很顺利，但不知什么原因，结果没有如我所愿。后来我又面试了很多工作，才知道面试失败是很正常的。</p><p>我决定不再让这些负面情绪来打击我的信心。所以我开始更加努力地工作、学习，化悲愤为动力。我会尽一切努力来保证某次面试能让我拿到 offer。</p><p>以下是我找工作的一些数据统计：</p><ul><li>通过申请平台提交求职申请：271次</li><li>提交之后，有公司以某种形式回应我：28次</li><li>电话面试：7次</li><li>面谈：8次</li><li>拿到 offer：3家公司（一家是可以签订全职合同，但可能性很小；一家是兼职形式；最终我得到了一份全职工作）</li><li>没有消息：<strong>多得数不过来</strong></li></ul><p>如果你正在找工作，不要让这些数字打击你！的确，这是很令人沮丧，让人想退缩。填了一份申请表，投了简历却从来没有得到任何回复，确实很糟糕，但请不要放弃！你一定会成功！就像我一样。</p><h2 id="--3">关于找工作 —— 我的建议</h2><p>关于找开发工作的建议或者技巧不胜枚举，我总结了自己找工作的一点经验，分享给大家：</p><ul><li>脸皮要厚，这是必须的，因为很多公司可能不会要你</li><li>申请任何你感兴趣的职位</li><li>即使某些职位你没有达到要求，一样申请（我的第一份开发者工作就是这么找到的）</li><li>花时间将简历做好一点</li><li>不要因为某些公司拒绝你而觉得自己是个失败者</li><li>向公司展示你可以不需要教程构建一个项目</li><li>当需要帮助时，就寻求帮助（对我来说很难）</li><li>去各种平台上申请工作，别忘了 <a href="https://jobs.github.com/">GitHub jobs</a> 也可以</li><li>保证充足的睡眠、锻炼，以及注意饮食健康（健康是根本）</li><li>时不时休息一下</li><li>不要和别人比较，你的工作。技术等等</li><li>不要在意花了多长时间，3个月或3年（像我一样），这不是一场比赛</li><li>努力学习，永不言弃</li></ul><p>最后，希望你一切顺利！如果你需要建议或帮助，可以在 <a href="https://twitter.com/jj_goose" rel="nofollow">Twitter</a> 或 <a href="https://www.linkedin.com/in/jj-goose/" rel="nofollow">LinkedIn</a> 上和我联系。我喜欢帮助别人，结识新朋友。</p><p>在我的个人<a href="https://jonathansexton.me/blog" rel="nofollow">博客</a>上，我也会写一些与 web 开发相关的文章。每个月我会更新一次，里面有我觉得不错的东西，你可以考虑订阅一下。</p><p>希望你有精彩的一天， happy coding!</p><p>原文：<a href="https://www.freecodecamp.org/news/landing-my-first-development-job-what-a-crazy-journey/">https://www.freecodecamp.org/news/landing-my-first-development-job-what-a-crazy-journey/</a>，作者：Jonathan Sexton</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 使用 React Hooks 创建可复用的动画组件 ]]>
                </title>
                <description>
                    <![CDATA[ 动画总是会取悦用户。看到各种文章的介绍，你可能会觉得开发者们喜欢使用 React Hooks ，但我发现自己开始慢慢对 Hooks 产生厌倦了。 某个意外的发现让我对 React Hooks 有了新的认识，它不仅仅是一种新的开发方式。也许你已经从文章标题猜到是什么了，没错，就是动画！ 我正在开发一个基于 React 的，使用网格布局组合卡片组件的应用，当删除某个卡片组件时，为它添加动画效果，看起来像下面一样： 但是，和图中效果相比较始终还是有点细微差别。在我的接下来的解决方案中，很好地利用了 React Hooks。 我们将要做什么？  * 开始构建一个基本的项目骨架  * 为元素的消失添加动画效果，解决一些小问题  * 最终效果实现后，将其重构为一个可复用的动画组件  * 在顶部导航和侧边导航中使用该动画组件 如果你没耐心，这里有整个项目的仓库地址 [https://github.com/csepulv/animated-visibility] ，每一步都有相应的标记（链接地址和描述参考 README 文件）。 骨架 我使用 create-react-app [https ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/animating-visibility-with-css-an-example-of-react-hooks/</link>
                <guid isPermaLink="false">5dbaefd7ca1efa04e196a2b1</guid>
                
                    <category>
                        <![CDATA[ React Hooks ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Leo Zou ]]>
                </dc:creator>
                <pubDate>Thu, 31 Oct 2019 14:31:50 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/photo-1572366798564-d40537fbe594.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>动画总是会取悦用户。看到各种文章的介绍，你可能会觉得开发者们喜欢使用 React Hooks ，但我发现自己开始慢慢对 Hooks 产生厌倦了。</p><p>某个意外的发现让我对 React Hooks 有了新的认识，它不仅仅是一种新的开发方式。也许你已经从文章标题猜到是什么了，没错，就是动画！</p><p>我正在开发一个基于 React 的，使用网格布局组合卡片组件的应用，当删除某个卡片组件时，为它添加动画效果，看起来像下面一样：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/11/2.gif" class="kg-image" alt="2" width="600" height="654" loading="lazy"></figure><p>但是，和图中效果相比较始终还是有点细微差别。在我的接下来的解决方案中，很好地利用了 React Hooks。</p><h2 id="-">我们将要做什么？</h2><ul><li>开始构建一个基本的项目骨架</li><li>为元素的消失添加动画效果，解决一些小问题</li><li>最终效果实现后，将其重构为一个可复用的动画组件</li><li>在顶部导航和侧边导航中使用该动画组件</li></ul><p>如果你没耐心，这里有整个项目的仓库<a href="https://github.com/csepulv/animated-visibility">地址</a>，每一步都有相应的标记（链接地址和描述参考 README 文件）。</p><h2 id="--1">骨架</h2><p>我使用 <a href="https://facebook.github.io/create-react-app/">create-react-app</a> 创建了一个简单的应用程序，它是一个简单的卡片网格结构，每个单独卡片可以被隐藏。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/11/3.gif" class="kg-image" alt="3" width="600" height="784" loading="lazy"></figure><p>实现代码很简单，效果也很无趣。当用户点击眼睛图标时，我们改变卡片的 <code>display</code> 属性。</p><pre><code>function Box({ word }) {
  const color = colors[Math.floor(Math.random() * 9)];
  const [visible, setVisible] = useState(true);
  function hideMe() {
    setVisible(false);
  }
  let style = { borderColor: color, backgroundColor: color };
  if (!visible) style.display = "none";
  return (
    &lt;div className="box" style={style}&gt;
      {" "}
      &lt;div className="center"&gt;{word}&lt;/div&gt;{" "}
      &lt;button className="button bottom-corner" onClick={hideMe}&gt;
        {" "}
        &lt;i className="center far fa-eye fa-lg" /&gt;{" "}
      &lt;/button&gt;{" "}
    &lt;/div&gt;
  );
}
</code></pre><p>（上面的代码中使用到了 React Hooks，但这不是 Hooks 最有趣的用途）</p><h2 id="--2">添加动画</h2><p>我没有构建自己的动画库，而是使用了一个像 <a href="https://daneden.github.io/animate.css/">animate.css</a> 这样的动画库。<a href="https://github.com/digital-flowers/react-animated-css">react-animated-css</a> 是一个很好的库，它为 animate.css 提供了一个包装器。</p><p>安装 react-animated-css</p><pre><code class="language-shell">npm install --save react-animated-css
</code></pre><p>在 <code>index.html</code> 中添加 animate.css</p><pre><code class="language-html">&lt;link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.css" /&gt;
</code></pre><p>在上面的 <code>Box</code> 组件中，将渲染结果改为</p><pre><code>return (
  &lt;Animated animationIn="zoomIn" animationOut="zoomOut" isVisible={visible}&gt;
    &lt;div className="box" style={style}&gt;
      &lt;div className="center"&gt;{word}&lt;/div&gt;
      &lt;button className="button bottom-corner" onClick={hideMe}&gt;
        &lt;i className="center far fa-eye fa-lg" /&gt;
      &lt;/button&gt;
    &lt;/div&gt;
  &lt;/Animated&gt;
);
</code></pre><h2 id="--3">不完全是我们想要的东西</h2><p>animate.css 会为 <code>opacity</code> 和其他 css 属性添加动画；但不能在 <code>display</code> 属性上添加 css 过渡效果，所以将卡片隐藏后，它始终在文档流中占据着位置。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/11/4.gif" class="kg-image" alt="4" width="600" height="766" loading="lazy"></figure><p>如果你搜索一下，<a href="https://stackoverflow.com/questions/13037637/css-animation-and-display-none">有些解决方案</a>是建议使用定时器在动画结束时设置 <code>display: none</code>。</p><p>所以我们可以添加以下代码。</p><pre><code>function Box({ word }) {
  const color = colors[Math.floor(Math.random() * 9)];
  const [visible, setVisible] = useState(true);
  const [fading, setFading] = useState(false);

  function hideMe() {
    setFading(true);
    setTimeout(() =&gt; setVisible(false), 650);
  }

  let style = { borderColor: color, backgroundColor: color };

  return (
    &lt;Animated
      animationIn="zoomIn"
      animationOut="zoomOut"
      isVisible={!fading}
      style={visible ? null : { display: "none" }}
    &gt;
      &lt;div className="box" style={style}&gt;
        &lt;div className="center"&gt;{word}&lt;/div&gt;
        &lt;button className="button bottom-corner" onClick={hideMe}&gt;
          &lt;i className="center far fa-eye fa-lg" /&gt;
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/Animated&gt;
  );
}
</code></pre><p>(注意：默认的动画时长是 1000ms，我使用的是 650ms，为了在设置 <code>display</code> 属性之前减少卡顿/暂停现象，这只是个人喜好)。</p><p>这样我们就能得到想要的效果。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/11/5.gif" class="kg-image" alt="5" width="600" height="735" loading="lazy"></figure><h2 id="--4">构建一个可复用的组件</h2><p>现在到此为止，但目前有两个问题（对于我来说）</p><ul><li>我不想复制/粘贴 <code>Animated</code> 代码块，样式，功能，来重复实现相同效果。</li><li><code>Box</code> 组件混合了不同类型的逻辑，例如：违反了关注点分离的概念。准确的说，<code>Box</code> 的主要功能是渲染卡片内容，但是动画细节混入了。</li></ul><h2 id="--5">类组件</h2><p>我们可以创建一个传统的 React 类组件来管理和动画相关的状态：切换隐藏/显示，设置 <code>display</code> 属性的超时时间。</p><pre><code>class AnimatedVisibility extends Component {
  constructor(props) {
    super(props);
    this.state = { noDisplay: false, visible: this.props.visible };
  }

  componentWillReceiveProps(nextProps, nextContext) {
    if (!nextProps.visible) {
      this.setState({ visible: false });
      setTimeout(() =&gt; this.setState({ noDisplay: true }), 650);
    }
  }

  render() {
    return (
      &lt;Animated
        animationIn="zoomIn"
        animationOut="zoomOut"
        isVisible={this.state.visible}
        style={this.state.noDisplay ? { display: "none" } : null}
      &gt;
        {this.props.children}
      &lt;/Animated&gt;
    );
  }
}
</code></pre><p>然后使用它</p><pre><code>function Box({ word }) {
  const color = colors[Math.floor(Math.random() * 9)];
  const [visible, setVisible] = useState(true);

  function hideMe() {
    setVisible(false);
  }

  let style = { borderColor: color, backgroundColor: color };

  return (
    &lt;AnimatedVisibility visible={visible}&gt;
      &lt;div className="box" style={style}&gt;
        &lt;div className="center"&gt;{word}&lt;/div&gt;
        &lt;button className="button bottom-corner" onClick={hideMe}&gt;
          &lt;i className="center far fa-eye fa-lg" /&gt;
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/AnimatedVisibility&gt;
  );
}
</code></pre><p>这就实现了一个可复用的组件，但是还有点复杂，我们还可以优化一下。</p><h2 id="react-hooks-and-useeffect">React Hooks and useEffect</h2><p><a href="https://reactjs.org/docs/hooks-intro.html">React Hooks</a> 是 React 16.8 中的新特性，它们为 React 组件的生命周期和状态管理提供了一种更简单的方法</p><p><a href="https://reactjs.org/docs/hooks-effect.html">useEffect</a> 钩子为 <code>componentWillReceiveProps</code> 的使用提供了一种优雅的替代方案,它的代码更简洁，我们还可以使用函数式组件。</p><pre><code>function AnimatedVisibility({ visible, children }) {
  const [noDisplay, setNoDisplay] = useState(!visible);
  useEffect(() =&gt; {
    if (!visible) setTimeout(() =&gt; setNoDisplay(true), 650);
    else setNoDisplay(false);
  }, [visible]);

  const style = noDisplay ? { display: "none" } : null;
  return (
    &lt;Animated
      animationIn="zoomIn"
      animationOut="zoomOut"
      isVisible={visible}
      style={style}
    &gt;
      {children}
    &lt;/Animated&gt;
  );
}
</code></pre><p><code>useEffect</code> 钩子还是有点不一样，它的主要目的是副作用：改变状态，调用异步函数等等。在我们的例子中，它根据之前的 <code>visible</code> 的值修改了内部的 <code>noDisplay</code> 布尔值。</p><p>将 <code>visible</code> 作为依赖添加到 <code>useEffect</code> 的依赖数组中，当 <code>visible</code> 的值发生变化时， <code>useEffect</code> 钩子才会被调用。</p><p>和类组件的杂乱相比较，我认为 <code>useEffect</code> 是一种更好的解决方案。</p><h2 id="-sidebars-navbars">组件复用：Sidebars 和 Navbars</h2><p>大家都喜欢 Sidebar 和 Navbar，我们来添加一个吧。</p><pre><code>function ToggleButton({ label, isOpen, onClick }) {
  const icon = isOpen ? (
    &lt;i className="fas fa-toggle-off fa-lg" /&gt;
  ) : (
    &lt;i className="fas fa-toggle-on fa-lg" /&gt;
  );
  return (
    &lt;button className="toggle" onClick={onClick}&gt;
      {label} {icon}
    &lt;/button&gt;
  );
}

function Navbar({ open }) {
  return (
    &lt;AnimatedVisibility
      visible={open}
      animationIn="slideInDown"
      animationOut="slideOutUp"
      animationInDuration={300}
      animationOutDuration={600}
    &gt;
      &lt;nav className="bar nav"&gt;
        &lt;li&gt;Item 1&lt;/li&gt;
        &lt;li&gt;Item 2&lt;/li&gt;
        &lt;li&gt;Item 3&lt;/li&gt;
      &lt;/nav&gt;
    &lt;/AnimatedVisibility&gt;
  );
}

function Sidebar({ open }) {
  return (
    &lt;AnimatedVisibility
      visible={open}
      animationIn="slideInLeft"
      animationOut="slideOutLeft"
      animationInDuration={500}
      animationOutDuration={600}
      className="on-top"
    &gt;
      &lt;div className="sidebar"&gt;
        &lt;ul&gt;
          &lt;li&gt;Item 1&lt;/li&gt;
          &lt;li&gt;Item 2&lt;/li&gt;
          &lt;li&gt;Item 3&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/AnimatedVisibility&gt;
  );
}

function App() {
  const [navIsOpen, setNavOpen] = useState(false);
  const [sidebarIsOpen, setSidebarOpen] = useState(false);

  function toggleNav() {
    setNavOpen(!navIsOpen);
  }

  function toggleSidebar() {
    setSidebarOpen(!sidebarIsOpen);
  }

  return (
    &lt;Fragment&gt;
      &lt;main className="main"&gt;
        &lt;header className="bar header"&gt;
          &lt;ToggleButton
            label="Sidebar"
            isOpen={sidebarIsOpen}
            onClick={toggleSidebar}
          /&gt;
          &lt;ToggleButton label="Navbar" isOpen={navIsOpen} onClick={toggleNav} /&gt;
        &lt;/header&gt;
        &lt;Navbar open={navIsOpen} /&gt;
        &lt;Boxes /&gt;
      &lt;/main&gt;
      &lt;Sidebar open={sidebarIsOpen} /&gt;
    &lt;/Fragment&gt;
  );
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/11/6.gif" class="kg-image" alt="6" width="600" height="545" loading="lazy"></figure><h2 id="--6">还没结束...</h2><p>到这里我们就可以停下了，但就像我之前提到的关注点分离，我更倾向于避免在 <code>Box</code>、<code>Sidebar</code> 和 <code>Navbar</code> 的 render 方法中混合 <code>AnimatedVisibility</code> 组件（代码有点重复）。</p><p>我们可以创建一个高阶组件（HOC）。由于状态管理的原因， HOCs 通常会涉及到类组件。</p><p>但是使用了 React Hooks，我们只需要组合 HOC 就可以了（函数式编程概念）。</p><pre><code class="language-js">function AnimatedVisibility({
  visible,
  children,
  animationOutDuration,
  disappearOffset,
  ...rest
})
// ... same as before
}


function makeAnimated(
  Component,
  animationIn,
  animationOut,
  animationInDuration,
  animationOutDuration,
  disappearOffset
) {
  return function({ open, className, ...props }) {
    return (
      &lt;AnimatedVisibility
        visible={open}
        animationIn={animationIn}
        animationOut={animationOut}
        animationInDuration={animationInDuration}
        animationOutDuration={animationOutDuration}
        disappearOffset={disappearOffset}
        className={className}
      &gt;
        &lt;Component {...props} /&gt;
      &lt;/AnimatedVisibility&gt;
    );
  };
}

export function makeAnimationSlideLeft(Component) {
  return makeAnimated(Component, "slideInLeft", "slideOutLeft", 400, 500, 200);
}

export function makeAnimationSlideUpDown(Component) {
  return makeAnimated(Component, "slideInDown", "slideOutUp", 400, 500, 200);
}

export default AnimatedVisibility
</code></pre><p>然后在 App.js 中使用这些基于函数式的 HOCs</p><pre><code>function Navbar() {
  return (
    &lt;nav className="bar nav"&gt;
      &lt;li&gt;Item 1&lt;/li&gt;
      &lt;li&gt;Item 2&lt;/li&gt;
      &lt;li&gt;Item 3&lt;/li&gt;
    &lt;/nav&gt;
  );
}

function Sidebar() {
  return (
    &lt;div className="sidebar"&gt;
      &lt;ul&gt;
        &lt;li&gt;Item 1&lt;/li&gt;
        &lt;li&gt;Item 2&lt;/li&gt;
        &lt;li&gt;Item 3&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}

const AnimatedSidebar = makeAnimationSlideLeft(Sidebar);
const AnimatedNavbar = makeAnimationSlideUpDown(Navbar);

function App() {
  const [navIsOpen, setNavOpen] = useState(false);
  const [sidebarIsOpen, setSidebarOpen] = useState(false);

  function toggleNav() {
    setNavOpen(!navIsOpen);
  }

  function toggleSidebar() {
    setSidebarOpen(!sidebarIsOpen);
  }

  return (
    &lt;Fragment&gt;
      &lt;main className="main"&gt;
        &lt;header className="bar header"&gt;
          &lt;ToggleButton
            label="Sidebar"
            isOpen={sidebarIsOpen}
            onClick={toggleSidebar}
          /&gt;
          &lt;ToggleButton label="Navbar" isOpen={navIsOpen} onClick={toggleNav} /&gt;
        &lt;/header&gt;
          &lt;AnimatedNavbar open={navIsOpen} /&gt;
        &lt;Boxes /&gt;
      &lt;/main&gt;
      &lt;AnimatedSidebar open={sidebarIsOpen} className="on-top"/&gt;
    &lt;/Fragment&gt;
  );
}
</code></pre><h2 id="--7">接下来呢？</h2><p>对于简单的动画，可以使用我所提到的方法。如果比较复杂，我会使用像 <a href="https://github.com/chenglou/react-motion">react-motion</a> 这样的库。</p><p>不仅仅是动画，React Hooks 让我们可以编写可读性高、更简洁的代码。但是，我们需要在思维上有个调整，像 &nbsp;useEffect 这样的 Hooks 不完全是 React 生命周期函数的替代品，你需要深入学习和研究。</p><p>我建议看看像 <a href="https://usehooks.com/">useHooks.com</a> 这样的网站，还有像 <a href="https://github.com/streamich/react-use">react-use</a> 这样的库（不同钩子用例的集合）。</p><p>原文：<a href="https://www.freecodecamp.org/news/animating-visibility-with-css-an-example-of-react-hooks/">https://www.freecodecamp.org/news/animating-visibility-with-css-an-example-of-react-hooks/</a>，作者：Christian Sepulveda</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 在 Node 和 Express 中使用 ES6 （及以上）语法 ]]>
                </title>
                <description>
                    <![CDATA[ 也许你已经在前端开发中使用过 ES6 语法了，但是当你转向后端开发，开始使用 Node.js 和 Express 时，有没有发现它们不能完全支持 ES6（以及上） 语法新特性？如果你遇到这种情况，那应该好好读一下这篇文章。我会一步步介绍怎么配置开发和生产环境以及配置脚本，还会介绍一个小技巧，关于怎么监视 node.js 应用程序中的文件变动并自动重启服务。 目录内容  * 准备工作  * 安装 Express  * 脚本配置  * 小技巧  * TL;DR 准备工作 在开始之前，我们需要做些准备工作。  1. 确保你安装了 Node.js 和 npm。可以通过 Node.js Source [https://nodejs.org/en/download/]      或者 NVM (Node Version Manager) [https://github.com/creationix/nvm] ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-enable-es6-and-beyond-syntax-with-node-and-express/</link>
                <guid isPermaLink="false">5d8d588efbfdee429dc5feb9</guid>
                
                <dc:creator>
                    <![CDATA[ Leo Zou ]]>
                </dc:creator>
                <pubDate>Fri, 27 Sep 2019 00:36:18 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/09/1_VAo90seDRpFYq7utRkPEJg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>也许你已经在前端开发中使用过 ES6 语法了，但是当你转向后端开发，开始使用 Node.js 和 Express 时，有没有发现它们不能完全支持 ES6（以及上） 语法新特性？如果你遇到这种情况，那应该好好读一下这篇文章。我会一步步介绍怎么配置开发和生产环境以及配置脚本，还会介绍一个小技巧，关于怎么监视 node.js 应用程序中的文件变动并自动重启服务。</p><h3 id="-">目录内容</h3><ul><li>准备工作</li><li>安装 Express</li><li>脚本配置</li><li>小技巧</li><li>TL;DR</li></ul><h3 id="--1">准备工作</h3><p>在开始之前，我们需要做些准备工作。</p><ol><li>确保你安装了 Node.js 和 npm。可以通过 <a href="https://nodejs.org/en/download/" rel="nofollow noopener">Node.js Source</a> 或者 <a href="https://github.com/creationix/nvm" rel="nofollow noopener">NVM (Node Version Manager)</a> 来安装，我推荐安装最新版或者目前稳定版。</li><li>接下来，我们需要安装 Express Generator cli，它可以快速帮我们生成 Express 应用骨架，在命令行工具中输入：</li></ol><p><code>npm i -g express-generator</code></p><ol><li>对终端命令有基本了解。我会在这篇教程中介绍大部分命令，所以你即使不会也不用太担心，跟着教程学就行了。</li><li>安装好编辑器，打开命令行终端</li></ol><p>好啦，准备工作就是这些。</p><h3 id="-express">安装 Express</h3><p>我们使用 Express generator 来创建一个新项目，它会自动帮我们生成一些代码，移动一些文件，并将其中一些语法转换为 ES6 语法。在这个阶段我们就可以验证 ES6 语法是否能正常使用。</p><h4 id="--2">项目设置</h4><p>在命令行工具中输入下面的命令，你可以自定义你喜欢的项目名 <code>your-project-name</code> ， <code>--no-view</code> 指定我们不需要在项目骨架中使用模板引擎，例如 handlebars，ejs，pug 等。</p><p><code>express your-project-name --no-view</code></p><p>创建项目后，我们进入项目根目录。如果你使用的是 Windows Powershell 和 Linux 终端，输入下面的命令：</p><p><code>cd your-project-name</code></p><p>接下来打开代码编辑器，我使用的是 VSCode，你可以使用任何你喜欢的编辑器</p><h4 id="--3">安装包，移动和删除部分文件</h4><p>使用下面的命令为我们的项目安装依赖，并将其中某些文件夹移动位置</p><p><code>npm install</code></p><p>在等待安装的过程中，你可以做如下几步操作：</p><ul><li>创建 <code>src/</code> 目录</li><li>将 <code>bin/</code> ， <code>app.js</code> 和 <code>routes/</code> 移动到 <code>src</code> 目录</li><li>将 <code>bin</code> 目录中的 <code>www</code> 文件重命名为 <code>www.js</code></li><li>将 <code>public/</code> 移动到项目根目录</li><li>删除 <code>routes/users.js</code> ，我们暂时不需要</li></ul><p>整个项目结构如下：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-61.png" class="kg-image" alt="image-61" width="800" height="515" loading="lazy"></figure><p>因为修改了文件结构，我们的服务器启动脚本现在就失效了，待会儿我们再解决这个问题。</p><h4 id="es6-">ES6 语法转换</h4><p>将 Express 应用生成器生成的代码转换为 ES6 语法的过程有点枯燥，所以我直接将代码贴在下面，你可以复制粘贴。</p><ul><li><code>bin/www.js</code> 文件：</li></ul><pre><code>// bin/www.js
</code></pre><pre><code>/** * Module dependencies. */
</code></pre><pre><code>import app from '../app'; import debugLib from 'debug'; import http from 'http';

const debug = debugLib('your-project-name:server');
</code></pre><pre><code>// generated code below.
</code></pre><p>我们几乎只需要修改文件开头和末尾的代码，不需要改动其他部分。</p><ul><li><code>routes/index.js</code> 文件：</li></ul><pre><code>// routes/index.js
</code></pre><pre><code>
import express from 'express'; var router = express.Router();

/* GET home page. */ router.get('/', function(req, res, next) { res.render('index', { title: 'Express' }); });

export default router;
</code></pre><ul><li><code>app.js</code> 文件：</li></ul><pre><code>// app.js
</code></pre><pre><code>import express from 'express'; import path from 'path'; import cookieParser from 'cookie-parser'; import logger from 'morgan';

import indexRouter from './routes/index';

const app = express();

app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, '../public')));

app.use('/', indexRouter);

export default app;
</code></pre><p>因为 <code>public/</code> 被移动到了项目根目录，所以我们需要在 <code>app.js</code> 中修改 Express 静态资源路径，注意，在这里我们将 <code>'public'</code> 改为 <code>'../public'</code> 。</p><p><code>app.use(express.static(path.join(__dirname, '../public')));</code></p><p>其次，我们删除了 <code>routes/users.js</code> 文件，所以还需要在 <code>app.js</code> 中移除以下代码</p><pre><code>// remove these lines
</code></pre><p><code>var usersRouter = require('./routes/users'); app.use('/users', usersRouter);</code></p><p>现在代码语法转换已经完成了，我们接下来开始配置脚本。</p><h3 id="--4">脚本配置</h3><p>在这个阶段，我们会一步步来配置，开发环境的生产环境的配置有点区别。我们会组合部门脚本方便重用。</p><h4 id="-npm-run-all">安装 <code>npm-run-all</code></h4><p>由于某些终端命令不能在 Windows cmd 上运行，我们需要安装 <code>npm-run-all</code> 包，这样我们的脚本就可以在任何环境下运行。 在终端中输入以下命令：</p><p><code>npm install --save npm-run-all</code></p><h4 id="-babel-">安装 babel 和其他包</h4><p>Babel 是一个 Javascript 编译器，主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法，以便能够运行在当前和旧版本的浏览器或其他环境中，比如 Node.js。在项目根目录打开终端命令行，输入下面命令，我们会安装最新版的 babel（Babel 7）。</p><p><code>npm install -D @babel/core @babel/cli @babel/preset-env @babel/node</code></p><p>也许你已经注意到了，在上面的那些命令中，我有时候使用 -D，有时使用 --save，这两种标志是在告诉 npm 我们的包是是作为 <code>devDependency</code> 还是 <code>dependency</code> ，即开发依赖和生产依赖。当安装完成后，我们就可以添加 dev 脚本了。</p><h4 id="-dev-">添加 dev 脚本</h4><p>我前面说过， <code>package.json</code> 中的脚本命令现在无法运行，因为我们修改了部分文件。其实现在它也运行不了，因为我们使用了 ES6 import 语法。这时候我们需要利用之前安装的包，babel 配置文件，和 <code>babel-node</code> 来让 node server 运行起来。</p><p>在项目根目录创建 <code>.babelrc</code> 文件，写入以下代码：</p><pre><code>{ "presets": ["@babel/preset-env"] }
</code></pre><p>因为我们使用 Babel 来转换不同类型的 js 语法，所以需要在 <code>.babelrc</code> 中配置 <code>preset-env</code> 预设（之前安装的），它会告诉 Babel 去转换哪种类型。</p><p>在这些都设置好后，我们就可以测试 node server能否在 ES6 语法环境下运行，首先，在 <code>package.json</code> 中添加 dev 脚本：</p><p><code>"scripts": { "start": "node ./bin/www", "server": "babel-node ./src/bin/www", "dev": "NODE_ENV=development npm-run-all server" }</code></p><p>在上面的代码中我们添加了 server 和 dev 两个脚本，使用代码分隔将他们组合起来，再通过 <code>npm-run-all</code> 来运行所有命令。</p><p>现在输入以下命令来测试服务器能否正常启动：</p><p><code>npm run dev</code></p><p>可以正常工作！</p><p>目前， <code>start</code> 脚本命令还不能运行，我们会在后面添加 <code>prod</code> 脚本时来修复。</p><h4 id="-prod-">添加 prod 脚本</h4><p>prod 脚本 和 dev 脚本有点区别，我们需要将 <code>src</code> 目录中的所有 js 文件代码转换为 nodejs 能够识别的语法形式。运行 prod 脚本会生成一个和 <code>src/</code> 目录结构类似的 <code>dist/</code> 文件夹，但是每次在运行该脚本之前，我们需要将旧的 <code>dist/</code> 文件夹删除，确保我们运行的是最新生成的代码。下面是具体步骤：</p><ul><li>创建 build 脚本，它会转换 <code>src/</code> 中的文件代码并生成新的 <code>dist/</code> 文件夹。</li><li>安装 rimraf 包，并新建 clean 脚本，用来删除 <code>dist/</code> 文件夹。</li><li>新建 prod 脚本，将 clean，build，start server 脚本组合起来。</li></ul><h4 id="clean-">Clean 脚本</h4><p>在创建 build 脚本之前，我们先要安装 rimraf 包，用来删除某个文件夹</p><p><code>npm install rimraf --save</code></p><p>安装好后，在 <code>package.json</code> 的 scripts 字段中加入 clean 脚本，我们会在 build 脚本中使用到它，现在整个 scripts 字段结构如下：</p><p><code>"scripts": { "start": "node ./bin/www", "server": "babel-node ./src/bin/www", "dev": "NODE_ENV=development npm-run-all server", "clean": "rimraf dist" },</code></p><h4 id="build-">Build 脚本</h4><p>现在我们来添加 build 脚本，会用到 babel-cli（之前安装过的），如下：</p><p><code>"scripts": { "start": "node ./bin/www", "server": "babel-node ./src/bin/www", "dev": "NODE_ENV=development npm-run-all server", "clean": "rimraf dist", "build": "babel ./src --out-dir dist" },</code></p><h4 id="prod-">Prod 脚本</h4><p>prod 脚本组合了 build，clean，和 start 脚本，现在我们来修改下 start 脚本：</p><p><code>"scripts": { "start": "npm run prod", "server": "babel-node ./src/bin/www", "server:prod": "node ./dist/bin/www", "dev": "NODE_ENV=development npm-run-all server", "clean": "rimraf dist", "build": "babel ./src --out-dir dist", "prod": "NODE_ENV=production npm-run-all clean build server:prod" },</code></p><p>注意我们在 scripts 字段中还添加了一个 server:prod 脚本，它的作用是在生成的 <code>dist/</code> 文件夹中运行 node server。我们还将 start 脚本指向了 prod 脚本，因为托管平台(如 Heroku 或 AWS)一般都是使用 npm start 命令来启动服务。</p><p>到目前为止，我们的所有配置完成了，现在就可以在 Node 中使用最新的 js 语法。</p><h3 id="--5">小技巧：监视文件变化并自动重启服务</h3><p>使用 nodemon 我们可以在 nodejs 上自动重启服务。同样先安装 nodemon 包，并新建配置文件 <code>nodemon.json</code> ，在项目根目录下的终端中运行此命令：</p><p><code>npm i -D nodemon</code></p><p><code>nodemon.json</code> 配置文件：</p><pre><code>
{ "exec": "npm run dev", "watch": ["src/*", "public/*"], "ext": "js, html, css, json" }
</code></pre><p>现在，只要 <code>src/</code> 和 <code>public/</code> 文件夹中的文件有变化，服务器就会自动重启。</p><p>我们将其添加到 <code>package.json</code> 的 scripts 字段中：</p><pre><code>
"scripts": { "start": "npm run prod", "server": "babel-node ./src/bin/www", "server:prod": "node ./dist/bin/www", "dev": "NODE_ENV=development npm-run-all server", "clean": "rimraf dist", "build": "babel ./src --out-dir dist", "prod": "NODE_ENV=production npm-run-all clean build server:prod", "watch": "nodemon" },
</code></pre><p>运行 watch 脚本：</p><p><code>npm run watch</code></p><h3 id="tl-dr">TL;DR</h3><p>我将整个教程简化为以下几个步骤，并附上仓库地址，你可以参考学习：</p><ul><li>在命令行终端中使用 <code>express your-project-name</code> 新建项目。</li><li>新建 <code>src/</code> 目录，将 <code>bin/</code> ， <code>routes/</code> 和 <code>app</code> 移动到该目录；将部分代码转换为 ES6 语法；重命名 <code>bin/www</code> 为 <code>www.js</code> 。</li><li>安装开发依赖和生产依赖</li></ul><pre><code>npm i -D @babel/cli @babel/core @babel/node @babel/preset-env nodemon

npm i --save rimraf npm-run-all
</code></pre><ul><li>package.json 中添加脚本</li></ul><p>“scripts”: { “start”: “npm run prod”, “server”: “babel-node ./src/bin/www”, “server:prod”: “node ./dist/bin/www”, “dev”: “NODE_ENV=development npm-run-all server”, “clean”: “rimraf dist”, “build”: “babel ./src --out-dir dist”, “prod”: “NODE_ENV=production npm-run-all clean build server:prod”, “watch”: “nodemon” },</p><ul><li>新建 <code>nodemon.json</code> 和 <code>.babelrc</code> ，并配置</li></ul><pre><code>
// nodemon.json { "exec": "npm run dev", "watch": ["src/*", "public/*"], "ext": "js, html, css, json" }

// .babelrc { "presets": ["@babel/preset-env"] }
</code></pre><ul><li>运行 <code>npm run dev</code> ， <code>npm run prod</code> ， <code>npm run watch</code> 测试脚本</li><li>完整的<a href="https://github.com/jcunanan05/express-es6-sample/tree/for-article" rel="nofollow noopener">仓库代码</a></li></ul><p>希望你在本教程中能学到东西，感谢你的阅读!</p><p>Happy coding!</p><p>原文链接：<a href="https://www.freecodecamp.org/news/how-to-enable-es6-and-beyond-syntax-with-node-and-express-68d3e11fe1ab/">https://www.freecodecamp.org/news/how-to-enable-es6-and-beyond-syntax-with-node-and-express-68d3e11fe1ab/</a>，作者：Jonathan Cunanan</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
