<?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[ 余博伦 - 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[ 余博伦 - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 10 May 2026 19:19:12 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/author/yu/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 2024 年你的第一门编程语言应该学什么？[已解决] ]]>
                </title>
                <description>
                    <![CDATA[ 大多数人的编程之旅都是从搜索引擎开始的。 例如搜索“XXX 语言教程”。 但要怎么决定从哪门语言开始呢？ “硅谷的人总是开 Java 的玩笑，我想应该先学 Java。” 或者： "Haskell！现在 Haskell 这么火！" 又或者： "一定要学 Go！你看它的吉祥物多么可爱！" 或者当我们不知所措的时候，只能搜： "入门学什么编程语言比较好？" 人们顾虑的问题通常就那么几个，下面这张信息图很好地回答了这些疑惑： Image credit [http://carlcheo.com/startcoding]选择第一门编程语言的过程十分有趣，这就好像是个人的信仰选择问题一样。 也许因为你像个孩子一样喜欢玩橡皮泥，稀里糊涂都打算开始学 Ruby。我还是要提醒你，不要草率做决定。 想要真正掌握你的第一门编程语言，你需要投入成千上百小时来学习实践。 所以你要考虑清楚以下这几个方面：  * 这门语言的岗位需求大不大  * 这门语言有没有发展前景  * 语言的学习难度  * 在学习过程中你能运用它开发什么样的练手项目（把你的成果分享给周围的朋友才能激励你坚持学习下去 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/what-programming-language-should-i-learn-first/</link>
                <guid isPermaLink="false">5d31400dfbfdee429dc5ef54</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Tue, 09 Jan 2024 04:13:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/1_1XEF9NuNQy0rSu4kVdbb6A.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/what-programming-language-should-i-learn-first-19a33b0a467d/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">What Programming Language Should I Learn First in 2024? [Solved]</a>
      </p><p>大多数人的编程之旅都是从搜索引擎开始的。</p><p>例如搜索“XXX 语言教程”。</p><p>但要怎么决定从哪门语言开始呢？</p><p>“硅谷的人总是开 Java 的玩笑，我想应该先学 Java。”</p><p>或者：</p><p>"Haskell！现在 Haskell 这么火！"</p><p>又或者：</p><p>"一定要学 Go！你看它的吉祥物多么可爱！"</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-15.png" class="kg-image" alt="image-15" width="600" height="400" loading="lazy"></figure><p>或者当我们不知所措的时候，只能搜：</p><p>"入门学什么编程语言比较好？"</p><p>人们顾虑的问题通常就那么几个，下面这张信息图很好地回答了这些疑惑：</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://pic2.zhimg.com/80/v2-d5279a67971e0d64ff2fa29eb0501789_hd.png" class="kg-image" alt="v2-d5279a67971e0d64ff2fa29eb0501789_hd" width="600" height="400" loading="lazy"><figcaption><a href="http://carlcheo.com/startcoding" rel="noopener">Image credit</a></figcaption></figure><p>选择第一门编程语言的过程十分有趣，这就好像是个人的信仰选择问题一样。</p><p>也许因为你像个孩子一样喜欢玩橡皮泥，稀里糊涂都打算开始学 Ruby。我还是要提醒你，不要草率做决定。</p><p>想要真正掌握你的第一门编程语言，你需要投入成千上百小时来学习实践。</p><p>所以你要考虑清楚以下这几个方面：</p><ul><li>这门语言的岗位需求大不大</li><li>这门语言有没有发展前景</li><li>语言的学习难度</li><li>在学习过程中你能运用它开发什么样的练手项目（把你的成果分享给周围的朋友才能激励你坚持学习下去）</li></ul><p>每年都会有新的编程语言出现，以及随着而来的学术论文亦或者是搞笑段子：</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-6a8dc1c8a42520a03d612928988d7c04_hd.jpg" class="kg-image" alt="v2-6a8dc1c8a42520a03d612928988d7c04_hd" width="600" height="400" loading="lazy"></figure><p>第一门编程语言可选择的范围很广。下面这张图很清晰地显示了过去几年中几门语言学习的 Google 搜索热度变化：<br></p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-693368bd57c79ee3487e36fe016885fd_hd.png" class="kg-image" alt="v2-693368bd57c79ee3487e36fe016885fd_hd" width="600" height="400" loading="lazy"></figure><p>Java 有起有落，而 Python 逐渐成为了最受欢迎的入门语言。除此之外，还有最近几年逐步火起来的 JavaScript。</p><p>在我展开讨论之前，先明确几点：</p><ul><li>我并不会在这里争论哪门语言要比哪门优越</li><li>我认同一名合格的程序员最终应该掌握不止一门编程语言</li><li>我想说明的是，对于刚入门的初学者来说，还是应该先专注于一门语言的学习。而这门语言，我想你可能早就在标题中发现了——就是 JavaScript</li></ul><p>我们先来聊聊现在学校里的编程教学是什么情况。</p><h2 id="-">计算机基础教学</h2><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-94f1beeccb3bfc6cfec2c81c1acfe46d_hd.png" class="kg-image" alt="v2-94f1beeccb3bfc6cfec2c81c1acfe46d_hd" width="600" height="400" loading="lazy"></figure><p>一般在大学教授编程课程的都是计算机系，而计算机专业一般数学和电子方面的内容又比较多。当然你可能早就听说过：</p><blockquote>计算机科学的教育无法使任何人成为专业的程序员，就好像学习怎么使用刷子和颜料无法让任何人成为画家一样—— Eric S. Raymond（《大教堂与集市》作者）</blockquote><p>即使在 2020 年的今天，许多大学还像教计算机科学一样教编程，像教数学一样教计算机科学。</p><p>所以许多课程中编排的入门语言是 C 这样底层抽象的语言，或者是专门针对数学的 MATLAB.</p><p>一些专业权威的机构也推出了他们的编程语言年度排行榜，例如 <a href="https://link.zhihu.com/?target=http%3A//www.tiobe.com/tiobe-index/" rel="nofollow noreferrer">TIOBE Index</a>，又或者是下面这个来自 <a href="https://link.zhihu.com/?target=http%3A//spectrum.ieee.org/computing/software/the-2016-top-programming-languages" rel="nofollow noreferrer">IEEE</a>的榜单：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-16.png" class="kg-image" alt="image-16" width="600" height="400" loading="lazy"></figure><p>大多数这类榜单 10 年来都没有什么变化。</p><p>但事实上不是这样的，包括在学术界。</p><p>早在 2014 年，Python 就超过了 Java，成为了最受美国各大 CS（Computer Science）机构欢迎的教学语言。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-17.png" class="kg-image" alt="image-17" width="600" height="400" loading="lazy"></figure><p>而在实际上的生产工作中，也发生了和权威机构发布的完全不一样的变化（数据来自 <em>87,354</em> 名开发者参与的 Stack Overflow 2019 年度调查）：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-36.png" class="kg-image" alt="image-36" width="600" height="400" loading="lazy"></figure><p>多一半的开发者都在使用 JavaScript。它最早只在前端开发应用，现在也逐步在后端流行开来。甚至开始延伸到游戏开发和物联网领域。</p><p>工作岗位上对 JavaScript 的需求也仅次于 Java（数据来自 <a href="https://link.zhihu.com/?target=http%3A//www.indeed.com/jobtrends/q-java-q-python-q-javascript-q-ruby-q-php-q-android-q-ios.html" rel="nofollow noreferrer">Indeed.com</a>）：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-19.png" class="kg-image" alt="image-19" width="600" height="400" loading="lazy"></figure><p>所以我们也围绕 JavaScript 技术栈建立了我们的<a href="https://link.zhihu.com/?target=https%3A//www.freecodecamp.com/" rel="nofollow noreferrer">开源社区</a>。在过去的五年里，有超过 40,000 名学员通过在 <strong>freeCodeCamp </strong>学习找到了编程相关的工作。</p><p>不过 JavaScript 真的也适合你么？它值得你为之献出第一次么？我们来继续分析：</p><h3 id="--1">事实一：岗位需求</h3><p>如果你只是为了好奇好玩而学编程的话，可以忽略这一点。但如果你和大多数人一样，想通过掌握编程技能找到工作的话，这点对你就非常重要了。</p><p>像我之前提到的，JavaScript 是除 Java 之外需求量最大的编程语言。</p><p>另外还有一点：JavaScript 已经发展了 20 多年，而直到最近，一些诸如 Netflix, Walmart 和 PayPal 一类的大公司才开始全栈应用 JS 构建他们的应用。</p><p>所以就造成了市场上 JavaScript 开发者供不应求的状况（数据来自 <a href="https://link.zhihu.com/?target=http%3A//www.indeed.com/jobtrends/q-java-q-python-q-javascript-q-ruby-q-php-q-android-q-ios.html" rel="nofollow noreferrer">Indeed.com</a>）。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-20.png" class="kg-image" alt="image-20" width="600" height="400" loading="lazy"></figure><p>从图上来看，每个 Java 岗位大概有 2.7 人在竞争，IOS 和 PHP 也平均都有 2 人以上竞争。</p><p>而通过计算，每个 JavaScript 岗位只有 0.7，这就成了属于 JS 开发者的卖家市场。</p><p><em>译者注：为了更具说服力，特此补充国内的编程语言岗位情况（数据来源 </em><a href="https://blog.csdn.net/juwikuang/article/details/100550704">2019 年 9 月中国编程语言排行榜</a><em>）：</em></p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-35.png" class="kg-image" alt="image-35" width="600" height="400" loading="lazy"></figure><h2 id="--2">事实二：发展前景</h2><p>在 GitHub 上，平均每个 JavaScript 的项目收到的 pull requests 要比其他语言多两倍以上。其增长速度也远超别的流行语言。</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-d90e80afd63f1087f50c70bf10a41665_hd.png" class="kg-image" alt="v2-d90e80afd63f1087f50c70bf10a41665_hd" width="600" height="400" loading="lazy"></figure><p>JavaScript 的整个生态体系也因为 Google, Microsoft, Facebook, Netflix 这类大公司的投资而受益匪浅。</p><p>例如 TypeScript(一种 JavaScript 的超集，提供更丰富特性，可编译为普通 JS)有着超过 100 名开源贡献者，而这里面大多数都是微软和谷歌的员工。</p><p>而且这类集团公司很少有使用 Java 的。因为 Java 的所有者 Oracle 经常会因为各种有关 Java 开发的原因起诉别的公司。</p><h2 id="--3">事实三：学习难度</h2><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-21.png" class="kg-image" alt="image-21" width="600" height="400" loading="lazy"></figure><p>大多数的程序员应该都会认同，高级的脚本语言通常比较好学。JavaScript 当然属于此类，也包括 Ruby 和 Python.</p><p>即便很多大学课程教授的都是 Java 或 C++，这类语言也真的很难上手。</p><h2 id="--4">事实四：你能实践的练手项目</h2><p>这是 JavaScript 最大的优势。JS 可以运行在任何有浏览器的设备上。你几乎可以用 JS 开发任何应用，而且很方便就能分享发布到任何地方。</p><p>正是由于 JavaScript 无处不在，Stack Overflow 的联合创始人 Jeff Atwood 才说出他的那句经典定律：</p><blockquote>任何可以用 JavaScript 写成的应用，最终都会使用 JavaScript 写成。</blockquote><p>现实也在不断的佐证，<a href="https://link.zhihu.com/?target=https%3A//www.reddit.com/r/atwoodslaw/" rel="nofollow noreferrer">证据在此</a>。</p><p>Java 也曾号称是跨平台语言。可也许你了解到，Oracle 官方在今年早些时候终止了<a href="https://link.zhihu.com/?target=http%3A//motherboard.vice.com/read/a-brief-history-of-the-java-applet" rel="nofollow noreferrer">Java Applets</a> 的支持。</p><p>Python 也经常会遇到类似的问题：</p><blockquote>我怎么才能把我写的这个游戏发给我的朋友？或者能够不安装什么应用就在手机上运行么？ — James Hague in <a href="https://link.zhihu.com/?target=http%3A//prog21.dadgum.com/203.html" rel="nofollow noreferrer">Retiring Python as a Teaching Language</a></blockquote><p>相比之下，JS 要方便很多。下面的这些应用都来自我们开源社区的学员，你只需要在浏览器里打开链接就能开始玩啦：</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-22.png" class="kg-image" alt="image-22" width="600" height="400" loading="lazy"><figcaption><a href="https://link.zhihu.com/?target=http%3A//s.codepen.io/adambeagle/debug/qOamaz" rel="nofollow noreferrer">1970s style Simon game</a></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://pic2.zhimg.com/80/v2-a1da22984966e4030f5968fd3962ff6d_hd.png" class="kg-image" alt="v2-a1da22984966e4030f5968fd3962ff6d_hd" width="600" height="400" loading="lazy"><figcaption><a href="https://link.zhihu.com/?target=http%3A//s.codepen.io/safx/debug/Ewcym" rel="nofollow noreferrer">Conway’s Game of Life</a></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-23.png" class="kg-image" alt="image-23" width="600" height="400" loading="lazy"><figcaption><a href="https://link.zhihu.com/?target=http%3A//s.codepen.io/duttakapil/debug/BKGjOa" rel="nofollow noreferrer">Star Wars-themed Wikipedia Search</a></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-24.png" class="kg-image" alt="image-24" width="600" height="400" loading="lazy"><figcaption><a href="https://link.zhihu.com/?target=http%3A//s.codepen.io/Megabyteceer/debug/qbXJMQ" rel="nofollow noreferrer">A roguelike dungeon crawler game</a></figcaption></figure><h3 id="--5"><br>先专注学好一门语言，再去学别的。</h3><p>如果你总是在各个语言之间摇摆不定，<a href="https://link.zhihu.com/?target=https%3A//medium.freecodecamp.com/a-cautionary-tale-of-learning-to-code-my-own-eddb24d9d5a7" rel="nofollow noreferrer">你很难取得什么实质上的进步</a>。</p><p>为了避免在入门阶段止步不前，你需要扎实学好你的第一门语言。之后再学习别的语言你就会感觉到异常轻松。</p><p>等到那个阶段，你就可以逐步成长为一名掌握许多语言的全面的开发者啦：</p><ul><li>C 对于你理解计算机原理特别有帮助，例如内存管理之类的。在高性能计算中非常有用。</li><li>C++ 在游戏开发中运用广泛</li><li>Python 在科学研究和数据分析中应用广泛</li><li>如果你想在大型的科技公司中工作，Java 就非常重要。</li></ul><p>但还是先学会 JavaScript 再说吧:)</p><p>我知道评论里会有很多人要和我吵起来。虽然我知道这不可能，但我还是要试着说服你一下：</p><p><strong>Q1：JavaScript 运行速度不是很慢么？</strong></p><p>在很多实际运用场景中，JavaScript 和一些高性能语言运行一样快。</p><p>Node.js 要比 Python、Ruby、PHP 快上好几个数量级。</p><p>甚至已经接近了 C++, Java, Go 的性能。</p><p>下面是一个比较全面的编程语言“跑分评测”：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-25.png" class="kg-image" alt="image-25" width="600" height="400" loading="lazy"></figure><p><br><strong>Q2：JavaScript 连静态语言都不是！</strong></p><p>和 Python/Ruby 一样，JavaScript 属于动态语言，使用起来也很方便。举个例子，假如我想把变量 exampleArray 设为数组，我会先给它赋值，然后通过 length 函数来获取数组中元素的数量。</p><pre><code class="language-js">exampleArray = [1, 2]
-&gt; [1, 2]
exampleArray.length
-&gt; 2
</code></pre><p>但假如我不小心赋值给了它一个字符串，代码照样运行不会报错，可并不是我想要的结果：</p><pre><code class="language-text">exampleArray = "text"
-&gt; "text"
exampleArray.length
-&gt; 4
</code></pre><p>这一类错误在动态类型的语言中经常会遇到。大多数的开发者都会专门写一些检查和测试来避免此类错误的发生。</p><p>如果你非要学一门静态语言的话，我依旧推荐你学习 JavaScript，之后再开始学习 TypeScript。</p><blockquote>TypeScript 是有学习曲线的，但在掌握了 JavaScript 之后，你的学习会很顺利。— <a href="https://link.zhihu.com/?target=https%3A//medium.freecodecamp.com/when-should-i-use-typescript-311cb5fe801b" rel="nofollow noreferrer">Alex Ewerlöf on TypeScript</a></blockquote><p><strong>Q3：我想要学的是怎么开发移动 App</strong></p><p>那你也还应该先学 JavaScript 呀~</p><ol><li>JavaScript 有一些很棒的工具可以开发原生的移动应用，例如 <a href="https://link.zhihu.com/?target=http%3A//ngcordova.com/" rel="nofollow noreferrer">Angular Cordova</a>和 <a href="https://link.zhihu.com/?target=https%3A//facebook.github.io/react-native/" rel="nofollow noreferrer">React Native</a>.</li><li>为了让你的移动 App 真的像模像样，它至少得有个后端，你用一些合适的 Web 开发框架可以很轻松地实现，例如 Node.js+Express.js</li></ol><p>而且移动开发的春天也正是 JS 的流行带来的。</p><p>在 Stack Overflow的调查中，有近一半的开发者的岗位都是 Web 开发，移动开发岗只占了 8%。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/08/image-26.png" class="kg-image" alt="image-26" width="600" height="400" loading="lazy"></figure><p>“为某事专门下一个 App”的境况也已不再，大多数的智能手机用户<a href="https://link.zhihu.com/?target=http%3A//www.recode.net/2016/9/16/12933780/average-app-downloads-per-month-comscore" rel="nofollow noreferrer">开始趋于不下载新的 App 了</a>。</p><p>当然——人们还在用着 App。绝大多数都是大厂的微信、支付宝一类（原文：Mostly Facebook, Google Maps, and handful of others）。市场对移动开发的需求也越来越小。</p><p>移动开发的前景也难以预期。而且在许多方面，使用 JavaScript 来开发维护和部署移动应用要更加轻松简单。所以像 Facebook 和 Google 这样的公司在研发更好的 JavaScript 工具上投入的越来越多。</p><p>在 2016 年，几乎所有的开发都和 Web 开发有关。所有的事情都依附着互联网这个大平台。而且下一波将要崛起的设备——家庭智能、自动驾驶汽车等也都需要依附于网络。</p><p><strong>Q4：JavaScript 不是一个只花 10 天写着玩的语言么？</strong></p><p>JavaScript 有一段<a href="https://link.zhihu.com/?target=http%3A//www.w3school.com.cn/js/pro_js_history.asp" rel="nofollow noreferrer">简史</a>。</p><p>人们也经常会拿 JavaScript 开<a href="https://link.zhihu.com/?target=http%3A//blog.csdn.net/bitfan/article/details/10362461" rel="nofollow noreferrer">各种各样的玩笑</a>。</p><p>同样人们也喜欢吐槽 C++，可不管有多少人吐槽，C++ 依然很成功。</p><p><em>译者注：这就和 “PHP 是全世界最好的语言”是一个道理。</em></p><p>所以如果再有人在你面前说 JS 怎么怎么不好的话，请记住 C++ 之父的那句名言：</p><blockquote>世界上只有两种编程语言：一种是天天被人喷的，另一种是没人用的。— Bjarne Stroustrup</blockquote> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 工具推荐丨提升前端开发和设计效率的 10 大利器 ]]>
                </title>
                <description>
                    <![CDATA[ 原文：From design to development, 10 tools I can’t live without [https://www.freecodecamp.org/news/from-design-to-development-10-tools-i-cant-live-without-96006445e636/] ，作者：Jonathan Z White [https://www.freecodecamp.org/news/author/jonathanzwhite/] Atom [https://link.zhihu.com/?target=https%3A//atom.io/] Atom 是由 GitHub 推出的开源代码编辑器。过去的一年里我使用的最多的就是它。Atom 拥有插件管理、自动补全、主题等所有必要的功能。 相比 Sublime 的插件管理界面，Atom 简直人性化太多了。你可以使用 APM 或者图形界面来管理你的插件。不需要手动修改设置文件。 在 Atom 刚刚推出的时候它确实很慢，不过现在的版本运行起来已经非常快了。只有在打开一些巨型文件的时 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/these-web-development-or-design-tools-will-help-you-a-lot/</link>
                <guid isPermaLink="false">5d3a9d9ffbfdee429dc5f3e9</guid>
                
                    <category>
                        <![CDATA[ 工具 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Thu, 10 Mar 2022 02:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/designing-1909281_960_720.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>原文：<a href="https://www.freecodecamp.org/news/from-design-to-development-10-tools-i-cant-live-without-96006445e636/">From design to development, 10 tools I can’t live without</a>，作者：<a href="https://www.freecodecamp.org/news/author/jonathanzwhite/">Jonathan Z White</a></p><h3 id="atom"><a href="https://link.zhihu.com/?target=https%3A//atom.io/" rel="nofollow noreferrer">Atom</a></h3><p>Atom 是由 GitHub 推出的开源代码编辑器。过去的一年里我使用的最多的就是它。Atom 拥有插件管理、自动补全、主题等所有必要的功能。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-68.png" class="kg-image" alt="image-68" width="800" height="500" loading="lazy"></figure><p>相比 Sublime 的插件管理界面，Atom 简直人性化太多了。你可以使用 APM 或者图形界面来管理你的插件。不需要手动修改设置文件。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-69.png" class="kg-image" alt="image-69" width="800" height="500" loading="lazy"></figure><p>在 Atom 刚刚推出的时候它确实很慢，不过现在的版本运行起来已经非常快了。只有在打开一些巨型文件的时候才会出现卡顿。</p><p>要是你对 Atom 的性能优化感兴趣的话，可以阅读 <a href="https://link.zhihu.com/?target=http%3A//blog.atom.io/2014/07/02/moving-atom-to-react.html" rel="nofollow noreferrer">Moving Atom To React</a> 和 &nbsp;<a href="https://link.zhihu.com/?target=https%3A//github.com/atom/atom/pull/5624" rel="nofollow noreferrer">Implement text editor DOM updates manually instead of via React</a></p><h3 id="dragdis"><a href="https://link.zhihu.com/?target=https%3A//dragdis.com/" rel="nofollow noreferrer">DragDis</a></h3><p>DragDis 是一个收集设计灵感的工具，可以安装 Chrome 插件，使用起来非常方便。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-70.png" class="kg-image" alt="image-70" width="800" height="544" loading="lazy"></figure><p>我自己是根据每周的时间来分类我的素材的，这也能让我很好的记录自己品味的变化。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-71.png" class="kg-image" alt="image-71" width="800" height="544" loading="lazy"></figure><p>DragDis 也支持全屏查看，用起来真是赏心悦目。</p><h3 id="iterm2"><a href="https://link.zhihu.com/?target=https%3A//www.iterm2.com/" rel="nofollow noreferrer">iTerm2</a></h3><p>iTerm 是一个非常简洁的控制台应用。在 iTerm2 中有许多新特性，例如无限制分割界面，直接在控制台中查看图片，搜索等。用起来比原生控制台要方便多了。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-72.png" class="kg-image" alt="image-72" width="800" height="500" loading="lazy"></figure><h3 id="muzli"><a href="https://link.zhihu.com/?target=https%3A//muz.li/" rel="nofollow noreferrer">Muzli</a></h3><p><a href="https://link.zhihu.com/?target=https%3A//muz.li/" rel="nofollow noreferrer">Muzli</a> 是一个设计类资讯内容聚合的 Chrome 插件。包含了 Designer News, Dribbble, Behance 在内的所有主流设计类网站内容。Muzli 默认会在你打开的新标签页显示。</p><p>最棒的一点是 Muzli 还有一个编辑推荐板块，这就感觉有一个私人助理每天专门为你整理前段设计资讯一样。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-73.png" class="kg-image" alt="image-73" width="800" height="544" loading="lazy"></figure><h3 id="noiz-io"><a href="https://link.zhihu.com/?target=http%3A//noiz.io/" rel="nofollow noreferrer">Noiz.io</a></h3><p>很多开发者都喜欢享受咖啡厅惬意的环境。<a href="https://link.zhihu.com/?target=http%3A//noiz.io/" rel="nofollow noreferrer">Noiz.io</a> 把这种体验带到了你的家中。它可以播放包括雨声、咖啡厅、雷声、海浪等环境背景音，让你感觉渐入佳境。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-74.png" class="kg-image" alt="image-74" width="800" height="500" loading="lazy"></figure><h3 id="invision"><a href="https://link.zhihu.com/?target=https%3A//www.invisionapp.com/" rel="nofollow noreferrer">Invision</a></h3><p><a href="https://link.zhihu.com/?target=https%3A//www.invisionapp.com/" rel="nofollow noreferrer">Invision</a> 是一个可协作的原型设计平台，非常适合前端开发者和设计师之间进行协作。设计师可以上传设计稿，并添加链接把它们串联起来。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-75.png" class="kg-image" alt="image-75" width="800" height="500" loading="lazy"></figure><p>通过为页面上不同的部分添加链接，设计师可以很好地为用户和开发者解释交互流程。当作用户调研测试工具也非常好用。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-76.png" class="kg-image" alt="image-76" width="800" height="500" loading="lazy"></figure><p>Invision 最近也推出了名为 <a href="https://link.zhihu.com/?target=http%3A//blog.invisionapp.com/boards-share-design-inspiration-assets/" rel="nofollow noreferrer">Boards</a> 的素材收集功能，你也可以通过这些素材创建模板，并且能够和团队成员协同使用。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-77.png" class="kg-image" alt="image-77" width="800" height="544" loading="lazy"></figure><h3 id="what-the-font"><a href="https://link.zhihu.com/?target=https%3A//www.myfonts.com/WhatTheFont/" rel="nofollow noreferrer">What the Font</a></h3><p>文字排版是设计中非常重要的内容。<a href="https://link.zhihu.com/?target=https%3A//www.myfonts.com/WhatTheFont/" rel="nofollow noreferrer">What the Font</a> 是一个非常棒的 Chrome 插件，只需通过点选就可以知道网页上使用的是什么字体。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-79.png" class="kg-image" alt="image-79" width="800" height="544" loading="lazy"></figure><h3 id="postman"><a href="https://link.zhihu.com/?target=https%3A//www.getpostman.com/" rel="nofollow noreferrer">Postman</a></h3><p>作为一名前端开发者，经常需要测试调用 API，例如和后端的接口协同、微信小程序开发等等。<a href="https://link.zhihu.com/?target=https%3A//www.getpostman.com/" rel="nofollow noreferrer">Postman</a> 可以让 RESTful API 的测试变得异常轻松。</p><p>只需要在图形化的操作界面上输入请求地址和参数，Postman 就能够以多种格式返回请求的结果。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-80.png" class="kg-image" alt="image-80" width="800" height="500" loading="lazy"></figure><h3 id="wappalyzer"><a href="https://link.zhihu.com/?target=https%3A//wappalyzer.com/" rel="nofollow noreferrer">Wappalyzer</a></h3><p><a href="https://link.zhihu.com/?target=https%3A//wappalyzer.com/" rel="nofollow noreferrer">Wappalyzer</a> 是一个 Chrome 插件，可以让你查看当前的网站使用了那些库和框架，使用什么服务器，什么语言等等。你还能在其官网查看当前各类框架类库的流行趋势。可以让你发现许多网站的秘密袄~</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-81.png" class="kg-image" alt="image-81" width="800" height="544" loading="lazy"></figure><h3 id="boom-2"><a href="https://link.zhihu.com/?target=http%3A//www.globaldelight.com/boom/index.php" rel="nofollow noreferrer">Boom 2</a></h3><p><a href="https://link.zhihu.com/?target=http%3A//www.globaldelight.com/boom/index.php" rel="nofollow noreferrer">Boom 2</a> 是 Mac 上的一个均衡器软件。写代码的时候来点音乐助兴再好不过了。使用 Boom 2 你可以自定义音乐的 EQ。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-82.png" class="kg-image" alt="image-82" width="800" height="500" loading="lazy"></figure><p>Boom 中也包含了许多预置的声音效果，和 Bose 耳机搭配使用可以让你获得完全不同的听觉体验。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/03/image-83.png" class="kg-image" alt="image-83" width="800" height="500" loading="lazy"></figure><p>这里还有许多不胜枚举的插件和应用: <a href="https://link.zhihu.com/?target=https%3A//chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc%3Fhl%3Den" rel="nofollow noreferrer">JSON Viewer for Chrome</a>, <a href="https://link.zhihu.com/?target=http%3A//noonpacific.com/" rel="nofollow noreferrer">Noon Pacific</a>, <a href="https://link.zhihu.com/?target=https%3A//justgetflux.com/" rel="nofollow noreferrer">Flux</a>, <a href="https://link.zhihu.com/?target=https%3A//itunes.apple.com/us/app/bettersnaptool/id417375580%3Fmt%3D12" rel="nofollow noreferrer">Better Snap Tool</a>。</p><p>要是上面列出的这些推荐中没有你最喜欢的，欢迎在评论区和大家分享。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 掌握学习方法——作为开发者最重要的能力 ]]>
                </title>
                <description>
                    <![CDATA[ 具备高效的学习能力和编程能力同样重要。 作为一名开发者，即使你的精力被微信、微博、知乎（译者注：原文是 Hacker News,Twitter,Reddit,Facebook）分散，你每天在工作中都需要学习。 在上班的时候你经常会遇到新的代码库和技术挑战。回家看看开源项目和别人的作品，也需要你跟进他们的进度。 技术发展变化非常快，你会发现你无时无刻不在追赶着新的工具、语言、框架的潮流。 常言道：学如逆水行舟，不进则退。 在过去的一年里，我从一个连 Chrome 调试台都打不开的小白，变成了一个在一流电子货币加密公司的开发工程师，我非常快地掌握了编程的能力。 但是，学习对我来说并没有那么轻松。 坦白来讲，在学习的过程中充满了煎熬。有太多的未知和不确定。 “这样我怎么坚持的下去呢？”我想。 “要是每天学习写代码这么痛苦，我会疯掉的，看来我对编程并不感兴趣吧？” “要是我感兴趣的话不应该觉得轻松点么？艺术家搞创作的时候需要绞尽脑汁么？作家也会江郎才尽么？运动员也会遭遇瓶颈么？我们去做自己感兴趣的事情时都会觉得难受么？” “学习不该使我快乐么？” 学海无涯有捷径么？ 有 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/learning-how-to-learn-the-most-important-developer-skill/</link>
                <guid isPermaLink="false">5d3a9628fbfdee429dc5f346</guid>
                
                    <category>
                        <![CDATA[ 学习编程 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Mon, 28 Feb 2022 02:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/nick-morrison-FHnnjk1Yj7Y-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>具备高效的学习能力和编程能力同样重要。</p><p>作为一名开发者，即使你的精力被微信、微博、知乎（译者注：原文是 Hacker News,Twitter,Reddit,Facebook）分散，你每天在工作中都需要学习。</p><p>在上班的时候你经常会遇到新的代码库和技术挑战。回家看看开源项目和别人的作品，也需要你跟进他们的进度。</p><p>技术发展变化非常快，你会发现你无时无刻不在追赶着新的工具、语言、框架的潮流。</p><p>常言道：<strong>学如逆水行舟，不进则退。</strong></p><p>在过去的一年里，我从一个连 Chrome 调试台都打不开的小白，变成了一个在一流电子货币加密公司的开发工程师，我非常快地掌握了编程的能力。</p><p>但是，学习对我来说并没有那么轻松。</p><p>坦白来讲，在学习的过程中充满了煎熬。有太多的未知和不确定。</p><p>“这样我怎么坚持的下去呢？”我想。</p><p>“要是每天学习写代码这么痛苦，我会疯掉的，看来我对编程并不感兴趣吧？”</p><p>“要是我感兴趣的话不应该觉得轻松点么？艺术家搞创作的时候需要绞尽脑汁么？作家也会江郎才尽么？运动员也会遭遇瓶颈么？我们去做自己感兴趣的事情时都会觉得难受么？”</p><p>“学习不该使我快乐么？”</p><h2 id="-"><strong>学海无涯有捷径么？</strong></h2><p>有是当然有。学习新的编程知识是很难受的，因为它需要你自律和努力。</p><p>但你可以痛并快乐着。</p><p>怎么才能获得学习的快乐呢？</p><p><strong>很简单：</strong> 我改变了我对学习的看法。学习并不是困难的而是有趣的。</p><p>请容我在接下来的篇幅里娓娓道来。</p><h2 id="--1"><strong>万事开头难</strong></h2><p>学习写代码最难的就是开始。</p><p>试想一下你要学习的第一门编程语言。你首先要了解它的语法和格式。你还得理解值、类型、操作符、控制流、函数、高阶函数、作用域、闭包、递归等等……</p><p>这就好像是学杂耍——一上来就让你耍 18 颗球一样。</p><p>最早我用了好几个礼拜才理解了闭包到底是什么玩意儿。我读文档的时候感觉我理解了，当我准备应用一个闭包时，就又不知所措了。</p><p>这是很普遍的，作为一名老师我了解到：想要理解一个新的概念，往往需要你尝试一次、两次甚至更多。</p><p>但只要一个人坚持的足够久，总会有豁然开朗的时候。就像当我读完了无数有关闭包的博文、Stack Overflow 和文档之后的体验。</p><p>每一段我阅读过的材料都让我有了一些新的理解，直到最后我完全理解了闭包。</p><p>理解闭包对我来说意义深远，因为成就感鼓励了我继续前行，后来我甚至自己写了一篇解读闭包的博文。</p><h2 id="--2"><strong>学习是过程，不是结果</strong></h2><p>如果我们把“学习”视作我们必须完成的一件事，我们就会急功近利。这样我们才能赶快完成好在课余时间去玩玩别的。</p><p>只可惜学海无涯，学无止境。要是你把学习当作一场赛跑，你永远也到不了终点，反而会带来失落和失望。</p><p>相反，如果你把学习理解为一种过程，你就能体会和感受到一点一滴的进步，这也将鼓励你继续前行。</p><p>学习就好像锻炼一样。太剧烈了会受伤，你的伤痛会一直持续，甚至恢复之后你也忘却不了那种痛苦。以后每次运动的时候你都会记起。除非你每次的痛苦都能得到缓解，你慢慢的习惯和适应了它。最后你获得了强健的体魄和有型的身材，这也将鼓励你继续锻炼下去。</p><p>运动是一个积极效应的循环：</p><p>这在学习上也同样适用。</p><h2 id="--3"><strong>学习可以渐入佳境</strong></h2><p>试想你在构建你的第一款 Web 应用。</p><p>最一开始你只能面对一屏幕空旷的代码编辑器。开发工作对你来说像是不可能完成的任务。你什么都不懂，在你真的能开发出来个什么玩意儿之前还有太多东西要学。</p><p>令人欣慰的是，你还是勇敢的去尝试了。</p><p>从现在开始，你每次只关注和完成一个小点。</p><p>首先是构思你的应用。你要做个什么出来？目标用户是谁？有什么困难?</p><p>之后，你开始画一些你脑海里构思的草图。并拿给你的朋友或者发到网上给别人看，再慢慢改良它。</p><p>再然后，你去搜索那些最适用你开发这个应用的工具、框架、语言。</p><p>脚踏实地的，你绞尽脑汁去完成你的目标。</p><p>有时候你可能写写代码。</p><p>更多的时候是在处理Bug和暂时解决不了的难题。</p><p>有时候你实在烦的不行，那就休息一下。</p><p>或者别的时候你不想写代码，但是可以去看看相关的文章资料。</p><p>最后，经过几周的努力，你终于为你的构想打好了基础。这时，开发你的应用感觉上就不那么痛苦了。你从之前的努力中获得了成就感，接下来你只需要完善功能就好了，就像你之前已经做过无数次那样，这根本就不是事儿。</p><p>你把一项令人痛苦和胆怯的工作转换成了循序渐进，享受其中的工作。</p><p>这就是成长，这就是进步。不管是编程、跳舞、跑步、阅读：他们都不轻松，而且学习是没有止境。</p><p>你要享受你付出其中的过程，享受随之并来的痛苦。你慢慢会理解到那不能称得上是痛苦——而是一种个人努力的成就感和自我满足。</p><p>换句话讲，煎熬和享受都是相对的。记住这个循环：</p><h2 id="--4"><strong>一种学习技术的方法</strong></h2><p>下面我介绍一种我所掌握的学习方法。可这并不是什么终极秘籍，如果你有不同的意见，可以在评论区提出。</p><p>我们拿如何学习 <a href="https://link.zhihu.com/?target=http%3A//reactjs.cn/" rel="nofollow noreferrer">React</a> 来举例。</p><h3 id="--5"><strong>明确你学习的目的</strong></h3><p>首先：我要先搜一下有关 React 的文档，了解一下这个框架的背景和它想解决的问题。</p><p>明确“为什么”对于你的学习是非常有帮助和意义的，他回答了下面这些问题：</p><ul><li>它的独特之处在哪里？</li><li>学这个对我有用么？</li><li>它主要是为了解决什么问题？</li><li>它只是昙花一现哗众取宠的小玩具，还是能够从此改变我对编程的理解？</li></ul><h3 id="--6"><strong>了解核心概念</strong></h3><p>其次：我会认真读完文档里的介绍和示例。</p><p>到目前为止我还没有上手尝试。阅读一项技术的核心概念一定要在动手实践之前。这对你之后的学习至关重要。</p><p>这也使我避免了在不知道 React 是个什么玩意儿的情况下就稀里糊涂地用它，搞堆Bug出来。</p><h3 id="--7"><strong>尝试编码</strong></h3><p>之后，当我有一种我已经了然于胸的感觉时，就是我上手实践的时候了。</p><p>我开始跟着视频教程试着用这种新框架编写一些非常简单的小东西，或者跟着文档里的教程指引写写代码。</p><h3 id="--8"><strong>遇到坑</strong></h3><p>我不可避免地会掉到坑里。</p><p>读文档当然小菜一碟，可是自己实践的时候就完全不知所措。</p><p>这时我开始有半途而废的念头。但遇到困难正是应该迎头而上的时刻。没有付出哪儿有回报。只有懦夫才会放弃！</p><p>接下来我开始做这些事：</p><ol><li>首先我需要确定一下我到底遇到了什么 Bug，之后假设几种导致它的可能性，即使我还不太了解，猜猜也罢。</li><li>接下来离开电脑跟前，稍微放松一下换换心情换换气。可其实心头上总是难以放下那个我没有解决了的问题。</li><li>接下来我根据我的假设开始调试——而不是直接去网上搜答案。要知道，全凭自己的思考获得答案是一种非常难能可贵的体验。即使你犯了很多错误，它也能加深你的印象好下次不再犯。</li><li>如果我的假设被验证了，那么万事大吉！反之，我就会去搜文档，博客，或者 Stack Overflow 或者任何其他可以辅助我的资料。</li><li>当我阅读这些资料的时候，我会把那些可能帮到忙的信息记录下来。</li><li>还是没有办法?没关系，即使我搜的这一大堆资料对解决目前的问题没有帮助，我也通过阅读学到了很多，而且它们也有可能解决我之后会遇到的问题。</li><li>直到这时，我才会在知乎上提个问题（译者注：原文为 Stack Overflow）或者问问同学同事。</li><li>与此同时，我会不断地重复研究这个问题，它总有被解决的时候。</li></ol><p>有时候这个过程可能只需要几秒，而有时候需要几个小时甚至更久。无论怎样，在这个过程中你都能学到很多东西。</p><p>在编程中解决 Bug 就好像在隧道里寻找射灯一样。你总会找到它，可是沿途你会发现和了解更多有关隧道的信息。在学习上，这些了解正是你的收获。</p><p>调试错误其实是一个了解和发现的过程，享受它吧。</p><h3 id="--9"><strong>温故而知新</strong></h3><p>在学习的过程中，我开发了一些简单的小东西，跨过了一些坎。就像你所了解的，这过程肯定纠结，我需要用这个新工具进行更多实践。</p><p>所以接下来我会在开发一些练手小项目。不是好高骛远地去搞一个大项目，而是做一些可以构建我应用的基础模块。</p><p>例如我在网上看到一个用 React 写的有增删改查功能的待办事项应用。那么我可以做一个另外一种形式的增删改查的，确保我能根据参考项目的逻辑写出来的，而不是可能会出错让我受挫的应用。</p><h3 id="--10"><strong>掌握</strong></h3><p>熟能生巧，所以我不停地构建小项目，知道我感觉我已经掌握了它的核心概念。</p><p>最后，我开始试着不看文档和示例把所有的知识梳理起来。直到这时，我才会开始完全独立地做自己的项目。</p><p>在整个学习过程中，我不断地挑战稍微难一些的任务，但也不至于难道打击的我不想干的程度。</p><p>最后，我会在这项学习让我厌恶之前，赶快转移注意。</p><h2 id="--11"><strong>学习使你快乐</strong></h2><p>通过一些努力和方法，学习编程可以变得非常有趣。最初它看起来很复杂，我想这也是为什么很多人不敢开始的原因——并不是因为它无聊，而是因为它困难。</p><p>通过不断地联系这种学习方法，它将会形成一种肌肉记忆。你不用太努力去想它。你只需要驾驭挫折和享受成就。</p><p>就好像变魔术一样，学习变得轻松多了。</p><p>你是如何学习掌握新知识的？欢迎留言分享！</p><p>原文链接：<a href="https://www.freecodecamp.org/news/learning-how-to-learn-the-most-important-developer-skill-7bf62dfaf67d/">Learning How to Learn: The Most Important Developer Skill</a>，作者：Preethi Kasireddy</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 一点都不高大上，手把手教你使用 Travis CI 实现持续部署 ]]>
                </title>
                <description>
                    <![CDATA[ > 持续集成、持续交付、持续部署。听起来就像是在大型软件工程，高端开发项目组里才会应用到的概念。其实不然，通过运用一些开源免费的工具和平台，不管是你的个人博客还是 side-projects 都能够享受到开发任务自动化的便利。 这次我们的教程主要会分为以下几步：  1. 注册并设置 Travis CI  2. 在开发服务器（或本地）上生成密匙并与部署服务器互信  3. 安装 Ruby 2.0 以上版本并安装 travis 的命令行工具  4. 编写测试并在项目中配置 travis  5. 编写 travis 自动部署脚本  6. 提交代码检验运行 本教程以最基础的部署 php 站点为例（其实与部署的应用本身关系不大，不管是 NodeJS 还是 Hexo 一类的静态站点生成全部都大同小异，只需要替换自动执行的命令就可以了） 注册并设置 Travis CI 先打开 Travis CI 官网 [https://link.zhihu.com/?target=https%3A//travis-ci.com/] ，点击右上角使用Github登录的按钮（这里假设读者已经注册并掌握 GitHub ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/continuous-deployment-with-travis-ci/</link>
                <guid isPermaLink="false">5d327acffbfdee429dc5f01c</guid>
                
                    <category>
                        <![CDATA[ Travis CI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 持续集成 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PHP ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Mon, 31 Jan 2022 07:20:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/v2-24b2803140c11b9bf00cd5bd542222cc_1200x500.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <blockquote>持续集成、持续交付、持续部署。听起来就像是在大型软件工程，高端开发项目组里才会应用到的概念。其实不然，通过运用一些开源免费的工具和平台，不管是你的个人博客还是 side-projects 都能够享受到开发任务自动化的便利。</blockquote><p>这次我们的教程主要会分为以下几步：</p><ol><li>注册并设置 Travis CI</li><li>在开发服务器（或本地）上生成密匙并与部署服务器互信</li><li>安装 Ruby 2.0 以上版本并安装 travis 的命令行工具</li><li>编写测试并在项目中配置 travis</li><li>编写 travis 自动部署脚本</li><li>提交代码检验运行</li></ol><p>本教程以最基础的部署 php 站点为例（其实与部署的应用本身关系不大，不管是 NodeJS 还是 Hexo 一类的静态站点生成全部都大同小异，只需要替换自动执行的命令就可以了）</p><h2 id="-travis-ci">注册并设置 Travis CI</h2><p>先打开 <a href="https://link.zhihu.com/?target=https%3A//travis-ci.com/" rel="nofollow noreferrer">Travis CI 官网</a>，点击右上角使用Github登录的按钮（这里假设读者已经注册并掌握 GitHub 的基本使用了）</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-487060daf3a1875833ce135966526ed8_hd.png" class="kg-image" alt="v2-487060daf3a1875833ce135966526ed8_hd" width="600" height="400" loading="lazy"></figure><p>登录成功后，你应该会看到和下图差不多的页面，按照提示进行操作：</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-35a0e932cf8db58f535d929f7b3b1b31_hd.png" class="kg-image" alt="v2-35a0e932cf8db58f535d929f7b3b1b31_hd" width="600" height="400" loading="lazy"></figure><p>你可以打开先看一眼你在 Travis CI 上项目的页面，不过现在肯定是空空如也一片，我们在官网上需要进行的操作暂且到此为止。</p><h2 id="-">在开发服务器（或本地）生成密匙并与部署服务器互信</h2><p>不管是本地还是开发服务器，这里已经默认了你的开发环境是 Linux/类 Unix 系统，不要问我 Windows 该怎么办，Win10 可以安装 Ubuntu 子系统，当然你要是不觉得蛋疼也可以下载一些类似 ssh key generator 的软件。</p><p>这里其实只需要用到两个命令。</p><p>首先在本地或开发服务器上生成密匙，在命令行里输入：</p><pre><code class="language-bash">ssh-keygen -t rsa
</code></pre><p>之后只需要按照提示操作，你大概会看到类似下面的内容：</p><pre><code class="language-bash"># 来自Digital Ocean
ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/demo/.ssh/id_rsa): 
# 这里的密码一定要留空袄
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/demo/.ssh/id_rsa.
Your public key has been saved in /home/demo/.ssh/id_rsa.pub.
The key fingerprint is:
4a:dd:0a:c6:35:4e:3f:ed:27:38:8c:74:44:4d:93:67 demo@a
The key's randomart image is:
+--[ RSA 2048]----+
|          .oo.   |
|         .  o.E  |
|        + .  o   |
|     . = = .     |
|      = S = .    |
|     o + = +     |
|      . o + o .  |
|           . o   |
|                 |
+-----------------+
</code></pre><p>接下来你需要将你开发环境生成的密匙拷贝到你的部署服务器上。之所以进行这一步是为了实现免密码登录 ssh，因为 travis-ci 自动执行命令是不支持交互式输入密码的。</p><p>同样只需要一个命令：</p><pre><code class="language-bash">ssh-copy-id &lt;登录部署服务器用户名&gt;@&lt;部署服务器地址&gt;
# 如果ssh默认端口不是22
ssh-copy-id &lt;登录部署服务器用户名&gt;@&lt;部署服务器地址&gt; -p &lt;部署服务器ssh端口&gt;
# 示例
ssh-copy-id travis@123.123.123.123 -p 12345
</code></pre><p>接下来也同样按提示操作，第一次输入密码登录完成后，就可以使用密匙测试免密登录啦，当然为了安全起见，记得这里专门为持续部署新建一个权限适宜的用户袄。</p><h2 id="-ruby-2-0-travis-">安装 Ruby 2.0 以上版本并安装 travis 的命令行工具</h2><p>简单的 <strong>apt-get install ruby </strong>并不能顺利解决问题，travis 命令行工具依赖 ruby2.0 以上的版本。</p><p>这个地方其实是一个坑，我想大部分同学和我一样都是使用 Ubuntu 系统，默认使用<strong>apt-get install ruby2.0 </strong>安装的事实上是 1.9 版本，这特么就很尴尬了。</p><p>所以我们不得不下载源码手动编译安装。如果你的开发环境之前安装过ruby记得先删掉：</p><pre><code class="language-bash">sudo apt-get -y update
sudo apt-get -y install build-essential zlib1g-dev libssl-dev libreadline6-dev libyaml-dev
cd /tmp
# 由于众所周知的网络原因，此处可能需要使用到http_proxy
wget http://ftp.ruby-lang.org/pub/ruby/2.1/ruby-2.1.5.tar.gz 
tar -xvzf ruby-2.1.5.tar.gz
cd ruby-2.1.5/
./configure --prefix=/usr/local
make
sudo make install
</code></pre><p>如果嫌麻烦你可以把上述命令保存成一个 <strong>.sh </strong>文件一键执行。安装完成后使用 <strong>ruby -v </strong>验证一下版本。</p><p>之后再运行：</p><pre><code class="language-bash"># 由于众所周知的网络原因，此处可能需要使用到http_proxy
gem install travis
</code></pre><p>如果网络实在太差，可以使用 <a href="https://link.zhihu.com/?target=https%3A//ruby.taobao.org/" rel="nofollow noreferrer">RubyGems 镜像</a></p><pre><code class="language-bash">gem sources --add https://gems.ruby-china.org/
gem sources --remove https://rubygems.org/
gem sources --remove http://rubygems.org/
gem sources -l
</code></pre><p>安装完成后，切换到你开发环境的项目目录下，运行：</p><pre><code class="language-bash">travis login
</code></pre><p>根据提示，输入你刚刚用于 travis-ci 网站登录的 GitHub 账户名及密码。</p><h2 id="-travis">编写测试并在项目中配置 travis</h2><p>下面我以使用 PHPUnit 对 PHP 进行测试为例对持续部署项目进行配置：</p><p>其实你用 mocha 测试 JS 什么的也是一样的。</p><pre><code class="language-php">&lt;?php
//假如你的PHP项目中并没有安装PHPUnit依赖，就像我这么写吧，不要用use关键字引入，否则在travis-ci运行时会报错
class Test extends PHPUnit_Framework_TestCase
{
    public function testAutoPass()
    {
        $this-&gt;assertEquals(
            'yubolun',
            'yubolun'
        );
    }
}
</code></pre><p>之后在你的项目根目录新建一个名为 <strong>.travis.yml </strong>的文件：</p><pre><code class="language-yaml">language: php
php:
- 5.6
before_script: composer require phpunit/phpunit
script: phpunit Test.php
</code></pre><p>前端项目也很类似：</p><pre><code class="language-yaml">language: node_js
node_js:
  - '6.9.5'
  - '7.5.0'
before_script: npm install
script: npm run test
</code></pre><p>以上只是举个例子，更多详细的配置内容请查阅<a href="https://link.zhihu.com/?target=https%3A//docs.travis-ci.com/" rel="nofollow noreferrer">官网文档</a>。</p><h2 id="-travis-">编写 travis 自动部署脚本</h2><p>做好基本的项目配置之后，我们需要配置持续部署的自动运行脚本。</p><p>首先使用 <strong>travis encrypt-file </strong>命令对你刚刚在开发环境生成的密匙进行加密（这样一来可以放心地将密匙保存在公开的开源项目当中）。</p><pre><code class="language-bash"># 此处的--add参数表示自动添加脚本到.travis.yml文件中
travis encrypt-file ~/.ssh/id_rsa --add
</code></pre><p>之后再打开 <strong>.travis.yml </strong>文件，你会看到一段类似如下内容的命令：</p><pre><code class="language-yaml">before_install:
  - openssl aes-256-cbc -K $encrypted_830d3b21a25d_key -iv $encrypted_830d3b21a25d_iv
    -in id_rsa.enc -out ~/.ssh/id_rsa -d
</code></pre><p>默认生成的命令可能会在/前面带转义符\，我们不需要这些转义符，手动删掉所有的转义符，否则可能在后面引发莫名的错误。</p><p>之后为了保证命令的顺利运行，我们还需要正确地设置权限和认证：</p><pre><code class="language-yaml">before_install:
  - openssl aes-256-cbc -K $encrypted_830d3b21a25d_key -iv $encrypted_830d3b21a25d_iv
    -in id_rsa.enc -out ~/.ssh/id_rsa -d
# 添加如下两行内容，Host后面的ip替换成你的部署服务器地址
  - chmod 600 ~/.ssh/id_rsa
  - echo -e "Host 123.123.123.123\n\tStrictHostKeyChecking no\n" &gt;&gt; ~/.ssh/config
</code></pre><p><strong>P.S. 此处的配置文件只是示例啊，不要直接复制，每次生成的加密都是不一样的。</strong></p><p>之后，也是最重要的一步，配置你执行持续部署的命令：</p><pre><code class="language-yaml">language: php
php:
- 5.6
before_install:
- openssl aes-256-cbc -K $encrypted_830d3b21a25d_key -iv $encrypted_830d3b21a25d_iv
  -in id_rsa.enc -out ~/.ssh/id_rsa -d
- chmod 600 ~/.ssh/id_rsa
- echo -e "Host 123.123.123.123\n\tStrictHostKeyChecking no\n" &gt;&gt; ~/.ssh/config
before_script: composer require phpunit/phpunit
script: phpunit Test.php
# 添加一个名为after_success的钩子，并写入你需要执行部署操作的命令
after_success:
- ssh travis@123.123.123.123 -p 12345 'cd /var/www &amp;&amp; git pull'
</code></pre><p>在这里你可以运行任意的脚本，比方说我的项目只需要把代码 pull 下来就算部署完成了，其他的例如静态博客可以 <strong>hexo g</strong>，或者是 node 应用的 <strong>pm2 startup</strong>，前端项目也可以先 <strong>webpack </strong>一下等等，别跑 <strong>rm -rf</strong>，其他的随意。</p><h2 id="--1">提交代码检验运行</h2><p>上述的步骤全都部署完成后，只需要使用git将你的所有改动提交到 GitHub 上，travis-ci 就会自动运行啦，最后别忘了登录到你的部署服务器检验一下效果袄~</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-a6160eb4a70cc923e0c9d3f32ab889b1_hd.png" class="kg-image" alt="v2-a6160eb4a70cc923e0c9d3f32ab889b1_hd" width="600" height="400" loading="lazy"></figure><p>至此大功告成，接下来你只需要愉快地写代码，提交 Git。剩下的测试、编译、部署工作全部都会自动完成啦。</p><h1 id="--2">参考资料</h1><ul><li><a href="https://link.zhihu.com/?target=https%3A//cnodejs.org/topic/5885f19c171f3bc843f6017e" rel="nofollow noreferrer">利用 travis-ci 持续部署 nodejs 应用</a></li><li><a href="https://link.zhihu.com/?target=http%3A//stackoverflow.com/questions/18490591/how-to-install-ruby-2-on-ubuntu-without-rvm" rel="nofollow noreferrer">How to install Ruby 2 on Ubuntu without RVM</a></li><li><a href="https://link.zhihu.com/?target=https%3A//www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys--2" rel="nofollow noreferrer">How To Set Up SSH Keys</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 自学前端开发：代码之外需要关注的问题 ]]>
                </title>
                <description>
                    <![CDATA[ 不要只知道蒙着头写代码，想要学习成为一名优秀的前端开发者，你还有许多代码之外值得关注的问题。 学好英语 一定要学好英语，虽然英文不好也可以学会前端。但你一定会遇到比英语好的人更多的困难。因为你只能看中文的教程和书籍，学习框架和工具只能依赖中文文档，交流问题只敢去中文社区。而前端 99% 的工具框架都是歪果仁发明的，国人发明的火起来的框架工具 Vue/FIS 等，两只手就能数的过来，并且大部分也是在国际社区里火起来的。还是英文的资源更权威丰富，甚至 Vue 的开发者尤大本人都不愿意浪费他陪老婆孩子的时间来教你学英语： 中文的学习资源虽然也足够丰富，可是质量良莠不齐。初学者根本无法分辨一个教程的好坏，甚至其中有没有错误，假如选错了学习资料，很可能就会被误导。而假如你英文好，就可以直接去看官方的教程文档，这是绝对权威可靠的。 工作中遇到的框架选型没有中文文档怎么办？遇到了某个库本身的 Bug 没有中文资料怎么办？遇到这类情况周围又没人帮你的话你会寸步难行。这时你没有挫败感么？不会觉得自己很 Low 很弱么？ 英文不好你写代码的时候甚至需要用拼音给变量命名，看不懂术语和缩写，别人给你解 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/what-you-should-know-beyond-codes-when-learning-to-code/</link>
                <guid isPermaLink="false">5d2c7ea3fbfdee429dc5ee25</guid>
                
                    <category>
                        <![CDATA[ 自学编程 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Sat, 27 Nov 2021 07:30:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/03/huper-by-joshua-earle-4yBogrmcEmM-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>不要只知道蒙着头写代码，想要学习成为一名优秀的前端开发者，你还有许多代码之外值得关注的问题。</p><h3 id="-">学好英语</h3><p>一定要学好英语，虽然英文不好也可以学会前端。但你一定会遇到比英语好的人更多的困难。因为你只能看中文的教程和书籍，学习框架和工具只能依赖中文文档，交流问题只敢去中文社区。而前端 99% 的工具框架都是歪果仁发明的，国人发明的火起来的框架工具 Vue/FIS 等，两只手就能数的过来，并且大部分也是在国际社区里火起来的。还是英文的资源更权威丰富，甚至 Vue 的开发者尤大本人都不愿意浪费他陪老婆孩子的时间来教你学英语：</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-ae0c24d81a6686db80799bfe45720107_hd.png" class="kg-image" alt="v2-ae0c24d81a6686db80799bfe45720107_hd" width="600" height="400" loading="lazy"></figure><p>中文的学习资源虽然也足够丰富，可是质量良莠不齐。初学者根本无法分辨一个教程的好坏，甚至其中有没有错误，假如选错了学习资料，很可能就会被误导。而假如你英文好，就可以直接去看官方的教程文档，这是绝对权威可靠的。</p><p>工作中遇到的框架选型没有中文文档怎么办？遇到了某个库本身的 Bug 没有中文资料怎么办？遇到这类情况周围又没人帮你的话你会寸步难行。这时你没有挫败感么？不会觉得自己很 Low 很弱么？</p><p>英文不好你写代码的时候甚至需要用拼音给变量命名，看不懂术语和缩写，别人给你解释 Java 和 JavaScript 之间的区别还需要靠周杰和周杰伦。</p><p>所以请一定学好英文，否则即使你学会了前端开发，也无法在前端开发工程师的路上走很远，很多问题你无法解决，跟不上最新的流行趋势，遇到困难都需要依靠别人，你看到的教程资源都是那些懂英文的人吃剩下的，那么你自己的技术水平也永远要屈居人下。</p><p>话说回来，前端相关的英文也并不难，高频的词汇也不会超过托福雅思。而且对于一般人来讲，你只要能看懂英文文档大意就可以了，另外和歪果仁交流其实也不是什么难事：</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-1ca0fd78449f2c9a678dd4043abccfb5_hd.png" class="kg-image" alt="v2-1ca0fd78449f2c9a678dd4043abccfb5_hd" width="600" height="400" loading="lazy"></figure><h3 id="--1">学会搜索</h3><p>你要知道这个世界上有着和你一样千千万万的前端学习者，并且每一个人都是从入门到熟悉到精通一步步走过去的。别的不敢保证，编程学习的资源在网上异常丰富，你遇到的问题 101%（多 1% 不怕你不信）绝对也有人遇到过。所以只要你善用搜索，一定可以靠自己找到问题的答案。</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-1b144a3476528f68774b97a00945d3ed_hd.png" class="kg-image" alt="v2-1b144a3476528f68774b97a00945d3ed_hd" width="600" height="400" loading="lazy"></figure><p>例如知乎上存在着大量重复的问题，而且这些问题每天都不停地在出现。很多人都选择无视搜索这一强大的功能，遇到问题连思考都不思考张嘴就问，殊不知他遇到的问题别人可能几年之前就遇到过，而且已经得到了很好的解答。</p><p>你看或不看，答案就在那里。</p><p>绝大多数人一提到搜索引擎就只知道百度，你在百度上搜个“前端开发”很有可能就此被带到培训机构的沟里去，学习效果无法保证，被坑钱是肯定的。编程类其实有相当多的优质资源都可以免费获取到，打个比方我每天免费分享给大家的学习教程，翻译的国外文章，完全也可以拿着它们去当每月10k学费的培训班教材。</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-70c102be1adf773c6b231d2b82efc2f3_hd.png" class="kg-image" alt="v2-70c102be1adf773c6b231d2b82efc2f3_hd" width="600" height="400" loading="lazy"></figure><p>至于具体怎么用，正好锻炼一下，用你的百度去搜吧。</p><p>当然也有可能你虽然烦百度的广告，可是又离不开它，我再附送一个百度去广告大礼包，下面这个回答里有百度去广告版本的 Chrome，也有可以直接安装的插件链接：</p><p><a href="https://www.zhihu.com/question/19823250/answer/131195823">百度搜索有那么多缺点，大家为什么还要用呢？ - 余博伦的回答 - 知乎</a><br></p><p>如何输入搜索关键词？学习知乎体其实有非常大的帮助，例如</p><ul><li>如何学习前端开发?</li><li>学习前端开发是一种什么样的体验？</li><li>前端开发工程师月薪十万难么？（此为恶搞）</li></ul><p>搜索诸如此类的问题，你可以找到大量优质的答案。此时此刻我又忍不住要分享一点点干货，除了搜索引擎之外，你还可以在别的优质站点搜索：</p><ul><li><a href="https://www.zhihu.com/">知乎</a></li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/" rel="nofollow noreferrer">GitHub</a> （不用担心网站是英文的，你完全可以直接搜索中文）</li><li>S<a href="https://link.zhihu.com/?target=https%3A//segmentfault.com/" rel="nofollow noreferrer">egmentfault</a> （中文版 Stack OverFlow）</li><li><a href="https://link.zhihu.com/?target=http%3A//www.uisdc.com/" rel="nofollow noreferrer">优设</a></li></ul><h3 id="--2">学会提问</h3><p>学习一门技术的过程中，我们免不了有拜师学艺的想法。知乎优秀回答者啊，前端大神啊，或者是一个学校的师兄师姐，搞开发的同学等等。</p><p>作为一名小萌新你就像个好奇宝宝，你满脑子都是各种各样的问题，遇到见过的没见过的都想随口问一句。殊不知可爱的好奇宝宝和烦人的熊孩子之间没有什么不可逾越的鸿沟。</p><p>如何提问？如何能够让人愿意解答你的问题？如何不烦人？</p><p>这就需要你运用到各种提问的技巧。首先请教问题，心一定要诚，知乎上有一种关闭问题的原因叫做“代为完成的个人任务”。你不能把自己遇到的所有问题都当成是别人的问题提出来，人首先要靠自己，在自己靠不住的情况下再寻求别人的帮助。</p><p>在你真正需要提出一个可以提的问题时，也需要真诚。你不能不假思索地随便写一个疑问句。</p><p>举个实际的例子，你在项目中遇到了一个实现轮播图组件的需求，你不知道JS该怎么写。你不能像一个乞丐一样提问说：</p><p>轮播图组件该如何实现？（求求各位大大行行好帮我写个轮播图的吧）</p><p>然后问题描述是空的，就好像拿着一个空碗一样等人施舍。</p><p>你应该抱着探讨的态度虚心求教，并且善用一些语言的技巧，最后附上自己对这个问题的初步思考，例如：</p><p>轮播图组件的实现有哪些方式？</p><p>问题描述：下面是我初步实现的一些代码，可能还有一些bug，我也试着在网上找过相关的组件了，可是搞不清哪种才是最优的方案，还望各位大大能够指点一二。</p><p>这样一看你的档次就高了起来，你不是求别人告诉你，而是和别人平等地探讨问题。这样回答你的人也可以拥有一个更平和的心态，让他觉得他的回答不是施舍赐予，而是平等的学术讨论。你也就能获得更具价值的答案。</p><p>其实关于如何提问，有一篇2001年的文章已经回答得非常好了。在这里分享给大家，与诸君共勉：</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.dianbo.org/9238/stone/tiwendezhihui.htm" rel="nofollow noreferrer">提问的智慧</a></li></ul><h2 id="--3">学习方式</h2><p>很多新手学编程都喜欢看视频，每次看完都似乎仿佛好像可能理解里面讲的是什么了。回头你让他写代码，他一行都写不下去。</p><p>学习习惯比较好的可能会选择看书或者读文档。在这里我有必要声明一下，即使纸质文本和视频讲解的是完全相同的内容，学习文字也要比视频的效果好很多。</p><p>看书是主动学习，看视频是被动学习。主动翻页和视频进度条自己走（只有人拖条看A片，没有人拖条看教程）是完全不同的两种效果。你可以自主把握获取知识的速度和节奏。</p><p>当然我也不是说完全摒弃看视频的学习方式，从视频中你也可以获取到文档书本中获取不到的信息。例如别人是如何写代码以及遇到问题时是如何思考的，另外可能就是治你不愿意主动学习的懒病。</p><p>现在还有相当一部分人喜欢通过订阅知识分享平台来学习，例如知乎/掘金/开发者头条/简书等等。不可否认的是你确实可以从中获取相当丰富的知识，可惜大多数人从来都是看题目点收藏，根本不读内容，更别说在读完之后点个赞了。而且事实上你在这些知识分享平台获得的也是碎片化的信息，本质上和你刷微博朋友圈没有任何区别，只是逼格高一点点罢了。</p><p>就像你正在读我写的这篇文章一样，你确实能学到点东西，可只适用于茶余饭后的消遣。它不足以支撑你系统掌握一门技术。</p><p>所以想要真正扎实掌握前端知识体系，必须去读书，看文档，辅以看视频、刷知乎等等。千万不能本末倒置。</p><h2 id="--4">动手实践</h2><p>其实动手实践也应该包含在学习方法里，它的意义是如此重要，所以我把动手实践专门划分在一个段落里。上述的主要是理论知识的学习，而我们要认清编程本质上是一门技术，一门手艺（我当然承认编程其实是一门艺术）。一定要能够动手做出实际的东西，写下一行行代码才算你真正掌握。</p><p>否则你只能拿着书里学到的那些名词术语装装逼而已。在交流群里胡侃半天，结果别人问你造过什么轮子，开发过什么项目你就傻眼了。现在前端岗位招聘动不动要求两年三年经验，你要上哪里找去？</p><ul><li>f<a href="www.freecodecamp.orghttps://chinese.freecodecamp.org/">reeCodeCamp 中文网</a></li><li><a href="https://link.zhihu.com/?target=http%3A//ife.baidu.com/task/all" rel="nofollow noreferrer">百度前端技术学院开发任务</a></li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/phodal/ideabook" rel="nofollow noreferrer">一个全栈增长工程师的练手项目集</a></li></ul><p>一定要有自己的个人项目，一定要写自己的技术笔记，有条件也可以为开源项目做贡献。</p><p>只看书没有任何用，光看视频也然并卵。</p><p>一定要不停地实践实践实践！</p><p>一个只实践不看书的有可能会成为一位大神（在实践中就能学会很多），但一个只看书不实践的只能成为一个喷子。</p><p>一定要记住：</p><p><strong>学而不练则忘。</strong></p><h3 id="--5">认清就业现状</h3><p>前几年可能还好，现在所有人都知道前端工资高。互联网泡沫没破的时候，应届毕业生第一次定岗就有能拿 20k 的，这都是真实发生过的事情。可就像你买彩票几乎不中奖一样，你从来不能把未来寄托在幸运之上，你需要有与之相匹配的实力。否则你即使遇到瞎了眼的面试官能拿到 Offter，在正式的工作中你也没能力保住岗位。</p><p>现在所有人都意识到了互联网行业赚钱，有点技术梦想的，不甘现实蹉跎的都想要通过学前端找到高薪工作。学法的学医的学会计的送快递的挖矿的，感觉 360 行有 361 行（多一行不怕你不信）都想转前端。</p><p>前端的工作机会确实多，需求量也确实大。可也得分清场合地域。</p><p>应聘难度从易到难为：</p><p>非互联网公司但有 Web 开发需求的&lt;互联网小型创业公司&lt;知名网站、应用&lt;BAT</p><p>待遇薪资当然也是一样的序列。所以你需要认清自己的目标，找准自己的位置。最底层的页面仔工资真的还不如一个送外卖的，但与此同时，当然也有能让你实现财务自由的岗位。</p><h3 id="--6">坚持不懈&amp;当断则断</h3><p>学习可以很愉快但从来都不是一件轻松的事情。程序员的进阶之路尤其如此，就像你知道山口山升级的那一声是如此清脆响亮余音绕梁，但那需要你刷多少本，杀多少怪才能听到那么一声一样。</p><p>你学习的计划和安排可以很明确，但这并不代表它很简单就能实现。你会遇到无数的挫折，你需要解决无数的 Bug，你更需要无数的练习，才能达到你期望的目标。</p><p>你可以找一份码农的工作锻炼自己，但这仅仅是锻炼，你不可能当一辈子码农。</p><p>如果你真的喜欢编程，喜欢前端，那么在你写下每一行代码的时候一定能体验到那种快感。而如果每一篇教程都让你难以理解，每一行代码都让你痛苦不堪，千万不要强迫自己。</p><p>因为你可能并不适合编程。改变命运的方式不止这一种，高薪的岗位也不止这一家。条条大路通罗马，人要对自己好一点，如果发现自己真的不适合，那就早一点放弃，节省下的时间还可以用来实现你生命中的其他奇迹。</p><p>但假如你真的热爱编程，喜欢前端，无论前路多么坎坷，请你一定坚持下去！</p><h2 id="qa">Q&amp;A</h2><p><strong>Q: 看完了前端的编程书籍，看的时候感觉理解了，可是写代码的时候还是没有任何长进怎么办？</strong></p><p>其实一些比较经典的推荐书籍安排都很好，每个讲解的知识点都有相应的代码实现。请你不要只是看过去，看书的时候打开你的电脑，把每一个示例都敲一遍。读完一个章节之后也试着用代码写写每一章的知识点，相信你会有一个不一样的体验的。</p><p><strong>Q: 学习前端需要了解算法和数据结构么？</strong></p><p>算法和数据结构一般都是面试的时候装逼用的，也可以在程序员之间相互吹逼时使用。但无论如何作为一名合格的前端在面试的时候拿 JS 写个快速排序还是应该做到的。在实际工作中一般运用不到什么算法和数据结构的高级知识，等到你真正有机会用到的时候，你自然也成长到那一步了。</p><p><strong>Q: 为什么要熟悉原生 JS，我 jQuery 用得很溜不可以么?</strong></p><p>不是所有技术栈都包含jQuery，jQuery虽然适用于很多场景，但并不是万能的。你不能把自己的技术实现全部都建立在一个别人开发出来的库上，那样你只是会用一个工具，而不是懂一门编程语言。</p><p>太过于依赖 jQuery 别人只敢让你去写业务实现，而技术选型一类更高层次的活你根本都没资格接触。</p><p><strong>Q: 非计算机专业想要学习前端开发从哪里开始？报培训班靠谱么？</strong></p><p>现在国内哪所大学有专门教前端的专业？前端从业者大部分都不是科班出身好么，计算机专业的都去搞数据分析和机器学习了，怎么稀得做前端开发这么 LOW 的工作（此处为自嘲）。所以有千千万万的前端开发从业者和前端入门学习者和你是一样的，不要以为自己是什么特殊群体，保持一颗平常心。</p><p>培训班也相当于是一种被动学习，并不是说报培训班没有一点作用，只是大多数情况下你报班只会得不偿失。自制力好的人不需要报班通过自学也能小有所成，而懒惰的人即使培训班毕业了也找不到工作。</p><p>培训即使有效果，高昂的学费也是把你钱的坑了。我免费分享给你这么多教程，你连个赞都不点，我从来和你要过钱么？</p><p><strong>Q: 我正在学习前端开发，想要早一点找到相关工作怎么办？</strong></p><p>那么你就先去找工作，看工作的职位描述对你的技术有什么需求，根据你目标岗位的技术需求来学习。我们拿拉勾网的前端开发技术要求来举一个具体的例子：</p><ul><li>熟练掌握 HTML5、CSS3、JavaScript 开发</li><li>这一条表示你要有扎实的 HTML5/CSS3/JavaScript 基础</li><li>熟悉 W3C 标准与 ES 规范，熟悉 Web 语义化</li><li>你需要了解一些 Web 相关标准</li><li>熟练掌握盒模型、常用布局以及浏览器和移动设备兼容性</li><li>能够熟练使用 CSS 构建页面，能够处理好各类屏幕大小设备的兼容性</li><li>熟练使用至少一种 JS 框架，掌握其原理，能独立开发常用组件</li><li>熟悉 Angular/React 一类的框架，并且用这类框架开发过成型的项目</li><li>熟练使用各种调试、抓包工具，能独立分析、解决和归纳问题</li><li>熟练掌握 Chrome 调试工具一类应用软件的使用</li><li>具有至少一门服务器端编程的实战经验</li><li>你得会 Python/PHP/Node.js 一类的服务器端语言，并且能够独立搭建起 Web 应用的运行环境</li><li>具有性能优化经验</li><li>了解客户端/服务器端缓存，CSS/JS 代码优化一类的性能方面知识</li><li>熟悉各种常用设计模式和常用 MV*框架</li><li>了解掌握设计模式和 Angular/React 等框架</li></ul><p>然后再根据每一条要求去学习相关的知识，准备相应的实践项目。准备好就去面试吧，如果面不到就再回来继续好好学，千万不要急功近利。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ JavaScript 模块化入门 Ⅱ：模块打包构建 ]]>
                </title>
                <description>
                    <![CDATA[ 在上一篇教程 [https://chinese.freecodecamp.org/news/javascript-modules-a-beginner-guide/] 里我们已经讨论过什么是模块，为什么要使用模块以及多种实现模块化的方式。 这次，我们会聊一聊什么是模块打包，为什么要打包模块，模块打包的方式工具，还有它当前在 Web 开发中的运用。 什么是模块打包？ 粗俗一点来讲，模块打包就是把一小坨一小坨的代码粘成一大坨。 实际操作起来的时候当然还需要关注一些细节。 为什么要打包模块？ 一般来讲，我们用模块化组织代码的时候，都会把模块划分在不同的文件和文件夹里，也可能会包含一些诸如 React 和 Underscore 一类的第三方库。 而后，所有的这些模块都需要通过<script>标签引入到你的 HTML 文件中，然后用户在访问你网页的时候它才能正常显示和工作。每个独立的<script>标签都意味着，它们要被浏览器分别一个个地加载。 这就有可能导致页面载入时间过长。 为了解决这个问题，我们就需要进行模块打包，把所有的模块合并到一个或几个文件中，以此来减少 HTTP 请求 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/javascript-modules-part-2-module-bundling/</link>
                <guid isPermaLink="false">5d3a9a8dfbfdee429dc5f392</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Mon, 15 Nov 2021 06:20:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/v2-0e892f7f3142809a1229a0ad46130f9e_1200x500.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>在<a href="https://chinese.freecodecamp.org/news/javascript-modules-a-beginner-guide/">上一篇教程</a>里我们已经讨论过什么是模块，为什么要使用模块以及多种实现模块化的方式。</p><p>这次，我们会聊一聊什么是模块打包，为什么要打包模块，模块打包的方式工具，还有它当前在 Web 开发中的运用。</p><h3 id="-">什么是模块打包？</h3><p>粗俗一点来讲，模块打包就是把一小坨一小坨的代码粘成一大坨。</p><p>实际操作起来的时候当然还需要关注一些细节。</p><h3 id="--1">为什么要打包模块？</h3><p>一般来讲，我们用模块化组织代码的时候，都会把模块划分在不同的文件和文件夹里，也可能会包含一些诸如 React 和 Underscore 一类的第三方库。</p><p>而后，所有的这些模块都需要通过&lt;script&gt;标签引入到你的 HTML 文件中，然后用户在访问你网页的时候它才能正常显示和工作。每个独立的&lt;script&gt;标签都意味着，它们要被浏览器分别一个个地加载。</p><p>这就有可能导致页面载入时间过长。</p><p>为了解决这个问题，我们就需要进行模块打包，把所有的模块合并到一个或几个文件中，以此来减少 HTTP 请求数。这也可以被称作是从开发到上线前的构建环节。</p><p>还有一种提升加载速度的做法叫做代码压缩（混淆）。其实就是去除代码中不必要的空格、注释、换行符一类的字符，来保证在不影响代码正常工作的情况下压缩其体积。</p><p>更小的文件体积也就意味着更短的加载时间。要是你仔细对比过带有 .min 后缀的例如 &nbsp;jquery.min.js 和 jquery.js 的话，应该会发现压缩版的文件相较之下要小很多。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-60a0bef5aeb7549f5849bbcf32c0d80e_hd.png" class="kg-image" alt="v2-60a0bef5aeb7549f5849bbcf32c0d80e_hd" width="340" height="77" loading="lazy"></figure><p>Gulp 和 Grunt 一类的构建工具可以很方便地解决上述的需求，在开发的时候通过模块来组织代码，上线时再合并压缩提供给浏览器。</p><h3 id="--2">打包模块的方法有哪些？</h3><p>如果你的代码是通过之前介绍过的模块模式来组织的，合并和压缩它们其实就只是把一些原生的 JS 代码合在一起而已。</p><p>但如果你使用的是一些浏览器原生不支持的模块系统（例如 CommonJS 或 AMD，以及 ES6 模块的支持现在也不完整），你就需要使用一些专门的构建工具来把它们转换成浏览器支持的代码。这类工具就是我们最近经常听说的 Browserify, RequireJS, Webpack 等等模块化构建、模块化加载工具了。</p><p>为了实现模块化构建或载入的功能，这类工具提供许多诸如在你改动源代码后自动重新构建（文件监听）等一系列的功能。</p><p>下面我们就一起来看一些实际的例子吧：</p><h3 id="-commonjs">打包 CommonJS</h3><p>在上一篇教程中我们了解到， CommonJS 是同步载入模块的，这对浏览器来说不是很理想。其实下面介绍的模块化构建工具 Browserify 在上一篇也提到过。它是一个专门用来打包 CommonJS 模块以便在浏览器里运行的构建工具。</p><p>举个例子，假如你在 main.js 文件中引入了一个用来计算平均数的功能模块：</p><pre><code class="language-js">var myDependency = require('myDependency');

var myGrades = [93, 95, 88, 0, 91];

var myAverageGrade = myDependency.average(myGrades);
</code></pre><p>在这个示例中，我们只有一个名为 myDependency 的模块依赖。通过下面的命令， Browserify 会依次把 main.js 里引入的所有模块一同打包到一个名为 bundle.js 的文件里：</p><pre><code class="language-bash">browserify main.js -o bundle.js
</code></pre><p>Browserify 首先会通过抽象语法树（<a href="https://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Abstract_syntax_tree" rel="nofollow noreferrer">AST</a>）来解析代码中的每一个 require 语句，在分析完所有模块的依赖和结构之后，就会把所有的代码合并到一个文件中。然后你在 HTML 文件里引入一个 bundle.js 就够啦。</p><p>多个文件和多个依赖也只需要再稍微配置一下就能正常工作了。</p><p>之后你也可以使用一些例如 Minify-JS 的工具来压缩代码。</p><h3 id="-amd">打包 AMD</h3><p>假若你使用的是 AMD，你会需要一些例如 RequireJS 或 Curl 的 AMD 加载器。模块化加载工具可以在你的应用中按需加载模块代码。</p><p>需要再次提醒一下，AMD 和 CommonJS 的最主要区别是 AMD 是异步加载模块的。这也就意味着你不是必须把所有的代码打包到一个文件里，模块加载不影响后续语句执行，逐步加载的的模块也不会导致页面阻塞无法响应。</p><p>不过在实际应用中，为了避免用户过多的请求对服务器造成压力。大多数的开发者还是选择用 RequireJS optimizer, <a href="https://link.zhihu.com/?target=http%3A//requirejs.org/docs/optimization.html" rel="nofollow noreferrer">r.js</a> 一类的构建工具来合并和压缩 AMD 的模块。</p><p>总的来说，AMD 和 CommonJS 在构建中最大的区别是，在开发过程中，采用 AMD 的应用直到正式上线发布之前都不需要构建。</p><p>要是你对 CommonJS vs. AMD 的讨论感兴趣，可以看这一篇 <a href="https://link.zhihu.com/?target=http%3A//tomdale.net/2012/01/amd-is-not-the-answer/" rel="nofollow noreferrer">AMD is Not the Answer</a></p><h3 id="webpack">Webpack</h3><p>Webpack 是新推出的构建工具里最受欢迎的。它兼容 CommonJS, AMD, ES6 各类规范。</p><p>也许你会质疑，我们已经有这么多诸如 Browserify 或 RequireJS 的工具了，为什么还需要 Webpack 呢？究其原因之一，Webpack 提供许多例如 code splitting（代码分割） 的有用功能，它可以把你的代码分割成一个个的 chunk 然后按需加载优化性能。</p><p>举个例子，要是你的 Web 应用中的一些代码只在很少的情况下才会被用到，把它们全都打包到一个文件里是很低效的做法。所以我们就需要 code splitting 这样的功能来实现按需加载。而不是把那些很少人才会用到的代码一股脑儿全都下载到客户端去。</p><p>code splitting 只是 Webpack 提供的众多强大功能之一。当然，网上也为这些模块化构建工具吵得不可开交。你要是感兴趣的话也可以在下面这些地方观摩一下：</p><ul><li><a href="https://link.zhihu.com/?target=https%3A//gist.github.com/substack/68f8d502be42d5cd4942" rel="nofollow noreferrer">https://gist.github.com/substack/68f8d502be42d5cd4942</a></li><li><a href="https://link.zhihu.com/?target=http%3A//mattdesl.svbtle.com/browserify-vs-webpack" rel="nofollow noreferrer">Browserify vs. Webpack</a></li><li><a href="https://link.zhihu.com/?target=http%3A//blog.namangoel.com/browserify-vs-webpack-js-drama" rel="nofollow noreferrer">Browserify VS Webpack</a></li></ul><h3 id="es6-">ES6 模块</h3><p>看他们吵够了的话，接下来我就要介绍一下 &nbsp;ES6模块了。假如你采用 ES6 模块，在不远的将来对那些构建工具的需求可能会小一些。首先我们还是看看 ES6 模块是怎么加载的吧。</p><p>ES6 模块和 CommonJS, AMD 一类规范最主要的区别是，当你载入一个模块时，载入的操作实际实在编译时执行的——也就是在代码执行之前。所以去掉那些不必要的 exports 导出语句可以优化我们应用的性能。</p><p>有一个经常会被问到的问题：去除 exports 和冗余代码消除（UglifyJS 一类工具执行后的效果）之间有什么区别？</p><p>答案是这个要具体情况具体分析，感兴趣的话可以上 GitHub 看这个 Repo：<a href="https://link.zhihu.com/?target=https%3A//github.com/rollup/rollup" rel="nofollow noreferrer">Rollup’s wiki</a></p><p>让 ES6 模块与冗余代码消除（Dead code elimination）不同的是一种叫做 tree shaking 的技术。Tree shaking 其实恰好是冗余代码消除的反向操作。它只加载你需要调用的代码，而不是删掉不会被执行的代码。我们还是用一个具体的例子说明吧：</p><p>假设我们有如下一个使用 ES6 语法，名为 utils.js 的函数：</p><pre><code class="language-js">export function each(collection, iterator) {
  if (Array.isArray(collection)) {
    for (var i = 0; i &lt; collection.length; i++) {
      iterator(collection[i], i, collection);
    }
  } else {
    for (var key in collection) {
      iterator(collection[key], key, collection);
    }
  }
 }

export function filter(collection, test) {
  var filtered = [];
  each(collection, function(item) {
    if (test(item)) {
      filtered.push(item);
    }
  });
  return filtered;
}

export function map(collection, iterator) {
  var mapped = [];
  each(collection, function(value, key, collection) {
    mapped.push(iterator(value));
  });
  return mapped;
}

export function reduce(collection, iterator, accumulator) {
    var startingValueMissing = accumulator === undefined;

    each(collection, function(item) {
      if(startingValueMissing) {
        accumulator = item;
        startingValueMissing = false;
      } else {
        accumulator = iterator(accumulator, item);
      }
    });

    return accumulator;
}
</code></pre><p>现在我们也不清楚到底需要这个函数的哪些功能，所以先全部引入到 main.js 中：</p><pre><code class="language-js">//main.js
import * as Utils from './utils.js';
</code></pre><p>之后我们再调用一下 each 函数：</p><pre><code class="language-js">//main.js
import * as Utils from './utils.js';

Utils.each([1, 2, 3], function(x) { console.log(x) });
</code></pre><p>通过 "tree shaken" 之后的 main.js 看起来就像下面这样：</p><pre><code class="language-text">//treeshake.js 
function each(collection, iterator) {
  if (Array.isArray(collection)) {
    for (var i = 0; i &lt; collection.length; i++) {
      iterator(collection[i], i, collection);
    }
  } else {
    for (var key in collection) {
      iterator(collection[key], key, collection);
    }
  }
 };

each([1, 2, 3], function(x) { console.log(x) });
</code></pre><p>注意到这里只导出了我们调用过的 each 方法。</p><p>再如果我们只调用 filter 方法的话：</p><pre><code class="language-js">//main.js
import * as Utils from './utils.js';

Utils.filter([1, 2, 3], function(x) { return x === 2 });
</code></pre><p>"Tree shaken" 之后就会变成这样：</p><pre><code class="language-js">function each(collection, iterator) {
  if (Array.isArray(collection)) {
    for (var i = 0; i &lt; collection.length; i++) {
      iterator(collection[i], i, collection);
    }
  } else {
    for (var key in collection) {
      iterator(collection[key], key, collection);
    }
  }
 };

function filter(collection, test) {
  var filtered = [];
  //注意在filter中调用了each，所以两个方法都会被引入
  each(collection, function(item) {
    if (test(item)) {
      filtered.push(item);
    }
  });
  return filtered;
};

filter([1, 2, 3], function(x) { return x === 2 });
</code></pre><p>很神奇不是么？</p><p>你也可以自己在 Rollup.js 的实时预览编辑器里做做试验：<a href="https://link.zhihu.com/?target=http%3A//rollupjs.org/" rel="nofollow noreferrer">live demo and editor</a></p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-c15de2bbc52eff93e1cceac5598b8f8a_hd.png" class="kg-image" alt="v2-c15de2bbc52eff93e1cceac5598b8f8a_hd" width="720" height="501" loading="lazy"></figure><h3 id="-es6-">构建 ES6 模块</h3><p>现在我们已经了解到 ES6 模块载入的与众不同了，但我们还没有聊到底该怎么构建 ES6 模块。</p><p>因为浏览器对 ES6 模块的原生支持还不够完善，所以现阶段还需要我们做一些补充工作。</p><p>让 ES6 模块在浏览器中顺利运行的常用方法有以下几种：</p><p>1.使用语法编译器（Babel 或 Traceur）来把ES6语法的代码编译成 ES5 或者 CommonJS, AMD, UMD 等其他形式。然后再通过 Browserify 或 Webpack 一类的构建工具来进行构建。</p><p>2.使用 <a href="https://link.zhihu.com/?target=http%3A//rollupjs.org/" rel="nofollow noreferrer">Rollup.js</a>，这其实和上面差不多，只是 Rollup 还会捎带的利用“tree shaking”技术来优化你的代码。在构建 ES6 模块时 Rollup 优于 Browserify 或 Webpack 的也正是这一点，它打包出来的文件体积会更小。Rollup 也可以把你的代码转换成包括 ES6, CommonJS, AMD, UMD, IIFE 在内的各种格式。其中 IIFE 和 UMD 可以直接在浏览器里运行，AMD, CommonJS, ES6 等还需要你通过 Browserify, Webpack, RequireJS 一类的工具才能在浏览器中使用。</p><h3 id="--3">小心踩坑</h3><p>这里有一些坑还需要和大家说明一下。转换语法优雅的 ES6 代码以便在浏览器里运行并不是一件令人舒爽的事情。</p><p>问题在于，什么时候我们才能免去这些多余的工作。</p><p>令人感动的答案是：“差不多快了。”</p><p>ECMAScript 目前包含一个名为 <a href="https://link.zhihu.com/?target=https%3A//github.com/ModuleLoader/es6-module-loader" rel="nofollow noreferrer">ECMAScript 6 module loader API</a> 的解决方案。简单来讲，这个解决方案允许你动态加载模块并缓存。还是来举例说明：</p><p><strong>myModule.js</strong></p><pre><code class="language-js">export class myModule {
  constructor() {
    console.log('Hello, I am a module');
  }

  hello() {
    console.log('hello!');
  }

  goodbye() {
    console.log('goodbye!');
  }
}
</code></pre><p><strong>main.js</strong></p><pre><code class="language-js">System.import('myModule').then(function(myModule) {
  new myModule.hello();
});

// ‘Hello!, I am a module!’
</code></pre><p>同样，你可以在 script 标签上设置 type=module 的属性来直接定义模块：</p><pre><code class="language-html">&lt;script type="module"&gt;
  // loads the 'myModule' export from 'mymodule.js'
  import { hello } from 'mymodule';
  new Hello(); // 'Hello, I am a module!'
&lt;/script&gt;
</code></pre><p>更加详细的介绍也可以在 GitHub上查看：<a href="https://link.zhihu.com/?target=https%3A//github.com/ModuleLoader/es6-module-loader" rel="nofollow noreferrer">es6-module-loader</a>。</p><p>如果你现在就想测试这个解决方案的话，我在这里也安利一下 <a href="https://link.zhihu.com/?target=https%3A//github.com/systemjs/systemjs" rel="nofollow noreferrer">SystemJS</a>. SystemJS 支持在浏览器端和Node动态加载之前介绍过所有格式的模块（ES6 modules, AMD, CommonJS 等），通过把已加载的模块还存在"module registry"里来避免重复加载。它也同样支持转换 ES6 的代码至其他格式。</p><h3 id="-es6--1">我们已经有了原生 ES6 模块，还需要那些乱七八糟的玩意儿么？</h3><p>越来越多的人使用 ES6 模块产生了一些有趣的影响：</p><p><strong>HTTP/2 出现之后，模块化构建工具是不是都该被淘汰了？</strong></p><p>在 HTTP/1 中，一次 TCP 连接只允许一个请求，所以我们需要通过减少载入的文件数来优化性能。而 HTTP/2 改变了这一切，请求和响应可以并行，一次连接也允许多个请求。</p><p>每次请求的消耗也会远远小于 HTTP/1，所以载入一堆模块就不再是一个影响性能的问题了。所以许多人认为打包模块完全就是多余的了。这听起来很合理，但我们也需要具体情况具体分析。</p><p>其中有一条，模块化构建解决了一些 HTTP/2 解决不了的问题。例如去除冗余的代码以压缩体积。要是你开发的是一个对性能要求很高的网站，模块化构建从长远上考虑会给你带来更多好处。当然，要是你不那么在意性能问题，以后完全就可以省却这些烦人的步骤了。</p><p>总之，我们离所有的网站都采用 HTTP/2 传输还有相当一段时间。短期内模块化构建还是很有必要的。</p><p>要是你对 HTTP/2 的其他特性也感兴趣，可以查阅这里：<a href="https://link.zhihu.com/?target=https%3A//http2.github.io/faq/%23what-are-the-key-differences-to-http1x" rel="nofollow noreferrer">HTTP/2</a></p><p><strong>CommonJS , AMD, UMD 这类标准会过时么？</strong></p><p>一旦 ES6 成为了模块化的标准，我们还需要这些非原生的东西么？</p><p>这点还值得商榷。</p><p>在 JavaScript 中采用统一标准，通过 import 和 export 来使用模块，省略所有繁杂的多余步骤确实很爽。不过到底要多久 ES6 才能成为真正的模块化标准呢？</p><p>反正不会很快。</p><p>并且开发者也有各自的偏好，“唯一的解决方案”永远也不会存在。</p><h2 id="--4">总结</h2><p>我希望这两篇文章对于你理解 JS 模块有所帮助，要是你忘了之前聊过的内容，可以现在点开再看看：</p><p><a href="https://chinese.freecodecamp.org/news/javascript-modules-a-beginner-guide/">JavaScript 模块化入门 Ⅰ：理解模块</a></p><p>有任何问题和建议也欢迎在评论区讨论。</p><p>原文链接：<a href="https://www.freecodecamp.org/news/javascript-modules-part-2-module-bundling-5020383cf306/">JavaScript Modules Part 2: Module Bundling</a>，作者：Preethi Kasireddy</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 掌握这 5 大核心概念，你就理解了 React ]]>
                </title>
                <description>
                    <![CDATA[ 几年前，我的一个朋友向我吹捧有个叫做 React 的框架会如何革新 Web 开发。其实一开始我觉得它只是又一个昙花一现的框架罢了。可在之后的时间里，React 名声鹊起，逐渐变得不容小觑了。 也许你和我之前的状况差不多：总是听到 React 这儿好那儿爽，可是真正坐下来学习 React 的时候又毫无头绪。 好消息是我在这里替你总结了，其实 React 只有“五大核心概念”。 不过也请不要误会我的意思，并不是说我一篇文章就能能让你摇身一变成为精通 React 的大神，但如果你打算或者正在学习 React 的话，我至少能帮你理清思路。 现在揭晓这五大核心概念：  1. 组件  2. JSX  3. Props & State  4. 组件 API  5. 组件类型 概念一：React 组件的作用 你需要了解有关 React 的第一要点就是——组件。你编写的所有 React 代码基本上就是一个包含许多小组件在内的大组件。 那么到底什么是组件呢？我们可以拿 HTML 标签 <select> 来举一个很恰当的例子。原生的下拉框标签不止包括边框、文本、下拉箭头，它还掌控着自身打开关闭 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/the-5-things-you-need-to-know-to-understand-react/</link>
                <guid isPermaLink="false">5d3838d5fbfdee429dc5f210</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Tue, 02 Nov 2021 07:20:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/v2-1f16105426dfc07c064857af2d358c00_1200x500.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>几年前，我的一个朋友向我吹捧有个叫做 React 的框架会如何革新 Web 开发。其实一开始我觉得它只是又一个昙花一现的框架罢了。可在之后的时间里，React 名声鹊起，逐渐变得不容小觑了。</p><p>也许你和我之前的状况差不多：总是听到 React 这儿好那儿爽，可是真正坐下来学习 React 的时候又毫无头绪。</p><p>好消息是我在这里替你总结了，其实 React 只有“五大核心概念”。</p><p>不过也请不要误会我的意思，并不是说我一篇文章就能能让你摇身一变成为精通 React 的大神，但如果你打算或者正在学习 React 的话，我至少能帮你理清思路。</p><p>现在揭晓这五大核心概念：</p><ol><li>组件</li><li>JSX</li><li>Props &amp; State</li><li>组件 API</li><li>组件类型</li></ol><h2 id="-react-">概念一：React 组件的作用</h2><p>你需要了解有关 React 的第一要点就是——组件。你编写的所有 React 代码基本上就是一个包含许多小组件在内的大组件。</p><p>那么到底什么是组件呢？我们可以拿 HTML 标签 &lt;select&gt; 来举一个很恰当的例子。原生的下拉框标签不止包括边框、文本、下拉箭头，它还掌控着自身打开关闭的逻辑。</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-102bc8ac17757b77bdbe5424f29e4f3f_hd.jpg" class="kg-image" alt="v2-102bc8ac17757b77bdbe5424f29e4f3f_hd" width="709" height="315" loading="lazy"></figure><p>现在来设想一下你需要构建一个你自定义样式和行为逻辑的 &lt;select&gt;：</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-1204cbae35260b137352c7c28d101adf_hd.jpg" class="kg-image" alt="v2-1204cbae35260b137352c7c28d101adf_hd" width="622" height="468" loading="lazy"></figure><p>这其实就是 React 能够帮你做到的。<strong>React 组件能够像原生的 HTML 标签一样输出特定的界面元素，并且也能包括一些元素相关逻辑功能的代码。</strong></p><p>现在我们一般会用 ES6 的 Class 语法来声明一个 React 组件，它包含一个能够返回 HTML 的 render 方法。（当然也可以用函数声明，我们在之后会聊到）</p><pre><code class="language-js">class MyComponent extends React.Component {
  render() {
    return &lt;p&gt;Hello World!&lt;p&gt;;
  }
}
</code></pre><h2 id="-jsx-">概念二：JSX 是什么玩意儿？</h2><p>是的你没看错，按照上面 React 组件的示例代码，React 的意思就是让我们把 HTML 和 JS 代码全都写在一起。React 是通过一种叫做JSX的语法扩展（X 代表 XML）来实现的。</p><p>JSX 乍看起来可能很奇怪，不过你慢慢会习惯的。</p><p>是的我知道，按照我们以往的传统，应该尽量把 HTML 和 JavaScript 的代码分开才是。不过看样子现在忘记这教条才是提高你前端开发效率的正道。</p><p>我们还是来举几个 JSX 实际应用的例子吧，比如你可以通过 {} 大括号来在 JSX 中显示 JS 变量：</p><pre><code class="language-text">class MyComponent extends React.Component {
  render() {
    return &lt;p&gt;Today is: {new Date()}&lt;/p&gt;;
  }
}
</code></pre><p>你不再需要什么前端模板标签之类的东西了，你可以直接在 JSX 中使用三元运算符一类的逻辑：</p><pre><code class="language-js">class MyComponent extends React.Component {
  render() {
    return &lt;p&gt;Hello {this.props.someVar ?  'World' : 'Kitty'}&lt;/p&gt;;
  }
}
</code></pre><p>顺便提一句，可能你现在对 ES6 还不是特别的了解，那么我推荐你去看看阮老师的<a href="https://link.zhihu.com/?target=http%3A//es6.ruanyifeng.com/" rel="nofollow noreferrer">ECMAScript 6 入门</a>。</p><h2 id="-props-state-">概念三：Props &amp; State 又是啥？</h2><p>你可能会疑惑上个例子里的 this.props.someVar 是从哪里冒出来的。</p><p>只要你对 HTML 有所了解，应该能够理解 &lt;a&gt; 标签的 href 属性是什么意思。延伸到 React 当中，属性就被称作 props（properties 的缩写）。组件之间可以通过 Props 进行交互。</p><pre><code class="language-js">class ParentComponent extends React.Component {
  render() {
    return &lt;ChildComponent message="Hello World"/&gt;;
  }
}
class ChildComponent extends React.Component {
  render() {
    return &lt;p&gt;And then I said, “{this.props.message}”&lt;/p&gt;;
  }
}
</code></pre><p>也正因如此，React 当中的数据流是单向的：数据只能从父组件传向子组件，反过来则不行。</p><p>可是组件不可能只接受从父组件传来的数据（例如还有用户在 input 当中的输入），这时 state 就派上了用场。</p><p>原文的例子实在是不接地气，在这里我情不自禁想要引用一句古诗来解释 props 和 state 之间的区别：</p><p>人有悲欢离合，月有阴晴圆缺。</p><p>我们可以把一个人的基因性别名字（我知道某些东西其实是可变的但请不要钻牛角尖好吗），月亮的大小重量理解为 props，而随时可变的情感和圆缺则可以被理解为 state.</p><p>要注意，组件的 state 同样也能被传入到子组件中作为子组件 prop 的值。你需要明确的就是在 React 当中整个数据流都是向下传递的，包括路由、数据层、各个组件等等，从整个应用的 state 中来并汇聚到一起。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-3646b34f7e404824597688b431957e0a_hd.png" class="kg-image" alt="v2-3646b34f7e404824597688b431957e0a_hd" width="720" height="450" loading="lazy"></figure><p>在组建中，我们可以通过一个叫 setState 的方法来修改 state，一般我们都会在事件处理的方法中调用它：</p><pre><code class="language-js">class MyComponent extends React.Component {
  handleClick = (e) =&gt; {
    this.setState({clicked: true});
  }
  render() {
    return &lt;a href="#" onClick={this.handleClick}&gt;Click me&lt;/a&gt;;
  }
}
</code></pre><p>一般 React 应用当中的绝大多数数据都是 prop，只有当用户输入内容时才会使用 state 来处理。</p><p>注意在上述的代码中，我们使用了自动绑定的语法，如果你想了解更多可以阅读官方文档 <a href="https://link.zhihu.com/?target=https%3A//facebook.github.io/react/docs/handling-events.html" rel="nofollow noreferrer">Handling Events</a>.</p><h2 id="-api">概念四：组件 API</h2><p>在之前的内容当中我们已经提及了 render 和 setState 两个方法，他们都包含在组件 API 方法之中。还有一个比较有用的方法 <a href="https://link.zhihu.com/?target=https%3A//facebook.github.io/react/docs/react-component.html%23constructor" rel="nofollow noreferrer">constructor</a>，我们一般会在其中初始化 state 并做一些方法的绑定。</p><p>除了这三个方法之外，React 还提供了一些列按照特定次序触发的<a href="https://link.zhihu.com/?target=https%3A//facebook.github.io/react/docs/state-and-lifecycle.html" rel="nofollow noreferrer">生命周期函数</a>。不过先不需要担心，只有当你深入一些了解 React 之后才有机会使用到它们。</p><p>我们并不会在这里展开篇幅讲解 React 的 API，因为学习 React 更主要的目的是学习如何编程和它的构建理念，而不是死记硬背一些无聊的 API 方法。</p><h2 id="-">概念五：组件类型</h2><p>我们在 React 当中一般按照如下的方法定义一个组件：</p><pre><code class="language-js">class MyComponent extends React.Component {
  render() {
    return &lt;p&gt;Hello World!&lt;p&gt;;
  }
}
</code></pre><p>在 Class 中我们还可以申明一个组件的许多其他方法，而在更多的情况下我们可以写一种函数式组件。</p><p>类似于自定义一个模板标签一样，函数式组件接收一个 props 参数并返回特定的 HTML 内容，不过你当然仍可以在其中调用一些 JS 代码：</p><pre><code class="language-js">const myComponent = props =&gt; {
  return &lt;p&gt;Hello {props.name}! Today is {new Date()}.&lt;/p&gt;
}
</code></pre><p>因为通常你的组件可能并不需要多么复杂的交互，也不需要多余的其他方法，用函数式写法可以让你的代码更加简洁。</p><p>当然在这样的组件当中你也没有办法使用 setState 方法，也即是说函数式组件没有 state，所以也可以被称作是无状态组件。</p><p>当然，如果你接触 React 比较早，可能也见过下面这种写法：</p><pre><code class="language-js">var Greeting = React.createClass({ 

  render: function() {     
    return &lt;h1&gt;Hello, {this.props.name}&lt;/h1&gt;;   
  }
});
</code></pre><p>不同的组件类型也就延伸出了组件角色的概念，人们在实践过程中开始将组件分为两种角色，一种关注 UI 逻辑，用来展示或隐藏内容；另一种关注数据交互，例如加载服务器端的数据。</p><p>这两种组件被称作容器组件和展示组件。分别用来处理不同的业务逻辑：</p><pre><code class="language-js">//presentational component

class CommentList extends React.Component {
  constructor(props) {
    super(props);
  }

  render() { 
    return &lt;ul&gt; {this.props.comments.map(renderComment)} &lt;/ul&gt;;
  }

  renderComment({body, author}) {
    return &lt;li&gt;{body}—{author}&lt;/li&gt;;
  }
}

//container component

class CommentListContainer extends React.Component {
  constructor() {
    super();
    this.state = { comments: [] }
  }

  componentDidMount() {
    $.ajax({
      url: "/my-comments.json",
      dataType: 'json',
      success: function(comments) {
        this.setState({comments: comments});
      }.bind(this)
    });
  }

  render() {
    return &lt;CommentList comments={this.state.comments} /&gt;;
  }
}
</code></pre><p>这就又有点类似于 view/controller 的概念了。不过说来说去只是构建代码的不同方式而已，区分逻辑当然有其好处（例如分离业务逻辑，更好的代码复用），当然你也可以完全不吃这一套。</p><p><strong>高阶组件</strong></p><p>最后我们再稍微涉猎一些<a href="https://link.zhihu.com/?target=https%3A//facebook.github.io/react/docs/higher-order-components.html" rel="nofollow noreferrer">高阶组件</a>的概念（higher-order components 通常缩写为HOCs）。</p><p>其实可以把它理解为一个工厂方法，你可以传入一个组件并得到一个 HOC 返回的附加了更多功能的新组件。HOC 不能直接在 render 方法中调用。如果你想了解更多，可以去看 react-router 当中实际应用的<a href="https://link.zhihu.com/?target=https%3A//github.com/ReactTraining/react-router/blob/master/upgrade-guides/v2.4.0.md%23withrouter-hoc-higher-order-component" rel="nofollow noreferrer">例子</a>。</p><p>这里还有一篇<a href="https://zhuanlan.zhihu.com/p/24776678">深入理解 React 高阶组件</a>。</p><h2 id="--1">总结</h2><ul><li>React 的代码是由一个个的组件构成的。</li><li>组件采用了 JSX 语法扩展的写法。</li><li>数据流总是从父组件到子组件，除 state 可以通过调用方法修改之外。</li><li>组件包含一些特定方法和生命周期函数。</li><li>你也完全可以用函数声明只有 render 方法的无状态组件。</li><li>区分处理 UI 和数据逻辑的组件是一种很好的开发实践。</li><li>高阶组件函数可以传入一个组件并为其赋予更多功能。</li></ul><p>信不信由你，目前我们介绍的内容已经涵盖了 React 开发者在日常工作中应用的 90% 的知识。听起来可能有些晦涩抽象，单React当中涉及的内容总能被简化为 functions 和 props.</p><p>等到你真正理解这些知识之后，React 也就不会那么可怕了。在你掌握了 React 的模式，瞟一眼就能看懂它的代码之后，也就能自信地装 X：</p><blockquote>切，React 已经 out 啦~</blockquote><p>更多有关 React 的资源链接：</p><ul><li><a href="https://link.zhihu.com/?target=https%3A//github.com/markerikson/react-redux-links" rel="nofollow noreferrer">react-redux-links</a></li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/enaqx/awesome-react" rel="nofollow noreferrer">awesome-react</a></li></ul><p>有任何好的意见建议或有关 React 的想法观点，欢迎在评论区参与讨论。</p><p>原文链接：<a href="https://www.freecodecamp.org/news/the-5-things-you-need-to-know-to-understand-react-a1dbd5d114a3/">React’s Five Fingers of Death. Master these five concepts, then master React</a>，作者：Sacha Greif</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS Modules 快速上手 ]]>
                </title>
                <description>
                    <![CDATA[ 通过渲染编译 JS 模板和 CSS 文件来实现 CSS 模块化的方式不止一种。在今天的教程中，我们只着重讨论一种在项目中应用 CSS Modules 的实现方式：  * 第一部分：什么是 CSS Modules？为什么要使用它？  * 第二部分：CSS Modules 快速上手  * 第三部分：在 React 中使用 CSS Modules 在我之前经手的一个项目中，有一个需求是 CSS 不能依赖客户端的 JS 文件。也就是说在部署之前必须打包构建好所有的 HTML/CSS 文件。我们当时用的是  Webpack [https://link.zhihu.com/?target=https%3A//webpack.github.io/]  模块构建工具。文章接下来会介绍如何实现上述这个需求。 本篇教程中的代码示例在：discountry/webpack-css-modules-example [https://github.com/discountry/webpack-css-modules-example] 安装Webpack 在安装完NPM和Node [https://doc ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/introduction-to-css-modules-part-two/</link>
                <guid isPermaLink="false">5d41a00dfbfdee429dc5f522</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Mon, 20 Sep 2021 14:08:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/app-1013616_960_720.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>通过渲染编译 JS 模板和 CSS 文件来实现 CSS 模块化的方式不止一种。在今天的教程中，我们只着重讨论一种在项目中应用 CSS Modules 的实现方式：</p><ul><li>第一部分：什么是 CSS Modules？为什么要使用它？</li><li>第二部分：CSS Modules 快速上手</li><li>第三部分：在 React 中使用 CSS Modules</li></ul><p>在我之前经手的一个项目中，有一个需求是 CSS 不能依赖客户端的 JS 文件。也就是说在部署之前必须打包构建好所有的 HTML/CSS 文件。我们当时用的是 <a href="https://link.zhihu.com/?target=https%3A//webpack.github.io/" rel="nofollow noreferrer">Webpack</a> 模块构建工具。文章接下来会介绍如何实现上述这个需求。</p><p><strong>本篇教程中的代码示例在：<a href="https://github.com/discountry/webpack-css-modules-example">discountry/webpack-css-modules-example</a></strong></p><h2 id="-webpack">安装Webpack</h2><p>在安装完<a href="https://docs.npmjs.com/getting-started/installing-node">NPM和Node</a>之后，我们需要新建一个空文件夹，然后在该目录下运行：</p><pre><code class="language-text">npm init --y
</code></pre><p>这个命令会按照默认设置生成一个package.json文件。此文件主要包含了某个项目的依赖列表，也就是在我们运行npm install时会被安装的包都写在这个文件里面。</p><p>我们用<a href="https://link.zhihu.com/?target=https%3A//webpack.github.io/" rel="nofollow noreferrer">Webpack</a>来完成构建步骤。它可以监听CSS/JavaScript/HTML文件，并处理所有的中间环节。我差点忘了你可能还不了解Webpack到底是什么。<a href="https://link.zhihu.com/?target=http%3A//blog.madewithlove.be/post/webpack-your-bags/" rel="nofollow noreferrer">你可以把它理解为一个构建系统或打包工具：</a></p><p>事实上它是两者的结合。Webpack会将你项目中所有的资源（图片/CSS/HTML/JS）视为模块，你可以导入、编辑、操作、并打包到你最终的输出文件中。——Maxime Fabre</p><p>即使这听起来很奇怪也请别担心。在Sass和Gulp还有NPM刚刚出来的时候，一时间也很难让人接受。</p><p>首先让我们配置好Webpack确保它能正常运作。第一步需要在全局安装Webpack，这样你才可以在命令行里使用它：</p><pre><code class="language-bash">npm install webpack -g
</code></pre><p>之后再在你的项目中安装Webpack</p><pre><code class="language-text">npm i -D webpack
</code></pre><p>现在我们需要在项目中创建一个index.js文件，把它放到/src文件夹里。我个人习惯于把所有的静态资源（图片/字体/CSS等）存在一个文件夹里，自己写的代码存在/src文件夹内，而电脑生成的代码则会放在/build文件夹。我们并不需要手动创建/build文件夹，可以让Webpack自动完成将/src下的代码打包到/build的操作。</p><p>在/src文件夹里我们可以先创建一个名为alert.js的文件。另外还需要在项目的根目录创建webpack.config.js配置文件。现在我们的项目结构大概是下面这个样子：</p><pre><code class="language-text">package.json
webpack.config.js
/node_modules
/src
  index.js
  alert.js
</code></pre><p>在webpack.config.js配置文件中，写入以下内容：</p><pre><code class="language-js">module.exports = {
  entry: './src',
  output: {
    path: 'build',
    filename: 'bundle.js',
  },
};
</code></pre><p>这样配置之后，每次我们在项目中运行webpack命令时，Webpack都会检测/src目录下的文件。</p><p>接下来在src/index.js加入：</p><pre><code class="language-js">require("./alert.js");
</code></pre><p>然后在alert.js里添加：</p><pre><code class="language-js">alert("LOUD NOISES");
</code></pre><p>之后在项目的根目录创建index.html文件，然后添加一个链接到打包输出文件的script标签：</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Document name&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;CSS Modules demo&lt;/h1&gt;

    &lt;script src="build/bundle.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><p>这里的bundle.js就是webpack打包之后会生成的文件。我们只需要在项目中运行webpack命令就可以生成它了。为了更方便一些，我们可以在package.json中写上构建的脚本：</p><pre><code class="language-js">"scripts": {
  "test": "echo 'Error: no test specified' &amp;&amp; exit 1"
},
</code></pre><p>这一段是npm默认的脚本配置，我们可以把它替换成如下内容：</p><pre><code class="language-js">"scripts": {
    //如果是Windows则改为 webpack &amp;&amp; start index.html
  "start": "webpack &amp;&amp; open index.html"
},
</code></pre><p>之后在项目的命令行中输入npm start命令，我们就能自动完成webpack的构建并在浏览器中打开网页查看结果。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-df8e27c00ff4a60e47e58c6b74a6b6a8_hd.png" class="kg-image" alt="v2-df8e27c00ff4a60e47e58c6b74a6b6a8_hd" width="600" height="400" loading="lazy"></figure><p>看起来效果不错！目前为止webpack的功能应该都走通了。你可以删掉alert.js测试一下，我们再次试着运行npm start时就会看到错误信息。</p><p>在Webpack无法找到我们导入的模块时就会报错。接下来让我们更深入地了解一下webpack吧。</p><h2 id="-loader-">配置加载器(Loader)</h2><p>加载器(Loader)是webpack的使用中非常重要的一部分。你可以把加载器看作一个小插件，在我们导入特定类型的文件时，对应的加载器就会起作用。</p><p>例如使用Babel加载器可以允许我们使用一些ES6的新特性来写JS代码。不需要像刚才那样使用require而是可以使用import来导入模块，以及箭头函数之类的<a href="https://link.zhihu.com/?target=http%3A//es6.ruanyifeng.com/" rel="nofollow noreferrer">新的特性</a>：</p><p>Babel起到一个类似于编译器或预处理器的作用，它允许我们用ES6的语法书写，之后把我们的代码转换成可以兼容运行的ES5代码。</p><p>通过下面这行命令来安装Babel的相关依赖：</p><pre><code class="language-bash">npm i -D babel-loader babel-core babel-preset-es2015
</code></pre><p>在根目录创建一个.babelrc文件，在里面设置：</p><pre><code class="language-json">{
  "presets": ["es2015"]
}
</code></pre><p>现在我们来配置，让Babel处理所有我们自己编写的.js文件。注意配置好，不能让Babel干扰一些可能会使用的第三方库。修改webpack.config.js为如下内容：</p><pre><code class="language-js">var path = require('path');

module.exports = {
  entry:  './src',
  output: {
  path: 'build',
    filename: 'bundle.js',
  },
  module: {
    loaders: [
      {
        test: /.js/,
        loader: 'babel',
        include: path.resolve(__dirname, 'src'),
       }
    ],
  }
};
</code></pre><p>加载器(Loader)配置中的test值用来匹配对应的文件类型，include用来指定在哪个路径下该加载器生效。</p><p>我们先来测试一下Babel是不是已经能在Webpack里正常运作了。创建一个新的文件src/robot.js，写入以下内容：</p><pre><code class="language-js">const greetings = (text, person) =&gt; {
  return `${text}, ${person}. I read you but I’m sorry, I’m afraid I can’t do that.`;
}

export default greetings;
</code></pre><p>这一段JS代码使用了一些ES6的新特性，例如export, const以及let, 箭头函数、模板标签等。</p><p>现在我们可以试着在src/index.js里通过import导入模块：</p><pre><code class="language-js">import greetings from './robot.js'
document.write(greetings("Affirmative", "Dave"));
</code></pre><p>之后再运行一次npm start，这时你浏览器打开的网页里应该就会多出一行字了。</p><p>很酷不是么？但截至目前我们还没有料到CSS Modules呢。在我们开始下一步之前，先删掉src/下的所有测试代码。</p><h2 id="-">载入样式</h2><p>再安装两个加载器，我们的项目模板差不多就准备好了：</p><pre><code class="language-bash">npm i -D css-loader style-loader
</code></pre><p>css-loader用来读取CSS文件，style-loader则负责处理并将样式加载到页面中。我们先创建src/app.css来测试一下：</p><pre><code class="language-css">.element {
  background-color: blue;
  color: white;
  font-size: 20px;
  padding: 20px;
}
</code></pre><p>之后通过import语句导入到src/index.js文件中：</p><pre><code class="language-js">import styles from './app.css'

let element = `
  &lt;div class="element"&gt;
    &lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequatur laudantium recusandae itaque libero velit minus ex reiciendis veniam. Eligendi modi sint delectus beatae nemo provident ratione maiores, voluptatibus a tempore!&lt;/p&gt;
  &lt;/div&gt;
`

document.write(element);
</code></pre><p>等等！我们刚刚是在JS代码里导入了样式文件么？这确实是可以实现的。只需要我们再配置一下webpack.config.js里的内容：</p><pre><code class="language-js">var path = require('path');

module.exports = {
  entry:  './src',
  output: {
  path: 'build',
    filename: 'bundle.js',
  },
  module: {
    loaders: [
      {
        test: /.js/,
        loader: 'babel',
        include: path.resolve(__dirname, 'src'),
       },
      {
        test: /\.css/,
        loaders: ['style', 'css'],
        include: path.resolve(__dirname, 'src'),
      }
    ],
  }
};
</code></pre><p>然后运行npm start我们将会看到：</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-d6a76f324ea8ff74b2062c322d95cc40_hd.png" class="kg-image" alt="v2-d6a76f324ea8ff74b2062c322d95cc40_hd" width="600" height="400" loading="lazy"></figure><p>这时可以试着用【审查元素】检查一下文档内容，我们会发现，style-loader在&lt;head&gt;中写入了一个&lt;style&gt;标签：<br></p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-3e0f8e65ca38e242289c5341684e458e_hd.png" class="kg-image" alt="v2-3e0f8e65ca38e242289c5341684e458e_hd" width="600" height="400" loading="lazy"></figure><p>现在来捋一捋刚刚到底发生了什么。我们在一个JavaScript文件里请求了另外一个CSS文件，CSS的内容被写入到了最终的网页里。所以在现实中的应用可能是在一个按钮组件中，buttons.js文件添加了buttons.css作为依赖。然后将按钮组件导入到其他JS文件中，最后组成模板，并输出HTML。这样的方式可以让我们的代码组织更合理并且很方便阅读。</p><p>为了让我们的代码更加清晰，我个人倾向于把CSS输出为单独的文件，而不是直接嵌入HTML里面。为了实现这个需求，我们需要安装一个叫做<a href="https://link.zhihu.com/?target=https%3A//github.com/webpack/extract-text-webpack-plugin" rel="nofollow noreferrer">extract text</a> 的 <a href="https://link.zhihu.com/?target=https%3A//webpack.github.io/docs/using-plugins.html" rel="nofollow noreferrer">Wepack 插件</a>。</p><p>将载入的所有CSS模块输出为一个独立的CSS文件。这样你的样式就不至于和JS代码混淆在一起，而是生成一个独立的CSS打包文件。假如你的样式文件体积较大的话，这种方式可以加快页面加载速度，因为样式文件可以和JS文件同时载入。</p><p>通过下面这行命令来安装插件：</p><pre><code class="language-bash">npm i -D extract-text-webpack-plugin
</code></pre><p>之后再对webpack.config.js配置文件稍作修改，替换CSS文件的加载器：</p><pre><code class="language-js">var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry:  './src',
  output: {
  path: 'build',
    filename: 'bundle.js',
  },
  module: {
    loaders: [
      {
        test: /.js/,
        loader: 'babel',
        include: path.resolve(__dirname, 'src'),
       },
      {
        test: /\.css/,
        loader: ExtractTextPlugin.extract("css"),
      }
    ],
  },
  plugins: [
    new ExtractTextPlugin("styles.css")
  ]
};
</code></pre><p>这样ExtractTextPlugin插件就会为我们生成styles.css文件。</p><p>这时我们就不再需要style-loader了。运行完webpack命令后，你打开/build文件夹就能够找到新生成的styles.css文件。你还需要把生成的样式文件链接手动添加到index.html中：</p><pre><code class="language-html">&lt;link rel="stylesheet" href="build/styles.css"&gt;
</code></pre><p>试着运行npm start，奇迹就发生啦~页面没有什么别的变化，但现在是通过外联CSS实现的。</p><p>那么接下来要如何设置才能利用CSS Modules的作用域特性呢？只需要对webpack.config.js稍作修改：</p><pre><code class="language-js">{
  test: /\.css/,
  loader: ExtractTextPlugin.extract('css?modules&amp;importLoaders=1&amp;localIdentName=[name]__[local]___[hash:base64:5]'),
}
</code></pre><p>上面这个配置会生成长得变态的类名。Webpack通过CSS加载器来实现这个功能。</p><p>现在来修改我们的index.js，通过styles.element的方式访问CSS类：</p><pre><code class="language-js">import styles from './app.css'

let element = `
  &lt;div class="${styles.element}"&gt;
    &lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequatur laudantium recusandae itaque libero velit minus ex reiciendis veniam. Eligendi modi sint delectus beatae nemo provident ratione maiores, voluptatibus a tempore!&lt;/p&gt;
  &lt;/div&gt;
`

document.write(element);
</code></pre><p>最后再运行一次npm start，我们就可以看到一个不需要担心作用域的页面生成啦：</p><pre><code class="language-html">&lt;div class="app__element___2YM3c"&gt;
  ...
&lt;/div&gt;
</code></pre><p>不过目前为止我们举的例子仍然很抽象，还有很多问题没有涉及到。在真正的开发工作中，我们肯定不能直接任性地通过document.write来输出页面。我们该如何架构我们的模块和文件？实现CSS Modules的功能只完成了一半的工作而已，接下来我们还得考虑如何从别的项目里迁移代码。</p><p>在下一篇教程里，我们将会讨论如何通过React来构建简单的模块，同时也会补充介绍如何在项目中应用类似Sass和PostCSS的预处理器的特性。</p><p><a href="https://css-tricks.com/css-modules-part-2-getting-started/">参考资料</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 非计算机专业出身的我是如何在两年内成长为前端工程师的 ]]>
                </title>
                <description>
                    <![CDATA[ 首先请允许我自我介绍一下，我的名字叫 Sergei Garcia，我是一名拥有两年工作经验的全职前端开发工程师，之前在福布斯 500 强咨询公司和小公司都工作过。这对大多数人来说可能没什么，但对我意味着职业生涯上的里程碑。我两年之前除了在网上学过一点点 C# 和 Java 以外，没有任何的编程经验，没读过计算机专业的学位，并且也没有去过培训班。 之前我在许多网络社区里汲取了很多营养，获得了很多帮助。现在也该是我写一些东西分享给大家的时候了。虽然我并不是什么大神，但我想通过了解我的这些经历，至少能帮你少走一些弯路。 如果你比较着急，想要快速了解如何从零开始成为一名前端工程师的话，也可以跳过只看：最佳捷径  这个章节。 废话不多说，进入正题： 掌握基础 在我刚打算开始学习前端开发时，想到的第一个问题就是“我到底该学些什么？”。在网上搜了搜，我发现大部分初学者都在关注以下几个知识点：  * JavaScript  * HTML & CSS  * CSS 预处理器(Less & Sass)  * 响应式设计  * JS框架  * 设计模式  * Git  * NodeJS  * 自动 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/my-journey-to-becoming-a-web-developer/</link>
                <guid isPermaLink="false">5d2dd5f9fbfdee429dc5eeb2</guid>
                
                    <category>
                        <![CDATA[ Web开发 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Mon, 09 Aug 2021 04:30:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/v2-e064cfb9712ce120a8940dc2158a0ffc_1200x500.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>首先请允许我自我介绍一下，我的名字叫 Sergei Garcia，我是一名拥有两年工作经验的全职前端开发工程师，之前在福布斯 500 强咨询公司和小公司都工作过。这对大多数人来说可能没什么，但对我意味着职业生涯上的里程碑。我两年之前除了在网上学过一点点 C# 和 Java 以外，没有任何的编程经验，没读过计算机专业的学位，并且也没有去过培训班。</p><p>之前我在许多网络社区里汲取了很多营养，获得了很多帮助。现在也该是我写一些东西分享给大家的时候了。虽然我并不是什么大神，但我想通过了解我的这些经历，至少能帮你少走一些弯路。</p><p>如果你比较着急，想要快速了解如何从零开始成为一名前端工程师的话，也可以跳过只看：<strong>最佳捷径</strong> 这个章节。</p><p>废话不多说，进入正题：</p><h2 id="-">掌握基础</h2><p>在我刚打算开始学习前端开发时，想到的第一个问题就是“我到底该学些什么？”。在网上搜了搜，我发现大部分初学者都在关注以下几个知识点：</p><ul><li>JavaScript</li><li>HTML &amp; CSS</li><li>CSS 预处理器(Less &amp; Sass)</li><li>响应式设计</li><li>JS框架</li><li>设计模式</li><li>Git</li><li>NodeJS</li><li>自动化构建工具</li></ul><h3 id="javascript">JavaScript</h3><p>我是在<a href="https://link.zhihu.com/?target=https%3A//www.codeschool.com/" rel="nofollow noreferrer">CodeSchool</a>（付费）和<a href="https://link.zhihu.com/?target=https%3A//www.codecademy.com/" rel="nofollow noreferrer">Codecademy</a>（免费）上开始学习JavaScript的。有人可能不了解这两个网站，他们都属于交互式学习的平台，可以一边看视频一边读教程，然后在浏览器就可以编写代码通过测验。我觉得对初学者来说这是最友好的学习方式。</p><p>在我掌握了一些基础之后，就开始阅读<a href="https://link.zhihu.com/?target=http%3A//eloquentjavascript.net/" rel="nofollow noreferrer"> Eloquent Javascript: A Modern Introduction to Programming</a>这本书（你可以点击链接获取免费的在线英文版，也可以在<a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/19933548/" rel="nofollow noreferrer">JavaScript编程精解</a>找到中文版）。网上很多人向我推荐这本教程，最早学习阅读它的时候是很痛苦的，不过我很庆幸我坚持了下来。这本书很棒，因为它涵盖了JS的方方面面。</p><p>假如你对jQuery感兴趣也可以去学学，不过我推荐先放到之后再说。</p><h3 id="htmlcss">HTML&amp;CSS</h3><p>之后我按照CodeSchool的<a href="https://link.zhihu.com/?target=https%3A//www.codeschool.com/learn/html-css" rel="nofollow noreferrer">HTML&amp;CSS 学习路径</a>学习了HTML&amp;CSS的基础知识。同样值得推荐的还有Codecademy的<a href="https://link.zhihu.com/?target=https%3A//www.codecademy.com/learn/web" rel="nofollow noreferrer">HTML&amp;CSS</a>课程，另外Udacity的<a href="https://link.zhihu.com/?target=https%3A//www.udacity.com/course/intro-to-html-and-css--ud304" rel="nofollow noreferrer">HTML和CSS简介</a>可能相对更深入一些。</p><p><strong>P.S.</strong> Jon Duckett 所著的 <a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/21338365/" rel="nofollow noreferrer">HTML &amp; CSS设计与构建网站</a>也是学习入门HTML/CSS的一本非常棒的高分热销书。</p><h3 id="less-sass">LESS/SASS</h3><p>Less &amp; Sass 一类的CSS预处理器在CSS之上添加许多有用的特性，你可以通过这些预处理器使用CSS原生不支持的高级功能，然后再将它们编译成为CSS。</p><p>目前主流的CSS预处理器有Less &amp; Sass两种。Sass可能更受欢迎一些，Less也挺好用的，它上手需要安装的依赖更少一些。你也可以先直接体验一下：在<a href="https://link.zhihu.com/?target=http%3A//winless.org/online-less-compiler" rel="nofollow noreferrer">WinLess’s Online Less Compiler</a>你可以在线编写Less代码，并且有一些示例供你参考；在<a href="https://link.zhihu.com/?target=http%3A//www.sassmeister.com/" rel="nofollow noreferrer">SassMeister</a>你可在线体验Sass.</p><p>Less或者Sass你想先学哪个都可以，它们都有很多相似之处。想了解更多可以查看<a href="https://link.zhihu.com/?target=http%3A//shelbymoulden.com/blog/%3Fpost%3Dcomparison-between-less-and-sass" rel="nofollow noreferrer">Comparison between LESS &amp; SASS</a></p><h3 id="--1">响应式设计</h3><p>关于学习响应式设计，Udacity的<a href="https://link.zhihu.com/?target=https%3A//www.udacity.com/course/responsive-web-design-fundamentals--ud893" rel="nofollow noreferrer">Responsive Web Design Fundamentals</a>课程非常不错。</p><p>假如你还能学习了解一下<strong>Bootstrap</strong>的话，上手响应式设计应该会更快一些，它的<a href="https://link.zhihu.com/?target=http%3A//getbootstrap.com/css/" rel="nofollow noreferrer">官方文档</a>就是一个很好的开始的地方。</p><h3 id="angularjs">AngularJS</h3><p>如果你想要了解AngularJS到底是什么，可以观看Google开发者的视频<a href="https://link.zhihu.com/?target=https%3A//www.youtube.com/watch%3Fv%3DHCR7i5F5L8c" rel="nofollow noreferrer">Design Decisions in AngularJS</a>.</p><p>刚开始学习Angular的时候我就打算在它的官网读读文档，可惜那文档写的一点都不友好，晦涩难懂。Codeschool上有关AngularJS的课程也不怎么样，内容设置勉强合理，但代码答题的环节有很多Bug，我明明写对的答案就是无法通过测验。</p><p>最后我终于找到了一个很棒的网站<a href="https://link.zhihu.com/?target=https%3A//egghead.io/" rel="nofollow noreferrer">Egghead.io</a>，它的课程把Angular拆分成一个个小的知识点，每个2-5分钟就可以学完。（网站同样提供React/Node等JS相关教程）</p><h3 id="--2">设计模式</h3><p>事实上设计模式就是一些在编程开发中解决共性问题的经验总结。这方面的知识在所有编程语言之间是通用的，同样也有助于让你写出别人更易读懂的代码，你也能更好地理解别人。</p><p>我找到了两个比较好的教程<a href="https://link.zhihu.com/?target=https%3A//s.codepen.io/discountry/fullpage/JavaScript%2520Design%2520Patterns" rel="nofollow noreferrer">JavaScript Design Patterns</a>和<a href="https://link.zhihu.com/?target=https%3A//addyosmani.com/resources/essentialjsdesignpatterns/book/" rel="nofollow noreferrer">Learning JavaScript Design Patterns</a>.</p><p>这里有中文版的<a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/24744217/" rel="nofollow noreferrer">JavaScript设计模式</a>，只可惜普遍评价翻译的奇烂无比，要是你对英文不自信，那就只好忍耐一下了。</p><h3 id="chrome-">Chrome开发者工具</h3><p>这应该是对前端开发者最有用的工具之一了，掌握学习它非常有必要。你可以在Codeschool的<a href="https://link.zhihu.com/?target=http%3A//discover-devtools.codeschool.com/" rel="nofollow noreferrer">Explore and Master Chrome DevTools</a>课程学习。</p><h3 id="git-">Git（版本控制系统）</h3><p>最早我不了解Git的时候以为根本没有学它的必要。Git可以记录你对代码的每一次改动，要是你有什么地方写错了，也可以很方便地退回到任意一个版本（其实版本控制对所有人都非常有用，试想你在改稿改到第十版的时候，老板说他突然觉得还是第一版最好，结果你只保存了最后一版的心情吧）。<a href="https://link.zhihu.com/?target=https%3A//try.github.io/levels/1/challenges/1" rel="nofollow noreferrer">Try Github</a>是一个了解Git非常好的教程，<a href="https://link.zhihu.com/?target=https%3A//www.atlassian.com/git/tutorials/" rel="nofollow noreferrer">Atlassian’s Git training</a>可以让你对Git有更深入的了解。最后Codeschool的<a href="https://link.zhihu.com/?target=https%3A//www.codeschool.com/learn/git" rel="nofollow noreferrer">Git Learning Path</a>也是学习Git非常不错的参考。</p><h3 id="nodejs">NodeJS</h3><p>掌握NodeJS对一名前端开发者来讲非常有帮助。<a href="https://link.zhihu.com/?target=http%3A//nodeschool.io/" rel="nofollow noreferrer">NodeSchool.io</a>是一个学习Node非常好的地方。</p><h3 id="-gruntgulp-">自动化构建工具(Grunt&amp;Gulp)</h3><p>我自己从来都想不到还有像Grunt和Gulp这样神奇的工具。简单来讲，这些自动化构建工具可以通过脚本自动完成一些任务。例如将Less/Sass编译成为CSS形式。而且你可以设置构建工具监听你对代码的修改，每次修改完成后自动编译，你直接就可以在浏览器里看到实时的效果。这节约了大量的开发时间。</p><p>学习使用Grunt和Gulp都需要你了解NodeJS的相关知识，相比Grunt来讲，Gulp更容易配置一些，我也推荐你学习Gulp，当然这全在于你的个人喜好。</p><p>你可以在<a href="https://link.zhihu.com/?target=http%3A//Scotch.io" rel="nofollow noreferrer">http://Scotch.io</a>上学习<a href="https://link.zhihu.com/?target=https%3A//scotch.io/tutorials/a-simple-guide-to-getting-started-with-grunt" rel="nofollow noreferrer">Grunt</a>和<a href="https://link.zhihu.com/?target=https%3A//scotch.io/tutorials/automate-your-tasks-easily-with-gulp-js" rel="nofollow noreferrer">Gulp</a>.</p><h2 id="--3">我在第一份工作中遇到的困难和挑战</h2><p>在我掌握了这些前端开发的基础之后，我已经有了应聘前端初级岗位的能力。全靠我扎实的JavaScript基础，我才找到了第一份工作。在接下来的一年里，我仍然在继续努力提升自己。</p><p>我的第一个项目就需要开发可复用的Web组件，这令我感到很紧张。我当时犯过的错误主要有两个：</p><p>1.<strong>害怕失败</strong>。因为我只是个新人，我很怕自己的代码写错或写的太烂，所以我浪费很多时间重复地检查，确保自己没有犯错并使用了最佳实践。这也导致我固步自封，没办法掌握新的东西或创造性地实现需求。</p><p>2.<strong>盲目效仿</strong>。我当时经常会盲目效仿那些比我有经验的人。也不去思考别人为什么那么做，代码为什么那么写。我也效仿相同的做法是因为我觉得他们都比我有经验，而不去了解这些最佳实践背后的意义和原因。</p><p>感谢我的项目主管最终帮我克服了这些。他不断地鼓励我尝试新的东西，即使有时候会出错；也鼓励我多思考多质疑。最后我学到了很多东西，也明白了这些最佳实践是怎么总结出来的。</p><p>在项目中应用AngularJS对我来说也是一大挑战，因为很多东西我都只是会用而已，AngularJS就是这么神奇，无法解释其背后的原理。我几次也都想要了解其背后的工作原理，可是那些文档实在是太难懂。直到我后来找到了一本非常棒的书<a href="https://link.zhihu.com/?target=http%3A//teropa.info/build-your-own-angular/" rel="nofollow noreferrer">Build Your Own AngularJS</a>.我只是读了Scopes和Watchers章节，就让我很好地了解了angular的工作机制。</p><p>一年之后我遇到的挑战是Web开发的迅猛发展。我正在沾沾自喜掌握了AngularJS和Grunt，Gulp和ReactJS就火了起来。等我又花了一年功夫学习之后，Webpack又开始流行。自己掌握的知识过气并不是一件令人舒服的事情。后来，我的一位同事的观点改变了我的看法：</p><p>框架和库也许会过时，但是它们背后的原理和概念会经受住时间的考验。</p><p>完全正确。AngularJS也许有些过时了，可是理解它例如Directives背后的原理也有助于理解React的组件。</p><p>除此之外，我在随后的项目中没有遇到过太大的困难。在我学习前端开发这两年里，最重要的一点是保持热情不断学习新的东西。前端的发展变化实在是太快了。</p><p>另外一方面，明白有些东西可以不去学对于一名前端开发者的成长也非常重要。很多人都抱怨前端技术的革新异常迅猛，几乎每天都有新的JS框架和库推出。最后我也终于明白：</p><p>你并不需要学习和掌握所有的框架和库。</p><p>也许你可以尝试每个框架的Hello wrold示例，但通常你只需要专注于最好和最适用于你自己的，或者手头的项目需要的就好。在层出不穷的框架中间抉择真的不是易事，好在我们能够在网上找到相当多的这类讨论。</p><h2 id="--4">进阶提高</h2><p>再然后，我又通过下面这些方法继续学习和提升：</p><h3 id="javascript-1">JavaScript</h3><p>读完 Eloquent JavaScript 之后，你以为你掌握了 JavaScript，但是 <a href="https://link.zhihu.com/?target=https%3A//github.com/getify/You-Dont-Know-JS" rel="nofollow noreferrer">You Don’t Know JS</a> 这套书会摧毁你的这种自信。我的资深前端同事向我推荐了好几次这套书，直到我真的一页页翻开了这套书，我才了解到JS究竟有多复杂，还有许多没有彻底了解JS时会踩的坑。</p><p>阅读这套书确实开启了我的思路，我同样也推荐给那些自以为很了解 JS 的人读一读。随后，这里还有两个很棒的学习资料：</p><ul><li><a href="https://link.zhihu.com/?target=https%3A//vimeo.com/97419177" rel="nofollow noreferrer">JavaScript, The Better Parts</a>: 来自 D. Crockford 的演讲，主要涵盖了 JS 最大的缺点，优点，以及如何利用它们。</li><li><a href="https://link.zhihu.com/?target=https%3A//medium.com/javascript-scene/the-two-pillars-of-javascript-ee6f3281e7f3%23.91eor7lrd" rel="nofollow noreferrer">The Two Pillars of JavaScript</a>: 来自 Eric Eliott 的一篇文章，主要讲解了 JS 的两大要点——原型继承和函数式编程。</li></ul><p>在你对JS有了一个深刻的认识之后，尝试着学习JS的最新标准 ECMASCript 2015 (a.k.a. ES6)吧。这有一篇非常棒的介绍 ES6 的文章 <a href="https://link.zhihu.com/?target=https%3A//www.smashingmagazine.com/2015/10/es6-whats-new-next-version-javascript/" rel="nofollow noreferrer">ECMAScript 6 (ES6): What’s New In The Next Version Of JavaScript</a>，你也可以直接在浏览器里尝试一下 ES6 语法 <a href="https://link.zhihu.com/?target=https%3A//babeljs.io/repl/" rel="nofollow noreferrer">Babel’s online transpiler</a>.</p><h3 id="css">CSS</h3><p>CSS 的代码很容易就会变得非常凌乱。想要写出条理清晰的 CSS 有很多种解决方案，我在这里强烈推荐两种比较好的：</p><ul><li><a href="https://link.zhihu.com/?target=https%3A//smacss.com/" rel="nofollow noreferrer">SMACSS</a>: CSS 的可扩展模块化架构。适用于各种大小级别的站点。</li><li><a href="https://link.zhihu.com/?target=http%3A//getbem.com/" rel="nofollow noreferrer">BEM</a>: 一种实现前端模块代码复用的标准方案。</li></ul><p>我个人比较喜欢 SMACSS，因为它看起来更清晰一点，但也有很多公司在实践中使用BEM标准。</p><p>同样，你也需要开始关注 CSS 的性能了，这有两篇文章： <a href="https://link.zhihu.com/?target=https%3A//www.smashingmagazine.com/2016/03/managing-mobile-performance-optimization/" rel="nofollow noreferrer">Managing Mobile Performance Optimization</a> 和 <a href="https://link.zhihu.com/?target=http%3A//www.html5rocks.com/en/tutorials/speed/high-performance-animations/" rel="nofollow noreferrer">High Performance Animation</a> 都可以帮助你理解入门。</p><h3 id="javascript-">JavaScript 构建工具</h3><p>到这一步你应该以及很熟悉 Grunt/Gulp 了，接下来就需要把JS的构建工具加入到你的自动化构建工具中，以此来更好地管理组织你的 JS 代码。目前最流行的两个是：</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//browserify.org/" rel="nofollow noreferrer">Browserify</a>: 打包你 JS 的模块化代码使其得以在浏览器中运行。</li><li><a href="https://link.zhihu.com/?target=https%3A//webpack.github.io/" rel="nofollow noreferrer">Webpack</a>: 这是一个更高级的构建工具，除了 JS 以外还能管理构建 CSS 代码甚至是图片一类的静态资源，就是配置起来比较复杂。</li></ul><p><a href="https://link.zhihu.com/?target=http%3A//Scotch.io" rel="nofollow noreferrer">http://Scotch.io</a> 上的一个小教程 <a href="https://link.zhihu.com/?target=https%3A//scotch.io/tutorials/getting-started-with-browserify" rel="nofollow noreferrer">Getting Started with Browserify</a> 可以让你快速入门Browserify，<a href="https://link.zhihu.com/?target=https%3A//medium.com/%40dtothefp/why-can-t-anyone-write-a-simple-webpack-tutorial-d0b075db35ed%23.dv2lqnxl9" rel="nofollow noreferrer">Why Can’t Anyone Write a Simple Webpack Tutorial</a> 是入门 Webpack 的一个非常棒的教程。我自己并不经常使用 Webpack，它虽然配置复杂，但用起来还是非常爽的。最新的流行趋势就是 Webpack.</p><h3 id="reactjs">ReactJS</h3><p>ReactJS 越来越受欢迎，而且火得一发不可收拾。甚至有人开始讨论“React要灭掉Angular了吗？”。<a href="https://link.zhihu.com/?target=http%3A//Scotch.io" rel="nofollow noreferrer">http://Scotch.io</a>上的教程<a href="https://link.zhihu.com/?target=https%3A//scotch.io/tutorials/learning-react-getting-started-and-concepts" rel="nofollow noreferrer">Learning React.js: Getting Started and Concepts</a> 可以让你对 React 有一个完整直观的印象。之后你可以跟着 <a href="https://link.zhihu.com/?target=https%3A//egghead.io/courses/react-fundamentals" rel="nofollow noreferrer">React Fundamentals</a> 教程试着开发一个 React 的 App，当然你也可以查阅 <a href="https://link.zhihu.com/?target=https%3A//facebook.github.io/react/docs/getting-started.html" rel="nofollow noreferrer">React 官方文档</a>。</p><p>由于React只注重于视图的实现，同时我也推荐你学习Redux，大多数的Redux教程都比较复杂，<a href="https://link.zhihu.com/?target=https%3A//css-tricks.com/learning-react-redux/" rel="nofollow noreferrer">CSS Tricks Leveling Up with React: Redux</a>这一篇还算深入浅出地讲解了Redux。当然你也可能听说过Flux，要是你很难在它们之间抉择的话可以查看这一篇讨论<a href="https://link.zhihu.com/?target=http%3A//stackoverflow.com/questions/32461229/why-use-redux-over-facebook-flux" rel="nofollow noreferrer">Why use Redux over Facebook Flux</a>.</p><p><strong>P.S</strong> 当然还有别的流行框架可以学习： Vue刚刚发布了2.0版本，学习Vue可以查看作者本人的<a href="https://zhuanlan.zhihu.com/p/23134551">新手向：Vue 2.0 的建议学习顺序</a>。 学习React可以从<a href="https://link.zhihu.com/?target=http%3A//reactjs.cn/react/docs/getting-started-zh-CN.html" rel="nofollow noreferrer">中文文档</a>开始。</p><h2 id="--5">回顾我所犯的错及从中总结的经验</h2><p>在学习前端开发的两年里我犯了许多错，最严重地一点是，在我基础还不扎实地时候就开始使用框架和库了。我想这种情况应该在学习任何语言时都可能会遇到，不过对于JS尤其突出。因为JS真的是一个充满了坑地语言。</p><p>在我学习AngularJS地时候曾经遇到了一个有关$scope的Bug，我用了3天都没搞明白怎么回事。最后才发现了并不是Angular的毛病，而是因为我对JS本身的this原理理解不够导致的。</p><h3 id="--6">代码工整</h3><p>我很少看到有关这个话题的讨论，刚开始的时候我并不在意自己的代码是否工整。大多数人都是在抱怨自己之前写的代码有多脏多烂。那么为什么就没人讲讲他们之前写得干净工整的代码呢？</p><p>我希望这种情况能够得到改善，这需要我们每个人的努力。努力写出含义明确的变量名，即使你需要多打几个字母。否则你只能在之后加上注释来解释清楚，而到了最后别人甚至你自己都很难读懂那些代码是什么意思。所以从现在开始改变吧。</p><p>写出干净工整的代码也能够让你的同事更愿意与你合作，也会让你在工作生活中更顺心一些。</p><h3 id="jquery">jQuery</h3><p>有人可能注意到了，我没怎么提到jQuery.因为在我的实际经验中，jQuery对我的害处更大一些，你可能不太理解，请听我解释：在我刚开始学习的时候，我感觉jQuery可以被应用在任何地方，解决任何问题。所以我几乎在所有地方都是用jQuery，一旦遇到了任何问题，就去寻找使用jQuery的解决办法。不要误解我的意思，jQuery确实很棒，实在好用的有些过分，所以也就让我忽视了，在我写的jQuery代码中有90%其实可以用很简单的原生JS实现。</p><p>你现在可能会想：jQuery也不是什么重量级框架，而其你可以用比原生JS少很多的代码实现一些功能，用它到底有什么不对呢？确实，使用jQuery而不是原生代码并不是主要的问题。而是我在实现一些功能时必须依赖jQuery才能想到解决方法。而这在我接手一些不使用jQuery的项目中当然就成为了很严重的问题。使用jQuery让我对它产生了严重的依赖，也让我几乎了解不到一些JS的原生功能。我掌握的这些方法脱离了jQuery根本就无法使用。</p><p>在那以后，我就强迫自己尽量不去使用jQuery，除非是在一些需要大量操作DOM的情况下。再强调一遍，我不是说jQuery不好，但假若我有一次从头再来的机会的话，我一定会先学习如何脱离jQuery来开发，而不是依赖于它。要是你现在也遇到相同的麻烦，可以看这篇<a href="https://link.zhihu.com/?target=http%3A//youmightnotneedjquery.com/" rel="nofollow noreferrer">You Might Not Need jQuery</a>.</p><h3 id="--7">教程资源</h3><ul><li><a href="https://link.zhihu.com/?target=https%3A//www.codeschool.com/" rel="nofollow noreferrer">CodeSchool</a></li><li>HTML/CSS一类的基础教程很不错。</li><li><a href="https://link.zhihu.com/?target=https%3A//teamtreehouse.com/" rel="nofollow noreferrer">Team Treehouse</a></li><li>教程的质量相当不错，你可以免费试用，不过试用期后每月是30刀袄。</li><li><a href="https://link.zhihu.com/?target=https%3A//egghead.io/" rel="nofollow noreferrer">egghead.io - Learn professional JavaScript tools with Tutorial Videos &amp; Training</a><br></li></ul><h3 id="--8">关于付费教程</h3><p>确实，有些人不花一分钱学习编程可以得到那些花了钱的人一样的学习效果。我在前面列出的学习资源里大部分是免费的当然也有付费的。有些东西确实还是在视频里有人手把手教你好理解一些。</p><p>没错，很多付费的教程的确也非常糟糕，我之前就买到过。但像Egghead.io, CodeSchool, Team Treehouse这些网站上的教程非常棒，通过这些系统的教程学习1-2个月，比起你在良莠不齐博客和文章里学习效率要高太多。</p><p>付费教程并不是必须的，但我想你只要是没穷到那份儿上，选择一些优质的付费教程还是对你非常有帮助的。</p><h3 id="--9">成功秘笈</h3><p>在过去两年里，我见过许多的开发者。但是很少遇到比较杰出的，让他人仰慕的开发者。我总觉出这类人都有一些通共的特点，这也是成为一名成功的前端开发者的秘籍：</p><ul><li><strong>热爱你的工作。</strong>这是最重要的一点特质。要是你根本不喜欢写代码，代码也不会喜欢你。在一个领域杰出的人往往是对其所在充满热情的人。</li><li><strong>大方地分享你的知识。</strong>你也许很想把自己解决一些问题的代码保密，但请别这么做。乐于分享他知识的人往往是最有价值的人，因为他们可以进入任何一个团队并带领团队进步。</li><li><strong>跟紧潮流趋势。</strong>不管是阅读博客，还是参与编程问题的讨论，甚至是在休息时谈论前端开发的话题，跟紧潮流趋势也会让你保持领先的位置。</li></ul><h2 id="--10">最佳捷径</h2><p>也许你对我的经历和碎碎念并不感兴趣，所以我在这里提供了这个学习资源的列表：</p><p><strong>JavaScript</strong></p><ol><li><a href="https://link.zhihu.com/?target=https%3A//www.codeschool.com/learn/javascript" rel="nofollow noreferrer">CodeSchool</a> 或 <a href="https://link.zhihu.com/?target=https%3A//teamtreehouse.com/tracks/full-stack-javascript" rel="nofollow noreferrer">Treehouse’s</a> Javascript learning path (付费) 或 <a href="https://link.zhihu.com/?target=https%3A//www.codecademy.com/learn/javascript" rel="nofollow noreferrer">Codecademy’s Javascript course</a>.</li><li><a href="https://link.zhihu.com/?target=http%3A//eloquentjavascript.net/" rel="nofollow noreferrer">Eloquent JavaScript</a></li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/getify/You-Dont-Know-JS" rel="nofollow noreferrer">You Don’t Know JS</a></li><li><a href="https://link.zhihu.com/?target=http%3A//jstherightway.org/" rel="nofollow noreferrer">JS: The Right Way</a></li><li><a href="https://link.zhihu.com/?target=https%3A//egghead.io/courses/learn-es6-ecmascript-2015" rel="nofollow noreferrer">Learn ES6</a> by Egghead.io</li></ol><p><strong>HTML &amp; CSS</strong></p><ol><li><a href="https://link.zhihu.com/?target=https%3A//www.codeschool.com/learn/html-css" rel="nofollow noreferrer">CodeSchool</a> 或 <a href="https://link.zhihu.com/?target=https%3A//teamtreehouse.com/tracks" rel="nofollow noreferrer">Treehouse’s</a> HTML &amp; CSS learning path(付费) 或 <a href="https://link.zhihu.com/?target=https%3A//www.amazon.com/HTML-CSS-Design-Build-Websites/dp/1118008189/ref%3Dsr_1_3%3Fie%3DUTF8%26qid%3D1471454089%26sr%3D8-3%26keywords%3Djon%2Bducket" rel="nofollow noreferrer">HTML and CSS: Design and Build Websites</a> by John Ducket 或 <a href="https://link.zhihu.com/?target=https%3A//www.codecademy.com/learn/web" rel="nofollow noreferrer">Codecademy’s HTML &amp; CSS course</a>.</li><li><a href="https://link.zhihu.com/?target=https%3A//css-tricks.com/specifics-on-css-specificity/" rel="nofollow noreferrer">Specifics on CSS Specifity</a> by CSS Tricks</li><li><a href="https://link.zhihu.com/?target=http%3A//learnlayout.com/" rel="nofollow noreferrer">Learn CSS Layout</a></li><li><a href="https://link.zhihu.com/?target=https%3A//smacss.com/" rel="nofollow noreferrer">SMACSS</a></li><li><a href="https://link.zhihu.com/?target=http%3A//blog.froont.com/9-basic-principles-of-responsive-web-design/" rel="nofollow noreferrer">9 basic principles of responsive web design</a> by Froont</li><li><a href="https://link.zhihu.com/?target=https%3A//www.udacity.com/course/responsive-web-design-fundamentals--ud893" rel="nofollow noreferrer">Responsive Web Design Fundamentals</a> by Google on Udacity (如果你没看过 CodeSchool 或 Treehouse learning path)</li><li><a href="https://link.zhihu.com/?target=https%3A//www.smashingmagazine.com/2016/03/managing-mobile-performance-optimization/" rel="nofollow noreferrer">Managing Mobile Performance Optimization</a> by Smashing Magazine 或 <a href="https://link.zhihu.com/?target=https%3A//www.udacity.com/course/browser-rendering-optimization--ud860" rel="nofollow noreferrer">Browser Rendering Optimization</a> 以及 <a href="https://link.zhihu.com/?target=https%3A//www.udacity.com/course/website-performance-optimization--ud884" rel="nofollow noreferrer">Website Performance Optimization</a> by Google on Udacity.</li><li><a href="https://link.zhihu.com/?target=https%3A//developers.google.com/web/fundamentals/%3Fhl%3Den" rel="nofollow noreferrer">Web fundamentals</a> by Google</li></ol><p><strong>Developer Tools</strong></p><ol><li><a href="https://link.zhihu.com/?target=http%3A//discover-devtools.codeschool.com/" rel="nofollow noreferrer">Explore and Master DevTools</a> by CodeSchool</li><li><a href="https://link.zhihu.com/?target=https%3A//www.codecademy.com/learn/learn-git" rel="nofollow noreferrer">Learn Git</a> by Codecademy 和 <a href="https://link.zhihu.com/?target=https%3A//try.github.io/levels/1/challenges/1" rel="nofollow noreferrer">Try Github</a> by Codeschool</li><li><a href="https://link.zhihu.com/?target=https%3A//www.smashingmagazine.com/2012/01/introduction-to-linux-commands/" rel="nofollow noreferrer">Introduction to Linux Commands</a> by Smashing Magazine</li><li><a href="https://link.zhihu.com/?target=https%3A//scotch.io/tutorials/automate-your-tasks-easily-with-gulp-js" rel="nofollow noreferrer">Automate Your Tasks Easily with Gulp.js</a> by Scotch.io</li></ol><p><strong>AngularJS</strong></p><ol><li><a href="https://link.zhihu.com/?target=https%3A//www.youtube.com/watch%3Fv%3DHCR7i5F5L8c" rel="nofollow noreferrer">Design Decisions in AngularJS</a> by Google Developers (介绍 AngularJS)</li><li><a href="https://link.zhihu.com/?target=https%3A//egghead.io/courses/angularjs-app-from-scratch-getting-started" rel="nofollow noreferrer">AngularJS fundamentals</a> by Egghead.io</li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/johnpapa/angular-styleguide/blob/master/a1/README.md" rel="nofollow noreferrer">John Papa’s Angular Styleguide</a></li><li><a href="https://link.zhihu.com/?target=https%3A//scotch.io/tutorials/creating-a-single-page-todo-app-with-node-and-angular" rel="nofollow noreferrer">Creating a Single Page Todo App with Node and Angular</a> (MEAN) by Scotch.io</li><li><a href="https://link.zhihu.com/?target=https%3A//egghead.io/courses/angularjs-application-architecture" rel="nofollow noreferrer">AngularJS application structure</a> by Egghead.io (Paid) OR Scotch.io’s <a href="https://link.zhihu.com/?target=https%3A//scotch.io/tag/angular-js" rel="nofollow noreferrer">Angular Courses</a></li></ol><p><strong>ReactJS</strong></p><ol><li><a href="https://link.zhihu.com/?target=https%3A//scotch.io/tutorials/learning-react-getting-started-and-concepts" rel="nofollow noreferrer">Learning React.js: Getting Started and Concepts</a> by Scotch.io</li><li><a href="https://link.zhihu.com/?target=https%3A//egghead.io/lessons/javascript-intro-to-webpack" rel="nofollow noreferrer">Intro to webpack</a> by Egghead.io</li><li><a href="https://link.zhihu.com/?target=https%3A//egghead.io/courses/react-fundamentals" rel="nofollow noreferrer">React Fundamentals</a> by Egghead.io</li><li><a href="https://link.zhihu.com/?target=https%3A//css-tricks.com/learning-react-redux/" rel="nofollow noreferrer">Leveling Up with React: Redux</a> by CSS Tricks</li></ol><p><strong>Back End</strong></p><ol><li><a href="https://link.zhihu.com/?target=http%3A//nodeschool.io/" rel="nofollow noreferrer">NodeJS tutorials by NodeSchool.io</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.looah.com/source/view/2284" rel="nofollow noreferrer">How I explained REST to my Wife</a></li><li><a href="https://link.zhihu.com/?target=https%3A//scotch.io/tutorials/creating-a-single-page-todo-app-with-node-and-angular" rel="nofollow noreferrer">Creating a Single Page Todo App with Node and Angular</a> by Scotch.io (Node, ExpressJS, MongoDB, Angular, REST)</li></ol><h3 id="--11">推荐文章</h3><p>这是我自己喜欢的一些资源和文章，仅做推荐。（所以就不翻译啦，因为文章也是英文）</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//jgthms.com/web-design-in-4-minutes/" rel="nofollow noreferrer">Web Design in 4 minutes</a>. A very creative and original interactive tutorial that teaches you the fundamentals of web design.</li><li><a href="https://link.zhihu.com/?target=http%3A//www.awwwards.com/" rel="nofollow noreferrer">Awwards</a>. Looking for web design inspiration? Look no further.</li><li><a href="https://link.zhihu.com/?target=https%3A//medium.com/javascript-scene/why-hiring-is-so-hard-in-tech-c462c3230017" rel="nofollow noreferrer">Why Hiring is so hard in tech</a> by Eric Eliott. Here Eric is does an amazing job at summarizing how it’s surprisingly hard to find great developers, and how to become one.</li><li><a href="https://link.zhihu.com/?target=http%3A//kristof%2520kovacs%2520software%2520architect%252C%2520consultant/" rel="nofollow noreferrer">NoSQL database systems mega comparison</a> by Kristof Kovacs. This is a superb comparison between the most popular NoSQL database systems out there. MongoDB, Redis, CouchDB, Cassandra, ElasticSearch, they and more are all here.</li><li><a href="https://link.zhihu.com/?target=https%3A//xss-game.appspot.com/" rel="nofollow noreferrer">XSS Game</a>. Cross-site scripting (XSS) bugs are one of the most common and dangerous types of vulnerabilities in Web applications. Using this awesome resource you can learn how to find and exploit XSS bugs, and how to prevent them from happening to your web application.</li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/Droogans/unmaintainable-code" rel="nofollow noreferrer">How To Write Unmaintainable Code</a>. Hilarious article on how to <strong>NOT</strong> write maintainable, clean code.</li></ul><h3 id="--12">推荐工具软件</h3><p>推荐一些对我自己很有帮助的工具软件。</p><ul><li><a href="https://link.zhihu.com/?target=https%3A//www.jetbrains.com/webstorm/" rel="nofollow noreferrer">Jetbrains Webstorm</a>: 超强前端IDE，学生可以免费使用。</li><li><a href="https://link.zhihu.com/?target=https%3A//atom.io/" rel="nofollow noreferrer">Atom.io</a>: Github出品的免费开源的代码编辑器。</li><li><a href="https://link.zhihu.com/?target=https%3A//www.sublimetext.com/" rel="nofollow noreferrer">Sublime Text</a>: 号称最性感的编辑器。</li><li><a href="https://link.zhihu.com/?target=http%3A//caniuse.com/" rel="nofollow noreferrer">caniuse.com</a>: 查询浏览器的兼容性，非常好用。</li><li><a href="https://link.zhihu.com/?target=https%3A//c9.io/" rel="nofollow noreferrer">Cloud 9</a>: 提供一个在线的Linux虚拟环境，你可以在上面使用Git，Node，部署演示项目等等。</li><li><a href="https://link.zhihu.com/?target=https%3A//codepen.io/" rel="nofollow noreferrer">CodePen</a>, <a href="https://link.zhihu.com/?target=http%3A//plnkr.co/edit" rel="nofollow noreferrer">Plunker</a> and <a href="https://link.zhihu.com/?target=https%3A//jsfiddle.net/" rel="nofollow noreferrer">JSFiddle</a>: 在线写前端代码的地方，可以实时预览，也方便分享给别人。</li><li><a href="https://link.zhihu.com/?target=http%3A//www.vanillalist.com/" rel="nofollow noreferrer">Vanilla List</a>: 一个收集只使用原生JS的库（不依赖jQuery）的列表。</li><li><a href="https://link.zhihu.com/?target=http%3A//youmightnotneedjquery.com/" rel="nofollow noreferrer">You Might Not Need jQuery</a></li><li><a href="https://link.zhihu.com/?target=https%3A//www.publicapis.com/" rel="nofollow noreferrer">PublicAPIs</a>: 所有开放的公共API</li><li><a href="https://link.zhihu.com/?target=https%3A//www.gravit.io/" rel="nofollow noreferrer">Gravit.io</a>: 在线设计Web原型，免费袄。</li><li><a href="https://link.zhihu.com/?target=https%3A//color.adobe.com/" rel="nofollow noreferrer">Adobe Kuler</a>:Adobe家推出的工具，用来给网站配色。</li><li><a href="https://link.zhihu.com/?target=http%3A//chir.ag/projects/name-that-color" rel="nofollow noreferrer">Name that color</a>:不知道CSS某个颜色类该怎么命名？到这里来查询吧。</li></ul><p>原文链接：<a href="https://www.freecodecamp.org/news/my-journey-to-becoming-a-web-developer-from-scratch-without-a-cs-degree-2-years-later-and-what-i-4a7fd2ff5503/">My journey to becoming a web developer from scratch without a CS degree (and what I learned from…</a>，作者：Sergei Garcia</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 什么是 CSS Modules？为什么要使用它？ ]]>
                </title>
                <description>
                    <![CDATA[ 最近我对 CSS 模块特别感兴趣，要是你以前还从未听说过 CSS Modules，那么这个系列就是专门写给你的。首先我们会介绍一下 CSS Modules 是什么以及为什么要将 CSS 模块化，之后大概介绍一下如何应用 CSS Modules。最后如果你想进一步提升自己，可以阅读第三部分介绍的如何在 React 环境下使用 CSS Modules。  * 第一部分：什么是 CSS Modules？为什么要使用它？    [https://chinese.freecodecamp.org/news/introduction-to-css-modules-part-one/]  * 第二部分：CSS Modules 快速上手    [https://chinese.freecodecamp.org/news/introduction-to-css-modules-part-two/]  * 第三部分：在 React 中使用 CSS Modules    [https://chinese.freecodecamp.org/news/introduction-to-css-modules- ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/introduction-to-css-modules-part-one/</link>
                <guid isPermaLink="false">5d3d65bcfbfdee429dc5f4f0</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Mon, 26 Jul 2021 12:02:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/07/altumcode-XMFZqrGyV-Q-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>最近我对 CSS 模块特别感兴趣，要是你以前还从未听说过 CSS Modules，那么这个系列就是专门写给你的。首先我们会介绍一下 CSS Modules 是什么以及为什么要将 CSS 模块化，之后大概介绍一下如何应用 CSS Modules。最后如果你想进一步提升自己，可以阅读第三部分介绍的如何在 React 环境下使用 CSS Modules。<br></p><ul><li>第一部分：<a href="https://chinese.freecodecamp.org/news/introduction-to-css-modules-part-one/">什么是 CSS Modules？为什么要使用它？</a></li><li>第二部分：<a href="https://chinese.freecodecamp.org/news/introduction-to-css-modules-part-two/">CSS Modules 快速上手</a></li><li>第三部分：<a href="https://chinese.freecodecamp.org/news/introduction-to-css-modules-part-three-react/">在 React 中使用 CSS Modules</a></li></ul><h2 id="-css-modules-">什么是 CSS Modules？</h2><p>根据 CSS Modules 在 GitHub上的<a href="https://link.zhihu.com/?target=https%3A//github.com/css-modules/css-modules" rel="nofollow noreferrer">项目</a>，它被解释为：</p><p>所有的类名和动画名称默认都有各自的作用域的 CSS 文件。</p><p>所以 CSS Modules 既不是官方标准，也不是浏览器的特性，而是在构建步骤（例如使用 Webpack 或 Browserify）中对 CSS 类名和选择器限定作用域的一种方式（类似于命名空间）。</p><p>我们还是先看一个具体的例子来解释清楚它到底是什么，以及为什么要使用 CSS Modules 吧。我们通常给 HTML加一个 CSS 的类名来控制它的样式：</p><pre><code class="language-html">&lt;h1 class="title"&gt;An example heading&lt;/h1&gt;
</code></pre><p>CSS 样式像下面这样：</p><pre><code class="language-css">.title {
  background-color: red;
}
</code></pre><p>只要把 CSS 文件加载到 HTML 文件中，这里的 &lt;h1&gt; 标签背景就会被设置成红色。我们不需要对 HTML 或 CSS 做什么特殊的处理，浏览器本来就支持这种最基本的文件类型。</p><p>而 CSS Modules 的使用方式就不一样了，我们需要把所有的标签写到JS文件里。下面是一个简单的示例：</p><pre><code class="language-js">import styles from "./styles.css";

element.innerHTML = 
  `&lt;h1 class="${styles.title}"&gt;
     An example heading
   &lt;/h1&gt;`;
</code></pre><p>在 JS 中你可以通过类似 styles.title 的方式访问 CSS 文件中的 .title 类。然后在构建过程中，我们的构建工具会搜索我们用 import 语句载入的名为 styles.css 的文件，之后把源文件解析成新的 HTML 和 CSS 文件，类名会被特定的格式替换：</p><p><strong>HTML</strong></p><pre><code class="language-html">&lt;h1 class="_styles__title_309571057"&gt;
  An example heading
&lt;/h1&gt;
</code></pre><p><strong>CSS</strong></p><pre><code class="language-css">._styles__title_309571057 {
  background-color: red;
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-33634704e521458996f2f64ae77cac60_hd.png" class="kg-image" alt="v2-33634704e521458996f2f64ae77cac60_hd" width="600" height="400" loading="lazy"></figure><p>类属型的 .title 完全被新生成的命名替换掉了，CSS 的源文件也不会被载入。</p><p>在 <a href="https://link.zhihu.com/?target=http%3A//www.sitepoint.com/understanding-css-modules-methodology/" rel="nofollow noreferrer">Hugo Giraudel 的教程</a> 里也提到：</p><p>在使用 CSS 模块时，类名是动态生成的，唯一的，并准确对应到源文件中的各个类的样式。</p><p>这也是实现样式作用域的原理。它们被限定在特定的模板里。例如我们在 buttons.js 里引入 buttons.css 文件，并使用 .btn 的样式，在其他诸如 forms.js 里是不会被.btn影响的，除非它也引入了 buttons.css.</p><p>可我们是出于什么目的把 CSS 和 HTML 文件搞得这么零碎呢？我们为什么要使用 CSS 模块呢？</p><h2 id="-css-modules--1">为什么要使用 CSS Modules？</h2><p>通过 CSS Modules，我们可以保证单个组件的所有样式：</p><ol><li>集中在同一个地方</li><li>只应用于该组件</li></ol><p>另外，</p><pre><code class="language-js">import buttons from "./buttons.css";
import padding from "./padding.css";

element.innerHTML = `&lt;div class="${buttons.red} ${padding.large}"&gt;`;
</code></pre><p>通过这样的方式可以解决 CSS 全局作用域的问题。</p><p>你一定经历过着急着赶工想要尽快写完 CSS，而根本没有考虑过你的代码会造成什么不良影响吧。</p><p>你也一定干过在某个样式文件的结尾加上随意命名的乱七八糟的样式之类吧。</p><p>你肯定也见过那些你不知道有什么效果，甚至到底有没有被使用的样式吧。</p><p>你难道不想安全地写出不影响其他样式的 CSS 么？担心样式是独立或者依赖别的什么东西么？或者可能会覆盖别的地方的样式？</p><p>诸如此类的问题都足够让人头疼了。而且随着项目的扩张，会越来越令人绝望。</p><p>但使用 CSS Modules 就可以避免这些问题。除非你在某个模块中载入一个 CSS 样式，其他情况下这个样式都不会影响别的 HTML。</p><h2 id="composes-">composes 关键词属性</h2><p>假如我们有如下一个名为 type.css 的样式文件：</p><pre><code class="language-css">.serif-font {
  font-family: Georgia, serif;
}

.display {
  composes: serif-font;
  font-size: 30px;
  line-height: 35px;
}
</code></pre><p>之后我们在模板里声明其中的第二个属性：</p><pre><code class="language-js">import type from "./type.css";

element.innerHTML = 
  `&lt;h1 class="${type.display}"&gt;
    This is a heading
  &lt;/h1&gt;`;
</code></pre><p>生成的结果大概是这个样子：</p><pre><code class="language-html">&lt;h1 class="_type__display_0980340 _type__serif_404840"&gt;
  Heading title
&lt;/h1&gt;
</code></pre><p>样式中的两个属性通过 composes 关键字都加载到了该元素上，实现了类似 Sass 中 @extend 的功能。</p><p>我们甚至可以通过 composes 继承其他文件中的样式：</p><pre><code class="language-css">.element {
  composes: dark-red from "./colors.css";
  font-size: 30px;
  line-height: 1.2;
}
</code></pre><h2 id="bem-">BEM 代码规范不再是必须的</h2><p>在编写 CSS 模块时我们不再需要遵守 <a href="https://link.zhihu.com/?target=https%3A//css-tricks.com/bem-101/" rel="nofollow noreferrer">BEM</a> 规范，有这么两个原因：</p><ol><li><strong>简化语法——</strong>在 CSS Modules 中通过类似 type.display 的表达已经能够很好地被理解了。比起某些 BEM 中例如 .font-size__serif--large 这样的命名要更清晰。</li><li><strong>作用域——</strong>比如我们的一个 CSS 中的 .big 是用来描述文字大小的，另一个 CSS 中的 .big 是用来增加间距的。通过使用 CSS Modules，我们在能够随意使用相同命名类的同时，更不用担心它们之间起冲突。即使是在同一个文件中引入这两个 CSS，最后生成的结果也会把两个样式区别开来。</li></ol><p>这仅仅是使用 CSS Modules 的一点点好处而已。</p><p>如果你想了解更多 CSS Modules 的优点，可以看 Glen Madden 写的<a href="https://link.zhihu.com/?target=http%3A//glenmaddern.com/articles/css-modules" rel="nofollow noreferrer">这篇文章</a>。</p><p>在下一篇中，我们将会讨论如何在项目中通过 Webpack 来使用 CSS Modules，通过使用一些 ES6 的最新特性以及具体的例子来学习。</p><p>原文链接：<a href="https://css-tricks.com/css-modules-part-1-need/">https://css-tricks.com/css-modules-part-1-need/</a>，作者：Robin Rendle</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ JavaScript 权威面试指南 ]]>
                </title>
                <description>
                    <![CDATA[ 根据 Stack Overflow [https://insights.stackoverflow.com/survey/2017#most-popular-technologies]  的调查，JavaScript 自2014年以来就成为了最受欢迎的编程语言。也难怪超过三分之一的开发人员工作都需要了解一些 JavaScript 的知识。所以，如果你打算在不久的将来从事开发工作，你多少都应该熟悉一下这种非常流行的语言。 这篇文章的目的是汇集所有在技术面试中经常提到的 JavaScript 相关概念。有了这篇指南，你就可以在一个地方温故一下你需要了解的关于 JavaScript 的所有知识点。 类型及其转换 JavaScript 内置了7种类型：null, undefined , boolean, number, string, object以及 symbol  (ES6). 除了 object 以外，这几种类型都可以归类为原始类型。 typeof 0              // number typeof true   ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/the-definitive-javascript-handbook-for-a-developer-interview/</link>
                <guid isPermaLink="false">5d2dd4a4fbfdee429dc5eea4</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Fri, 16 Jul 2021 09:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/1_FfREbc94Ge3K3DYG_tEqaQ.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>根据 <a href="https://insights.stackoverflow.com/survey/2017#most-popular-technologies">Stack Overflow</a> 的调查，JavaScript 自2014年以来就成为了最受欢迎的编程语言。也难怪超过三分之一的开发人员工作都需要了解一些 JavaScript 的知识。所以，如果你打算在不久的将来从事开发工作，你多少都应该熟悉一下这种非常流行的语言。</p><p>这篇文章的目的是汇集所有在技术面试中经常提到的 JavaScript 相关概念。有了这篇指南，你就可以在一个地方温故一下你需要了解的关于 JavaScript 的所有知识点。</p><h2 id="-">类型及其转换</h2><p>JavaScript 内置了7种类型：<code>null</code>, <code>undefined</code> , <code>boolean</code>, <code>number</code>, <code>string</code>, <code>object</code>以及 <code>symbol</code> (ES6).</p><p>除了 <code>object</code> 以外，这几种类型都可以归类为<strong>原始类型</strong>。</p><pre><code class="language-js">typeof 0              // number
typeof true           // boolean
typeof 'Hello'        // string
typeof Math           // object
typeof null           // object  !!
typeof Symbol('Hi')   // symbol (New ES6) 
</code></pre><ul><li>Null 与 Undefined</li></ul><p><strong>Undefined</strong> 表示尚未定义。它被用作表示未初始化变量，未提供的函数参数，对象缺少的属性的默认值。当函数没有返回值时也会默认返回 <code>undefined</code> .</p><p><strong>Null</strong> 则表示空值。它可以被赋值给一个变量来表示的“没有值”。</p><ul><li>隐式类型转换</li></ul><p>让我们来看下面这个栗子：</p><pre><code class="language-js">var name = 'Joey';
if (name) {
  console.log(name + " doesn't share food!")  // Joey doesn’t share food!
} 
</code></pre><p>在这种情况下，字符串变量 <code>name</code> 会被转换为 <code>true</code> ，所以我们能够在命令行里输出这段话。那我们到底要如何确定这些真假值的转换呢？</p><p>Falsy 类型的值是指在强制类型转换时会被转换为布尔 <code>false</code> 的值。</p><p>Falsy 类型值包括：<code>""</code>, <code>0</code>, <code>null</code>, <code>undefined</code>, <code>NaN</code>, <code>false</code>.</p><p>除了 Falsy 类型值以外的都被称为 truthy 类型值，它们会被转换为 <code>true</code>.</p><pre><code class="language-js">Boolean(null)         // false
Boolean('hello')      // true 
Boolean('0')          // true 
Boolean(' ')          // true 
Boolean([])           // true 
Boolean(function(){}) // true 
</code></pre><p>没错。你可能注意到了。空的数组，对象和函数布尔值也会被转换为 <code>true</code> ！</p><ul><li>String &amp; Number 运算</li></ul><p>你需要注意的第一件事是 <code>+</code> 操作符。这是一个棘手的操作符，因为它同时适用于数值运算和字符串连接。</p><p>但是，<code>*</code>，<code>/</code>和<code>-</code>操作符都是数字运算专用的。当这些运算符与字符串一起使用时，会强制转换字符串为数字类型的值。</p><pre><code class="language-js">1 + "2" = "12"
"" + 1 + 0 = "10"
"" - 1 + 0 = -1
"-9\n" + 5 = "-9\n5"
"-9\n" - 5 = -14
"2" * "3" = 6
4 + 5 + "px" = "9px"
"$" + 4 + 5 = "$45"
"4" - 2 = 2
"4px" - 2 = NaN
null + 1 = 1
undefined + 1 = NaN 
</code></pre><ul><li>== 与 ===</li></ul><p>对此大多数人的理解肯定是 <code>==</code> 只比较值相等，而 <code>===</code> 在比较的同时还会检查类型。不过这种解释其实是错误的。</p><p>事实上，<code>==</code> 是比较强制类型转换之后的结果，而 <code>===</code> 则是直接比较。</p><pre><code class="language-js">2 == '2'            // True
2 === '2'           // False
undefined == null   // True
undefined === null  // False 
</code></pre><p>强制类型转换有时候会造成一些混乱，我们来看下面这个栗子：</p><pre><code class="language-js">let a = '0';
console.log(Boolean(a)); // True
let b = false;
console.log(Boolean(b)); // False 
</code></pre><p>好，根据以上结果，请告诉我下面这此比较的输出：</p><pre><code class="language-js">console.log(a == b); //(1) 
</code></pre><p>上述代码事实上返回了 True，那么这是为什么呢？</p><p>在 JavaScript 的机制中，当你拿一个其它类型的值和 <code>boolean</code> 类型进行比较时，JavaScript 会将这个布尔值转换为 <code>number</code> 类型再进行比较。（2）</p><p>此时这个问题就变成了 <code>number</code> 和 <code>string</code> 类型值之间的比较。根据我们之前所说的，JavaScript 会把 <code>string</code> 类型转换为 <code>number</code> 类型再比较两个数字。（3）</p><p>所以最后的表达式被转换为了 <code>0 == 0</code>，结果理所当然是 True.</p><pre><code class="language-js">'0' == false   //(1)
'0' == 0       //(2)
 0  == 0       //(3) 
</code></pre><p>如果你想全面理解这种比较是如何进行的，可以查阅<a href="https://link.zhihu.com/?target=http%3A//www.ecma-international.org/ecma-262/5.1/%23sec-11.9.3" rel="nofollow noreferrer">ES5文档</a>。</p><p>这里也有一个 JavaScript 当中各种类型值对比结果的<a href="https://link.zhihu.com/?target=http%3A//dorey.github.io/JavaScript-Equality-Table/" rel="nofollow noreferrer">参照表</a>。</p><p>下面是一些特殊比较的示例：</p><pre><code class="language-js">false == ""  // true
false == []  // true
false == {}  // false
"" == 0      // true
"" == []     // true
"" == {}     // false
0 == []      // true
0 == {}      // false
0 == null    // false 
</code></pre><h2 id="--1">赋值与引用</h2><p>简单值（或者称为原始值 primitives）均是 <code>null</code>, <code>undefined</code> , <code>boolean</code>, <code>number</code>, <code>string</code>, 以及 <code>symbol</code> (ES6)类型的赋值。</p><p>复合值则是对 <code>object</code>，包含 <code>array</code> 以及 <code>function</code> 在内的引用。</p><pre><code class="language-js">var a = 2;        // 'a' hold a copy of the value 2.
var b = a;        // 'b' is always a copy of the value in 'a'
b++;
console.log(a);   // 2
console.log(b);   // 3
var c = [1,2,3];
var d = c;        // 'd' is a reference to the shared value
d.push( 4 );      // Mutates the referenced value (object)
console.log(c);   // [1,2,3,4]
console.log(d);   // [1,2,3,4]
/* Compound values are equal by reference */
var e = [1,2,3,4];
console.log(c === d);  // true
console.log(c === e);  // false 
</code></pre><p>当你想要复制一份复合值的时候，你需要通过一些方法对其进行<strong>拷贝</strong>（这里区分<a href="https://www.zhihu.com/question/23031215">浅拷贝及深拷贝</a>）。这样引用才不会指向同一个值：</p><pre><code class="language-js">const copy = c.slice()    // 'copy' references to a new value
console.log(c);           // [1,2,3,4]
console.log(copy);        // [1,2,3,4]
console.log(c === copy);  // false 
</code></pre><h2 id="--2">作用域</h2><p>作用域是指代码执行时的上下文，它定义了变量以及函数生效的范围。</p><p><strong>全局作用域</strong>指的是最外层的作用域。所有在函数外部声明的变量都会在全局作用域当中，可以在任何地方访问到。在浏览器当中，window 对象就属于全局作用域。</p><p><strong>局部作用域</strong>是指例如在某个函数内部的范围。在局部作用域中声明的变量只能够在其内部被访问到。</p><pre><code class="language-js">function outer() {
  let a = 1;
  function inner() {
    let b = 2;
    function innermost() {
      let c = 3;
      console.log(a, b, c);   // 1 2 3
    }
    innermost();
    console.log(a, b);        // 1 2 — 'c' is not defined
  }
  inner();
  console.log(a);             // 1 — 'b' and 'c' are not defined
}
outer(); 
</code></pre><p>为了便于理解，你可以把作用域想象为一扇扇从大到小排列的门。最矮的人（上述代码1，2，3表示高矮）可以进入最小的门（innermost 的作用域），同时也能通过最大的门（outer 的作用域）。</p><p>而个子高的人在通过门时则会被卡住（也就是在外部访问不到内部定义的变量）。</p><h2 id="-hoisting">变量提升 Hoisting</h2><p>在编译过程中，JavaScript 会自动把 <code>var</code> 和 <code>function</code> 声明移动到顶部的行为被称为 <strong>hoisting</strong>.</p><p>函数声明会被完整地提升。这就意味着你在编写代码时可以在声明一个函数之前就调用它：</p><pre><code class="language-js">console.log(toSquare(3));  // 9

function toSquare(n){
  return n*n;
} 
</code></pre><p>变量只会被部分提升。例如只有 <code>var</code> 的声明会被提升，而赋值则不会。</p><p><code>let</code> 以及 <code>const</code> 也不会被提升。</p><pre><code class="language-js">{  /* Original code */
  console.log(i);  // undefined
  var i = 10
  console.log(i);  // 10
}

{  /* Compilation phase */
  var i;
  console.log(i);  // undefined
  i = 10
  console.log(i);  // 10
}
// ES6 let &amp; const
{
  console.log(i);  // ReferenceError: i is not defined
  const i = 10
  console.log(i);  // 10
}
{
  console.log(i);  // ReferenceError: i is not defined
  let i = 10
  console.log(i);  // 10
} 
</code></pre><h2 id="--3">函数表达式 与 函数声明</h2><ul><li>函数表达式</li></ul><p>函数表达式只有被执行之后才可用，它不会被提升（相当于赋值函数表达式给变量）。</p><pre><code class="language-js">var sum = function(a, b) {
  return a + b;
} 
</code></pre><ul><li>函数声明</li></ul><p>函数声明则可以在定义前后被任意调用，因为它最终会被提升。</p><pre><code class="language-js">function sum(a, b) {
  return a + b;
}
</code></pre><h2 id="-var-let-cost">变量声明方式：var let cost</h2><p>在 ES6 之前，只有 <code>var</code> 一种声明变量的方法。在某一函数内部声明的变量和方法只能在其函数作用域内部访问到。</p><p>一些在例如 <code>if</code> 或者 <code>for</code> 语句的块作用域内声明的变量，能够在其包含的大括号外被访问到。</p><p><strong>注意：</strong>未使用 <code>var</code>，<code>let</code> 或 <code>const</code> 关键字声明的变量会自动变成全局变量。</p><pre><code class="language-js">function greeting() {
  console.log(s) // undefined
  if(true) {
    var s = 'Hi';
    undeclaredVar = 'I am automatically created in global scope';
  }
  console.log(s) // 'Hi'
}
console.log(s);  // Error — ReferenceError: s is not defined
greeting();
console.log(undeclaredVar) // 'I am automatically created in global scope' 
</code></pre><p>ES6 中我们有了 <code>let</code> 和 <code>const</code> 这两个新的关键字。它们不会被提升，且可以在块级作用域内生效：</p><pre><code class="language-js">let g1 = 'global 1'
let g2 = 'global 2'
{   /* Creating a new block scope */
  g1 = 'new global 1'
  let g2 = 'local global 2'
  console.log(g1)   // 'new global 1'
  console.log(g2)   // 'local global 2'
  console.log(g3)   // ReferenceError: g3 is not defined
  let g3 = 'I am not hoisted';
}
console.log(g1)    // 'new global 1'
console.log(g2)    // 'global 2' 
</code></pre><p>另外有一个普遍的误解是 <code>const</code> 是不可变的。事实上它只是不能被重新赋值，但其指向的值是可以被操作的：</p><pre><code class="language-js">const tryMe = 'initial assignment';
tryMe = 'this has been reassigned';  // TypeError: Assignment to constant variable.
// You cannot reassign but you can change it…
const array = ['Ted', 'is', 'awesome!'];
array[0] = 'Barney';
array[3] = 'Suit up!';
console.log(array);     // [“Barney”, “is”, “awesome!”, “Suit up!”]
const airplane = {};
airplane.wings = 2;
airplane.passengers = 200;
console.log(airplane);   // {passengers: 200, wings: 2} 
</code></pre><h2 id="-closure">闭包 Closure</h2><p>闭包是一个函数及其词法环境的组合。闭包可以让我们在一个函数的作用范围外访问其内部的变量。</p><pre><code class="language-js">function sayHi(name){
  var message = `Hi ${name}!`;
  function greeting() {
    console.log(message)
  }
  return greeting
}
var sayHiToJon = sayHi('Jon');
console.log(sayHiToJon)     // ƒ() { console.log(message) }
console.log(sayHiToJon())   // 'Hi Jon!' 
</code></pre><p>1.获取变量到外部作用域。</p><p>返回的 <code>greeting</code> 方法访问了其内部作用域的 <code>message</code> 变量。</p><p>2.即使在外部函数返回之后也能访问到作用域外的变量。</p><p><code>sayHiToJon</code> 是在调用 <code>sayHi</code> 方法时对 <code>greeting</code> 的引用。这样我们就能够通过 <code>greeting</code>访问到作用域外的 <code>message</code> 变量。</p><p>闭包比较有用的地方在于我们可以用它来实现<strong>数据封装</strong>。有一些理念认为，有些数据不应该直接暴露在外，我们举个栗子来说明：</p><p>例如在下面这段代码当中，我们只能过通过 <code>elementary</code> 的实例来访问和操作 <code>SpringfieldSchool</code> 内部的 <code>staff</code> 变量，而不用担心其在其他地方被改动。</p><pre><code class="language-js">function SpringfieldSchool() {
  let staff = ['Seymour Skinner', 'Edna Krabappel'];
  return {
    getStaff: function() { console.log(staff) },
    addStaff: function(name) { staff.push(name) }
  }
}

let elementary = SpringfieldSchool()
console.log(elementary)        // { getStaff: ƒ, addStaff: ƒ }
console.log(staff)             // ReferenceError: staff is not defined
/* Closure allows access to the staff variable */
elementary.getStaff()          // ["Seymour Skinner", "Edna Krabappel"]
elementary.addStaff('Otto Mann')
elementary.getStaff()          // ["Seymour Skinner", "Edna Krabappel", "Otto Mann"] 
</code></pre><p>我们接着再来用闭包解决一个面试中最常见的问题吧：</p><p>下面这段代码存在什么问题？如何输出我们想要的结果？</p><pre><code class="language-js">const arr = [10, 12, 15, 21];
for (var i = 0; i &lt; arr.length; i++) {
  setTimeout(function() {
    console.log(`The value ${arr[i]} is at index: ${i}`);
  }, (i+1) * 1000);
} 
</code></pre><p>这段代码执行的输出结果中，每次 <code>i</code> 都等于4.这是因为 <code>setTimeout</code> 方法执行的时候，循环早已运行结束。</p><p>我们可以通过立即执行函数 IIFE 来解决这个问题，它可以创建出独立的作用域来存储每次传入 <code>i</code>的值。</p><pre><code class="language-js">const arr = [10, 12, 15, 21];
for (var i = 0; i &lt; arr.length; i++) {
  (function(j) {
    setTimeout(function() {
      console.log(`The value ${arr[j]} is at index: ${j}`);
    }, j * 1000);
  })(i)
} 
</code></pre><p>另外一个更简洁的答案是使用 <code>let</code> 关键字来声明变量 <code>i</code>，也能够得到相同的结果：</p><pre><code class="language-js">const arr = [10, 12, 15, 21];
for (let i = 0; i &lt; arr.length; i++) {
  setTimeout(function() {
    console.log(`The value ${arr[i]} is at index: ${i}`);
  }, (i) * 1000);
} 
</code></pre><h2 id="-iife">立即执行函数表达式 IIFE</h2><p>正如其名，立即执行函数在定义时就会被执行。我们通常在创建一个新的变量作用域时使用到它。</p><p>表达式外的括号用来和函数声明作以区分。</p><p>结尾的括号表示对函数的调用。</p><pre><code class="language-js">var result = [];
for (var i=0; i &lt; 5; i++) {
  result.push( function() { return i } );
}
console.log( result[1]() ); // 5
console.log( result[3]() ); // 5
result = [];
for (var i=0; i &lt; 5; i++) {
  (function () {
    var j = i; // copy current value of i
    result.push( function() { return j } );
  })();
}
console.log( result[1]() ); // 1
console.log( result[3]() ); // 3 
</code></pre><p>通过使用IIFE你可以：</p><ul><li>使你能过添加私有数据到一个方法中</li><li>创建新的作用环境</li><li>防止污染全局命名空间</li></ul><h2 id="--4">上下文</h2><p>上下文的概念经常会同作用域之间混淆。为了保持条理清晰，我们需要注意以下两条：</p><ul><li>上下文是在函数被调用时确定的。它通常指的是你的代码当中某一部分的值。</li><li>作用域值的则是变量能过被访问到的范围。</li></ul><pre><code class="language-js">// 作用域
var param = 1;      // global scope
function myScope(){
    var param = 2;     // local scope
}
// 上下文
this.prop = 1;      // global context
function myContext(){
    this.prop = 2;   // local context
}
var myInstance = new myContext(); 
</code></pre><p>例如上述实例当中调用 <code>this</code> 的位置不同，<code>this</code> 的指向也是不同的，也就表示着不同的上下文；而作用域则是我们在编写代码时使用 <code>var</code> 关键字来确定的。</p><h2 id="-call-apply-bind">函数调用方式：call apply bind</h2><p>这三种方法可以改变函数调用时 <code>this</code> 的指向，区别则在于函数调用的时候。</p><ul><li><code>.call()</code> 会立即调用函数，并要求你按次序一个个传入参数。</li><li><code>.apply()</code> 也会立即调用函数，不过你需要以数组的形式传参。</li><li><code>.call()</code> 和 <code>.apply()</code> 效用几乎是相同的，它们都可以用来调用对象中的某个方法，具体怎么使用取决于你的使用场景里如何传参更方便。</li></ul><p><strong>应用示例：</strong></p><pre><code class="language-js">const Snow = {surename: 'Snow'}
const char = {
  surename: 'Stark',
  knows: function(arg, name) {
    console.log(`You know ${arg}, ${name} ${this.surename}`);
  }
}
char.knows('something', 'Bran');              // You know something, Bran Stark
char.knows.call(Snow, 'nothing', 'Jon');      // You know nothing, Jon Snow
char.knows.apply(Snow, ['nothing', 'Jon']);   // You know nothing, Jon Snow 
</code></pre><p><strong>注意：</strong> 如果你在使用 <code>.call()</code> 时传入了数组形式的参数，它会把整个数组当作一个参数使用。</p><p>不过在 ES6 里你倒是可以试试展开操作符的方法进行传参：</p><pre><code class="language-js">char.knows.call(Snow, ...["nothing", "Jon"]);  // You know nothing, Jon Snow 
</code></pre><p><code>.bind()</code> 不会直接触发某个方法，而是根据你传入的参数和上下文返回一个新的方法。当你想要在程序之后的某些上下文环境中调用一个方法时可以使用 <code>.bind()</code> 这种方式。</p><p>这在我们使用一些异步操作或者事件处理函数时非常有用。<code>.bind()</code> 的传参形式则类似于 <code>.call()</code> 你需要讲参数以逗号分隔传入：</p><pre><code class="language-js">const Snow = {surename: 'Snow'}
const char = {
  surename: 'Stark',
  knows: function(arg, name) {
    console.log(`You know ${arg}, ${name} ${this.surename}`);}
  }
const whoKnowsNothing = char.knows.bind(Snow, 'nothing');
whoKnowsNothing('Jon');  // You know nothing, Jon Snow 
</code></pre><h2 id="this-">this 关键字</h2><p>JavaScript 当中的 <code>this</code> 理解起来算比较复杂的。</p><p><code>this</code> 具体指向什么是由函数的执行上下文决定的（其实上一节已经有很多栗子了）。</p><p>关键字 <code>this</code> 类似于一个占位符。它会指向具体调用某个方法的对象。</p><p>下面这个检查表用来确定 <code>this</code> 的顺位规则：</p><ul><li><strong><code>new</code>binding</strong> 当使用 <code>new</code> 关键字调用某个函数时，<code>this</code> 会被绑定到新构造的对象上。</li></ul><pre><code class="language-js">function Person(name, age) {
  this.name = name;
  this.age =age;
  console.log(this);
}
const Rachel = new Person('Rachel', 30);   // { age: 30, name: 'Rachel' } 
</code></pre><ul><li><strong>显式绑定</strong> 当使用 <code>call</code> 或者 <code>apply</code> 方法调用函数时，<code>this</code> 会指向我们传入的对象。<code>bind</code>我们在前面已经介绍过了，返回的是一个新的函数而不是直接调用。</li></ul><pre><code class="language-js">function fn() {
  console.log(this);
}
var agent = {id: '007'};
fn.call(agent);    // { id: '007' }
fn.apply(agent);   // { id: '007' }
var boundFn = fn.bind(agent);
boundFn();         // { id: '007' } 
</code></pre><ul><li><strong>隐式绑定</strong> 当我们在某一具体上下文中调用一个函数时，<code>this</code> 会指向这个函数所属的对象。</li></ul><pre><code class="language-js">var building = {
  floors: 5,
  printThis: function() {
    console.log(this);
  }
}
building.printThis();  // { floors: 5, printThis: function() {…} } 
</code></pre><ul><li><strong>默认绑定</strong> 如果函数在调用时不遵从上述所有规则，那么 <code>this</code> 会被绑定在全局对象上（在浏览器里，这个全局对象就是 <code>window</code>）。</li></ul><p>这种情况会在我们定义独立函数时出现，如果一个函数在定义时不属于任何对象，它就会默认成为全局对象的一个属性。</p><pre><code class="language-js">function printWindow() {
  console.log(this)
}
printWindow();  // window object 
</code></pre><p><strong>注意：</strong> 即使是在不同的作用域下，调用这种独立函数也不会改变其 <code>this</code> 的指向：</p><pre><code class="language-js">function Dinosaur(name) {
  this.name = name;
  var self = this;
  inner();
  function inner() {
    alert(this);        // window object — the function has overwritten the 'this' context
    console.log(self);  // {name: 'Dino'} — referencing the stored value from the outer context
  }
}
var myDinosaur = new Dinosaur('Dino'); 
</code></pre><ul><li><strong>语法绑定</strong> 当你以 <code>=&gt;</code> 箭头函数的形式调用某一方法时，相当于为其传入了当前执行上下文的 <code>this</code> 值。</li></ul><pre><code class="language-js">function Cat(name) {
  this.name = name;
  console.log(this);   // { name: 'Garfield' }
  ( () =&gt; console.log(this) )();   // { name: 'Garfield' }
}
var myCat = new Cat('Garfield'); 
</code></pre><h2 id="--5">严格模式</h2><p>我们可以通过使用 <code>"use strict"</code> 指令来启用 JavaScript 的严格模式。它会为你的代码添加更多的限制及错误处理。</p><p>使用严格模式的好处有：</p><ul><li><strong>更方便调试</strong> 你能够看到更多的报错，例如在你试图为只读的全局对象或属性赋值时。</li><li><strong>防止意外产生全局变量</strong> 对未声明的变量进行赋值时会报错。</li><li><strong>禁止无效的删除操作</strong> 尝试删除变量、函数、不可删除的属性时会报错。</li><li><strong>禁止重复的属性名及参数</strong> 如果有命名重复的属性名或者参数值就会报错。</li><li><strong>让 eval() 的调用更加安全</strong> 在 <code>eval()</code> 方法内部定义的变量及函数不会污染其他作用域。</li><li><strong>禁止 this 指向全局对象</strong> 当 <code>this</code> 的值为 null 或者 undefined 时不会再默认指向到全局对象。这也就意味着在函数内部的 <code>this</code> 不会再默认指向 <code>window</code> 对象了。</li></ul><h2 id="new-">new 关键字</h2><p>关键字 <code>new</code> 是一种非常特殊的调用函数的方法，被通过 <code>new</code> 关键字调用的函数被称为<strong>构造函数</strong>。</p><p>所以 <code>new</code> 到底进行了哪些操作呢？</p><ol><li>创建了一个新的对象。</li><li>新对象的原型继承自构造函数的原型。</li><li>以新对象的 <code>this</code> 执行构造函数。</li><li>返回新的对象。如果构造函数返回了一个对象，那么这个对象会取代整个 <code>new</code> 出来的结果。</li></ol><pre><code class="language-js">// In order to better understand what happens under the hood, lets build the new keyword 
function myNew(constructor) {
  var obj = {}
  Object.setPrototypeOf(obj, constructor.prototype);
  return constructor.apply(obj, [...arguments].slice(1)) || obj
} 
</code></pre><p>那么在调用函数时使用 <code>new</code> 关键字与否到底有什么区别呢？</p><pre><code class="language-js">function Bird() {
  this.wings = 2;
}
/* invoking as a normal function */
let fakeBird = Bird();
console.log(fakeBird);    // undefined
/* invoking as a constructor function */
let realBird= new Bird();
console.log(realBird)     // { wings: 2 } 
</code></pre><h2 id="--6">原型与继承</h2><p>原型是 JavaScript 当中最容易造成困惑的一个概念。原因之一是因为<strong>原型</strong>这个词会在两个语境下使用：</p><ul><li><strong>原型关系</strong></li></ul><p>每个对象都有自己的原型对象，并会继承它原型的所有属性。</p><p>你可以通过 <code>.__proto__</code> 这种非标准的机制来获取一个对象的原型（在ES6中，在 ES5 标准里还可以通过 <code>Object.getPrototypeOf()</code> 方法来获取）。</p><p>一般的对象还会继承一个叫做 <code>.constructor</code> 的属性指向其构造函数。当你使用构造函数生成一个对象时，其 <code>.__proto__</code> 属性会指向构造函数的 <code>.prototype</code> 属性。</p><ul><li><strong>原型属性</strong></li></ul><p>每个被定义的函数都有一个名为 <code>.prototype</code> 的属性。</p><p>它是一个继承了原型链上所有属性的对象。这个对象也默认包括一个 <code>.constructor</code> 属性，指向原始的构造函数。</p><p>所有用构造函数生成的对象也会继承一个指向这个函数的 <code>.constructor</code> 属性（用控制台把对象打出来会比较好理解，也可以看下面的示例）。</p><pre><code class="language-js">function Dog(breed, name){
  this.breed = breed,
  this.name = name
}
Dog.prototype.describe = function() {
  console.log(`${this.name} is a ${this.breed}`)
}
const rusty = new Dog('Beagle', 'Rusty');

/* .prototype property points to an object which has constructor and attached 
properties to be inherited by objects created by this constructor. */
console.log(Dog.prototype)  // { describe: ƒ , constructor: ƒ }

/* Object created from Dog constructor function */
console.log(rusty)   //  { breed: "Beagle", name: "Rusty" }
/* Object inherited properties from constructor function's prototype */
console.log(rusty.describe())   // "Rusty is a Beagle"
/* .__proto__ property points to the .prototype property of the constructor function */ 
console.log(rusty.__proto__)    // { describe: ƒ , constructor: ƒ }
/* .constructor property points to the constructor of the object */
console.log(rusty.constructor)  // ƒ Dog(breed, name) { ... }
</code></pre><p><strong>原型链</strong></p><p>原型链描述了对象之间相互引用的关系。</p><p>当获取一个对象的属性时，JavaScript 引擎会先从这个对象本身开始查找。如果没有找到，就会转向其原型上的属性，直到第一次找到这个属性为止。原型链上的最后一个对象是内置的 <code>Object.prototype</code> 而它的原型则是 <code>null</code>（也就是所谓原型链的终点）。JavaScript 引擎在查找属性到这一层还是没有找到时就会返回 <code>undefined</code>.</p><p><strong>自有属性与继承属性</strong></p><p>对象的属性分为自有和继承两种。</p><p>自有属性也就是在对象内部定义的属性。</p><p>继承属性则是通过原型链获得的属性。继承属性是不可枚举的（也就是在 <code>for/in</code> 循环里看不到的）。</p><pre><code class="language-js">function Car() { }
Car.prototype.wheels = 4;
Car.prototype.airbags = 1;

var myCar = new Car();
myCar.color = 'black';

/*  Check for Property including Prototype Chain:  */
console.log('airbags' in myCar)  // true
console.log(myCar.wheels)        // 4
console.log(myCar.year)          // undefined

/*  Check for Own Property:  */
console.log(myCar.hasOwnProperty('airbags'))  // false — Inherited
console.log(myCar.hasOwnProperty('color'))    // true
</code></pre><p><strong>Object.create(obj)</strong> 方法可以指定原型来创建对象：</p><pre><code class="language-js">var dog = { legs: 4 };
var myDog = Object.create(dog);

console.log(myDog.hasOwnProperty('legs'))  // false
console.log(myDog.legs)                    // 4
console.log(myDog.__proto__ === dog)       // true 
</code></pre><p><strong>通过引用继承</strong></p><p>继承属性是原型对象上属性的一份引用拷贝。</p><p>如果对象在原型上的属性被改变了，继承这一属性的对象也会受到相同的影响。但假如属性被整个替换掉了，则不会影响到继承的对象：</p><pre><code class="language-js">var objProt = { text: 'original' };
var objAttachedToProt = Object.create(objProt);
console.log(objAttachedToProt.text)   // original

objProt.text = 'prototype property changed';
console.log(objAttachedToProt.text)   // prototype property changed

objProt = { text: 'replacing property' };
console.log(objAttachedToProt.text)   // prototype property changed 
</code></pre><p><strong>类继承与原型继承</strong></p><p>在类继承模式当中，对象继承自各式各样的类。就好像为对象设置好了一些模版和描述，并创建出了子类关系。我们可以通过 <code>new</code> 关键字从构造函数中创建这样的对象。</p><p>但类继承模式有以下这些缺点：</p><ul><li>死板的层级关系</li><li>高度耦合</li><li>基类薄弱</li><li>代码重复</li><li>以及传说中的大猩猩/香蕉问题——“What you wanted was a banana, what you got was a gorilla holding the banana, and the entire jungle.”</li></ul><p>在原型继承模式中，一个对象可以直接继承另一个对象。我们可以通过 <code>Object.create()</code> 或者其他对象方法及工厂函数来创建对象。</p><p>下面是三种不同的原型继承的形式：</p><ul><li><strong>原型代理</strong> 我们通常称那些用来给其他对象提供模型的对象为代理原型。当你继承一个代理原型时，新的对象可以获取对代理原型属性的引用。这种操作通常使用 <code>Object.create()</code> 来完成。</li><li><strong>拼接继承</strong> 通过拷贝一个对象的属性来进行继承，不会产生引用关系，这种操作通常使用 <code>Object.assign()</code> 来进行。</li><li><strong>函数继承</strong> 这种方法是通过工厂函数（工厂函数是指不通过 <code>new</code> 关键字创建并返回对象的函数）来创建对象，然后直接将新的属性添加到对象上。这种形式的好处是我们可以使用闭包进行数据封装。</li></ul><pre><code class="language-js">const person = function(name) {
  const message = `Hello! My name is ${name}`;
  return { greeting: () =&gt; console.log(message) }
}
const will = person("Will");
will.greeting();     // Hello! My name is Will 
</code></pre><p><strong>组合与继承</strong></p><p>开发者都公认在大多数情况下应该避免使用类继承。因为在这种模式下，你需要很清楚地定义设计你的代码它们是什么。</p><p>而另一方面，组合的模式则允许你从你的代码要做什么的角度来定义，从而提高你代码的灵活度和可复用性（<a href="https://link.zhihu.com/?target=https%3A//doc.react-china.org/docs/composition-vs-inheritance.html" rel="nofollow noreferrer">React组件</a>就是一个非常好的栗子）。</p><h2 id="javascript-">JavaScript 异步</h2><p>JavaScript 是一种单线程编程语言。这意味着 JavaScript 引擎一次只能处理一段代码。其主要影响之一是，当 JavaScript 遇到一段需要很长时间处理的代码时，它会阻塞后续的代码运行。</p><p>JavaScript 使用了一种存储运行函数信息的数据结构叫做<strong>调用栈</strong>。你可以吧调用栈想象为一摞书。每本放上去的书都会在之前的一摞书上面。最后放上去的书会最早被拿走，最先放上去的书则到最后才会被拿走（LIFO）。</p><p>用来解决大段代码非阻塞执行的方法叫做异步回调函数。这类函数可以推迟执行。</p><p>异步过程从一个放入堆或内存中的异步回调函数开始。你可以将堆视为一个<strong>事件管理器</strong>。调用栈可以访问事件管理器只在某个事件发生时才执行特定的函数。当某个事件发生后，事件管理器就会将该函数移至回调用队列。<strong>注意：</strong>当事件管理器处理一个函数时，之后的代码不会被阻塞并且能继续执行。</p><p>调用栈会不断检查其是否空闲。当它空闲时，如果有一个等待被调用的函数，则会检查调用队列。当有函数在等待执行时，队列中的第一个函数被压入调用栈并执行。这一过程被称为事件循环当中的一次执行循环.</p><p>我们还是用一个栗子来解释吧：</p><pre><code class="language-js">const first = function () {
  console.log('First message')
}
const second = function () {
  console.log('Second message')
}
const third = function() {
  console.log('Third message')
}

first();
setTimeout(second, 0);
third();

// Output:
  // First message
  // Third message
  // Second message 
</code></pre><ol><li>初始化浏览器的控制台，清空调用栈及事件管理器。</li><li><code>first()</code> 加入调用栈。</li><li><code>console.log("First message")</code> 加入调用栈。</li><li><code>console.log("First message")</code> 被执行并在浏览器控制台打印出"First message".</li><li><code>console.log("First message")</code> 被移出调用栈。</li><li><code>first()</code> 被移出调用栈。</li><li><code>setTimeout(second, 0)</code> 加入调用栈。</li><li><code>setTimeout(second, 0)</code> 被执行并由事件管理器管理。0ms 之后事件管理器将 <code>second()</code>移入调用队列。</li><li><code>setTimeout(second, 0)</code> 完成执行并被移出调用栈。</li><li><code>third()</code> 加入调用栈。</li><li><code>console.log("Third message")</code> 加入调用栈。</li><li><code>console.log("Third message")</code> 被执行并在浏览器控制台打印出"Third message".</li><li><code>console.log("Third message")</code> 被移出调用栈。</li><li><code>third()</code> 被移出调用栈。</li><li>调用栈空闲，<code>second()</code> 在调用队列中等待执行。</li><li>事件管理器将 <code>second()</code> 从调用队列中移入调用栈。</li><li><code>console.log("Second message")</code> 加入调用栈。</li><li><code>console.log("Second message")</code> 被执行并在浏览器控制台打印出"Second message".</li><li><code>console.log("Second message")</code> 被移出调用栈。</li><li><code>second()</code> 被移出调用栈。</li></ol><p><strong>注意：</strong>你为 <code>setTimeout</code> 方法传入的时间参数并不是 <code>second()</code> 延迟执行的时间，而是事件管理器将函数移入调用栈的等待时间。</p><p>能坚持读到最后真是难能可贵。欢迎在评论区交流讨论。</p><p>原文链接：<a href="https://www.freecodecamp.org/news/the-definitive-javascript-handbook-for-a-developer-interview-44ffc6aeb54e/">The Definitive JavaScript Handbook for your next developer interview</a>，作者：<a href="https://www.freecodecamp.org/news/author/gustavoaz7/">Gustavo Azevedo</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 你也可以成为 Web 开发工程师！——Web 开发工程师完全成长指南 ]]>
                </title>
                <description>
                    <![CDATA[ 这篇文章是教你如何成为一名专业 Web 开发工程师的养成指南。我从事 Web 开发的相关工作已经有 20 个年头了。在工作中我也很乐于帮助其他开发者。在接下来的内容里，我将告诉你想要成为一名 Web 开发者应该学些什么？怎么去学？在哪里学？（大多数是免费的资源）。最后我还会介绍如何获得开发的实践经验，以及最重要的一点——如何通过写代码赚到钱。 > 译者按：为了对初学者更加友好，我会将原文中的大多数链接替换成同类中文资源。 在我们正式开始之前有两点需要提醒的： 1.你完全可以跳过文中的部分内容。 不管你现在处于学习Web开发的那个阶段，这篇指南都会对你有所帮助。本篇教程的每个章节根据描述你掌握知识的进度命名。你可以直接跳到最符合你当前情况的部分开始读。不过作为一名初学者，或者只是才打算开始学习Web开发，还是从头开始阅读吧。 2.在你选定某个专业方向之前先把所有的都尝试一下。 赚钱不是最重要的，重要的是你需要热爱你的工作。但你不去尝试永远都不会知道自己喜欢什么。 在这篇教程中将会带你领略Web开发的各个领域，首先浅尝辄止，然后再帮你挑选你所感兴趣的方向。在一开始，你不需要精通 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/the-practical-guide-to-becoming-a-professional-web-developer/</link>
                <guid isPermaLink="false">5d41a57cfbfdee429dc5f558</guid>
                
                    <category>
                        <![CDATA[ Web开发 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Sun, 11 Jul 2021 12:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/1_PcdVjpFt9JgG1rKFTw6p_A.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>这篇文章是教你如何成为一名专业 Web 开发工程师的养成指南。我从事 Web 开发的相关工作已经有 20 个年头了。在工作中我也很乐于帮助其他开发者。在接下来的内容里，我将告诉你想要成为一名 Web 开发者应该学些什么？怎么去学？在哪里学？（大多数是免费的资源）。最后我还会介绍如何获得开发的实践经验，以及最重要的一点——如何通过写代码赚到钱。</p><blockquote>译者按：为了对初学者更加友好，我会将原文中的大多数链接替换成同类中文资源。</blockquote><p>在我们正式开始之前有两点需要提醒的：</p><p><strong>1.你完全可以跳过文中的部分内容。</strong></p><p>不管你现在处于学习Web开发的那个阶段，这篇指南都会对你有所帮助。本篇教程的每个章节根据描述你掌握知识的进度命名。你可以直接跳到最符合你当前情况的部分开始读。不过作为一名初学者，或者只是才打算开始学习Web开发，还是从头开始阅读吧。</p><p><strong>2.在你选定某个专业方向之前先把所有的都尝试一下。</strong></p><p>赚钱不是最重要的，重要的是你需要热爱你的工作。但你不去尝试永远都不会知道自己喜欢什么。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-9e1417f8e7ed48d5c3cb2bab6316900e_hd.jpg" class="kg-image" alt="v2-9e1417f8e7ed48d5c3cb2bab6316900e_hd" width="600" height="400" loading="lazy"></figure><p>在这篇教程中将会带你领略Web开发的各个领域，首先浅尝辄止，然后再帮你挑选你所感兴趣的方向。在一开始，你不需要精通任何技术，只需要了解一些皮毛然后就去看看别的。直到你找到了一个想要努力的方向，再进行深入的学习。</p><h2 id="-web-">我已经决定要学习编程了。我也喜欢Web开发，但就是不知道可以从哪里开始。</h2><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-9dbaa8c5fc149ee04a620e51e941cef3_hd.jpg" class="kg-image" alt="v2-9dbaa8c5fc149ee04a620e51e941cef3_hd" width="600" height="400" loading="lazy"></figure><p>我先得恭喜你做了一个明智的决定！下定决心的你其实已经迈出了一大步，学习Web开发非常刺激，当然有时候也会充满挫折。不过别担心，我这不就是来帮你的么？</p><p>你的首要任务是尽快地了解Web开发各个领域的基础知识（通常也统称“全栈”）。你需要掌握的知识会非常宽泛，但也都很基础。这些都只是为了帮助你寻找到你最喜欢的领域，同时掌握一些最基本的通用知识。这样在你决定专精某项知识之前，也能处理好各个方面的困难和挑战。</p><p><strong>学习HTML基础</strong></p><p>Hypertext Markup Language 超文本标记语言(HTML)用来控制描述现在你在浏览器里看到的网页的内容和布局。从这里开始，你将会了解到如何创建可以与之交互的 <strong>用户界面</strong>。在你掌握了更多的语言之后，现在的所学就会变得尤为重要。</p><p>我在下面列出了你需要掌握的有关HTML的基础知识（都是免费的在线教程，下列教程来自<a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/" rel="nofollow noreferrer">菜鸟教程</a>）：</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-intro.html" rel="nofollow noreferrer">简介</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-elements.html" rel="nofollow noreferrer">元素</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-headings.html" rel="nofollow noreferrer">标题</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-paragraphs.html" rel="nofollow noreferrer">段落</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-head.html" rel="nofollow noreferrer">头部</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-lists.html" rel="nofollow noreferrer">列表</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-links.html" rel="nofollow noreferrer">链接</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-images.html" rel="nofollow noreferrer">图像</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-tables.html" rel="nofollow noreferrer">表格</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-forms.html" rel="nofollow noreferrer">表单</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html-quicklist.html" rel="nofollow noreferrer">总结</a></li></ul><h2 id="-html-">我现在已经掌握了HTML基础</h2><p>很棒！这是重要的第一步！现在你该学点基本的JavaScript啦~</p><p><strong>学习JavaScript基础</strong></p><p>JavaScript是专门针对Web的编程语言，所有的主流浏览器（Chrome, Firefox, Safari, IE等）都内置支持JavaScript语言。你之前使用过的所有网站和Web应用也都包含大量的JavaScript代码。并且现在的JavaScript语言已经扩展到了包括<a href="https://link.zhihu.com/?target=https%3A//nodejs.org/en/" rel="nofollow noreferrer">服务器端</a>、<a href="https://link.zhihu.com/?target=http%3A//www.wired.com/2016/05/javascript-conquered-web-now-taking-desktop/" rel="nofollow noreferrer">桌面应用</a>、<a href="https://link.zhihu.com/?target=http%3A//postscapes.com/javascript-and-the-internet-of-things" rel="nofollow noreferrer">物联网设备</a>在内的各类平台。</p><p>不过这才刚刚开始，你只需要了解一些基础知识（以下链接来自<a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000" rel="nofollow noreferrer">廖雪峰JavaScript教程</a>）：</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143449917624134f5c4695b524e81a581ab5a222b05ec000" rel="nofollow noreferrer">快速入门</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434499190108eec0bdf14e704a09935cd112e501e31a000" rel="nofollow noreferrer">数据类型和变量</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143449921138898cdeb7fc2214dc08c6c67827758cd2f000" rel="nofollow noreferrer">数组</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143449922400335c44d4b8c904ff29a78fd4334347131000" rel="nofollow noreferrer">对象</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014345005693811782d9e338994ec19aa1c5325824bc15000" rel="nofollow noreferrer">条件判断</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434500620831b2aeb535f5e245c788493e9f4ff416c0000" rel="nofollow noreferrer">循环</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143449926746982f181557d9b423f819e89709feabdb4000" rel="nofollow noreferrer">函数</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434499832124d97d77b00706461f9daf1a390b75ade1000" rel="nofollow noreferrer">DOM浏览器对象</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434499851683f7f8d6b7717343248a75d5e7f930def4000" rel="nofollow noreferrer">操作DOM</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434499490767fe5a0e31e17e44b69dcd1196f7ec6fc6000" rel="nofollow noreferrer">JSON</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434499861493e7c35be5e0864769a2c06afb4754acc6000" rel="nofollow noreferrer">AJAX</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014344993159773a464f34e1724700a6d5dd9e235ceb7c000" rel="nofollow noreferrer">变量作用域</a></li></ul><h2 id="-html-javascript-">我已经掌握了HTML和JavaScript基础</h2><p>你真棒~接下来该收服CSS基础知识啦！</p><p><strong>学习CSS基础</strong></p><p>CSS 的全称是层叠样式表(Cascading Style Sheets)。CSS被用来定义你在HTML中编写的元素的外观。跟着MDN上的<a href="https://link.zhihu.com/?target=https%3A//developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Getting_Started" rel="nofollow noreferrer">CSS入门教程</a>学习基础知识，在这里学习<a href="https://link.zhihu.com/?target=http%3A//zh.learnlayout.com/" rel="nofollow noreferrer">如何用CSS对网页布局</a>。</p><p><strong>转向后端</strong></p><p>HTML/JavaScript/CSS都是“Web前端开发”的相关知识。也就是说你目前掌握的语言基本都是在浏览器里运行的。是时候看看后端是什么样子的了。接下来我们将学习如何写在服务器上运行的代码。你并不需要买一台真正的服务器回来，你自己的电脑已经足够强大啦。</p><p>有非常多的后端的编程语言，不过既然你已经了解了JavaScript，我推荐你学习NodeJS.NodeJS是一项能够在服务器端运行JS代码的技术。</p><p>除此外，你还需要了解一下Express框架和MongoDB.</p><p><strong>Express</strong></p><p>Express是一个基于NodeJS的Web应用开发框架，用来更方便地同网页进行请求响应交互。</p><p><strong>Mongo DB</strong></p><p>Mongo DB是一个数据库。用来存储和访问数据。</p><p>在这里学习<a href="https://link.zhihu.com/?target=http%3A//www.jdon.com/idea/nodejs/node-express-mongo.html" rel="nofollow noreferrer">Node.js + Express + MongoDB教程</a>。请放心，你并不需要完全精通Node或Mongo，只需要跟着教程让这个技术栈的应用跑起来就好了。</p><h2 id="-">我需要在前端、后端和全栈之间做抉择。</h2><p>在你确定你你已经理解了前后端的技术之后，就是时候做决定了。可如果你对之前所学还是一知半解，最好先返回去再了解一些相关的知识。（这就和玩游戏教学关卡通关之后选职业一个概念）</p><p>目前，你一共写了两种代码。一种用来和用户交互，另一种和数据交互。你更喜欢哪一种？</p><p>用户交互？那么你的选择是前端开发工程师！ 数据交互？那你的选择是后端开发工程师！ 都喜欢？恭喜你，你将选择成为一个全栈工程师！</p><p>哪个也没兴趣？也要祝贺你，通过之前的学习，你发现了其实Web开发并不适合你，你也不必在这上面浪费更多的时间和金钱了。还是不想放弃？也许你只是没找到自己喜欢的编程语言？在后面的“我想成为后端工程师”的章节里挑选你喜欢的语言吧！</p><h2 id="--1">我想成为全栈工程师！</h2><p>很不错！看来你得把这篇文章完完整整地读完啦！你需要学习的包含前端和后端的所有知识。</p><h2 id="-javascript-html-css-">我已经掌握了JavaScript/HTML/CSS基础，我想成为一名前端开发工程师。</h2><p>想要成为一名合格的前端开发工程师，你需要熟练掌握HTML/CSS/客户端JavaScript.同时你也需要熟练使用一些开发框架。</p><p>在开始下面内容的学习之前，确保你已经掌握了HTML基础知识。</p><p><strong>HTML进阶</strong></p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/html/html5-intro.html" rel="nofollow noreferrer">HTML5教程</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.w3cplus.com/css/advanced-html-css-lesson1-performance-organization.html" rel="nofollow noreferrer">HTML和CSS高级指南</a></li></ul><p><strong>JavaScript进阶</strong></p><p>为了让你更深入地了解JavaScrpit，我要推荐一个系列书籍，由Kyle Simpson撰写的《你不知道的JS》。而且整套书都在Github上开源免费！</p><ul><li><a href="https://link.zhihu.com/?target=https%3A//github.com/getify/You-Dont-Know-JS" rel="nofollow noreferrer">You-Dont-Know-JS on Github</a></li><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/26351021/" rel="nofollow noreferrer">你不知道的JavaScript（上卷）</a></li><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/26854244/" rel="nofollow noreferrer">你不知道的JavaScript（中卷）</a></li></ul><p>除了这套书以外，MDN的<a href="https://link.zhihu.com/?target=https%3A//developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference" rel="nofollow noreferrer">JavaScript参考文档</a>也会对你非常有用。</p><p>掌握了“前端三剑客”（HTML/CSS/JavaScript）固然很重要。但你想真的写出一些可以赚钱的代码，还需要熟悉一些框架。</p><p><strong>学习jQuery</strong></p><p><a href="https://link.zhihu.com/?target=http%3A//jquery.com/" rel="nofollow noreferrer">jQuery</a>是史上最受欢迎的JS库。虽然一些新近的框架不再依赖jQuery，但假如你想尽快找到一份工作的话，掌握jQuery是十分有必要的。</p><p>我推荐你在<a href="https://link.zhihu.com/?target=https%3A//www.freecodecamp.cn/challenges/learn-how-script-tags-and-document-ready-work" rel="nofollow noreferrer">FreeCodeCamp上学习jQuery</a>。之后你可以在<a href="https://link.zhihu.com/?target=https%3A//learn.jquery.com/using-jquery-core/" rel="nofollow noreferrer">jQuery学习官网</a>上了解更多的内容。</p><p>同时也不要忘了收藏<a href="https://link.zhihu.com/?target=http%3A//jquery.cuishifeng.cn/" rel="nofollow noreferrer">jQueryAPI文档</a>随时查阅。</p><p><strong>学习主流JS框架</strong></p><p>框架是为了帮助我们解决开发中经常会遇到的问题而开发出来的。JavaScript的框架数不胜数，我们来看看新近流行的一些JS框架，你也可以通过搜索引擎和招聘网站掌握各类框架的需求信息。</p><p><strong><a href="https://link.zhihu.com/?target=http%3A//facebook.github.io/react/" rel="nofollow noreferrer">React</a></strong></p><p>React是Facebook为了配合Flux架构开发的一款JS框架。主要用来构建用户界面。最近一段时间异常的火爆，已经远远甩开了AngularJS.所以你还在等什么：</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.ruanyifeng.com/blog/2015/03/react.html" rel="nofollow noreferrer">React 入门实例教程</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/react/react-tutorial.html" rel="nofollow noreferrer">React 教程</a></li></ul><p><strong>Angular 1 &amp; 2</strong></p><p>Angular JS是Google推出的JS框架。刚推出的时候也是红极一时，Angular适用于开发中大型的Web应用。不过有一点恶心人的是，Google在计划推出Angular 2版本时，感觉他们有必要完全重写。结果就导致了1和2用起来感觉完全像是两个不同的框架。假如你想成为一个Angular专家，你就相当于要同时掌握两个框架。</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/angularjs/angularjs-tutorial.html" rel="nofollow noreferrer">AngularJS 1 教程</a></li><li><a href="https://link.zhihu.com/?target=https%3A//neilq.gitbooks.io/angular-2-for-typescript-docs-zh/content/quickstart.html" rel="nofollow noreferrer">Angular 2 for TypeScript 中文手册</a></li></ul><p><strong>Vue.js</strong></p><p>Vue.js的开发者是<a href="https://www.zhihu.com/people/evanyou">尤雨溪</a>。大神也在玩知乎袄。Vue.js是一个用来构筑用户界面的非常轻量的框架，使用非常方便，上手也会很快。并且真的很强大，不会有Angular那么臃肿，也不像React的JSX那么变态。所以我很推荐新手从学习Vue.js开始。</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//cn.vuejs.org/" rel="nofollow noreferrer">Vue.js中文官网</a></li><li><a href="https://link.zhihu.com/?target=http%3A//cody1991.github.io/vue/2016/08/30/a-simple-vue-guide.html" rel="nofollow noreferrer">一个简单的 vue.js 实践教程</a></li></ul><p><strong>学习Bootstrap</strong></p><p>（译者）学习Bootstrap可以看我之前总结的这篇：</p><ul><li><a href="https://zhuanlan.zhihu.com/p/21472801">有关Bootstrap你想要知道的都在这里</a></li></ul><p>当然Bootstrap也可以和之前所学的框架协同使用：</p><ul><li><a href="https://link.zhihu.com/?target=https%3A//react-bootstrap.github.io/" rel="nofollow noreferrer">React Bootstrap</a></li><li><a href="https://link.zhihu.com/?target=https%3A//angular-ui.github.io/bootstrap/" rel="nofollow noreferrer">Angular Bootstrap</a></li></ul><p>恭喜！掌握了上述内容之后，你已经是一名合格的前端开发工程师了。</p><h2 id="--2">我想成为一名后端开发工程师！</h2><p>很不错的选择！首先你需要选择后端开发语言。可供选择的特别多，各有优劣。下图是一个编程语言受欢迎程度的排行榜。被框选起来的是Web开发中经常会用到的语言。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-4a1f1d409d446c40f8c13d09f0711c18_hd.png" class="kg-image" alt="v2-4a1f1d409d446c40f8c13d09f0711c18_hd" width="600" height="400" loading="lazy"></figure><p><br>要是你完全是个新手，不要着急做决定，先了解一下这几种语言的特性和语法，最后挑选出你喜欢的。</p><p>要是你已经掌握了某种语言，那么就专注于它吧！</p><p><strong><a href="https://link.zhihu.com/?target=https%3A//www.java.com/" rel="nofollow noreferrer">Java</a></strong></p><p>Java是一门广受欢迎的跨平台语言。它由Oracle公司开发和维护。Java可以用来开发Android应用，桌面软件，当然也能用来开发Web应用（只用做后端，或者用JSP技术也可以开发前端）。Java语言健壮可靠，而且网上有着无数的学习Java的资源。同样也是在大学里广泛教授的面向对象编程语言。</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.cnblogs.com/vamei/archive/2013/03/31/2991531.html" rel="nofollow noreferrer">Java快速教程</a></li><li><a href="https://link.zhihu.com/?target=https%3A//www.udemy.com/java-tutorial/%3Fdtcode%3DHtG3KQq20AeT" rel="nofollow noreferrer">Java Tutorial for Complete Beginners</a></li></ul><p><strong><a href="https://link.zhihu.com/?target=https%3A//msdn.microsoft.com/zh-CN/library/z1zx9t92.aspx" rel="nofollow noreferrer">C#</a></strong></p><p>C# 是微软为了对抗Java开发的编程语言。它在微软的平台上拥有良好的支持。它同样也是面向对象的，也不限于开发Web应用、桌面软件等。要是你忠于Windows的话，C#也许是个不错的选择。</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/csharp/csharp-tutorial.html" rel="nofollow noreferrer">C# 教程</a></li><li><a href="https://www.zhihu.com/question/20451584">Java 和 C# 最大的不同是什么？</a></li></ul><p><strong><a href="https://link.zhihu.com/?target=https%3A//www.python.org/" rel="nofollow noreferrer">Python</a></strong></p><p>Python是最适合新手，最容易学习的编程语言。而且Python广受欢迎，可以被应用在各个领域。人生苦短，请用Python！</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000" rel="nofollow noreferrer">Python 3教程</a></li></ul><p><strong>JavaScript</strong></p><p>相信通过之前的学习你对JavaScript已经有所了解了。NodeJS的出现让JS在服务器端运行成为了可能。现在再深入了解一下吧！</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.runoob.com/nodejs/nodejs-tutorial.html" rel="nofollow noreferrer">Node入门</a></li><li><a href="https://link.zhihu.com/?target=http%3A//nodeschool.io/zh-cn/" rel="nofollow noreferrer">NODESCHOOL</a></li></ul><p><strong><a href="https://link.zhihu.com/?target=https%3A//www.ruby-lang.org/zh_cn/" rel="nofollow noreferrer">Ruby</a></strong></p><p>Ruby是一朵奇葩。爱它的人对它痴狂，它处在编程语言排行榜的前10名，但增长却非常缓慢。Ruby本身是一种介于函数式编程和命令是编程之间的语言。我推荐你尝试一下，兴许你会变成它的狂热粉丝呢。另外，近些年来Ruby语言的工作机会也有很多。</p><ul><li><a href="https://link.zhihu.com/?target=https%3A//www.ruby-lang.org/zh_cn/documentation/quickstart/" rel="nofollow noreferrer">20分钟体验 Ruby</a></li></ul><p><strong><a href="https://link.zhihu.com/?target=http%3A//php.net/" rel="nofollow noreferrer">PHP</a></strong></p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-4d74dcd20e03977844284ea9b19e83b8_hd.png" class="kg-image" alt="v2-4d74dcd20e03977844284ea9b19e83b8_hd" width="600" height="400" loading="lazy"></figure><p>虽然近一段时间PHP看起来有点过气了。但是请不要忘记，PHP是全世界最好的语言。而且单就Web开发这一块来讲，全世界的网站有多一半是用PHP开发的。PHP7的推出极大地改善了其运行效率，Laravel框架也让编写PHP代码变得无比优雅。PHP不是原作者的菜，但译者最早学习的编程语言就是PHP，在这里也不想挑起语言之争，总之PHP值得你尝试着学习一下。</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.w3school.com.cn/php/" rel="nofollow noreferrer">PHP 教程</a></li></ul><h2 id="-web--1">我已经学了很多Web开发的知识，但是缺乏实践经验。</h2><p>没有任何经验的话是很难找到工作的。</p><p>第一步是试着完成一两个个人项目，来熟悉掌握开发流程。</p><p>在你的项目开发完毕后，试着在Github这类平台上发布会对你很有帮助。</p><p><strong>Github</strong></p><p><a href="https://link.zhihu.com/?target=http%3A//github.com/" rel="nofollow noreferrer">Github</a>基于版本控制软件Git建立，是全球最大的开源项目托管网站。你可以在上面储存、管理、发布你的代码。Github是你作为一名开发者必须使用的网站。</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.kancloud.cn/kancloud/how-to-use-github/42191" rel="nofollow noreferrer">GotGitHub</a></li></ul><p><strong>开发个人项目</strong></p><p>下面推荐一些你可以尝试的个人开发项目：</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//idlelife.org/archives/977" rel="nofollow noreferrer">使用React、Node.js、MongoDB、Socket.IO开发一个角色投票应用</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.cnblogs.com/shiyanlou/p/4238776.html" rel="nofollow noreferrer">Laravel完成一个多用户的博客系统</a></li></ul><p><a href="https://link.zhihu.com/?target=https%3A//www.freecodecamp.cn/" rel="nofollow noreferrer">FreeCodeCamp</a>上面同样有着各种各样的实践项目，在这里推荐两个：</p><ul><li><a href="https://link.zhihu.com/?target=https%3A//www.freecodecamp.cn/challenges/build-a-pomodoro-clock" rel="nofollow noreferrer">创建一个番茄钟计时器</a> （纯前端）</li><li><a href="https://link.zhihu.com/?target=https%3A//www.freecodecamp.com/challenges/manage-a-book-trading-club" rel="nofollow noreferrer">开发一个书籍分享网站</a> （全栈）</li></ul><p><strong>实践经验</strong></p><p>接下来你需要一些真实的经验。这意味着你需要与他人协作，参与到真实的项目中来。个人项目自然有其用处，但在找工作时还不够有说服力。</p><p><strong>1.为开源项目做贡献</strong></p><p>Github上面有着成千上万的开源项目，这些项目中有着许多公开的bug等着你去提供修复。在你的简历中加上你为一些知名项目贡献代码的事迹，将会是你浓墨重彩的一笔。你可以通过<a href="https://link.zhihu.com/?target=https%3A//www.codetriage.com/" rel="nofollow noreferrer">Code Triage</a>来关注你感兴趣的项目进展。</p><p><strong>2.为你的家人或朋友“打工”</strong></p><p>专门为你做生意的朋友或家人开发一款Web应用或者一个网站吧。为他们解决实际的问题，给他们提供帮助。不过在选人之前最好慎重考虑，最好这个人的需求可以在90天左右的时间开发完毕，而且你们俩的关系也最好是比较亲近的。不要因为开发中途的一些矛盾搞得你们最后连朋友都没得做。</p><p><strong>3.为非盈利组织工作</strong></p><p>这将会是一个非常棒的选择！为非盈利机构开发Web应用，解决他们的实际问题。你可以在<a href="https://link.zhihu.com/?target=https%3A//www.catchafire.org/" rel="nofollow noreferrer">Catch a Fire</a>上找到这样的项目。另外，如果你通过了<a href="https://link.zhihu.com/?target=http%3A//freecodecamp.com/" rel="nofollow noreferrer">FreeCodeCamp</a>的所有挑战，你也能够获得为非盈利机构开发Web项目的机会。</p><p><strong>4.出卖劳动力</strong></p><p>你可以在网上找一些外包项目来做，为了避免广告之嫌，译者在这里就不推荐国内的网站了，反正一搜一大把。</p><h2 id="--3">我现在已经积累了一些实践经验了，怎么才能找到工作呢？</h2><p><strong>写一份儿牛X闪闪的简历</strong></p><ul><li><a href="https://www.zhihu.com/question/23150301">一份优秀的前端开发工程师简历是怎么样的？</a></li><li><a href="https://www.zhihu.com/question/25002833">程序员简历应该怎么写？</a></li></ul><p><strong>开发一个在线简历网站</strong></p><p>开发一个介绍你自己的个人站点！你可以把你之前做过的所有项目都链接到上面。说明各个项目都解决了什么样的实际问题。这会对你很有帮助！</p><p><strong>准备好编程面试</strong></p><ul><li><a href="https://link.zhihu.com/?target=https%3A//github.com/hawx1993/Front-end-Interview-questions" rel="nofollow noreferrer">前端面试题收集</a></li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/taizilongxu/interview_python" rel="nofollow noreferrer">Python的面试题</a></li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/jwasham/google-interview-university/blob/master/README-cn.md" rel="nofollow noreferrer">一套完整的学习手册帮助自己准备 Google 的面试</a></li></ul><p><strong>掌握通用的面试技巧</strong></p><ul><li><a href="https://link.zhihu.com/?target=http%3A//group.cnblogs.com/topic/37628.html" rel="nofollow noreferrer">面试70问 经典回答</a></li><li><a href="https://www.zhihu.com/question/38255755">程序员面试要准备哪些方面的内容？</a></li><li><a href="https://www.zhihu.com/question/25039418">修改面试前你都做了什么准备？</a></li></ul><p><strong>出发去找工作吧！</strong></p><p>不要妄图一瞬间就找到你心仪的公司和喜爱的岗位。先找到一份可以写代码养活自己的工作再说。等到你积累了更多的经验，自然也就能迈出下一步了。</p><h2 id="--4">我想要成为一名自由职业者！</h2><p>自己当自己的老板听起来是非常爽的。但事实上自由职业并不像想象的那么轻松。在这里推荐<a href="https://link.zhihu.com/?target=https%3A//medium.com/%40brennandunn" rel="nofollow noreferrer">Brennan Dunn</a>写了许多有关自由职业者的文章：</p><p><a href="https://link.zhihu.com/?target=https%3A//doubleyourfreelancing.com/" rel="nofollow noreferrer">DoubleYourFreelancing.com</a></p><p>在外国的网站上注册成为自由职业者对大多数人来说有些不切实际，国内这一块发展也比较混乱，为了避免广告之嫌，译者也就不推荐链接了。</p><h2 id="-web--2">我朝着成为一名Web开发者的方向努力了，但我现在感觉力不从心。</h2><p>我很理解你的心情。这本来就不是一件容易的事情，而且任何口口声声说着学Web开发很容易的人自己其实都不怎么样，要么就是想要骗你钱。假如你现在有些不知所措，那么重新思考一下这些问题：</p><p><strong>不忘初心</strong></p><p>问问你自己，你甚至可以写下来！你当初为什么要决定走上这条路？你的想法仍然没有改变么？那么为什么要停下来呢！？继续迎难而上吧！</p><p><strong>脚踏实地</strong></p><p>现在你已经考虑了很多，脑子里想到了最坏的结果，也期冀最好的愿景，还有现实中最可能发生的情况。你完全可以把这些想法都记录下来。没有必要畏惧，面对现实，脚踏实地地一步步走下去。</p><p>欢迎在评论区分享你的心得体会。</p><p>原文链接：<a href="https://www.freecodecamp.org/news/the-practical-guide-to-becoming-a-professional-web-developer-2f255bc25c90/">The Practical Guide to Becoming a Professional Web Developer</a>，作者：<a href="https://www.freecodecamp.org/news/author/billsourour/">Bill Sourour</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ JavaScript 模块化入门 Ⅰ：理解模块 ]]>
                </title>
                <description>
                    <![CDATA[ 作为一名 JS 初学者。假如你听到了一些诸如“模块化构建&模块化载入” “Webpack&Browserify” 或者 “AMD&CMD”之类的术语，肯定瞬间就凌乱了。 JavaScript 的模块化听起来挺深奥，可其实理解它对开发者来说特别实用。 在这篇文章里，我会尽量深入浅出地把这些深奥的术语翻译成浅显易懂的人话（加上一些代码示例）。希望你多少能从中学到点东西。 为了避免长篇大论，整个内容会分为两篇文章，这是第一部分，主要介绍模块化是什么，为什么要使用模块。之后的第二部分会介绍如何打包 JS 模块，以及各类构建工具。 求解释到底什么是模块化 称职的作家会把他的书分章节和段落；好的程序员会把他的代码分成模块。 就好像书籍的一章，模块仅仅是一坨代码而已。 好的代码模块分割的内容一定是很合理的，便于你增加减少或者修改功能，同时又不会影响整个系统。 为什么要使用模块 模块化可以使你的代码低耦合，功能模块直接不相互影响。我个人认为模块化主要有以下几点好处： 1. 可维护性 ：根据定义，每个模块都是独立的。良好设计的模块会尽量与外部的代码撇清关系，以便于独立对其进行改进和维护。 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/javascript-modules-a-beginner-s-guide/</link>
                <guid isPermaLink="false">5d383cd6fbfdee429dc5f261</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Wed, 23 Jun 2021 08:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/v2-ad547e666f72dc8cd9ffb45217e7d69f_1200x500.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>作为一名 JS 初学者。假如你听到了一些诸如“模块化构建&amp;模块化载入” “Webpack&amp;Browserify” 或者 “AMD&amp;CMD”之类的术语，肯定瞬间就凌乱了。</p><p>JavaScript 的模块化听起来挺深奥，可其实理解它对开发者来说特别实用。</p><p>在这篇文章里，我会尽量深入浅出地把这些深奥的术语翻译成浅显易懂的人话（加上一些代码示例）。希望你多少能从中学到点东西。</p><p>为了避免长篇大论，整个内容会分为两篇文章，这是第一部分，主要介绍模块化是什么，为什么要使用模块。之后的第二部分会介绍如何打包 JS 模块，以及各类构建工具。</p><h2 id="-">求解释到底什么是模块化</h2><p>称职的作家会把他的书分章节和段落；好的程序员会把他的代码分成模块。</p><p>就好像书籍的一章，模块仅仅是一坨代码而已。</p><p>好的代码模块分割的内容一定是很合理的，便于你增加减少或者修改功能，同时又不会影响整个系统。</p><h2 id="--1">为什么要使用模块</h2><p>模块化可以使你的代码低耦合，功能模块直接不相互影响。我个人认为模块化主要有以下几点好处：</p><p><strong>1. 可维护性</strong>：根据定义，每个模块都是独立的。良好设计的模块会尽量与外部的代码撇清关系，以便于独立对其进行改进和维护。维护一个独立的模块比起一团凌乱的代码来说要轻松很多。</p><p><strong>2.命名空间</strong>：在 JavaScript 中，最高级别的函数外定义的变量都是全局变量（这意味着所有人都可以访问到它们）。也正因如此，当一些无关的代码碰巧使用到同名变量的时候，我们就会遇到“命名空间污染”的问题。</p><p>这样的问题在我们开发过程中是要极力避免的。</p><p>后面的内容里我也会举一些具体的例子来说明这一点。</p><p><strong>3.可复用性</strong>：现实来讲，在日常工作中我们经常会复制自己之前写过的代码到新项目中。</p><p>复制粘贴虽然很快很方便，但难道我们找不到更好的办法了么？要是……有一个可以重复利用的模块岂不妙哉？</p><h2 id="--2">如何引入模块</h2><p>引入模块有很多种方式，这里我们先介绍一些：</p><p><strong>模块模式</strong></p><p>模块模式一般用来模拟类的概念（因为原生 JavaScript 并不支持类，虽然最新的 ES6 里引入了 Class 不过还不普及）这样我们就能把公有和私有方法还有变量存储在一个对象中——这就和我们在 Java 或 Python 里使用类的感觉一样。这样我们就能在公开调用API的同时，仍然在一个闭包范围内封装私有变量和方法。</p><p>实现模块模式的方法有很多种，下面的例子是通过匿名闭包函数的方法。（在 JavaScript 中，函数是创建作用域的唯一方式。）</p><p><strong>例1：匿名闭包函数</strong></p><pre><code class="language-js">(function () {
  // 在函数的作用域中下面的变量是私有的

  var myGrades = [93, 95, 88, 0, 55, 91];

  var average = function() {
    var total = myGrades.reduce(function(accumulator, item) {
      return accumulator + item}, 0);

      return 'Your average grade is ' + total / myGrades.length + '.';
  }

  var failing = function(){
    var failingGrades = myGrades.filter(function(item) {
      return item &lt; 70;});

    return 'You failed ' + failingGrades.length + ' times.';
  }

  console.log(failing());

}());

// 控制台显示：'You failed 2 times.'
</code></pre><p>通过这种构造，我们的匿名函数有了自己的作用域或“闭包”。 这允许我们从父（全局）命名空间隐藏变量。</p><p>这种方法的好处在于，你可以在函数内部使用局部变量，而不会意外覆盖同名全局变量，但仍然能够访问到全局变量，如下所示：</p><pre><code class="language-js">var global = 'Hello, I am a global variable :)';

(function () {
  // 在函数的作用域中下面的变量是私有的

  var myGrades = [93, 95, 88, 0, 55, 91];

  var average = function() {
    var total = myGrades.reduce(function(accumulator, item) {
      return accumulator + item}, 0);

    return 'Your average grade is ' + total / myGrades.length + '.';
  }

  var failing = function(){
    var failingGrades = myGrades.filter(function(item) {
      return item &lt; 70;});

    return 'You failed ' + failingGrades.length + ' times.';
  }

  console.log(failing());
  console.log(global);
}());

// 控制台显示：'You failed 2 times.'
// 控制台显示：'Hello, I am a global variable :)'
</code></pre><p>要注意的是，一定要用括号把匿名函数包起来，以关键词 function 开头的语句总是会被解释成函数声明（JS 中不允许没有命名的函数声明），而加上括号后，内部的代码就会被识别为函数表达式。其实这个也叫作立即执行函数（IIFE）感兴趣的同学可以<a href="https://link.zhihu.com/?target=http%3A//web.jobbole.com/82520/" rel="nofollow noreferrer">在这里了解更多</a></p><p><strong>例2：全局引入</strong></p><p>另一种比较受欢迎的方法是一些诸如 jQuery 的库使用的<strong>全局引入</strong>。和我们刚才举例的匿名闭包函数很相似，只是传入全局变量的方法不同：</p><pre><code class="language-js">(function (globalVariable) {

  // 在函数的作用域中下面的变量是私有的
  var privateFunction = function() {
    console.log('Shhhh, this is private!');
  }

  // 通过全局变量设置下列方法的外部访问接口
  // 与此同时这些方法又都在函数内部

  globalVariable.each = function(collection, iterator) {
    if (Array.isArray(collection)) {
      for (var i = 0; i &lt; collection.length; i++) {
        iterator(collection[i], i, collection);
      }
    } else {
      for (var key in collection) {
        iterator(collection[key], key, collection);
      }
    }
  };

  globalVariable.filter = function(collection, test) {
    var filtered = [];
    globalVariable.each(collection, function(item) {
      if (test(item)) {
        filtered.push(item);
      }
    });
    return filtered;
  };

  globalVariable.map = function(collection, iterator) {
    var mapped = [];
    globalUtils.each(collection, function(value, key, collection) {
      mapped.push(iterator(value));
    });
    return mapped;
  };

  globalVariable.reduce = function(collection, iterator, accumulator) {
    var startingValueMissing = accumulator === undefined;

    globalVariable.each(collection, function(item) {
      if(startingValueMissing) {
        accumulator = item;
        startingValueMissing = false;
      } else {
        accumulator = iterator(accumulator, item);
      }
    });

    return accumulator;

  };

 }(globalVariable));
</code></pre><p>在这个例子中，globalVariable 是唯一的全局变量。这种方法的好处是可以预先声明好全局变量，让你的代码更加清晰可读。</p><p><strong>例3：对象接口</strong></p><p>像下面这样，还有一种创建模块的方法是使用独立的对象接口：</p><pre><code class="language-js">var myGradesCalculate = (function () {

  // 在函数的作用域中下面的变量是私有的
  var myGrades = [93, 95, 88, 0, 55, 91];

  // 通过接口在外部访问下列方法
  // 与此同时这些方法又都在函数内部

  return {
    average: function() {
      var total = myGrades.reduce(function(accumulator, item) {
        return accumulator + item;
        }, 0);

      return'Your average grade is ' + total / myGrades.length + '.';
    },

    failing: function() {
      var failingGrades = myGrades.filter(function(item) {
          return item &lt; 70;
        });

      return 'You failed ' + failingGrades.length + ' times.';
    }
  }
})();

myGradesCalculate.failing(); // 'You failed 2 times.' 
myGradesCalculate.average(); // 'Your average grade is 70.33333333333333.'
</code></pre><p><strong>例4：揭示模块模式 Revealing module pattern</strong></p><p>这和我们之前的实现方法非常相近，除了它会确保，在所有的变量和方法暴露之前都会保持私有：</p><pre><code class="language-js">var myGradesCalculate = (function () {

   // 在函数的作用域中下面的变量是私有的
  var myGrades = [93, 95, 88, 0, 55, 91];

  var average = function() {
    var total = myGrades.reduce(function(accumulator, item) {
      return accumulator + item;
      }, 0);

    return'Your average grade is ' + total / myGrades.length + '.';
  };

  var failing = function() {
    var failingGrades = myGrades.filter(function(item) {
        return item &lt; 70;
      });

    return 'You failed ' + failingGrades.length + ' times.';
  };

  // 将公有指针指向私有方法

  return {
    average: average,
    failing: failing
  }
})();

myGradesCalculate.failing(); // 'You failed 2 times.' 
myGradesCalculate.average(); // 'Your average grade is 70.33333333333333.'
</code></pre><p>到这里，其实我们只聊了模块模式的冰山一角。感兴趣的朋友可以阅读更详细的资料：</p><ul><li><a href="https://link.zhihu.com/?target=http%3A//www.oschina.net/translate/javascript-module-pattern-in-depth" rel="nofollow noreferrer">深入理解 JavaScript 模块模式</a></li><li><a href="https://link.zhihu.com/?target=http%3A//www.cnblogs.com/TomXu/archive/2011/12/30/2288372.html" rel="nofollow noreferrer">深入理解 JavaScript系列（3）：全面解析 Module 模式</a></li></ul><h2 id="commonjs-amd">CommonJS &amp; AMD</h2><p>上述的所有解决方案都有一个共同点：使用单个全局变量来把所有的代码包含在一个函数内，由此来创建私有的命名空间和闭包作用域。</p><p>虽然每种方法都比较有效，但也都有各自的短板。</p><p>有一点，作为开发者，你必须清楚地了解引入依赖文件的正确顺序。就拿 Backbone.js 来举个例子，想要使用 Backbone 就必须在你的页面里引入 Backbone 的源文件。</p><p>然而 Backbone 又依赖 Underscore.js，所以 Backbone 的引入必须在其之后。</p><p>而在工作中，这些依赖管理经常会成为让人头疼的问题。</p><p>另外一点，这些方法也有可能引起命名空间冲突。举个例子，要是你碰巧写了俩重名的模块怎么办？或者你同时需要一个模块的两个版本时该怎么办？</p><p>难道就没有不通过全局作用域来实现的模块方法么？</p><p>当然是有的。</p><p>接下来介绍两种广受欢迎的解决方案：CommonJS 和 AMD.</p><h2 id="commonjs">CommonJS</h2><p>CommonJS 扩展了JavaScript 声明模块的 API.</p><p>CommonJS 模块可以很方便得将某个对象导出，让他们能够被其他模块通过 require 语句来引入。要是你写过 Node.js 应该很熟悉这些语法。</p><p>通过 CommonJS，每个 JS 文件独立地存储它模块的内容（就像一个被括起来的闭包一样）。在这种作用域中，我们通过 module.exports 语句来导出对象为模块，再通过 require 语句来引入。</p><p>还是举个直观的例子吧：</p><pre><code class="language-js">function myModule() {
  this.hello = function() {
    return 'hello!';
  }

  this.goodbye = function() {
    return 'goodbye!';
  }
}

module.exports = myModule;
</code></pre><p>通过指定导出的对象名称，CommonJS 模块系统可以识别在其他文件引入这个模块时应该如何解释。</p><p>然后在某个人想要调用 myMoudle 的时候，只需要 require 一下：</p><pre><code class="language-js">var myModule = require('myModule');

var myModuleInstance = new myModule();
myModuleInstance.hello(); // 'hello!'
myModuleInstance.goodbye(); // 'goodbye!'
</code></pre><p>这种实现比起模块模式有两点好处：</p><ol><li>避免全局命名空间污染</li><li>明确代码之间的依赖关系</li></ol><p>并且这种书写方式也非常舒服友好，我自己很喜欢。</p><p>需要注意的一点是，CommonJS 以服务器优先的方式来同步载入模块，假使我们引入三个模块的话，他们会一个个地被载入。</p><p>它在服务器端用起来很爽，可是在浏览器里就不会那么高效了。毕竟读取网络的文件要比本地耗费更多时间。只要它还在读取模块，浏览器载入的页面就会一直卡着不动。（在下一篇第二部分的教程里我们会讨论如何解决这个问题）</p><h2 id="amd">AMD</h2><p>CommonJS 已经挺不错了，但假使我们想要实现异步加载模块该怎么办？答案就是 Asynchronous Module Definition（异步模块定义规范），简称 AMD.</p><p>通过 AMD 载入模块的代码一般这么写：</p><pre><code class="language-js">define(['myModule', 'myOtherModule'], function(myModule, myOtherModule) {
  console.log(myModule.hello());
});
</code></pre><p>这里我们使用 define 方法，第一个参数是依赖的模块，这些模块都会在后台无阻塞地加载，第二个参数则作为加载完毕的回调函数。</p><p>回调函数将会使用载入的模块作为参数。在这个例子里就是 myMoudle 和 myOtherModule.最后，这些模块本身也需要通过 define 关键词来定义。</p><p>拿 myModule 来举个例子：</p><pre><code class="language-js">define([], function() {

  return {
    hello: function() {
      console.log('hello');
    },
    goodbye: function() {
      console.log('goodbye');
    }
  };
});
</code></pre><p>重申一下，不像 CommonJS，AMD 是优先浏览器的一种异步载入模块的解决方案。（记得，很多人认为一个个地载入小文件是很低效的，我们将在下一篇文章理介绍如何打包模块）</p><p>除了异步加载以外，AMD 的另一个优点是你可以在模块里使用对象、函数、构造函数、字符串、JSON 或者别的数据类型，而 CommonJS 只支持对象。</p><p>再补充一点，AMD 不支持 Node 里的一些诸如 IO，文件系统等其他服务器端的功能。另外语法上写起来也比 CommonJS 麻烦一些。</p><h2 id="umd">UMD</h2><p>在一些同时需要 AMD 和 CommonJS 功能的项目中，你需要使用另一种规范：Universal Module Definition（通用模块定义规范）。</p><p>UMD 创造了一种同时使用两种规范的方法，并且也支持全局变量定义。所以 UMD 的模块可以同时在客户端和服务端使用。</p><p>下面是一个解释其功能的例子：</p><pre><code class="language-js">(function (root, factory) {
  if (typeof define === 'function' &amp;&amp; define.amd) {
      // AMD
    define(['myModule', 'myOtherModule'], factory);
  } else if (typeof exports === 'object') {
      // CommonJS
    module.exports = factory(require('myModule'), require('myOtherModule'));
  } else {
    // Browser globals (Note: root is window)
    root.returnExports = factory(root.myModule, root.myOtherModule);
  }
}(this, function (myModule, myOtherModule) {
  // Methods
  function notHelloOrGoodbye(){}; // A private method
  function hello(){}; // A public method because it's returned (see below)
  function goodbye(){}; // A public method because it's returned (see below)

  // Exposed public methods
  return {
      hello: hello,
      goodbye: goodbye
  }
}));
</code></pre><p>更多有关 UMD 的例子请看其 Github上的<a href="https://link.zhihu.com/?target=https%3A//github.com/umdjs/umd" rel="nofollow noreferrer">官方 repo</a>.</p><h2 id="-js">原生 JS</h2><p>希望你坚持读到了现在，我们最后再介绍一种定义模块的方式。</p><p>你可能注意到了，上述的这几种方法都不是 JS 原生支持的。要么是通过模块模式来模拟，要么是使用 CommonJS 或 AMD。</p><p>幸运的是在 JS 的最新规范 ECMAScript 6 (ES6) 中，引入了模块功能。</p><p>ES6 的模块功能汲取了 CommonJS 和 AMD 的优点，拥有简洁的语法并支持异步加载，并且还有其他诸多更好的支持。</p><p>我最喜欢的 ES6 模块功能的特性是，导入是实时只读的。（CommonJS 只是相当于把导出的代码复制过来）。</p><p>来看例子：</p><pre><code class="language-js">// lib/counter.js

var counter = 1;

function increment() {
  counter++;
}

function decrement() {
  counter--;
}

module.exports = {
  counter: counter,
  increment: increment,
  decrement: decrement
};


// src/main.js

var counter = require('../../lib/counter');

counter.increment();
console.log(counter.counter); // 1
</code></pre><p>上面这个例子中，我们一共创建了两份模块的实例，一个在导出的时候，一个在引入的时候。</p><p>在 main.js 当中的实例是和原本模块完全不相干的。这也就解释了为什么调用了 counter.increment() 之后仍然返回1。因为我们引入的 counter 变量和模块里的是两个不同的实例。</p><p>所以调用 counter.increment() 方法只会改变模块中的 counter .想要修改引入的 counter 只有手动一下啦：</p><pre><code class="language-js">counter.counter++;
console.log(counter.counter); // 2
</code></pre><p>而通过 import 语句，可以引入实时只读的模块：</p><pre><code class="language-js">// lib/counter.js
export let counter = 1;

export function increment() {
  counter++;
}

export function decrement() {
  counter--;
}


// src/main.js
import * as counter from '../../counter';

console.log(counter.counter); // 1
counter.increment();
console.log(counter.counter); // 2
</code></pre><p>这看起来很酷不是么？这样就实现了我们把模块分隔在不同的文件里，需要的时候又可以合并在一起而且不影响它的功能。</p><h2 id="--3">期待下一篇：模块打包</h2><p>我想看到这里的你应该已经对 JavaScript 模块化有了进一步的了解。</p><p>在下一篇教程里，我们会介绍：</p><ul><li>为什么要打包模块</li><li>几种不同的打包构建方式</li><li>ECMAScript 模块载入 API</li><li>其他</li></ul><p>欢迎在评论区讨论提问，如果有什么不对的地方也欢迎批评指正~</p><p>原文链接：<a href="https://www.freecodecamp.org/news/javascript-modules-a-beginner-s-guide-783f7d7a5fcc/">JavaScript Modules: A Beginner’s Guide</a>，作者：Preethi Kasireddy</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 你知道 Chrome 自带的开发者工具有这些功能吗 ]]>
                </title>
                <description>
                    <![CDATA[ Chrome 自带开发者工具。它的功能十分丰富，包括元素、网络、安全等等。今天我们主要介绍 JavaScript 控制台部分的功能。 我最早写代码的时候，也就是在 JS 控制台里输出一些服务器返回的内容，或者一些变量的值。但是后来通过一些深入的学习和了解，我发现 Chrome 的 JS 控制台原来还有这么多神奇的功能。 在这里我总结了一些特别有用的功能。要是你凑巧在 Chrome 里浏览这篇文章的话，现在就打开开发者工具，跟着随手试试吧！ 1. 选取 DOM 元素 要是你用过两天 jQuery 的话，一定对 $('.className') 或者 $('#id') 这种选择器不会陌生。上面这俩货分别是 jQuery 的类选择器和 ID 选择器。 在一个网页没有引入 jQuery 的情况下，在控制台里你也可以通过类似的方法选取 DOM。 不管 $('tagName') /$('.class')/ $('#id') 还是 $('.class #id') 等类似的选择器，都相当于原生JS的document.querySelector('') 方法。这个方法返回第一个匹配选择规则的DO ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-much-do-you-know-about-chrome-developer-tools/</link>
                <guid isPermaLink="false">5d3a9718fbfdee429dc5f369</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Chrome ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Thu, 17 Jun 2021 09:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/1_WWyilxdduXEkWudAJaqKsA.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong>Chrome </strong>自带开发者工具。它的功能十分丰富，包括元素、网络、安全等等。今天我们主要介绍 <strong>JavaScript 控制台</strong>部分的功能。</p><p>我最早写代码的时候，也就是在 JS 控制台里输出一些服务器返回的内容，或者一些变量的值。但是后来通过一些深入的学习和了解，我发现 Chrome 的 JS 控制台原来还有这么多神奇的功能。</p><p>在这里我总结了一些特别有用的功能。要是你凑巧在 Chrome 里浏览这篇文章的话，现在就打开开发者工具，跟着随手试试吧！</p><h3 id="1-dom-">1. 选取 DOM 元素</h3><p>要是你用过两天 jQuery 的话，一定对 $('.className') 或者 $('#id') 这种选择器不会陌生。上面这俩货分别是 jQuery 的类选择器和 ID 选择器。</p><p>在一个网页没有引入 jQuery 的情况下，在控制台里你也可以通过类似的方法选取 DOM。</p><p>不管 $('tagName') /$('.class')/ $('#id') 还是 $('.class #id') 等类似的选择器，都相当于原生JS的document.querySelector('') 方法。这个方法返回第一个匹配选择规则的DOM元素。</p><p>在 Chrome 的控制台里，你可以通过 $$('tagName') 或者 $$('.className') 记得是两个 $$ 符号来选择所有匹配规则的 DOM 元素。选择返回的结果是一个数组，可以通过数组的方法来访问其中的单个元素。</p><p><br>举个栗子 $$('className') 会返回给你所有包含 className 类属性的元素，之后你可以通过 $$('className')[0] 和$$('className')[1] 来访问其中的某个元素。</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-0be76f26dc59fc5a2f910a6557376c3b_hd.png" class="kg-image" alt="v2-0be76f26dc59fc5a2f910a6557376c3b_hd" width="720" height="325" loading="lazy"></figure><h3 id="2-chrome-">2. 一秒钟让 Chrome 变成所见即所得的编辑器</h3><p>你可能经常会困惑你到底能不能直接在浏览器里更改网页的文本内容。答案是肯定的，你可以只通过一行简单的指令把 Chrome 变成所见即所得的编辑器，直接在网页上随心所欲地删改文字。</p><p>你不需要再傻傻地右键审查元素，编辑源代码了。打开 Chrome 的开发者控制台，输入：</p><pre><code class="language-js">document.body.contentEditable=true
</code></pre><p>然后奇迹就发生啦！要是你正在用 Chrome 现在就可以试试！</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-56b77b9da4641560bad6101cd4cd6558_hd.png" class="kg-image" alt="v2-56b77b9da4641560bad6101cd4cd6558_hd" width="559" height="491" loading="lazy"></figure><h3 id="3-dom-">3. 获取某个 DOM 元素绑定的事件</h3><p>在调试的时候，你肯定需要知道某个元素上面绑定了什么触发事件。Chrome 的开发者控制台可以让你很轻松地找到它们。</p><p>getEventListeners($('selector')) 方法以数组对象的格式返回某个元素绑定的所有事件。你可以在控制台里展开对象查看详细的内容。</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-076155237e53e09b7631913d0e563221_hd.png" class="kg-image" alt="v2-076155237e53e09b7631913d0e563221_hd" width="720" height="197" loading="lazy"></figure><p>要是你需要选择其中的某个事件，可以通过下面的方法来访问：</p><pre><code class="language-js">getEventListeners($('selector')).eventName[0].listener
</code></pre><p>这里的 eventName 表示某种事件类型，例如：</p><pre><code class="language-js">getEventListeners($('#firstName')).click[0].listener
</code></pre><p>上面的例子会返回 ID 为 firstName 元素绑定的 click 事件。</p><h3 id="4-">4. 监测事件</h3><p>当你需要监视某个 DOM 触发的事件时，也可以用到控制台。例如下面这些方法：</p><ul><li>monitorEvents($('selector')) 会监测某个元素上绑定的所有事件，一旦该元素的某个事件被触发就会在控制台里显示出来。</li><li>monitorEvents($('selector'),'eventName') 可以监听某个元素上绑定的具体事件。第二个参数代表事件类型的名称。例如 monitorEvents($('#firstName'),'click') 只监测ID为firstName的元素上的click事件。</li><li>monitorEvents($('selector'),['eventName1','eventName3',….]) 同上。可以同时检测具体指定的多个事件类型。</li><li>unmonitorEvents($('selector')) 用来停止对某个元素的事件监测。</li></ul><h3 id="5-">5. 用计时器来获取某段代码块的运行时间</h3><p>通过 console.time('labelName') 来设定一个计时器，其中的 labelName 是计时器的名称。通过console.timeEnd('labelName') 方法来停止并输出某个计时器的时间。例如：</p><pre><code class="language-js">console.time('myTime'); //设定计时器开始 - myTime
console.timeEnd('mytime'); //结束并输出计时时长 - myTime

//输出: myTime:123.00 ms
</code></pre><p>再举一个通过计时器来计算代码块运行时间的例子：</p><pre><code class="language-js">console.time('myTime'); //开始计时 - myTime

for(var i=0; i &lt; 100000; i++){
  2+4+5;
}

console.timeEnd('mytime'); //结束并输出计时时长 - myTime

//输出 - myTime:12345.00 ms
</code></pre><h3 id="6-">6. 以表格的形式输出数组</h3><p>假设我们有一个像下面这样的数组：</p><pre><code class="language-js">var myArray=[{a:1,b:2,c:3},{a:1,b:2,c:3,d:4},{k:11,f:22},{a:1,b:2,c:3}]
</code></pre><p>要是你直接在控制台里输入数组的名称，Chrome会以文本的形式返回一个数组对象。但你完全可以通过console.table(variableName) 方法来以表格的形式输出每个元素的值。例如下图：</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-abfd37780b085970c42098f8071afefd_hd.png" class="kg-image" alt="v2-abfd37780b085970c42098f8071afefd_hd" width="720" height="200" loading="lazy"></figure><h3 id="7-">7. 通过控制台方法来检查元素</h3><p>你可以直接在控制台里输入下面的方法来检查元素</p><ul><li>inspect($('selector')) 会检查所有匹配选择器的 DOM 元素，并返回所有选择器选择的 DOM 对象。例如 inspect($('#firstName')) 选择所有 ID 是 firstName 的元素，inspect($('a')[3]) 检查并返回页面上第四个 p元素。</li><li>$0, $1, $2 等等会返回你最近检查过的几个元素，例如 $0 会返回你最后检查的元素，$1 则返回倒数第二个。</li></ul><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-e90e6e4af6d558254f013e1e44be7df0_hd.png" class="kg-image" alt="v2-e90e6e4af6d558254f013e1e44be7df0_hd" width="587" height="621" loading="lazy"></figure><h3 id="8-">8. 列出某个元素的所有属性</h3><p>你也可以通过控制台列出某个元素的所有属性：</p><p>dir($('selector')) 会返回匹配选择器的 DOM 元素的所有属性，你可以展开输出的结果查看详细内容。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-55921f16427b171b529693b3bbbc2342_hd.png" class="kg-image" alt="v2-55921f16427b171b529693b3bbbc2342_hd" width="527" height="231" loading="lazy"></figure><h3 id="9-">9. 获取最后计算结果的值</h3><p>你可以把控制台当作计算器使用。当你在 Chrome 控制台里进行计算时，可以通过 $_来获取最后的计算结果值，还是直接看例子吧：</p><pre><code class="language-js">2+3+4
9 //- The Answer of the SUM is 9

$_
9 // Gives the last Result

$_ * $_
81  // As the last Result was 9

Math.sqrt($_)
9 // As the last Result was 81

$_
9 // As the Last Result is 9
</code></pre><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-0f9403c639ff8182c5d1fb4e5775ea5d_hd.png" class="kg-image" alt="v2-0f9403c639ff8182c5d1fb4e5775ea5d_hd" width="397" height="233" loading="lazy"></figure><h3 id="10-">10. 清空控制台输出</h3><p>当你需要这么做的时候，只需要输入 clear() 然后回车就好啦！</p><p><strong>Chrome 开发者工具</strong>的强大远远超出你的想象！这只是其中的一部分小技巧而已，希望能够帮到你！</p><p>感谢您的阅读，要是您有什么自己的独门小技巧，也希望您在评论区与大家分享！</p><p>原文链接：<a href="https://www.freecodecamp.org/news/10-tips-to-maximize-your-javascript-debugging-experience-b69a75859329/#.cj9742xlv">Things you probably didn’t know you could do with Chrome’s Developer Console</a>，作者：Swagat Kumar Swain</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Redux 中的 reducer 到底是什么，以及它为什么叫 reducer？ ]]>
                </title>
                <description>
                    <![CDATA[ Redux 有 3 大核心概念：  * Action  * Reducer  * Store 其中 Action 和 Store 都非常好理解，我们可以直接按照其字面意思，将他们理解为动作和储存。 Action 表示应用中的各类动作或操作，不同的操作会改变应用相应的 state 状态，说白了就是一个带 type 属性的对象。 Store 则是我们储存state 的地方。我们通过 redux 当中的 createStore 方法来创建一个 store，它提供 3 个主要的方法，在这里我们可以模拟一下 createStore 的源码： // 以下代码示例来自redux官方教程 const createStore = (reducer) => {   let state;   ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/what-exactly-is-reducer-in-redux/</link>
                <guid isPermaLink="false">5d357931fbfdee429dc5f08f</guid>
                
                    <category>
                        <![CDATA[ Redux ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 余博伦 ]]>
                </dc:creator>
                <pubDate>Mon, 17 May 2021 10:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/07/web-developer.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong>Redux </strong>有 3 大核心概念：</p><ul><li>Action</li><li>Reducer</li><li>Store</li></ul><p>其中 <strong>Action </strong>和 <strong>Store </strong>都非常好理解，我们可以直接按照其字面意思，将他们理解为<strong>动作</strong>和<strong>储存</strong>。</p><p><strong>Action </strong>表示应用中的各类动作或操作，不同的操作会改变应用相应的 <strong>state </strong>状态，说白了就是一个带 <strong>type </strong>属性的对象。</p><p><strong>Store </strong>则是我们储存<strong>state </strong>的地方。我们通过 <strong>redux </strong>当中的 <strong>createStore </strong>方法来创建一个 <strong>store</strong>，它提供 3 个主要的方法，在这里我们可以模拟一下 <strong>createStore </strong>的源码：</p><pre><code class="language-js">// 以下代码示例来自redux官方教程
const createStore = (reducer) =&gt; {
  let state;
  let listeners = [];
  // 用来返回当前的state
  const getState = () =&gt; state;
  // 根据action调用reducer返回新的state并触发listener
  const dispatch = (action) =&gt; {
      state = reducer(state, action);
      listeners.forEach(listener =&gt; listener());
    };
  /* 这里的subscribe有两个功能
   * 调用 subscribe(listener) 会使用listeners.push(listener)注册一个listener
   * 而调用 subscribe 的返回函数则会注销掉listener
   */
  const subscribe = (listener) =&gt; {
      listeners.push(listener);
      return () =&gt; {
        listeners = listeners.filter(l =&gt; l !== listener);
      };
    };

  return { getState, dispatch, subscribe };
};
</code></pre><p>那么剩下的这个 <strong>reducer </strong>连翻译都很难翻译的东西应该怎么理解呢？</p><p>我们注意到 <strong>redux </strong>的官方文档里专门有一句对 reducer 命名的解释：</p><p>It's called a reducer because it's the type of function you would pass to <a href="https://link.zhihu.com/?target=https%3A//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce" rel="nofollow noreferrer">Array.prototype.reduce(reducer, ?initialValue)</a></p><p>中文版的文档把这一句话翻译成了：</p><p>之所以称作 <strong>reducer</strong> 是因为它将被传递给 <a href="https://link.zhihu.com/?target=https%3A//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce" rel="nofollow noreferrer">Array.prototype.reduce(reducer, ?initialValue)</a> 方法。</p><p>我们要注意到这里的中文翻译理解其实是错误的。原文的本意并不是说 <strong>redux </strong>里的 <strong>reducer </strong>会被传入到 <strong>Array.prototype.reduce</strong> 这个方法中。真的要翻译的话，应该翻译为：</p><p>之所以将这样的函数称之为 reducer，是因为这种函数与被传入 <strong>Array.prototype.reduce(reducer, ?initialValue)</strong> 的回调函数属于相同的类型。</p><p>为什么这么讲呢？我们来看一下 <strong>array </strong>使用 <strong>reduce </strong>方法的具体例子：</p><pre><code class="language-js">// 以下代码示例来自 MDN JavaScript 文档

/* 这里的callback是和reducer非常相似的函数
 * arr.reduce(callback, [initialValue])
 */

var sum = [0, 1, 2, 3].reduce(function(acc, val) {
  return acc + val;
}, 0);
// sum = 6

/* 注意这当中的回调函数 (prev, curr) =&gt; prev + curr
 * 与我们redux当中的reducer模型 (previousState, action) =&gt; newState 看起来是不是非常相似呢
 */
[0, 1, 2, 3, 4].reduce( (prev, curr) =&gt; prev + curr );
</code></pre><p>我们再来看一个简单的具体的 reducer 的例子：</p><pre><code class="language-js">// 以下代码示例来自redux官方教程

// reducer接受state和action并返回新的state
const todos = (state = [], action) =&gt; {
  // 根据不同的action.type对state进行不同的操作，一般都是用switch语句来实现，当然你要用if...else我也拦不住你
  switch (action.type) {
    case 'ADD_TODO':
      return [
        // 这里是ES7里的对象展开运算符语法
        ...state,
        {
          id: action.id,
          text: action.text,
          completed: false
        }
      ];
    // 不知道是什么action类型的话则返回默认state
    default:
      return state;
  }
};
</code></pre><p>如果非要翻译 <strong>reducer </strong>的话，可以将其翻译为缩减器或者折叠器？</p><p>为了进一步加深理解，我们再了解一下 <strong>reduce </strong>是什么东西，这个名词其实是函数式编程当中的一个术语，在更多的情况下，<strong>reduce </strong>操作被称为 <strong>Fold </strong>折叠（下图来自维基百科）。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-a32cb02859ea4ac0f8f50f1ec885d85c_hd.png" class="kg-image" alt="v2-a32cb02859ea4ac0f8f50f1ec885d85c_hd" width="320" height="158" loading="lazy"></figure><p>直观起见，我们还是拿 JavaScript 来理解。<strong>reduce </strong>属于一种高阶函数，它将其中的回调函数 <strong>reducer </strong>递归应用到数组的所有元素上并返回一个独立的值。这也就是“缩减”或“折叠”的意义所在了。</p><p><strong>总而言之一句话，redux 当中的 reducer 之所以叫做 reducer，是因为它和 Array.prototype.reduce 当中传入的回调函数非常相似。</strong></p><p>当然，如果你认为这种命名不完美容易产生歧义，你完全可以去给 <strong>redux </strong>提交一个 PR，提供一种更加恰当的命名方式。</p><p>有任何好的意见或者是建议欢迎在评论区参与讨论，如果文中有任何错误也欢迎在评论区批评指正。</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
