文章列表


一篇文章详细介绍如何在 JavaScript 中使用 Async/Await – 通过代码示例进行解释

<p>在学习 async/await 语法之前,您需要很好地了解 JavaScript promises。</p><p>async/await 的工作原理</p><p>async/await 语法是一种特殊语法,用于帮助您处理 promise 对象。它使您的代码更简洁、更清晰。</p><p>处理 时,需要将调用链接到返回 using 方法的函数或变量。PromisePromisethen/catch</p><p>当你有很多承诺时,你还需要很多方法链。例如,以下是使用该函数检索数据的方法:thenfetch()</p><p>fetch(<span style="color: #ce9178;">&#39;https://jsonplaceholder.typicode.com/todos/1&#39;</span>)</p><p>&nbsp; .then(<span style="color: #569cd6;">response</span> =&gt; response.json())</p><p>&nbsp; .then(<span style="color: #569cd6;">json</span> =&gt; console.log(json))</p><p>&nbsp; .catch(<span style="color: #569cd6;">error</span> =&gt; console.log(error))<span style="color: #6a9955;">;</span></p><p>典型的 Fetch API 实现</p><p>在上面的代码中,该函数返回一个 ,我们使用该方法处理它。在第一种方法中,我们接受 from 请求并使用该方法将其转换为对象。fetch()Promisethen()then()responsejson()</p><p>在第二种方法中,我们从对方法的调用中接收返回的数据,然后将该数据记录到控制台。then()jsonjson()</p><p>我们还添加了该方法来处理运行请求时可能发生的任何错误。catch()</p><p>代码真的不难理解,但是我们可以通过删除 and 链来使其更漂亮,这也删除了回调函数。.then().catch()</p><p>Await 关键字</p><p>该关键字基本上使 JavaScript 等待对象被解析或拒绝。您不必在方法中使用回调模式,而是可以将已实现的承诺分配给如下所示的变量:awaitPromisethen()</p><p>const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">&#39;https://jsonplaceholder.typicode.com/todos/1&#39;</span>)<span style="color: #6a9955;">;const json = await response.json();console.log(json)</span></p><p>使用 Await 代替 .then() 方法链接</p><p>关键字放在调用返回 promise 的函数或变量之前。它使 JavaScript 等待 promise 对象安定,然后再运行下一行中的代码。await</p><p>现在,如果运行上面的代码,可能会收到如下错误:</p><p>SyntaxError: await is only valid in async functions and the top level bodies of modules</p><p>在异步函数之外使用 Await 时出现语法错误</p><p>发生此错误的原因是必须在异步函数或模块中使用关键字。await</p><p>Async 关键字</p><p>若要创建异步函数,需要在函数名称前添加关键字。请看下面示例中的第 1 行:async</p><p>async function runProcess() {</p><p>&nbsp; const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">&#39;https://jsonplaceholder.typicode.com/todos/1&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; const <span style="color: #569cd6;">json</span> = await response.json()<span style="color: #6a9955;">;</span></p><p>&nbsp; console.log(json)}runProcess()<span style="color: #6a9955;">;</span></p><p>创建异步函数</p><p>在这里,我们创建了一个名为的异步函数,并将使用该关键字的代码放入其中。然后,我们可以通过调用它来运行异步函数,就像常规函数一样。runProcess()await</p><p>如何处理 Async/Await 中的错误</p><p>要处理 async/await 语法中可能发生的错误,可以使用 try/catch 块来捕获来自 promise 的任何拒绝。</p><p>请参阅以下示例:</p><p>async function runProcess() {</p><p>&nbsp; try {</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">&#39;https://jsonplaceholder.typicode.com/todos/1&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">json</span> = await response.json()<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; console.log(json)<span style="color: #6a9955;">;</span></p><p>&nbsp; } catch (error) {</p><p>&nbsp; &nbsp; console.log(error)<span style="color: #6a9955;">;</span></p><p>&nbsp; }}runProcess()<span style="color: #6a9955;">;</span></p><p>在异步函数中添加 try/catch</p><p>放在函数内部的 try/catch 块将处理来自 promise 对象的拒绝。runProcess()</p><p>现在,我们有了之前创建的标准 Promise 代码的完整 async/await 版本。以下是两者之间的比较:</p><p>PROMISE---异步Promise 与 Async/Await 代码比较</p><p>在 async/await 版本中,promise 的结果直接分配给变量。在标准 promise 版本中,promise 的结果作为参数传递给方法。.then()</p><p>大多数开发人员更喜欢 async/await 版本,因为它看起来更简单。</p><p>如何在 IIFE 和箭头函数中使用 Async/Await</p><p>立即调用函数表达式 (IIFE) 是一种用于在定义函数后立即执行函数的技术。</p><p>与常规函数和变量不同,IIFE 在执行后将从正在运行的进程中删除。</p><p>除了标准函数之外,您还可以制作异步 IIFE。当您只需要运行一次异步函数时,这很有用:</p><p>(async function () {</p><p>&nbsp; try {</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">&#39;https://jsonplaceholder.typicode.com/todos/1&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">json</span> = await response.json()<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; console.log(json)<span style="color: #6a9955;">;</span></p><p>&nbsp; } catch (error) {</p><p>&nbsp; &nbsp; console.log(error)<span style="color: #6a9955;">;</span></p><p>&nbsp; }})()<span style="color: #6a9955;">;</span></p><p>IIFE 异步函数示例</p><p>您还可以在创建异步函数时使用箭头语法,如下所示:</p><p>const <span style="color: #569cd6;">runProcess</span> = async () =&gt; {</p><p>&nbsp; try {</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">&#39;https://jsonplaceholder.typicode.com/todos/1&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">json</span> = await response.json()<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; console.log(json)<span style="color: #6a9955;">;</span></p><p>&nbsp; } catch (error) {</p><p>&nbsp; &nbsp; console.log(error)<span style="color: #6a9955;">;</span></p><p>&nbsp; }}<span style="color: #6a9955;">;runProcess();</span></p><p>Arrow 异步函数示例</p><p>您可以在代码中随意使用所需的语法。</p><p>为什么使用 async/await 语法?</p><p>async/await 语法使您能够在不使用 and 方法链接的情况下处理 promise,这也消除了对嵌套回调的需求。.then().catch()</p><p>当您在确定承诺后有一个复杂的流程时,这种好处是显着的。</p><p>回到上面的示例,假设方法中有一个条件语句,如下所示:.then()</p><p>fetch(<span style="color: #ce9178;">&#39;https://jsonplaceholder.typicode.com/todos/1&#39;</span>)</p><p>&nbsp; .then(<span style="color: #569cd6;">response</span> =&gt; response.json())</p><p>&nbsp; .then(<span style="color: #569cd6;">json</span> =&gt; {</p><p>&nbsp; &nbsp; if (<span style="color: #569cd6;">json.userId</span> == 1) {</p><p>&nbsp; &nbsp; &nbsp; <span style="color: #569cd6;">json.completed</span> == false<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; } else {</p><p>&nbsp; &nbsp; &nbsp; <span style="color: #569cd6;">json.completed</span> == true<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; }</p><p>&nbsp; })</p><p>&nbsp; .catch(<span style="color: #569cd6;">error</span> =&gt; console.log(error))<span style="color: #6a9955;">;</span></p><p>Promise 方法中的 if/else 块then()</p><p>在这里,您可以看到接受数据的回调函数内部有一个 if/else 块。json</p><p>与 async/await 版本相比,此代码很难推理和修改,如下所示:</p><p>(async function () {</p><p>&nbsp; try {</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">response</span> = await fetch(<span style="color: #ce9178;">&#39;https://jsonplaceholder.typicode.com/todos/1&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">json</span> = await response.json()<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; if (<span style="color: #569cd6;">json.userId</span> == 1) {</p><p>&nbsp; &nbsp; &nbsp; <span style="color: #569cd6;">json.completed</span> == false<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; } else {</p><p>&nbsp; &nbsp; &nbsp; <span style="color: #569cd6;">json.completed</span> == true<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; }</p><p>&nbsp; &nbsp; console.log(json)<span style="color: #6a9955;">;</span></p><p>&nbsp; } catch (error) {</p><p>&nbsp; &nbsp; console.log(error)<span style="color: #6a9955;">;</span></p><p>&nbsp; }})()<span style="color: #6a9955;">;</span></p><p>通过使用 async/await 语法,可以减少对方法链接和嵌套回调的需求。这会影响代码的可读性,尤其是当您有嵌套代码(如 if/else 和 for 循环块)时。</p><p>结论</p><p>现在,您已经了解了 async/await 语法的工作原理。该语法通过消除对 和 方法链接的需求,使使用 promise 变得更加容易,这也消除了对嵌套回调的需求。.then().catch()</p><p>即使关键字只能在函数内部使用,也可以使用 IIFE 仅调用异步函数一次。awaitasync</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: inherit; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 22px; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>

详细介绍什么是云计算,一篇面向初学者的云计算教程

<p>随着数字环境的不断发展和技术的进步,云计算仍然是开发人员学习的重要主题。</p><p>您可能在招聘信息中遇到过云要求,在对话中听到过人们谈论它,或者看到过提供云服务的公司的广告,现在您有兴趣了解更多信息。</p><p>在本文中,我将为您揭开云的神秘面纱,将复杂的概念分解为易于理解的部分。</p><p>以下是我们将在本文中介绍的内容:</p><p>云计算之前的世界</p><p>什么是云计算?</p><p>云服务提供商</p><p>不同的云服务</p><p>云计算帮助解决的挑战</p><p>云计算如何为您提供帮助?</p><p>云部署模型</p><p>因此,让我们深入研究并学习云计算基础知识,以便您可以开始进入这个不断发展的领域。</p><p>云计算之前的世界</p><p>要理解云计算,重要的是要了解云计算试图解决的问题。这将帮助您了解它的历史,并欣赏它为技术世界带来的便利。</p><p>在云出现之前,部署 Web 服务是一个非常昂贵的过程。若要部署 Web 应用程序,必须购买具有正确存储量和内存的服务器,将它们保存在现场,设置这些服务器,然后使用它们来托管应用程序。</p><p>除了原始服务器成本外,这还会带来许多额外成本,例如每次保持服务器正常运行和在线所需的电力和数据。还有安全问题,因为您需要防止您的服务器被不良行为者损坏或窃取。</p><p>除此之外,许多开发人员并不完全是服务器专家。因此,您要么必须培训您的开发人员成为系统管理员,要么雇用系统管理员来设置和配置服务器以使用您的应用程序。然后,要部署新的应用程序,您必须以新的成本重复整个过程。</p><p>在云出现之前,扩展应用程序并不容易。如果您试图管理成本而不购买太多服务器,或者雇用许多系统工程师,那么最终可能会没有足够的计算能力,并且需要扩展。扩展意味着购买更多服务器(或用更好的服务器替换现有服务器),配置它们以匹配现有配置,并在其上部署应用程序。</p><p>这些是我们在云计算之前面临的一些问题。现在,您可能想知道,“云计算如何解决这些问题?让我们来了解一下。</p><p>什么是云计算?</p><p>云计算是计算机系统资源的按需可用性,特别是数据存储(云存储)和计算能力,无需用户直接主动管理。</p><p>云计算依靠资源共享来实现一致性,通常使用即用即付模式,这有助于减少资本支出,但也可能导致用户意外的运营费用。- 维基百科</p><p>把云计算想象成从网吧租一台电脑。在网吧里,他们已经准备好了电脑——你只需进来,支付你想要的时间,然后在那段时间内使用电脑。</p><p>在云计算的情况下,您不必担心购买计算机、保护计算机或支付运行成本。云提供商涵盖了所有这些担忧。您很少需要担心软件问题,或者这些计算机上缺少特定软件。最好的部分是什么?您只需为您使用的计算机付费,并且只需为您使用它的时间付费。</p><p>因此,用更相关的术语来说,假设您有一个要部署的 Web 应用程序。您可以转到云服务提供商,选择应用程序所需的特定服务器要求,选择软件依赖项,然后部署应用程序,无需担心。</p><p>向一个五岁的孩子解释的云计算是“让别人管理你的计算需求”。你有一些网站需要上线,或者是一个移动应用程序,或者其他一些技术,而不是购买服务器来部署它,其他人购买并设置服务器。您只需上传文件即可。这几乎与租房相同,但现在您正在另一台计算机上租用计算空间。</p><p>云服务提供商</p><p>提供这些云服务的公司称为云服务提供商。这些公司已经拥有许多服务器和系统工程师。他们关心所有您不必担心的事情,例如服务器成本和运行成本。他们提供了一个 Web 界面,您可以在其中访问他们的服务器并在需要时使用它们。</p><p>目前,最受欢迎的云服务提供商是 Google(Google Cloud Platform)、Amazon AWS(Amazon Web Services)和 Microsoft (Azure)。这些公司提供类似的服务,但价格模型、功能等各不相同。</p><p>以下是他们各自提供的摘要:</p><p>谷歌</p><p>他们提供 IaaS(计算引擎)、容器即服务、CaaS(Kubernetes Engine)和 PaaS(App Engine)服务。他们还提供数据存储服务,包括 Google Cloud Storage、Cloud SQL 和 Cloud Bigtable 等工具。</p><p>AWS公司</p><p>这是第一家云服务提供商。他们提供 IaaS(弹性计算,EC2)、CaaS(弹性 Kubernetes 服务,EKS)和 PaaS(Elastic Beanstalk)服务。他们还提供数据存储服务,包括 Amazon S3 和 DynamoDb 等工具。</p><p>Microsoft</p><p>它们提供 IaaS(虚拟机)、CaaS(Kubernetes 服务、AKS)和 PaaS(应用服务)服务。他们还使用 Cosmos DB 等工具提供数据存储服务。</p><p>为了最大限度地利用资源,云服务提供商让其客户共享服务器。客户不必知道或担心此分配。</p><p>现在,让我们了解上述一些首字母缩略词/术语的含义,以便更好地了解这些云服务是什么。</p><p>不同的云服务</p><p>云服务提供商提供许多不同的计算服务。以下是最常见的服务:</p><p>SaaS(软件即服务)</p><p>萨斯-778x445极客超级</p><p>这项服务涉及您只使用某些软件,而不了解其源代码或主机环境或开发细节。您只需使用它并相信它正在正确管理和更新。</p><p>PaaS(平台即服务)</p><p>在这里,您只专注于应用程序开发,因为所有事情都已处理完毕(硬件、计算环境和所需的软件)。</p><p>IaaS(基础架构即服务)</p><p>这是所有云服务中最灵活的。在这里,你对事物拥有最大的控制权。您可以根据需要自定义和更改内容。</p><p>但你不拥有服务器。云服务提供商仅为您提供所需的基础架构,您负责创建自己的计算环境并安装应用程序运行所需的软件。</p><p>这里的想法类似于购买硬件。唯一的区别是,现在,你正在租用它,而且它是虚拟的(对你来说)。</p><p>云计算帮助解决的挑战</p><p>云计算消除了每次需要开发新应用程序时在现场购买和设置服务器的需要。这是一个很大的优势,因为它为公司节省了大量资金——无论是在服务器上,还是在设置和配置服务器以为您的应用程序工作的工程师上。</p><p>扩展通常并不容易,因为它通常涉及大量的设置和配置。例如,若要为应用程序提供更多存储,可以获取外部数据存储并连接到当前服务器。不过,这肯定有其局限性。</p><p>当您需要更好的服务器或额外的服务器时,可能会出现一个点。无论哪种方式,您为使其在以前的服务器上运行而安装的每个软件都必须在新服务器上重新安装。必须移动应用程序文件,依此类推。</p><p>此外,这些应用程序通常未充分利用这些硬件资源。从商业角度来看,这是一种损失。对此的初步解决方法是虚拟化。这基本上意味着创建虚拟(包含)环境,其中应用程序具有所有必需的软件,并且可以在服务器上正常运行。这导致了资源的更好利用。但这绝对不是完美的解决方案。</p><p>云计算如何为您提供帮助?</p><p>云计算提供了许多好处,其中一些在这里重点介绍:</p><p>支付订阅费用比构建整个数据中心更便宜。您有计划只允许您使用您使用的内容。</p><p>扩展和管理是云服务提供商的责任。</p><p>易于设置。开发人员只需专注于代码,因为所有实际的服务器和硬件设置都可以使用云服务提供商提供的用户界面完成。这样可以缩短开发时间,并更快地交付应用程序。</p><p>可及性。云服务提供商往往在全球拥有多个数据中心,以确保您的用户始终能够尽快访问您的服务。</p><p>数据安全。由于您的数据不再存储在您的物理空间中,因此不良行为者更难进入并破坏或窃取您的服务器。</p><p>云部署模型</p><p>云部署模型决定了数据(和应用程序)的存储位置以及客户如何与之交互。</p><p>公有云</p><p>在这里,一切都由云服务提供商处理。这是最受欢迎的模型。使用公有云时,您无需担心服务器维护,并且确信高可靠性和无限可扩展性的可能性。这通常意味着您与其他人共享服务器。</p><p>这是最便宜的模式,公司通常使用现收现付模式(因此您永远不必在财务上投入太多)。</p><p>这样做的一个潜在问题是,由云服务提供商处理所有内容意味着您对服务几乎没有控制权。</p><p>私有云</p><p>这类似于托管应用程序的传统方式。在这里,您确实拥有自己的数据中心。这意味着只有您可以使用服务器并对它们进行无限控制。</p><p>现在,区别在于,您为服务器的用户(通常是公司中的开发人员)提供自助服务界面。您仍然需要管理物理服务器,并负责其维护和扩展。</p><p>这种方法可能比公有云更安全,因为您可以控制并可以设置尽可能多的安全性。如果您的数据由于合规性要求而不能泄露,它也非常方便。</p><p>但这种方法的成本更高,尽管具有更可预测或固定的定价模型。这些服务器和硬件价格昂贵。拥有它们意味着有人管理它们,这意味着更多的费用。扩展还意味着每次都购买新设备。</p><p>混合云</p><p>什么是混合云混合云 |W3Codemasters(W3代码大师)</p><p>此方法合并了公有方法和云方法。它基本上可以为您提供更大的灵活性。您可以使用公共服务,也可以在需要时设置自己的公共服务。在这里,您可以通过服务器遵守法规,还可以通过云服务提供商提供高度可访问性。这种方法非常适合尝试从一种模型迁移到另一种模型的组织,在过渡期间保持业务运营。</p><p>这方面的一个示例应用程序是在公共云上托管应用程序,并将其连接到安全私有云上的数据库。</p><p>这种方法也比公共云更昂贵,因为您必须满足某些服务器的需求。当数据分布在多个服务器和应用程序之间时,它也可能变得复杂。</p><p>如何选择部署模型</p><p>公有云、私有云或混合云部署模型之间的选择取决于组织的独特要求。</p><p>公有云提供成本效益和全球覆盖</p><p>私有云提供增强的安全性和控制力</p><p>混合云提供了灵活性,并在两者之间实现了战略平衡。</p><p>该决定最终取决于安全需求、合规性要求、可伸缩性以及所需的 IT 基础架构控制级别等因素。</p><p>结论</p><p>现在,您应该有足够的信息来启动您在云计算领域的职业生涯。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>

Go 中的 new() 和 make() 函数 – 何时使用new函数,何时使用make函数

<p>Go,也称为 Golang,是一种静态类型的编译编程语言,旨在实现简单性和效率。</p><p>在处理切片、地图和通道等数据结构时,您可能会遇到 和 函数。虽然两者都用于内存分配,但它们有不同的用途。new()make()</p><p>在本文中,我们将探讨 Go 和 中的区别,并讨论何时使用它们。new()make()</p><p>功能new()</p><p>Go 中的函数是一个内置函数,它为指定类型的新零值分配内存,并返回指向该值的指针。它主要用于初始化和获取指向给定类型的新分配的零值的指针,通常用于结构等数据类型。new()</p><p>下面是一个简单的示例:</p><p>package mainimport <span style="color: #ce9178;">&quot;fmt&quot;</span>type Person struct {</p><p>&nbsp; &nbsp; Name &nbsp; &nbsp;string</p><p>&nbsp; &nbsp; Age &nbsp; &nbsp; int</p><p>&nbsp; &nbsp; Gender &nbsp;string}func main() {</p><p>&nbsp; &nbsp; // Using new() to allocate memory for a Person struct</p><p>&nbsp; &nbsp; p := new(Person)</p><p>&nbsp; &nbsp; // Initializing the fields</p><p>&nbsp; &nbsp; <span style="color: #569cd6;">p.Name</span> = <span style="color: #ce9178;">&quot;John Doe&quot;</span></p><p>&nbsp; &nbsp; <span style="color: #569cd6;">p.Age</span> = 30</p><p>&nbsp; &nbsp; <span style="color: #569cd6;">p.Gender</span> = <span style="color: #ce9178;">&quot;Male&quot;</span></p><p>&nbsp; &nbsp; fmt.Println(p)}</p><p>在此示例中,为新结构分配内存,并且是指向新分配的零值的指针。new(Person)Personp</p><p>功能make()</p><p>另一方面,该函数用于初始化切片、映射和通道——需要运行时初始化的数据结构。与 不同,返回指定类型的初始化(非零化)值。make()new()make()</p><p>让我们看一个使用切片的示例:</p><p>package mainimport <span style="color: #ce9178;">&quot;fmt&quot;</span>func main() {</p><p>&nbsp; &nbsp; // Using make() to create a slice with a specified length and capacity</p><p>&nbsp; &nbsp; s := make([]int, 10, 15)</p><p>&nbsp; &nbsp; // Initializing the elements</p><p>&nbsp; &nbsp; for i := 0<span style="color: #6a9955;">; i &lt; 10; i++ {</span></p><p>&nbsp; &nbsp; &nbsp; &nbsp; s[i] = i + 1</p><p>&nbsp; &nbsp; }</p><p>&nbsp; &nbsp; fmt.Println(s)}</p><p>在此示例中,创建一个长度为 10、容量为 15 的整数切片。该函数确保使用非零值初始化切片。make([]int, 10, 15)make()</p><p>何时使用和在 Go 中new()make()</p><p>用于值类型new()</p><p>在处理结构等值类型时,可用于为新的归零值分配内存。这适用于需要指向初始化结构的指针的方案。new()</p><p>p := new(Person)</p><p>用于引用类型:make()</p><p>对于切片、映射和通道(其中初始化涉及设置数据结构和内部指针),请使用创建初始化的实例。make()</p><p>s := make([]int, 5, 10)</p><p>指针与值:</p><p>请记住,返回一个指针,而返回一个非零值。根据是需要指针还是初始化值来选择适当的方法。new()make()</p><p>结论</p><p>了解 Go 中 和 之间的区别对于编写干净高效的代码至关重要。通过对适当的数据类型使用正确的方法,您可以确保在 Go 程序中正确分配和初始化内存。new()make()</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>

如何在 Red Hat Enterprise Linux 中管理用户和组

<p>为了在红帽企业 Linux (RHEL) 中工作时有效地保护您的系统并规范访问,您需要了解用户和组管理。</p><p>这是一个关键组件,对于单个和复杂的网络环境都很重要,因为它是熟练处理用户帐户和组的关键。</p><p>在本指南中,我们将深入探讨 RHEL 中用户和组管理的基础知识。您将获得必要的知识和技能,以便根据您的特定安全和操作需求自信地创建、修改和优化用户帐户和组。</p><p>您还将了解授予用户权限和实施基于组的访问控制的来龙去脉,并掌握确保强大的系统完整性和规范资源访问的基本工具和行之有效的方法。</p><p>先决条件</p><p>熟悉基本的 Linux 命令。如果你需要复习,你可以阅读我之前关于RHEL命令和关键概念的教程。</p><p>目录</p><p>以下是我们将在本综合指南中介绍的内容:</p><p>用户添加</p><p>什么是sudo?</p><p>用户模组</p><p>什么是 /etc/login.defs?</p><p>什么是 /etc/skel?</p><p>什么是 /etc/shadow?</p><p>组添加</p><p>组模组</p><p>实战练习</p><p>结束语</p><p>命令useradd</p><p>该命令是 RHEL 中用于创建新用户帐户的重要工具。此命令不仅将用户的信息添加到系统文件中,还可以设置其主目录和默认配置。useradd</p><p>命令的语法:useradd</p><p>useradd [options] username</p><p>什么是sudo?</p><p>在 Linux/Unix 的世界里,代表“超级用户做”。从本质上讲,它是一个命令,它授予普通用户运行具有完全管理或 root 权限的命令的能力。这对于由于安全原因可能限制普通用户的命令特别有用。sudo</p><p>例子:</p><p>只是一个快速提醒 - 如果您当前没有以 root 用户身份登录,请务必在使用我们将在本教程中讨论的命令之前使用。考虑作为一个方便的工具,它赋予你一些 root 用户的能力。我们将在以后的教程中更深入地讨论这个主题。sudouseraddsudo</p><p>目前,我以 root 用户身份登录。所以我不会在任何命令之前使用。sudo</p><p>创建用户:</p><p>useradd kedar</p><p>此命令创建一个名为“kedar”的新用户,并默认为他们设置一个主文件夹。稍后,我们将详细了解以及如何更改这些默认值。useradd</p><p>在 RHEL 中,创建用户时已经设置了一些值,但我们将在本教程中进一步探讨它们。</p><p>检查新添加的用户:</p><p>tail -1 /etc/passwd</p><p>/etc/passwd用作包含有关用户帐户的基本信息的集中式存储库。上述命令的输出将按以下方式显示:</p><p>kedar:x:1001:1001:John Doe:/home/john:/bin/bash</p><p>如果用户添加成功,您将看到上面的输出。现在可能会有一些变化,但看起来应该基本相同。</p><p>让我们分解这个输出并尝试理解它:</p><p>框架-1000004542上述输出的细分</p><p>用户名 – 用户帐户的名称。</p><p>密码占位符(已过时) – 从历史上看,此字段包含一个“x”字符,表示用户的加密密码存储在文件中。/etc/shadow</p><p>用户 ID (UID) – 分配给用户的唯一数字标识符。</p><p>组 ID (GID) – 与用户关联的主要组的数字标识符。</p><p>用户信息 (GECOS) – 此字段通常包括其他信息,如用户的全名、联系方式等。</p><p>主目录 – 用户主目录的路径。</p><p>登录 Shell – 用户登录时执行的默认 shell 或程序。</p><p>创建用户后,我们可以为该用户设置密码。这只能从 root 帐户完成。</p><p>为新创建的帐户设置密码</p><p>passwd kedar</p><p>这将要求您键入 kedar 用户的密码。设置密码后,您可以使用 GUI 登录 kedar 用户。如果要通过GUI登录,则设置密码非常重要。</p><p>在创建新用户时为用户设置不同的选项</p><p>现在我们知道在创建用户时有哪些选项可用,我们可以根据需要设置它们。</p><p>用户 ID (-u)</p><p>useradd -u 1234 kedar</p><p>上面带有该选项的命令会在创建用户 kedar 时将用户 ID 设置为 1234。-u</p><p>2. 初级组 (-g)</p><p>useradd -g 1232 kedar</p><p>如果存在现有组,并且您知道组 ID 或组名称,则可以将该组添加为 kedar 用户的主要组。</p><p>3. 中学组 (-G)</p><p>useradd -G developers kedar</p><p>用户 kedar 将被添加到已存在的名为 developers 的辅助组中。我们可以将用户添加到多个辅助组。</p><p>将 Linux 中的辅助组视为用户梦寐以求的俱乐部会员资格。虽然在计算机上工作时,它们会自动包含在主组中,但加入辅助组允许用户扩展其成员身份并访问其他文件和功能。</p><p>从本质上讲,这就像同时成为多个组的一部分,为用户提供额外的权限和探索系统不同部分的能力。</p><p>4. 用户信息</p><p>useradd -c <span style="color: #ce9178;">&quot;2 Month Intern&quot;</span> kedar</p><p>这会将更多信息添加到用户 kedar 作为“2 个月实习生”。这将显示在文件中。/etc/passwd</p><p>5. 主目录</p><p>useradd -d /etc/kedar/home kedar</p><p>现在,这会将主目录设置为 kedar 用户。默认情况下,在 RHEL 中,如果未指定,则主目录为 。/etc/kedar/home/home/kedar</p><p>6. 登录外壳</p><p>useradd -s /bin/shell kedar</p><p>在这里,kedar 用户将可以访问位于 /bin/shell 中的 shell。这将使用户 kedar 能够访问 shell。</p><p>/bin/bash 访问权限与用户登录系统时的默认 shell 有关。</p><p>在 Linux 世界中,/bin/bash shell 通常被称为 Bash shell,是“Bourne Again SHell”的缩写,在大多数 Linux 发行版上都很容易获得。当用户被授予 /bin/bash 访问权限时,这意味着在登录时,他们将看到 Bash shell 的命令行界面。</p><p>这个强大的 shell 使他们能够使用其独特的语法和功能与系统交互、运行命令和执行特定于 Bash 的脚本。</p><p>鉴于其广泛使用、高级功能以及与各种脚本语言和命令行任务的兼容性,/bin/bash shell 是许多用户的首选选项,作为其默认 shell。</p><p>如果要删除特定用户的 shell 访问权限,可以按如下方式设置 shell 访问权限:.这会将此用户的访问限制为登录其帐户,直到 shell 访问权限设置为 。/sbin/nologin/bin/shell</p><p>useradd -s /sbin/nologin kedar</p><p>命令usermod</p><p>usermod 命令在 Linux 中非常重要。它可以帮助管理员在创建用户帐户后轻松更改有关用户帐户的内容。这样可以节省时间,因为您不必删除并重新创建帐户。这是一种轻松管理用户的便捷方式。</p><p>命令的语法:usermod</p><p>usermod [options] username</p><p>例子:</p><p>更改用户名:</p><p>usermod -l newusername oldusername</p><p>此命令将用户名从 更改为 。oldusernamenewusername</p><p>更改用户 ID (UID):</p><p>usermod -u &lt;newUID&gt; username</p><p>此命令将替换为用户所需的新 UID。&lt;newUID&gt;</p><p>更改组 ID (GID):</p><p>usermod -g &lt;newGID&gt; username</p><p>此命令将替换为用户所需的新主组 ID。&lt;newGID&gt;</p><p>将用户添加到补充组:</p><p>usermod -aG group1,group2 username</p><p>此命令将用户添加到其他补充组(、 等)。group1group2</p><p>更改主目录:</p><p>usermod -d /newhome username</p><p>此命令将用户的主目录更改为 。/newhome</p><p>更改默认 shell:</p><p>usermod -s /bin/bash username</p><p>此命令将用户的默认 shell 更改为 。/bin/bash</p><p>设置帐户的到期日期:</p><p>usermod -e YYYY-MM-DD username</p><p>此命令为用户帐户设置到期日期 ()。YYYY-MM-DD</p><p>您可以使用 来浏览有关此命令的更多信息。使用命令时,您可以使用与 相同的选项来操作用户的信息。man usermoduseraddusermod</p><p>什么?/etc/login.defs</p><p>该文件是一个重要的配置文件,用于设置登录、密码策略和用户帐户创建的默认参数。它可以在通常的位置 /etc/login.defs 中找到,并且在确定用户管理和身份验证的系统范围的默认值方面起着关键作用。/etc/login.defs</p><p>用户 UID 还有一个固定范围,如下表所示:</p><p>框架-1000004563-1UID 范围表 - 特权用户:0-99,系统用户:201-999,普通用户:1000-60000</p><p>目录 /etc/login.defs 包含各种默认配置。通过访问此目录,我们可以根据自己的喜好修改这些设置。</p><p>此文件包含我们可以调整的几个不同选项,下面列出了其中一些选项:</p><p>PASS_MAX_DAYS &nbsp; 90PASS_MIN_DAYS &nbsp; 7PASS_WARN_AGE &nbsp; 14PASS_MIN_LEN &nbsp; &nbsp;8UID_MIN &nbsp; &nbsp; &nbsp; &nbsp; 1000UID_MAX &nbsp; &nbsp; &nbsp; &nbsp; 60000GID_MIN &nbsp; &nbsp; &nbsp; &nbsp; 1000GID_MAX &nbsp; &nbsp; &nbsp; &nbsp; 60000LOGIN_RETRIES &nbsp; 5LOGIN_TIMEOUT &nbsp; 60CREATE_HOME &nbsp; &nbsp; yesUMASK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 077</p><p>ENCRYPT_METHOD &nbsp;SHA512</p><p>CHFN_AUTH &nbsp; &nbsp; &nbsp; yesCHFN_RESTRICT &nbsp; rwh</p><p>DEFAULT_HOME &nbsp; &nbsp;/home</p><p>现在,您知道创建用户时默认设置的来源了。您可以根据需要更改这些设置。</p><p>什么?/etc/skel</p><p>在 Linux 和类似系统中,该文件夹就像新用户的入门包。它被称为“skel”,是“骨架”的缩写,因为它为新用户设置了基础知识。/etc/skel/</p><p>此文件夹包含一组复制到新用户主文件夹中的文件和文件夹。每当有新用户使用时,这些来自 /etc/skel/ 的基本文件都会自动放入他们的主文件夹中,确保它包含他们入门所需的内容。</p><p>这有助于为用户设置一个简单的起点。它为他们提供基本配置、默认设置,有时还提供示例文件。此方法可确保每个新用户都从标准设置和所需文件开始。</p><p>在 /etc/skel/ 文件夹中,您可能会找到 .bashrc、.profile 等常见文件和类似的配置文件。</p><p>什么?/etc/shadow</p><p>该文件是基于 Unix 的操作系统(如 Linux)的关键组件,因为它用作加密用户密码和其他密码相关数据的存储库。这种增强的安全措施超越了以前在 /etc/passwd 文件中存储密码的方法。/etc/shadow</p><p>/etc/shadow 文件包含与用户帐户密码有关的重要信息。文件中的每一行都代表一个特定的用户,并分为多个字段,每个字段用冒号 (:) 分隔。</p><p>这些字段通常包括用户名、加密密码(使用加密算法进行哈希处理,而不是实际密码)、自上次密码更改以来的天数(从 1970 年 1 月 1 日开始)、有关密码过期的信息(如最短和最长期限)以及警告期。它还指定在帐户被锁定之前允许的非活动天数,以及帐户是否有到期日期。</p><p>/etc/shadow 文件的示例条目</p><p>user:$6$PswrdHash$E7KLkQIGo7mxG5vDi7JelC5D8L0qbg38z1/WgNhAZDpCoe2GyGB6JefT9ftb/Rfm3uZOlFkktj/SkJTfSJziO.:18830:0:90:7:::</p><p>哪里:</p><p>user: 用户名</p><p>$6$PswrdHash$E7KLkQIG...:加密的密码哈希</p><p>$1$ 是 MD5</p><p>$2a$ 是河豚</p><p>$2y$ 是河豚</p><p>$5$ 是 SHA-256</p><p>$6$ 是 SHA-512</p><p>$y$ 是 yescrypt</p><p>这些符号有助于识别用于存储在文件中的每个密码哈希的哈希算法。例如,如果您看到以 开头的密码哈希,则表示该特定密码已使用 SHA-512 加密。/etc/shadow$6$</p><p>18830:上次密码更改日期(自 1970 年 1 月 1 日以来的天数)</p><p>0:最短密码期限</p><p>90:密码最长使用期限</p><p>7:密码警告期</p><p>帐户不活动和过期的其他字段</p><p>访问:为了访问和修改文件,您必须授予 root 用户权限或专用权限。/etc/shadow</p><p>修改:为了增强安全性,建议使用指定的命令,例如 ,它处理密码加密并有效地更新 /etc/shadow 文件。passwd</p><p>命令groupadd</p><p>在 RHEL 中,您可以使用该命令在系统上创建新组。它是用于管理用户组的基本命令,允许系统管理员添加组、设置其属性以及定义其成员身份。groupadd</p><p>组的所有默认设置都位于 中。/etc/login.defs 文件包含重要设置,例如 GID_MIN 和GID_MAX,前者用于确定常规组的最小 GID 值,后者用于设置最大 GID 值。此外,SYS_GID_MIN 和 SYS_GID_MAX 确定系统组的最小和最大 GID 值。/etc/login.defs</p><p>这些设置在系统内组的管理中起着至关重要的作用。</p><p>命令的语法:groupadd</p><p>groupadd [options] groupname</p><p>例子:</p><p>创建组:</p><p>groupadd developers</p><p>上面的命令创建一个名为“developers”的新组。</p><p>分配特定的 GID:</p><p>groupadd -g 1001 developers</p><p>此命令创建具有指定 GID(例如,GID 1001)的组。</p><p>您可以使用该命令根据需要探索更多选项。这将为您提供命令的文档。man groupaddgroupadd</p><p>命令groupmod</p><p>RHEL 中的命令对于系统管理员来说是一个有价值的工具,因为它使他们能够毫不费力地修改现有的组属性。groupmod</p><p>使用这个强大的命令,您可以更改组而无需重新创建它们,使其成为系统维护的重要资产。</p><p>命令的语法:groupmod</p><p>groupmod [options] groupname</p><p>例子:</p><p>更改组名称:</p><p>groupmod -n newgroupname oldgroupname</p><p>此命令将组名从 更改为 。oldgroupnamenewgroupname</p><p>更改 GID(组 ID):</p><p>groupmod -g &lt;newGID&gt; groupname</p><p>此命令将组的 GID 更改为 。&lt;newGID&gt;</p><p>将组添加到补充组:</p><p>groupmod -aG group1,group2 groupname</p><p>此命令将该组添加到其他补充组(、、 等)。group1group2</p><p>从组中添加用户:</p><p>groupmod -m -m user1,user2 developers</p><p>这会将 user1 和 user2 添加到 developers 组。</p><p>从群组中移除用户:</p><p>groupmod -M user1,user2 developers</p><p>这将从开发人员组中删除 user1 和 user2。</p><p>您可以使用该命令根据需要探索更多选项。这将为您提供命令的文档。man groupmodgroupmod</p><p>实战练习</p><p>练习 1:基本用户和组管理</p><p>创建用户和组</p><p>用于创建名为“testuser”的新用户。useradd</p><p>用于创建名为“testgroup”的组。groupadd</p><p>确保用户“testuser”是组“testgroup”的一部分。</p><p>练习 2:用户修改</p><p>修改用户属性</p><p>用于将 “testuser” 的默认 shell 更改为 。usermod/bin/bash</p><p>使用 将用户的登录名从“testuser”修改为“newuser”。usermod</p><p>通过检查 来确认更改。/etc/passwd</p><p>练习 3:组修改</p><p>组修改</p><p>用于将“testgroup”重命名为“newgroup”。groupmod</p><p>使用 更改“newgroup”的 GID(组 ID)。groupmod</p><p>使用 将 “newuser” 添加到 “newgroup” 中。usermod</p><p>练习 4:高级用户和组管理</p><p>设置用户和组限制</p><p>使用中的参数设置密码策略。/etc/login.defs</p><p>在 中配置组默认设置,例如 GID_MIN 和 GID_MAX。/etc/login.defs</p><p>练习 5:理解和/etc/shadow/etc/skel</p><p>探索密码存储和默认值</p><p>检查文件以了解密码存储格式。/etc/shadow</p><p>创建一个新用户并观察其在 中的输入。/etc/shadow</p><p>通过创建新用户并观察其主目录来探索和了解其用途。/etc/skel</p><p>练习 6:挑战</p><p>管理权限和访问控制</p><p>设置目录权限,以便只有“newgroup”中的“newuser”才能读/写特定文件夹。</p><p>试验和命令以更改所有权和权限。chownchmod</p><p>练习 7:真实场景</p><p>创建具有特定配置的用户</p><p>创建名为“admin”的用户,其中包含自定义的主目录 (/opt/admin) 和特定的默认 shell。</p><p>设置仅适用于“admin”用户的密码策略。</p><p>结束语</p><p>感谢您今天与我一起探索如何在 RHEL 中管理用户和组。您可以更深入地了解 Linux 专业知识领域,并继续关注我未来的教程中更多有见地的内容。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>

详细介绍如何使用 pnpm – 安装和常用命令

<p>PNPM 类似于 npm,但它更快、更高效。毕竟,起始 p 代表 p性能。</p><p>根据其创建者 Zoltan Kochan 的说法,pnpm“允许您节省千兆字节的磁盘空间”。</p><p>许多流行的项目,包括Next.js,Vite,Svelte,甚至freeCodeCamp都使用pnpm。因此,如果您还没有,现在是尝试此工具的好时机。我相信你的时间不会被浪费。</p><p>在本文中,我不会详细介绍为什么 pnpm 比 npm 更快、更高效。如果您想了解更多信息,可以查看官方文档。</p><p>本文的目的是快速开始使用 pnpm,以便您可以执行以前使用 npm 或 yarn 执行的日常任务。拿起你最喜欢的一杯茶或咖啡,让我们开始吧!</p><p>如何安装 pnpm</p><p>我假设您的机器上已经安装了现代版本的 Node.js。这些现代版本带有一个名为 .它允许您管理您的 Node 包管理器。corepack</p><p>是的,你没看错!这是 Node 的一个实验性功能,但它运行良好。</p><p>因此,要开始使用它,您首先需要通过从终端输入以下命令来启用它,该命令具有在系统上安装 pnpm(以及 yarn)的效果:</p><p>corepack enable</p><p>就是这么简单。现在,如果您运行,您将看到您刚刚安装的版本。但这可能不是 pnpm 的最新版本。如果是这种情况,可以使用以下命令安装最新版本的 pnpm:pnpm --version</p><p>corepack prepare pnpm@latest --activate</p><p>请记住,有很多方法可以在您的系统上安装 pnpm,您可以在安装文档中阅读所有这些方法。我最喜欢的是我上面展示的公式。corepack</p><p>如何配置 Shell 以提高效率(可选)</p><p>好了,你现在已经安装了pnpm。但是可以改进默认的命令行体验,以节省一些精力。</p><p>请注意,此部分是可选的。如果需要,可以跳到下一部分。但是,如果您真的想设置它以使 CLI 体验愉快,让我们学习如何做到这一点。</p><p>pnpm很难输入 - 所以设置一个别名</p><p>如果你发现像我一样很难打字,你可以设置一个别名来节省你的一些精力。如果您使用的是 Linux 或 MacOS,只需将以下内容放入 shell 配置中(、 或):pnpm.bashrc.zshrcconfig.fish</p><p>alias <span style="color: #569cd6;">pn</span>=pnpm</p><p>如果要在 Powershell (Windows) 中设置别名,可以查看此文档。</p><p>如何设置制表符补全</p><p>在 pnpm 中,有两种方法可以做到这一点。两者都有其优点和缺点。</p><p>首先,我将与您分享我最喜欢的方法。它是一个名为 shell 插件,可用于 zsh、fish shell 和 Powershell 核心。它仅涵盖最常用的命令。如果你是 Arch Linux 和 zsh 用户,你可以用任何 AUR 助手来安装它。例如,如果使用 ,请运行以下命令进行安装:pnpm-shell-completionyay</p><p>yay -S pnpm-shell-completion</p><p>然后在文件中添加以下行以加载它:.zshrc</p><p>source /usr/share/zsh/plugins/pnpm-shell-completion/pnpm-shell-completion.zsh</p><p>现在它应该起作用了。如果您使用任何其他受支持的 shell,请按照插件的文档了解如何安装它。</p><p>第二种方法内置于 pnpm 中。若要设置此样式的自动完成,请运行以下命令:</p><p>pnpm install-completion</p><p>然后按照它给你的步骤操作。此方法比第一种方法涵盖更多的命令。但它有一些限制——例如,它不能自动完成你的脚本。例如,它也无法自动完成要卸载的任何依赖项名称。package.json</p><p>如何使用pnpm</p><p>现在,您应该安装了带有别名和 Tab 完成符的 pnpm。不再有延迟——让我们看看如何使用 pnpm。</p><p>如何使用初始化新项目pnpm</p><p>若要获取当前目录中的默认值,请运行以下命令:package.json</p><p>pnpm init</p><p>与 npm 不同,它不会以交互方式创建它,您无需为此指定标志。-y</p><p>如何安装软件包</p><p>若要将包安装为依赖项,语法为:</p><p>pnpm add &lt;pkg&gt;</p><p>若要将包安装为开发依赖项,必须传递 (or ) 标志:-D--save-dev</p><p>pnpm add -D &lt;pkg&gt;</p><p>若要全局安装包,请使用以下标志:-g</p><p>pnpm add -g &lt;pkg&gt;</p><p>如何安装所有依赖项</p><p>假设您从 GitHub 克隆了一个项目。它确实有一个文件,但没有(你不应该用 Git 跟踪)。现在要安装其中的所有依赖项,该命令与以下命令非常相似:package.jsonnode_modulesnode_modulespackage.jsonnpm</p><p>pnpm install</p><p>或</p><p>pnpm i</p><p>如何运行脚本package.json</p><p>这个过程也与 非常相似。执行此操作的明确方法是使用该命令。如果您有一个名为 的脚本,则可以使用以下命令执行它:npmrunbuild</p><p>pnpm run build</p><p>你也可以用它来做同样的事情。这是一种速记格式,也可以做其他事情。在本文中,我们将很快了解有关速记的更多信息。pnpm build</p><p>如何运行依赖项附带的命令</p><p>您可以使用 运行依赖项附带的命令。pnpm exec</p><p>安装软件包时,如果它有 字段指定的命令 ,您将在目录中获得同名的可执行文件。其目的是执行相应的文件。binpackage.jsonnode_modules/.bin</p><p>pnpm exec在 (即 ) 之前,然后执行给定的命令。./node_modules/.<span style="color: #569cd6;">binPATHPATH</span>=./node_modules/.bin:$PATH</p><p>下面是一个示例,演示如何安装为开发依赖项,然后运行命令以创建文件:typescripttsctsconfig.json</p><p>pnpm add -D typescript</p><p>pnpm exec tsc --init</p><p>与命令类似,您也可以省略并仅用于执行相同的操作。当您的 .在下一节中,我们将仔细研究这种速记语法。pnpm runexecpnpm tsctscpackage.json</p><p>请注意,由于可以访问由 中指定的路径解析的所有命令,因此您可以访问许多系统命令,例如 、 等。pnpm execPATHrmls</p><p>如何工作pnpm &lt;command&gt;</p><p>pnpm &lt;command&gt;工作原理如下:</p><p>如果是 pnpm 命令(即 ,依此类推),则执行该命令。&lt;command&gt;addinstall</p><p>否则,如果是在 中找到的脚本,请执行 .&lt;command&gt;package.jsonpnpm run &lt;command&gt;</p><p>否则执行 .pnpm exec &lt;command&gt;</p><p>因此,作为一个方便的快捷方式,其中和是没有回退的显式命令。pnpm &lt;command&gt;pnpm execpnpm run</p><p>如何更新程序包</p><p>要根据 中的指定范围将包更新到最新版本,请运行以下命令:package.json</p><p>pnpm up</p><p>要将所有依赖项更新到其最新版本,请忽略 中指定的范围,请运行以下命令:package.json</p><p>pnpm up --latest</p><p>如何删除包</p><p>要从 和 ur 中删除包,可以使用 。例如,如果您安装了 ,则可以使用以下命令将其删除:node_modulespackage.jsonpnpm rmexpress</p><p>pnpm rm express</p><p>若要删除全局安装的包,请使用该标志。以下是删除全局安装的软件包的示例:-gnodemon</p><p>pnpm rm -g nodemon</p><p>有没有其他选择?npx</p><p>是的,这是命令。它与 npx 非常相似。它从注册表下载指定的包,而不将其安装为依赖项,然后运行它公开的任何默认命令二进制文件。pnpm dlx</p><p>例如,您可以运行 package 公开的命令,如下所示,以打印一头牛的 ASCII 艺术,说出您传递的字符串:cowsay</p><p>pnpm dlx cowsay hi freeCodeCamp</p><p>现在您可能想知道,如果一个包公开了多个命令二进制文件,那么选择哪个命令作为默认值?或者如何显式指定命令二进制文件?pnpm dlx</p><p>让我们先看看默认命令二进制文件是如何确定的:</p><p>如果字段只有一个条目,则使用该条目。binpackage.json</p><p>否则,如果字段中有与包名称匹配的命令名称,则忽略作用域部分(如果有),则使用该命令。binpackage.json</p><p>否则,pnpm 无法确定默认命令,并抛出一个错误,其中包含一条有用的错误消息,该消息很可能会回答第二个问题。</p><p>要显式指定特定命令,您需要先使用该选项安装软件包,然后在 之后指定该命令。--packagedlx</p><p>例如,包向命令二进制文件和 .现在,如果你想在没有 或 的情况下运行来创建一个文件,你可以像下面这样使用:typescripttsctsservertsc --inittsconfig.jsontypescriptnode_modulespackage.jsonpnpm dlx</p><p>pnpm --<span style="color: #569cd6;">package</span>=typescript dlx tsc --init</p><p>结论</p><p>在本教程中,您已经了解了 pnpm 是什么以及如何安装它。我们还介绍了您每天很可能需要的几个常见的 pnpm 命令。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>

对比PyTorch 与 TensorFlow – 哪个更适合深度学习项目?

<p>在本文中,我们将介绍两个流行的深度学习库——PyTorch 和 TensorFlow,看看它们如何比较。</p><p>如果您刚开始使用深度学习,可用的工具和框架将是压倒性的。行业专家可能会推荐 TensorFlow,而铁杆 ML 工程师可能更喜欢 PyTorch。</p><p>这两个框架都是强大的深度学习工具。虽然 TensorFlow 用于 Google 搜索和 Uber,但 Pytorch 为 OpenAI 的 ChatGPT 和特斯拉的自动驾驶仪提供支持。</p><p>在这两个框架之间进行选择是开发人员面临的共同挑战。如果您处于此位置,在本文中,我们将比较 TensorFlow 和 PyTorch,以帮助您做出明智的选择。</p><p>了解 PyTorch 和 TensorFlow</p><p>让我们从更好地了解我们的竞争者开始。</p><p>PyTorch 由 Facebook 的 AI 研究实验室创建,因其简单性和用户友好性而获得认可。Pytorch 可以有效地处理动态计算图。</p><p>计算图是数学运算及其关系的可视化表示。它就像一个流程图,显示数据如何流经深度学习模型。</p><p>训练神经网络涉及大量计算。因此,计算图可以帮助计算机在训练神经网络时有效地组织和执行计算。</p><p>PyTorch 易于使用,使其成为开发人员和研究人员的首选。对于喜欢简单明了的项目框架的人来说,PyTorch 是一个完美的选择。</p><p>TensorFlow 是 Google 的心血结晶,具有强大的生产能力和对分布式训练的支持。TensorFlow 在实际应用程序中需要大规模机器学习模型的场景中表现出色。</p><p>分布式训练是深度学习中用于训练大型复杂模型的一种技术。通过将训练过程分散到多台机器或设备上,它在处理海量数据集时非常有用。</p><p>Tensorflow 是深度学习模型中需要可扩展性和可靠性的公司的首选。</p><p>因此,正如您可能能够看到的,PyTorch 和 TensorFlow 之间的选择通常取决于项目的特定需求。</p><p>PyTorch 与 TensorFlow – 哪一个适合您?</p><p>易于学习和使用</p><p>当你开始一个新项目时,有一个更容易的学习曲线是很有帮助的。它既有助于构建项目,也有助于为您的项目雇用/培训工程师。</p><p>PyTorch 更简单,并且具有“Pythonic”的做事方式。它是初学者和研究人员的最爱。它的动态计算图意味着你可以即时改变事物,这非常适合实验。</p><p>TensorFlow 提供了一种更加结构化的方法。它的静态计算图需要更多的提前规划。TensorFlow 还具有陡峭的学习曲线。但这可以带来更优化和高性能的模型。</p><p>TensorFlow 2.0 在简单性方面也取得了长足的进步。它通过其 Eager Execution 功能融入了 PyTorch 的更多动态特性。</p><p>但是,在简单性和易学性方面,PyTorch 显然是赢家。</p><p>性能和可扩展性</p><p>在性能和可扩展性方面,TensorFlow 大放异彩。它可以轻松处理大规模的分布式训练。因此,TensorFlow 是生产环境的首选。</p><p>TensorFlow 的集成工具 TensorBoard 也是一个强大的可视化和调试工具。</p><p>PyTorch 正在迎头赶上,最近的更新提高了其可扩展性。</p><p>PyTorch 进行了改进,以支持分布式训练和可扩展性。它提供了一些工具,可帮助您在多个 GPU 甚至跨多台机器训练深度学习模型。</p><p>但 TensorFlow 在生产环境中部署大规模模型方面仍然处于领先地位。</p><p>社区与支持</p><p>框架的强度在一定程度上也由其社区决定。由于这些是开源框架,因此没有客户支持。因此,如果您在使用这些框架构建项目时遇到困难,则必须依靠社区寻求帮助。</p><p>TensorFlow 年纪更大,社区更大。它还拥有大量的教程、课程和书籍。</p><p>PyTorch 虽然更年轻,但其社区发展迅速。PyTorch 是最受欢迎的,尤其是在研究人员中,因为它很容易使用 Pytorch 来试验数据集。</p><p>这两个框架都有强大的支持,但 TensorFlow 的成熟度使其在这一领域略有优势。</p><p>灵活性和创新性</p><p>如果您正在从事前沿研究或需要更大的灵活性,PyTorch 是您的最佳选择。它的动态计算图允许更具创造性和更复杂的模型架构。</p><p>正如我之前所说,这种灵活性使 PyTorch 成为研究界最受欢迎的工具。在快速原型设计和实验是关键的情况下,PyTorch 是您的最佳选择。</p><p>TensorFlow 一直在努力增加灵活性。但这是一场艰难的战斗,因为 PyTorch 从一开始就是为了简单而构建的。</p><p>行业采用</p><p>1*3KA-wtadTjv6H9-LLSu9fwPyTorch(蓝色)与 TensorFlow(红色)</p><p>TensorFlow 在 tpyally 上占了上风,尤其是在大型公司和生产环境中。它的稳健性和可扩展性使其成为企业的安全选择。</p><p>但 PyTorch 正在迅速发展。正如您在趋势图中看到的那样,PyTorch 已经取代了 TensorFlow,成为搜索量最大的深度学习库。您可以在此处找到实时图表。</p><p>由于 PyTorch 的用户友好性和灵活性,多个行业开始采用 PyTorch 进行研究和开发。在 ChatGPT 等模型发布后,Pytorch 也证明了其作为生产级工具的能力。</p><p>以下是使用 TensorFlow 和 PyTorch 的公司列表。</p><p>使用 Tensorflow 的产品</p><p>Google 搜索和推荐:Google 使用 TensorFlow 来增强其搜索引擎和推荐系统。它有助于提高搜索准确性,并根据用户行为和偏好提供个性化推荐。</p><p>NVIDIA 深度学习加速器 (NVDLA):NVDLA 是用于深度学习应用程序的硬件加速器。它使用 TensorFlow 在此硬件上优化和部署模型。</p><p>Uber 的米开朗基罗:Uber 在其米开朗基罗平台中使用 TensorFlow 进行机器学习。它协助完成各种任务,包括 ETA 预测、欺诈检测和动态定价。</p><p>使用 PyTorch 的产品</p><p>Facebook:由于 PyTorch 来自 Facebook,因此 Facebook 将 PyTorch 用于各种内部 AI 研究和应用程序,包括内容推荐和语言翻译。</p><p>特斯拉自动驾驶仪:特斯拉的自动驾驶系统依靠 PyTorch 实现其深度学习组件,例如物体检测和导航。</p><p>OpenAI 的 GPT 模型:OpenAI 的许多语言模型,包括 GPT-2 和 GPT-3,都是使用 PyTorch 构建的。这些模型用于广泛的自然语言处理任务,包括文本生成和语言翻译。</p><p>结论</p><p>在 PyTorch 和 TensorFlow 之间进行选择取决于项目的需求。</p><p>对于那些需要易用性和灵活性的人来说,PyTorch 是一个不错的选择。如果您更喜欢从头开始的可扩展性、生产部署和成熟的生态系统,TensorFlow 可能是您的不二之选。</p><p>这两个框架都在不断发展,因此请密切关注它们的发展。你今天的选择可能不是你明天的选择。请记住,最好的工具是适合您项目需求的工具,而不是流行的工具。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>

详细介绍DOM 事件和 JavaScript 事件侦听器

<p>浏览器中的 JavaScript 代码使用事件驱动的编程模式。这意味着,当浏览器中发生特定的 DOM 事件时,将执行一段代码作为对该操作的响应。</p><p>在本文中,我将帮助您了解和理解如何使用 JavaScript 监听和响应 DOM 事件。</p><p>如果你需要复习一下 DOM,我写了一篇文章来解释 DOM 是什么以及 JavaScript 如何与之交互。</p><p>什么是 DOM 事件,为什么它们有用?</p><p>DOM 事件是浏览器公开的信号,可用于运行一段 JavaScript 代码。</p><p>当用户与我们创建的应用程序交互时,例如单击按钮或在输入字段中键入字母,就会发生这些 DOM 事件。</p><p>作为 Web 开发人员,您可以指示 JavaScript 侦听特定事件并执行一些操作来响应该事件。</p><p>例如:</p><p>单击按钮时,请更改段落的文本。</p><p>提交表单后,使用 Fetch API 执行 POST 请求。</p><p>在本文中,我将帮助您了解和理解如何使用 JavaScript 监听和响应 DOM 事件。</p><p>如何侦听 DOM 事件</p><p>若要侦听事件,需要使用该方法将事件侦听器附加到元素。addEventListener()</p><p>该方法接受两个参数:addEventListener()</p><p>要听的活动type</p><p>触发事件时要运行的函数</p><p>Element.addEventListener(type, function)<span style="color: #6a9955;">;</span></p><p>addEventListener() 方法语法</p><p>回到示例,假设您要在单击元素时更改段落的文本。这是你如何做到的:button</p><p>&lt;body&gt;</p><p>&nbsp; &lt;p <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">&quot;myParagraph&quot;</span>&gt;This is an example paragraph&lt;/p&gt;</p><p>&nbsp; &lt;button <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">&quot;changeText&quot;</span>&gt;Change Text&lt;/button&gt;</p><p>&nbsp; &lt;script&gt;</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">button</span> = document.querySelector(<span style="color: #ce9178;">&#39;#changeText&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; function newText(event) {</p><p>&nbsp; &nbsp; &nbsp; const <span style="color: #569cd6;">p</span> = document.querySelector(<span style="color: #ce9178;">&#39;#myParagraph&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; &nbsp; <span style="color: #569cd6;">p.innerText</span> = <span style="color: #ce9178;">&#39;The text has been changed&#39;</span><span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; }</p><p>&nbsp; &nbsp; button.addEventListener(<span style="color: #ce9178;">&#39;click&#39;</span>, newText)<span style="color: #6a9955;">; &nbsp;&lt;/script&gt;&lt;/body&gt;</span></p><p>使用 addEventListener() 方法的示例</p><p>要将 JavaScript 代码插入到 HTML 文档中,我们需要使用如上所示的标签。script</p><p>使用 method 选择按钮元素,然后在该元素上调用该方法。这意味着您将事件侦听器附加到按钮。document.querySelector()addEventListener()</p><p>首先,指定要侦听的事件,在本例中为事件。接下来,指定在发生该事件时要运行的函数。typeclick</p><p>在上面的代码中,函数将在事件被触发时执行。newTextclick</p><p>事件侦听器还将发送一个对象,该对象携带有关触发的事件的信息。这就是为什么上面的函数中有一个参数。eventeventnewText</p><p>您可以将事件记录到控制台以查看其详细信息:</p><p>function newText(event) {</p><p>&nbsp; console.log(event)<span style="color: #6a9955;">;}</span></p><p>记录事件对象</p><p>如果再次单击该按钮,将获得以下输出:</p><p>事件对象日志事件对象日志示例</p><p>根据触发事件时要执行的操作,可能需要使用对象中包含的信息。event</p><p>在这里,我们要做的就是更改段落的文本,因此不需要对象。稍后,我们将在处理键盘事件时看到使用该对象的示例。eventevent</p><p>您可以在浏览器中收听许多事件。以下是开发 Web 应用程序时可能需要的一些最常见的事件:</p><p>事件 &nbsp;事件被触发</p><p>点击 &nbsp;当您按下并松开鼠标主按钮时。用于跟踪按钮和可点击的电子设备</p><p>鼠标移动 &nbsp; &nbsp;移动鼠标光标时</p><p>鼠标悬停 &nbsp; &nbsp;当您将鼠标光标移到元素上时。这就像CSS悬停状态</p><p>鼠标输出 &nbsp; &nbsp;当鼠标光标移动到元素边界之外时</p><p>dblclick &nbsp; &nbsp;当您点击两次时</p><p>DOMContentLoaded &nbsp; &nbsp;当 DOM 内容完全加载时</p><p>键盘 &nbsp;当您按下键盘上的某个键时</p><p>键控 &nbsp;当您松开键盘上的某个键时</p><p>提交 &nbsp;提交表单时</p><p>如果您想阅读 DOM 事件类型的完整列表,可以访问此页面。</p><p>DOM 事件分为几类。在这里,我们将只看一下你可能在项目中使用的两个最常见的事件:键盘和鼠标事件。</p><p>键盘事件</p><p>对于键盘,您可以跟踪 和 事件,这些事件分别在您按下和释放键时运行。keydownkeyup</p><p>若要显示示例,请从控制台运行以下代码:</p><p>document.addEventListener(<span style="color: #ce9178;">&#39;keydown&#39;</span>, <span style="color: #569cd6;">event</span> =&gt; {</p><p>&nbsp; console.log(`A key is pressed: ${event.key}`)<span style="color: #6a9955;">;});document.addEventListener(&#39;keyup&#39;, event =&gt; {</span></p><p>&nbsp; console.log(`A key is released: ${event.key}`)<span style="color: #6a9955;">;});</span></p><p>捕获键盘事件</p><p>运行上述代码后,缓慢按下键盘上的一个键,然后缓慢松开。</p><p>您应看到如下所示的日志输出:</p><p>键盘事件日志记录键控和键控事件</p><p>请注意,只要您按下一个键,就会显示“keydown”日志,并且“keyup”日志仅在您松开该键时显示。</p><p>键盘事件通常附加到对象而不是特定元素,因为整个网站应该能够侦听该事件。document</p><p>鼠标事件</p><p>除了键盘事件之外,DOM 还提供了一种跟踪任何鼠标事件的方法。</p><p>您可以跟踪的最常见的鼠标事件是:</p><p>mousedown– 按下鼠标按钮</p><p>mouseup– 鼠标按钮被释放</p><p>click– 点击事件</p><p>dblclick– 双击事件</p><p>mousemove– 当鼠标移动到元素上时</p><p>contextmenu– 当上下文菜单打开时,例如单击鼠标右键</p><p>同样,您可以通过直接向对象添加事件侦听器来测试这些事件:document</p><p>document.addEventListener(<span style="color: #ce9178;">&#39;mousedown&#39;</span>, <span style="color: #569cd6;">event</span> =&gt; {</p><p>&nbsp; console.log(`The mouse is pressed`)<span style="color: #6a9955;">;});document.addEventListener(&#39;mouseup&#39;, event =&gt; {</span></p><p>&nbsp; console.log(`The mouse is released`)<span style="color: #6a9955;">;});</span></p><p>捕获鼠标事件</p><p>运行上面的代码,然后单击浏览器中的任意位置。您应该会看到分别记录的 和 事件。mousedownmouseup</p><p>如何删除事件侦听器</p><p>若要删除附加到元素的事件侦听器,需要调用该方法,将 of 事件和传递给该方法的 传递给该方法,如下所示:removeEventListener()typefunctionaddEventListener()</p><p>button.removeEventListener(<span style="color: #ce9178;">&#39;click&#39;</span>, newText)<span style="color: #6a9955;">;</span></p><p>删除事件侦听器的示例</p><p>上面的代码足以从元素中删除“click”事件侦听器。请注意,您需要如何在元素上调用方法,同时将函数传递给该方法。buttonremoveEventListener()newText</p><p>若要正确删除事件侦听器,需要具有对附加到事件的函数的引用。如果将无名函数传递给该方法,则无法删除该事件:addEventListener()</p><p>button.addEventListener(<span style="color: #ce9178;">&#39;click&#39;</span>, function (event) {</p><p>&nbsp; alert(<span style="color: #ce9178;">&#39;Button save is clicked&#39;</span>)<span style="color: #6a9955;">;});</span></p><p>无法删除无名称函数</p><p>如果没有上述示例中的函数名称,您将无法删除事件侦听器。</p><p>如何使用 HTML 属性侦听事件</p><p>除了使用该方法之外,您还可以通过将属性添加到 HTML 元素来侦听事件。addEventListener()on[eventname]</p><p>例如,假设您要收听按钮单击。您可以按如下方式将属性添加到按钮:onclick</p><p>&lt;body&gt;</p><p>&nbsp; &lt;button <span style="color: #569cd6;">onclick</span>=<span style="color: #ce9178;">&quot;handleClick()&quot;</span>&gt;Click Me!&lt;/button&gt;</p><p>&nbsp; &lt;script&gt;</p><p>&nbsp; &nbsp; function handleClick(event) {</p><p>&nbsp; &nbsp; &nbsp; alert(<span style="color: #ce9178;">&#39;The button is clicked!&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; } &nbsp;&lt;/script&gt;&lt;/body&gt;</p><p>使用 onclick HTML 属性侦听 click 事件</p><p>在上面的 button 元素中,我们添加属性并将函数传递给它。onclickhandleClick()</p><p>当我们单击该按钮时,该功能将被执行。handleClick()</p><p>您还可以使用 JavaScript 添加属性,如下所示:onclick</p><p>&lt;body&gt;</p><p>&nbsp; &lt;button <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">&quot;myBtn&quot;</span>&gt;Click Me!&lt;/button&gt;</p><p>&nbsp; &lt;script&gt;</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">myBtn</span> = document.querySelector(<span style="color: #ce9178;">&#39;#myBtn&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; <span style="color: #569cd6;">myBtn.onclick</span> = handleClick<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; function handleClick(event) {</p><p>&nbsp; &nbsp; &nbsp; alert(<span style="color: #ce9178;">&#39;The button is clicked!&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; } &nbsp;&lt;/script&gt;&lt;/body&gt;</p><p>使用 onclick 属性的示例</p><p>在这里,我们使用 JavaScript 将对函数的引用分配给属性。handleClickonclick</p><p>若要删除 onclick 属性,可以将该属性分配给 null:</p><p>const <span style="color: #569cd6;">myBtn</span> = document.querySelector(<span style="color: #ce9178;">&#39;#myBtn&#39;</span>)<span style="color: #6a9955;">;myBtn.onclick = null;</span></p><p>将 onclick 属性分配给 null</p><p>你应该使用哪一个?</p><p>正如你所看到的,有两种方法可以监听 DOM 事件:方法和 HTML 属性。你应该使用哪一个?addEventListener()on[eventname]</p><p>答案是,当您需要更多扩展性时可以使用该方法,当您希望事情简单时可以使用该方法。addEventListener()on[eventname]</p><p>在开发 Web 应用程序时,文件应仅用作页面的结构,而文件应定义 Web 应用程序可以具有的任何行为。.html.js</p><p>为了使应用程序更易于维护和扩展,JavaScript 应该可以访问 HTML 元素,但任何 HTML 元素都不能执行 JavaScript 函数。这就是为什么应该是推荐的方法。addEventListener()</p><p>但这并非没有代价:你用冗长来交换可扩展性,使你的代码阅读起来非常麻烦。addEventListener()</p><p>使用该属性时,只需在 HTML 元素中指定函数名称:on[eventname]</p><p>&lt;body&gt;</p><p>&nbsp; &lt;button <span style="color: #569cd6;">onclick</span>=<span style="color: #ce9178;">&quot;handleClick()&quot;</span>&gt;Click Me!&lt;/button&gt;</p><p>&nbsp; &lt;script&gt;</p><p>&nbsp; &nbsp; function handleClick(event) {</p><p>&nbsp; &nbsp; &nbsp; alert(<span style="color: #ce9178;">&#39;The button is clicked!&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; } &nbsp;&lt;/script&gt;&lt;/body&gt;</p><p>onclick 属性提供了简单性</p><p>但是当你使用该方法时,你需要查询你需要的元素,调用该方法,然后指定要运行的事件和回调函数:addEventListener()</p><p>&lt;body&gt;</p><p>&nbsp; &lt;button <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">&quot;myBtn&quot;</span>&gt;Click Me!&lt;/button&gt;</p><p>&nbsp; &lt;script&gt;</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">myBtn</span> = document.querySelector(<span style="color: #ce9178;">&#39;#myBtn&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; myBtn.addEventListener(<span style="color: #ce9178;">&#39;click&#39;</span>, handleClick)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; function handleClick(event) {</p><p>&nbsp; &nbsp; &nbsp; alert(<span style="color: #ce9178;">&#39;The button is clicked!&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; } &nbsp;&lt;/script&gt;&lt;/body&gt;</p><p>addEventListener() 方法提供可扩展性</p><p>如上所述,使用该属性时,还有两行不需要编写。on[eventname]</p><p>虽然它可能看起来微不足道,但当您处理具有许多 HTML 和 JS 文件的大型应用程序时,这将是一个严重的问题。</p><p>此外,该方法还允许您将多个侦听器附加到同一元素,如下所示:addEventListener()</p><p>&lt;body&gt;</p><p>&nbsp; &lt;button <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">&quot;myBtn&quot;</span>&gt;Click Me!&lt;/button&gt;</p><p>&nbsp; &lt;script&gt;</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">myBtn</span> = document.querySelector(<span style="color: #ce9178;">&#39;#myBtn&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; myBtn.addEventListener(<span style="color: #ce9178;">&#39;click&#39;</span>, handleClick)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; myBtn.addEventListener(<span style="color: #ce9178;">&#39;click&#39;</span>, handleClickTwo)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; function handleClick() {</p><p>&nbsp; &nbsp; &nbsp; console.log(<span style="color: #ce9178;">&#39;Run from handleClick function&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; }</p><p>&nbsp; &nbsp; function handleClickTwo() {</p><p>&nbsp; &nbsp; &nbsp; console.log(<span style="color: #ce9178;">&#39;Run from handleClickTwo function&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; } &nbsp;&lt;/script&gt;&lt;/body&gt;</p><p>addEventListener() 允许您分配多个侦听器</p><p>当您单击上面的按钮时,JavaScript 将执行两个事件侦听器。</p><p>对于该属性,这是不可能的,因为一次只能将一个函数指定为引用:onclick</p><p>&lt;body&gt;</p><p>&nbsp; &lt;button <span style="color: #569cd6;">id</span>=<span style="color: #ce9178;">&quot;myBtn&quot;</span>&gt;Click Me!&lt;/button&gt;</p><p>&nbsp; &lt;script&gt;</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">myBtn</span> = document.querySelector(<span style="color: #ce9178;">&#39;#myBtn&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; <span style="color: #569cd6;">myBtn.onclick</span> = handleClick<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; // when you assign a new function to onclick,</p><p>&nbsp; &nbsp; // the old function is overwritten</p><p>&nbsp; &nbsp; <span style="color: #569cd6;">myBtn.onclick</span> = handleClickTwo<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; function handleClick() {</p><p>&nbsp; &nbsp; &nbsp; console.log(<span style="color: #ce9178;">&#39;Run from handleClick function&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; }</p><p>&nbsp; &nbsp; function handleClickTwo() {</p><p>&nbsp; &nbsp; &nbsp; console.log(<span style="color: #ce9178;">&#39;Run from handleClickTwo function&#39;</span>)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; } &nbsp;&lt;/script&gt;&lt;/body&gt;</p><p>但是我从来没有遇到过需要两次收听同一事件的情况,所以这个优势可能根本没有用。</p><p>结论</p><p>浏览器公开的 DOM 事件使您能够以适当的方式响应用户操作。</p><p>这种使用事件侦听器执行特定任务的模式称为事件驱动编程,在使用 JavaScript 开发 Web 应用程序时,您将经常使用此模式。</p><p>有两种方法可以侦听事件:使用 JavaScript 方法和 HTML 属性。每种方法都有其优点和缺点,因此最好同时熟悉两者。addEventListener()on[eventname]</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>

Web Storage API – 如何在浏览器上存储数据

<p>Web 存储 API 是一组由浏览器公开的 API,以便您可以在浏览器中存储数据。</p><p>存储在 Web 存储中的数据使用键/值对格式,并且这两个数据都将存储为字符串。</p><p>Web 存储 API 中引入了两种类型的存储:本地存储和会话存储。</p><p>在本文中,我将向您展示如何使用 Web 存储 API,以及为什么它对 Web 开发人员有用。</p><p>Web 存储 API 的工作原理</p><p>Web 存储 API 公开了一组对象和方法,可用于在浏览器中存储数据。您存储在 Web 存储中的数据是私有的,这意味着其他网站无法访问它。</p><p>在 Google Chrome 中,您可以通过打开开发人员工具窗口并转到“应用程序”选项卡来查看 Web 存储,如下所示:</p><p>web-storage-location-1Google Chrome 中的 Web 存储位置</p><p>在上图中,您可以看到“存储”菜单还具有其他存储类型,例如索引数据库、Web SQL 和 cookie。Web SQL 标准已被弃用,并且 IndexedDB 很少使用,因为它太复杂了。存储在 IndexedDB 中的任何数据最好存储在服务器上。</p><p>至于 cookie,它是一种更传统的数据存储机制,最多只能存储 4 KB 的数据。相比之下,本地存储容量为 10 MB,会话存储容量为 5 MB。</p><p>这就是为什么我们在本文中只关注本地存储和会话存储的原因。</p><p>本地存储和会话存储说明</p><p>本地存储和会话存储是 Web 存储 API 支持的两种标准机制。</p><p>Web 存储是特定于域的,这意味着存储在一个域 (netflix.com) 下的数据不能被另一个域(www.netflix.com 或 members.netflix.com)访问</p><p>Web 存储也是特定于协议的。这意味着您存储在站点中的数据将无法在站点下使用。http://https://</p><p>本地存储和会话存储之间的主要区别在于本地存储将永久存储您的数据。如果要删除数据,则需要使用可用方法或从“应用程序”选项卡中手动清除数据。</p><p>相比之下,存储在会话存储中的数据仅在页面会话期间可用。当您关闭浏览器或选项卡时,将删除该特定选项卡的会话存储。</p><p>Local 和 Session Storage 都可以分别通过变量 和 下的对象进行访问。接下来,让我们看看这些存储类型的方法和属性。windowlocalStoragesesionStorage</p><p>本地存储和会话存储的方法和属性</p><p>本地存储和会话存储具有相同的方法和属性。若要在本地存储中设置新的键/值对,可以使用对象的方法:setItem()localStorage</p><p>localStorage.setItem(<span style="color: #ce9178;">&#39;firstName&#39;</span>, <span style="color: #ce9178;">&#39;Nathan&#39;</span>)<span style="color: #6a9955;">;</span></p><p>调用 setItem() 方法</p><p>如果您在浏览器中查看“本地存储”菜单,您应该会看到上述数据保存到存储中,如下所示:</p><p>本地存储集项目在本地存储中存储键/值对</p><p>您使用的密钥必须是唯一的。如果使用已存在的键设置另一个数据,则该方法会将以前的值替换为新值。localStoragesetItem()</p><p>若要从本地存储中获取值,需要调用该方法并传递保存数据时使用的密钥。如果密钥不存在,则将返回:getItem()getItem()null</p><p>const <span style="color: #569cd6;">firstName</span> = localStorage.getItem(<span style="color: #ce9178;">&#39;firstName&#39;</span>)<span style="color: #6a9955;">;console.log(firstName); // Nathanconst lastName = localStorage.getItem(&#39;lastName&#39;);console.log(lastName); // null</span></p><p>调用 getItem() 方法</p><p>若要删除本地存储中的数据,请调用该方法并传递指向要删除的数据的密钥:removeItem()</p><p>localStorage.removeItem(<span style="color: #ce9178;">&#39;firstName&#39;</span>)<span style="color: #6a9955;">;</span></p><p>调用 removeItem() 方法</p><p>该方法将始终返回 。当要删除的数据不存在时,该方法将不执行任何操作。removeItem()undefined</p><p>如果要清除存储,可以使用以下方法:clear()</p><p>localStorage.clear()<span style="color: #6a9955;">;</span></p><p>清除本地存储</p><p>该方法从您正在访问的存储对象中删除所有键/值对。clear()</p><p>本地存储和会话存储的属性</p><p>这两种存储类型都只有一个属性,即显示其中存储的数据量的属性。length</p><p>sessionStorage.setItem(<span style="color: #ce9178;">&#39;firstName&#39;</span>, <span style="color: #ce9178;">&#39;Nathan&#39;</span>)<span style="color: #6a9955;">;sessionStorage.setItem(&#39;lastName&#39;, &#39;Sebhastian&#39;);console.log(sessionStorage.length); // 2sessionStorage.clear();console.log(sessionStorage.length); // 0</span></p><p>访问会话存储的 length 属性</p><p>这就是您可以在 和 中访问的所有方法和属性。localStoragesessionStorage</p><p>如何在 Web 存储存储中存储 JSON 字符串</p><p>由于 Web 存储始终将数据存储为字符串,因此您可以将复杂数据存储为 JSON 字符串,然后在访问该字符串时将该字符串转换回对象。</p><p>例如,假设我想存储有关用户的以下信息:</p><p>const <span style="color: #569cd6;">user</span> = {</p><p>&nbsp; firstName: <span style="color: #ce9178;">&#39;Nathan&#39;</span>,</p><p>&nbsp; lastName: <span style="color: #ce9178;">&#39;Sebhastian&#39;</span>,</p><p>&nbsp; url: <span style="color: #ce9178;">&#39;https://codewithnathan.com&#39;</span>,}<span style="color: #6a9955;">;</span></p><p>对象数据示例</p><p>首先,我可能会将数据存储为一系列键/值对,如下所示:</p><p>localStorage.setItem(<span style="color: #ce9178;">&#39;firstName&#39;</span>, user.firstName)<span style="color: #6a9955;">;localStorage.setItem(&#39;lastName&#39;, user.lastName);localStorage.setItem(&#39;url&#39;, user.url);</span></p><p>将对象放入本地存储</p><p>但更好的方法是将 JavaScript 对象转换为 JSON 字符串,然后将数据存储在一个键下,如下所示:</p><p>const <span style="color: #569cd6;">user</span> = {</p><p>&nbsp; firstName: <span style="color: #ce9178;">&#39;Nathan&#39;</span>,</p><p>&nbsp; lastName: <span style="color: #ce9178;">&#39;Sebhastian&#39;</span>,</p><p>&nbsp; url: <span style="color: #ce9178;">&#39;https://codewithnathan.com&#39;</span>,}<span style="color: #6a9955;">;const userData = JSON.stringify(user);localStorage.setItem(&#39;user&#39;, userData);</span></p><p>使用 JSON.stringify() 将对象转换为 JSON 字符串</p><p>现在,本地存储将只有一个键/值对,其值为 JSON字符串。您可以打开“应用程序”选项卡来查看以下内容:</p><p>存储为JSON将 JSON 字符串存储在本地存储中</p><p>需要数据时,按如下方式调用 and 方法:getItem()JSON.parse()</p><p>const <span style="color: #569cd6;">getUser</span> = JSON.parse(localStorage.getItem(<span style="color: #ce9178;">&#39;user&#39;</span>))<span style="color: #6a9955;">;console.log(getUser);// {firstName: &#39;Nathan&#39;, lastName: &#39;Sebhastian&#39;, url: &#39;https://codewithnathan.com&#39;}</span></p><p>检索和解析作为对象的 JSON 字符串</p><p>在这里,您可以看到数据作为常规 JavaScript 对象返回。</p><p>本地存储与会话存储 – 使用哪一个?</p><p>根据我的经验,是首选的 Web 存储机制,因为只要您需要,数据就会持续存在。当您不需要数据时,可以使用该方法将其删除。localStorageremoveItem()</p><p>sessionStorage仅当需要存储临时数据时才使用,例如跟踪是否已向用户显示弹出框。</p><p>但这也有待讨论,因为您可能不希望在用户每次登录 Web 应用程序时都显示弹出窗口,而只显示一次。在这种情况下,您应该改用。localStorage</p><p>我的经验法则是先使用,并在情况需要时使用。localStoragesessionStorage</p><p>使用 Web 存储 API 的好处</p><p>现在您已经了解了 Web 存储 API 的工作原理,您可以看到它有一些好处:</p><p>将数据存储在浏览器上可以减少向服务器请求一条信息的需要。这可以提高 Web 应用程序的性能。</p><p>简单的键/值对格式允许您存储用户首选项和本地设置,这些设置应在会话之间保留。</p><p>Web 存储 API 使用简单,仅提供几个方法和一个属性。使用 JavaScript 设置和检索数据非常简单</p><p>它有离线支持。通过在本地存储必要的数据,Web 存储使您的 Web 应用程序能够脱机工作。</p><p>Web 存储也是一个标准化的 API,这意味着您编写的代码可以在许多不同的浏览器中工作。</p><p>但是,当然,并非所有数据都应存储在 Web 存储 API 中。您仍然需要一个服务器数据库来保存对应用程序很重要的记录。</p><p>结论</p><p>Web Storage 是一个有用的 API,可让您从浏览器快速存储和检索数据。使用 Web 存储,您可以在访问应用程序时存储用户的首选项。</p><p>localStorage允许您永久存储数据,直到手动删除数据,而只要浏览器或选项卡打开,它就会一直存在。sessionStorage</p><p>使用 Web 存储 API 的一些好处包括减少服务器请求、离线支持和易于使用的简单 API。它也是标准化的,因此它可以在不同的浏览器上运行。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>

如何在 JavaScript 中使用回调函数callback和高阶函数

<p>JavaScript 中处理和使用函数的方式非常有趣。它们非常灵活——我们可以将函数作为值分配给变量,将它们作为值从另一个函数返回,并将它们作为参数传递给另一个函数。我们可以做到这一切,因为 JavaScript 将函数视为一等公民。</p><p>在本文中,我将介绍什么是高阶函数和回调,以及它们在 JavaScript 中是如何工作的。</p><p>在 JavaScript 中充当一等公民</p><p>函数在 JavaScript 中被定义为一等公民或一等对象,因为函数被视为变量。</p><p>这意味着 JavaScript 中的函数可以是:</p><p>作为参数传递给另一个函数。</p><p>作为值分配给变量。</p><p>作为函数的值返回。</p><p>了解函数在 JavaScript 中的处理方式至关重要,因为它们是理解 JavaScript 中高阶函数和回调函数以及它们如何工作的构建块。</p><p>什么是高阶函数?</p><p>高阶函数是将函数作为参数并返回函数作为值的函数。</p><p>JavaScript 中提供了许多内置的高阶函数。我们将看一些,并利用如何将函数视为一等公民。我们还将创建自己的高阶函数。</p><p>首先,让我们看一些内置高阶函数的例子。</p><p>数组方法</p><p>数组方法通常是开发人员在学习 JavaScript 时首次引入的高阶函数。这些方法包括但不限于 JavaScript 提供的 、 、 、 和 数组方法。</p><p>这些数组方法或函数有很多共同点,但最常见的特征之一是它们都接受函数作为参数。下面是一个代码片段,演示了数组方法的工作原理:mapfilterforEachfindfindIndexsomeeveryforEach</p><p>const <span style="color: #569cd6;">people</span> = [</p><p>&nbsp; { firstName: <span style="color: #ce9178;">&quot;Jack&quot;</span>, year: 1988 },</p><p>&nbsp; { name: <span style="color: #ce9178;">&quot;Kait&quot;</span>, year: 1986 },</p><p>&nbsp; { name: <span style="color: #ce9178;">&quot;Irv&quot;</span>, year: 1970 },</p><p>&nbsp; { name: <span style="color: #ce9178;">&quot;Lux&quot;</span>, year: 2015 },]<span style="color: #6a9955;">;people.forEach(function (person) {</span></p><p>&nbsp; console.log(person)<span style="color: #6a9955;">;});// Output: &nbsp;Logs every person object in the array</span></p><p>从上面的代码示例中,我们可以看到该方法接受一个函数作为参数,它在数组上的每次迭代中调用该函数。因此,数组方法是一个高阶函数。forEachforEach</p><p>计时器事件</p><p>另一组常用的内置高阶函数是 and 函数,在 JavaScript 中称为计时器事件。setIntervalsetTimeout</p><p>每个函数都接受一个函数作为其参数之一,并使用它来创建时标事件。</p><p>看看下面的代码示例,看看它是如何工作的:setTimeout</p><p>setTimeout(function () {</p><p>&nbsp; console.log(<span style="color: #ce9178;">&quot;This is a higher order function&quot;</span>)<span style="color: #6a9955;">;}, 1000);// Output: &quot;This is a higher order function&quot; after 1000ms / 1 second</span></p><p>上面的代码片段是函数工作原理的最基本示例。它接受函数和持续时间(以毫秒为单位),并在提供的持续时间过后执行该函数。setTimeout</p><p>从上面的示例中,在 1000 毫秒或一秒后打印到控制台。This is a higher order function</p><p>setInterval(function () {</p><p>&nbsp; console.log(<span style="color: #ce9178;">&quot;This is a higher order function&quot;</span>)<span style="color: #6a9955;">;}, 1000);// Output: &quot;This is a higher order function&quot; after every 1000ms / 1 second</span></p><p>该函数类似于函数,就像数组方法一样——尽管它的功能不同。但是我们可以看到一个共同的模式:它也接受一个函数作为它的参数之一。setIntervalsetTimeout</p><p>与(在提供的持续时间过后执行函数)不同,每 1000 毫秒或 1 秒一遍又一遍地执行函数。setTimeoutsetInterval</p><p>如何创建和使用高阶函数</p><p>高阶函数不限于 JavaScript 提供的内置函数。</p><p>由于 JavaScript 中的函数被视为第一类对象,因此我们可以利用这种行为并构建高性能和可重用的函数。</p><p>在下面的示例中,我们将构建几个函数。他们将接受客户的姓名和问候语,然后将该信息打印到控制台。</p><p>首先,这里有一个简单的函数可以同时执行这两件事:</p><p>function greetCustomer(firstName, lastName, salutation) {</p><p>&nbsp; const <span style="color: #569cd6;">fullName</span> = `${firstName} ${lastName}`<span style="color: #6a9955;">;</span></p><p>&nbsp; console.log(`${salutation} ${fullName}`)<span style="color: #6a9955;">;}greetCustomer(&quot;Franklin&quot;, &quot;Okolie&quot;, &quot;Good Day&quot;);// Output: &quot;Good Day Franklin Okolie&quot;</span></p><p>greetCustomer接受 3 个参数:名字、姓氏和称呼。然后,它将对客户的问候语打印到控制台。</p><p>但是这个功能有一个问题——它做两件事:撰写客户的全名和打印问候语。</p><p>这不是最佳实践,因为函数应该只做一件事并把它做好。因此,我们将重构我们的代码。</p><p>另一个函数应包含客户的姓名,以便该函数只需将问候语打印到控制台。因此,让我们编写一个函数来处理这个问题:greetCustomer</p><p>function composeName(firstName, lastName) {</p><p>&nbsp; const <span style="color: #569cd6;">fullName</span> = `${firstName} ${lastName}`<span style="color: #6a9955;">;</span></p><p>&nbsp; return fullName<span style="color: #6a9955;">;}</span></p><p>现在我们有一个结合了客户名字和姓氏的函数,我们可以在以下位置使用该函数:greetCustomer</p><p>function greetCustomer(composerFunc, firstName, lastName, salutation) {</p><p>&nbsp; const <span style="color: #569cd6;">fullName</span> = composerFunc(firstName, lastName)<span style="color: #6a9955;">;</span></p><p>&nbsp; console.log(`${salutation} ${fullName}`)<span style="color: #6a9955;">;}greetCustomer(composeName, &quot;Franklin&quot;, &quot;Okolie&quot;, &quot;Good Day&quot;);// Output: &quot;Good Day Franklin Okolie&quot;</span></p><p>现在这看起来更干净了,每个函数只做一件事。该函数现在接受 4 个参数,并且由于其中一个参数是函数,因此它现在是一个高阶函数。greetCustomer</p><p>您之前可能想知道,一个函数是如何在另一个函数内部调用的,为什么?</p><p>现在,我们将深入探讨函数调用并回答这两个问题。</p><p>将函数作为值返回</p><p>请记住,高阶函数要么将函数作为参数,要么将函数作为值返回。</p><p>让我们重构函数以使用更少的参数并返回一个函数:greetCustomer</p><p>function getGreetingsDetails(composerFunc, salutation) {</p><p>&nbsp; return function greetCustomer(firstName, lastName) {</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">fullName</span> = composerFunc(firstName, lastName)<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; console.log(`${salutation} ${fullName}`)<span style="color: #6a9955;">;</span></p><p>&nbsp; }<span style="color: #6a9955;">;</span></p><p>最后一个版本接受了太多的论点。四个论点并不多,但如果你搞砸了论点的顺序,仍然会令人沮丧。一般来说,你的论点越少越好。greetCustomer</p><p>因此,在上面的示例中,我们有一个名为 Function 的函数,它接受并代表内部函数。然后,它返回内部函数,该函数本身接受 和 作为参数。getGreetingDetailscomposerFuncsalutationgreetCustomergreetCustomerfirstNamelastName</p><p>通过这样做,总体上有更少的论点。greetCustomer</p><p>有了这个,让我们来看看如何使用该函数:getGreetingDetails</p><p>const <span style="color: #569cd6;">greet</span> = getGreetingsDetails(composeName, <span style="color: #ce9178;">&quot;Happy New Year!&quot;</span>)<span style="color: #6a9955;">;greet(&quot;Quincy&quot;, &quot;Larson&quot;);// Output: &quot;Happy New Year Quincy Larson&quot;</span></p><p>现在退后一步,欣赏这个美丽的抽象。奇妙!我们利用高阶函数的魔力来简化函数。greetCustomer</p><p>让我们来看看一切是如何工作的。名为 Named 的高阶函数包含两个参数:一个用于组成客户名字和姓氏的函数,以及一个称呼。然后,它返回一个名为的函数,该函数接受客户的名字和姓氏作为参数。getGreetingDetailsgreetCustomer</p><p>返回的函数也使用接受的参数来执行某些操作。greetCustomergetGreetingDetails</p><p>在这一点上,您可能想知道,返回的函数如何使用提供给父函数的参数?特别是考虑到函数执行上下文的工作方式。这是可能的,因为关闭。现在让我们更多地了解它们。</p><p>闭合解释</p><p>闭包是一个函数,它有权访问创建它的范围内的变量,即使该范围在执行上下文中不再存在。这是回调的基本机制之一,因为在外部函数关闭后,回调仍然可以引用和使用在外部函数中创建的变量。</p><p>让我们举一个简单的例子:</p><p>function getTwoNumbers(num1, num2) {</p><p>&nbsp; return function add() {</p><p>&nbsp; &nbsp; const <span style="color: #569cd6;">total</span> = num1 + num2<span style="color: #6a9955;">;</span></p><p>&nbsp; &nbsp; console.log(total)<span style="color: #6a9955;">;</span></p><p>&nbsp; }<span style="color: #6a9955;">;}const addNumbers = getTwoNumbers(5, 2);addNumbers();//Output: 7;</span></p><p>此示例中的代码定义了一个名为的函数,并演示了闭包的工作原理。让我们更详细地探讨一下:getTwoNumbers</p><p>getTwoNumbers定义为采用两个参数的函数,并且 .num1num2</p><p>在里面,它返回另一个函数,这是一个名为 的内部函数。getTwoNumbersadd</p><p>调用该函数时,会计算 和 的总和,并将结果记录到控制台。addnum1num2</p><p>在函数之外,我们创建一个变量,调用它,并为其分配调用的结果。这有效地设置了一个闭包,现在“记住”值和 as 和 .getTwoNumbersaddNumbersgetTwoNumbers(5, 2)addNumbers52num1num2</p><p>最后,我们调用执行内部函数。由于是闭包,因此它仍然可以访问分别设置为 和 的值。它计算它们的总和并记录到控制台。addNumbers()addaddNumbersnum1num2527</p><p>如果您想了解有关关闭的更多信息,请在此处阅读更多内容。</p><p>回到我们的高阶函数。返回的函数作为值返回,我们将其存储在名为 的变量中。greetCustomergreet</p><p>这样做会使变量本身成为一个函数,这意味着我们可以将其作为函数调用并传入名字和姓氏的参数。greet</p><p>还有 violà 你有它。这些概念一开始可能有点复杂,但一旦你掌握了它们的窍门,它们就永远不会离开你。</p><p>我鼓励您再次通读前面的部分,在编辑器中播放代码,并掌握所有内容如何协同工作的窍门。</p><p>现在您已经深入了解了高阶函数的工作原理,让我们来谈谈回调函数。</p><p>什么是回调函数?</p><p>回调函数是作为参数传递到另一个函数的函数。</p><p>同样,作为一等公民的函数的决定性因素之一是它能够作为参数传递给另一个函数。这称为传递回调的行为。</p><p>让我们回过头来看看我们之前在学习 JavaScript 中提供的内置函数时讨论的计时事件。这又是函数:setTimeout</p><p>setTimeout(function () {</p><p>&nbsp; console.log(<span style="color: #ce9178;">&quot;This is a higher order function&quot;</span>)<span style="color: #6a9955;">;}, 1000);// Output: &quot;This is a higher order function&quot; after 1000ms / 1 seconds</span></p><p>我们已经确定该函数是一个高阶函数,因为它接受另一个函数作为参数。setTimeout</p><p>作为参数传递给函数的函数称为回调函数。这是因为它是在它传入的高阶函数中调用或执行的。setTimeout</p><p>为了更好地理解回调函数,让我们再看一下前面的函数:greetCustomer</p><p>// THIS IS A CALLBACK FUNCTION// IT IS PASSED AS AN ARGUMENT TO A FUNCTIONfunction composeName(firstName, lastName) {</p><p>&nbsp; const <span style="color: #569cd6;">fullName</span> = `${firstName} ${lastName}`<span style="color: #6a9955;">;</span></p><p>&nbsp; return fullName<span style="color: #6a9955;">;}// THIS IS A HIGHER ORDER FUNCTION// IT ACCPEPTS A FUNCTION AS A ARGUMENTfunction greetCustomer(composerFunc, firstName, lastName, salutation) {</span></p><p>&nbsp; const <span style="color: #569cd6;">fullName</span> = composerFunc(firstName, lastName)<span style="color: #6a9955;">;</span></p><p>&nbsp; console.log(`${salutation} ${fullName}`)<span style="color: #6a9955;">;}greetCustomer(composeName, &quot;Franklin&quot;, &quot;Okolie&quot;, &quot;Good Day&quot;);// Output: &quot;Good Day Franklin Okolie&quot;</span></p><p>是一个回调函数,它作为参数传递到函数中,这是一个高阶函数,并在此函数中执行。composeNamegreetCustomer</p><p>高阶函数和回调函数的区别</p><p>重要的是要了解这两个术语之间的区别,这样我们才能在技术面试中与队友进行更清晰的沟通:</p><p>高阶函数:接受函数作为参数和/或返回函数作为其值的函数。</p><p>回调函数:作为参数传递给另一个函数的函数。</p><p>一个包和一本书</p><p>为了进一步理解这些术语,我将分享一个简单的类比。</p><p>想象一下,你有一个包和一本书。你在参加聚会、上课、去教堂等时把书放在包里。</p><p>在这种情况下,袋子会接受您的书来携带它,并在您想使用它时将其归还。所以袋子就像一个高阶函数。</p><p>这本书一直放在袋子里,直到它准备好使用,所以它就像一个回调函数。</p><p>燃油和油箱</p><p>让我们看另一个类比<span style="color: #6a9955;">;燃料和油箱。</span></p><p>为了给汽车加油,我们必须将燃料倒入油箱,油箱接收燃料——就像高阶函数一样。</p><p>燃油被倒入油箱 - 就像一个回调函数。</p><p>我希望这些类比有助于进一步简化高阶函数和回调函数以及它们之间的区别。</p><p>结论</p><p>正如你所看到的,JavaScript中的函数非常灵活,可以以很多有用的方式使用。这种灵活性也导致了 JavaScript 中两个常见的技术术语,高阶函数和回调函数。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>

一文读懂javascript中的箭头函数与普通函数的区别及用法

<p>在 JavaScript 中,有两种主要的函数编写方式。您可以使用常规函数语法创建函数。或者,您可以使用箭头函数语法。</p><p>在本文中,您将学习如何使用这两个选项。您还将了解两者之间的区别以及何时适合使用它们。</p><p>要了解这两个选项之间的区别,让我们从查看它们的语法开始。</p><p>常规函数语法</p><p>在 JavaScript 中声明函数的常用方法是使用关键字。下面是一个示例:function</p><p>function sayHello(name) {</p><p>&nbsp; return <span style="color: #ce9178;">&#39;Hello &#39;</span> + name}</p><p>若要从常规函数返回值,必须显式使用关键字。否则,该函数将返回 .returnundefined</p><p>箭头函数语法</p><p>箭头函数是在 ECMAScript 6 (ES6) 中引入的。它们为您提供了一种在 JavaScript 中定义函数的更简洁的方法。</p><p>使用上一个示例中的相同函数,让我们看看如何使用箭头函数语法创建它。sayHello</p><p>const <span style="color: #569cd6;">sayHello</span> = (name) =&gt; {</p><p>&nbsp; return <span style="color: #ce9178;">&#39;Hello &#39;</span> + name}</p><p>与常规函数不同,如果只有一个语句,如上面的例子,则不必使用显式返回。您可以像这样将函数写在一行上。</p><p>const <span style="color: #569cd6;">sayHello</span> = (name) =&gt; <span style="color: #ce9178;">&#39;Hello &#39;</span> + name</p><p>请注意,大括号也会被移除,以隐式返回表达式的结果。如果只有一个参数,您甚至可以删除括号。请参阅以下示例:</p><p>const <span style="color: #569cd6;">sayHello</span> = <span style="color: #569cd6;">name</span> =&gt; <span style="color: #ce9178;">&#39;Hello &#39;</span> + name</p><p>是函数采用的唯一参数。这意味着您可以从参数中删除括号,它仍然可以正常工作。name</p><p>如何访问传递给函数的参数</p><p>JavaScript 提供了一种访问传递给函数的所有参数的方法。但是,你处理这些参数的方式取决于你正在使用的函数类型。</p><p>如何使用常规函数访问参数</p><p>您可以使用该对象访问传递给常规函数的所有参数。该对象是一个类似数组的对象,它保存传递给函数的所有参数。argumentsarguments</p><p>例:</p><p>function logNumbers(num1, num2) {</p><p>&nbsp; console.log(arguments)}logNumbers(8, 24)</p><p>屏幕截图-2024-01-11-at-5.01.51-PMarguments 对象的日志结果</p><p>从日志结果中可以看出,该对象包含作为参数传递给函数的两个数字。argumentslogNumbers</p><p>如何使用箭头函数访问参数</p><p>该对象在箭头函数中不可用。如果您尝试在箭头函数中访问它,JavaScript 将抛出引用错误。arguments</p><p>const <span style="color: #569cd6;">logNumbers</span> = (num1, num2) =&gt; {</p><p>&nbsp; console.log(arguments)}logNumbers(8, 24) // Uncaught ReferenceError: arguments is not defined</p><p>若要访问传递给箭头函数的参数,可以使用 rest 参数语法 ()。...</p><p>例:</p><p>const <span style="color: #569cd6;">logNumbers</span> = (...args) =&gt; {</p><p>&nbsp; console.log(args)}logNumbers(8, 24)</p><p>屏幕截图-2024-01-11-at-11.13.39-PM记录箭头函数参数的结果</p><p>使用 rest 参数语法 (),您可以访问传递给函数的所有参数。...logNumbers</p><p>重复的命名参数</p><p>常规函数和箭头函数之间的另一个区别是它们如何处理命名参数中的重复项。</p><p>常规函数中的重复命名参数</p><p>当常规函数的参数中具有重复的名称时,具有重复名称的最后一个参数将优先。让我们看一个例子:</p><p>function exampleFunction(a, b, a) {</p><p>&nbsp; console.log(a, b)}exampleFunction(<span style="color: #ce9178;">&quot;first&quot;</span>, <span style="color: #ce9178;">&quot;second&quot;</span>, <span style="color: #ce9178;">&quot;third&quot;</span>)</p><p>屏幕截图-2024-01-12-at-9.50.00-AM记录命名重复参数的结果</p><p>在上面的示例中,参数会覆盖参数的值,因为最后一个重复参数是优先的参数。thirdfirst</p><p>但在“严格模式”下,使用重复的命名参数将导致语法错误。</p><p><span style="color: #ce9178;">&quot;use strict&quot;</span>function exampleFunction(a, b, a) {</p><p>&nbsp; console.log(a, b)}exampleFunction(<span style="color: #ce9178;">&quot;first&quot;</span>, <span style="color: #ce9178;">&quot;second&quot;</span>, <span style="color: #ce9178;">&quot;third&quot;</span>)</p><p>屏幕截图-2024-01-12-at-10.29.11-AM严格模式不允许多次使用参数名称</p><p>箭头函数中的命名参数重复</p><p>箭头函数不允许在参数列表中多次使用相同的参数名称。这样做将导致语法错误。</p><p>例:</p><p>const <span style="color: #569cd6;">exampleFunction</span> = (a, b, a) =&gt; {</p><p>&nbsp; console.log(a, b)}exampleFunction(<span style="color: #ce9178;">&quot;first&quot;</span>, <span style="color: #ce9178;">&quot;second&quot;</span>, <span style="color: #ce9178;">&quot;third&quot;</span>)</p><p>屏幕截图-2024-01-12-at-10.29.11-AM-1箭头函数不允许重复的参数名称</p><p>功能吊装</p><p>在 JavaScript 中,提升是一种行为,在编译期间,在执行代码之前,变量和函数被移动到其包含范围的顶部。</p><p>在常规函数中托管</p><p>常规功能被吊到顶部。您甚至可以在它们被声明之前访问和调用它们。</p><p>regularFunction()function regularFunction() {</p><p>&nbsp; console.log(<span style="color: #ce9178;">&quot;This is a regular function.&quot;</span>)}</p><p>屏幕截图-2024-01-12-at-11.50.43-AM在声明常规函数之前记录调用常规函数的结果</p><p>以上是在声明常规函数之前调用该函数的示例。而且它工作正常,不会因为功能提升而抛出任何错误。</p><p>在箭头功能中提升</p><p>另一方面,箭头函数在初始化之前无法访问。</p><p>arrowFunction()const <span style="color: #569cd6;">arrowFunction</span> = () =&gt; {</p><p>&nbsp; console.log(<span style="color: #ce9178;">&quot;This is an arrow function.&quot;</span>)}</p><p>屏幕截图-2024-01-12-at-12.07.39-PM在声明箭头函数之前记录调用该函数的结果</p><p>与常规函数不同,尝试在声明箭头函数之前调用箭头函数将导致引用错误,如上面的输出所示。</p><p>如何处理函数中的绑定this</p><p>常规函数有自己的上下文。这是根据您调用或执行函数的方式动态确定的。this</p><p>另一方面,箭头函数没有自己的此上下文。相反,它们从创建箭头函数的周围词法上下文中捕获值。this</p><p>以下是使用常规函数和箭头函数的两种不同方案。您将看到上下文是如何确定的。this</p><p>1. 在简单函数调用期间设置值this</p><p>对于常规函数,一个简单的函数调用将值设置为对象(如果使用“严格模式”,则设置为):thiswindowundefined</p><p>function myRegularFunction() {</p><p>&nbsp; console.log(this)}</p><p>&nbsp; &nbsp; myRegularFunction()</p><p>屏幕截图-2024-01-12-at-4.15.11-PM对窗口对象的常规函数集的简单调用this</p><p><span style="color: #ce9178;">&quot;use strict&quot;</span>function myFunction() {</p><p>&nbsp; console.log(this)}</p><p>&nbsp; &nbsp; myFunction() // udefined</p><p>使用箭头函数时,无论您是否使用严格模式,简单的函数调用都会将值设置为周围的上下文。在下面的示例中,周围的上下文是全局窗口对象。this</p><p>const <span style="color: #569cd6;">myArrowFunction</span> = () =&gt; {</p><p>&nbsp; console.log(this)<span style="color: #6a9955;">;};myArrowFunction()</span></p><p>屏幕截图-2024-01-12-at-4.15.11-PM-1对窗口对象的箭头函数集的简单调用this</p><p>2. 在对象上调用或调用方法时</p><p>调用值为正则函数的方法时,该值将设置为调用该方法的对象。但是,当方法的值是箭头函数时,该值将设置为全局窗口对象。thisthis</p><p>const <span style="color: #569cd6;">myObject</span> = {</p><p>&nbsp; regularExample: function() {</p><p>&nbsp; &nbsp; console.log(<span style="color: #ce9178;">&quot;REGULAR: &quot;</span>, this)</p><p>&nbsp; },</p><p>&nbsp; arrowExample: () =&gt; {</p><p>&nbsp; &nbsp; console.log(<span style="color: #ce9178;">&quot;ARROW: &quot;</span>, this)</p><p>&nbsp; }}</p><p>&nbsp; &nbsp; myObject.regularExample()myObject.arrowExample()</p><p>屏幕截图-2024-01-12-at-5.46.04-PM具有常规函数的方法和具有箭头函数的方法的日志结果</p><p>虽然具有常规函数的方法将对象记录到控制台,但具有箭头函数的方法则记录全局窗口对象。</p><p>如何使用函数作为构造函数</p><p>对于常规函数,您可以使用关键字创建新实例。这会将值设置为您创建的新实例。newthis</p><p>对于箭头函数,不能将它们用作构造函数。这是因为箭头函数的值是词法范围的,即由周围的执行上下文确定。这种行为使它们不适合用作构造函数。this</p><p>下面是一个示例:</p><p>function RegularFuncBird(name, color) {</p><p>&nbsp; <span style="color: #569cd6;">this.name</span> = name &nbsp;<span style="color: #569cd6;">this.species</span> = color</p><p>&nbsp; console.log(this)}const <span style="color: #569cd6;">ArrowFuncBird</span> = (name, color) =&gt; {</p><p>&nbsp; <span style="color: #569cd6;">this.name</span> = name &nbsp;<span style="color: #569cd6;">this.color</span> = color</p><p>&nbsp; console.log(this)}new RegularFuncBird(<span style="color: #ce9178;">&quot;Parrot&quot;</span>, <span style="color: #ce9178;">&quot;blue&quot;</span>) new ArrowFuncBird(<span style="color: #ce9178;">&quot;Parrot&quot;</span>, <span style="color: #ce9178;">&quot;blue&quot;</span>)</p><p>屏幕截图-2024-01-12-at-5.53.17-PM尝试使用常规函数和箭头函数作为构造函数的日志结果</p><p>构造函数可以很好地处理关键字,但会导致类型错误。RegularFuncBirdnewArrowFuncBird</p><p>那么你应该使用哪一个呢?</p><p>对此没有直接的答案。您使用常规函数还是箭头函数取决于具体的用例。</p><p>建议在以下任何一种情况下使用常规函数:</p><p>当您需要使用带有关键字的构造函数时new</p><p>当需要动态作用域绑定时this</p><p>当您想要使用对象时arguments</p><p>您可以在以下任何情况下使用箭头函数:</p><p>当您想要更简洁的函数语法时</p><p>当您需要维护this</p><p>对于非方法函数(在大多数情况下)</p><p>正如您从本文中了解到的,两者都是在 JavaScript 中定义函数的有效方法。请记住,在它们之间进行选择并不总是个人喜好的问题。相反,它取决于您期望从函数中获得的行为类型。</p><p><br/></p><p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1.5em; padding: 0px; border: 0px; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-stretch: inherit; line-height: 1.5em; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.25em; vertical-align: baseline; min-width: 100%; color: rgb(10, 10, 35); text-wrap: wrap; background-color: rgb(255, 255, 255);"><br/></p>