<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>JavaScript on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/javascript/</link><description>Recent content in JavaScript on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Wed, 05 Nov 2025 00:00:00 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/tags/javascript/index.xml" rel="self" type="application/rss+xml"/><item><title>Let/Const</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/let-const/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/let-const/</guid><description>&lt;h2 id="var"&gt;Var&lt;/h2&gt;
&lt;p&gt;在 ES6 出现之前，必须使用 &lt;code&gt;var&lt;/code&gt; 声明。但是，前端开发出现的一些问题与使用 &lt;code&gt;var&lt;/code&gt; 声明的变量有关。这就是为什么必须要有新的方法来声明变量。首先，让我们在讨论这些问题之前更多地了解 &lt;code&gt;var&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="var-的作用域"&gt;var 的作用域&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用域&lt;/strong&gt;本质上是指变量/函数可供访问的范围。&lt;code&gt;var&lt;/code&gt;可以在全局范围声明或函数/局部范围内声明。&lt;/p&gt;
&lt;p&gt;当在最外层函数的外部声明&lt;code&gt;var&lt;/code&gt;变量时，作用域是全局的。这意味着在最外层函数的外部用&lt;code&gt;var&lt;/code&gt;声明的任何变量都可以在&lt;code&gt;windows&lt;/code&gt;中使用。&lt;/p&gt;
&lt;p&gt;当在函数中声明&lt;code&gt;var&lt;/code&gt;时，作用域是局部的。这意味着它只能在函数内访问。&lt;/p&gt;
&lt;p&gt;要进一步了解，请查看下面的示例。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hey hi&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function newFunction() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; hello &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里，&lt;code&gt;greeter&lt;/code&gt;是全局范围的，因为它存在于函数外部，而&lt;code&gt;hello&lt;/code&gt;是函数范围的。因此，我们无法在函数外部访问变量&lt;code&gt;hello&lt;/code&gt;。因此，如果我们这样做：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; tester &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hey hi&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function newFunction() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; hello &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console&lt;span style="color:#f92672"&gt;.&lt;/span&gt;log(hello); &lt;span style="color:#f92672"&gt;//&lt;/span&gt; error: hello is &lt;span style="color:#f92672"&gt;not&lt;/span&gt; defined
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们会收到错误消息，这是由于函数外部没有&lt;code&gt;hello&lt;/code&gt;导致的。&lt;/p&gt;
&lt;h3 id="var-变量可以重新声明和修改"&gt;var 变量可以重新声明和修改&lt;/h3&gt;
&lt;p&gt;这意味着我们可以在相同的作用域内执行下面的操作，并且不会出错&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hey hi&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;say Hello instead&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;又比如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hey hi&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;say Hello instead&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="var-的变量提升"&gt;var 的变量提升&lt;/h3&gt;
&lt;p&gt;变量提升是 JavaScript 的一种机制:在执行代码之前，变量和函数声明会移至其作用域的顶部。这意味着如果我们这样做:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console&lt;span style="color:#f92672"&gt;.&lt;/span&gt;log(greeter);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;say hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生面的代码会被解释为:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console&lt;span style="color:#f92672"&gt;.&lt;/span&gt;log(greeter); &lt;span style="color:#f92672"&gt;//&lt;/span&gt; greeter is undefined
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;say hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因此，将&lt;code&gt;var&lt;/code&gt;声明的变量会被提升到其作用域的顶部，并使用 undefined 值对其进行初始化.&lt;/p&gt;</description></item><item><title>数据类型</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-001/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-001/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;请讲下 &lt;code&gt;JavaScript&lt;/code&gt; 中的数据类型？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;前端面试中，估计大家都被这么问过。&lt;/p&gt;
&lt;p&gt;答：&lt;code&gt;Javascript&lt;/code&gt; 中的数据类型包括原始类型和引用类型。其中原始类型包括 &lt;code&gt;Null&lt;/code&gt;、&lt;code&gt;Undefined&lt;/code&gt;、&lt;code&gt;Boolean&lt;/code&gt;、&lt;code&gt;String&lt;/code&gt;、&lt;code&gt;Symbol&lt;/code&gt;、&lt;code&gt;BigInt&lt;/code&gt;。引用类型指的是 &lt;code&gt;Object&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;没错，我也是这么回答的，只是这通常是第一个问题，由这个问题可以引出很多很多的问题，比如&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Null&lt;/code&gt; 和 &lt;code&gt;Undefined&lt;/code&gt; 有什么区别？前端的判空有哪些需要注意的？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;typeof null&lt;/code&gt; 为什么是 &lt;code&gt;object&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;为什么 &lt;code&gt;ES6&lt;/code&gt; 要提出 &lt;code&gt;Symbol&lt;/code&gt;？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BigInt&lt;/code&gt; 解决了什么问题？&lt;/li&gt;
&lt;li&gt;为什么 &lt;code&gt;0.1 + 0.2 !== 0.3?&lt;/code&gt; 你如何解决这个问题？&lt;/li&gt;
&lt;li&gt;如何判断一个值是数组？&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="弱类型语言"&gt;弱类型语言&lt;/h2&gt;
&lt;p&gt;因为 &lt;code&gt;JavaScript&lt;/code&gt; 是弱类型语言或者说是动态语言。这意味着你不需要提前声明变量的类型，在程序运行的过程中，类型会被自动确定，也就是说你可以使用同一个变量保存不同类型的值&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// foo is a Number now
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// foo is a String now
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// foo is a Boolean now
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这一特性给我们带来便利的同时，也给我们带来了很多的类型错误。试想一下，假如 &lt;code&gt;JS&lt;/code&gt; 说是强类型语言，那么各个类型之间没法转换，也就有了一层隔阂或者说一层保护，会不会更加好维护呢？——这或许就是 &lt;code&gt;TypeScript&lt;/code&gt; 诞生的原因。&lt;/p&gt;
&lt;p&gt;对 &lt;code&gt;JavaScript&lt;/code&gt; 的数据类型掌握，是一个前端最基本的知识点&lt;/p&gt;
&lt;h2 id="null-还是-undefined"&gt;null 还是 undefined&lt;/h2&gt;
&lt;h3 id="定义"&gt;定义&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;undefined&lt;/code&gt; 表示未定义的变量。&lt;code&gt;null&lt;/code&gt; 值表示一个空对象指针。&lt;/p&gt;</description></item><item><title>类型判断</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-002/</link><pubDate>Mon, 04 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-002/</guid><description>&lt;p&gt;JS中的类型判断也是咱的老朋友了，如果要你说两句，那便是啥玩意&lt;code&gt;typeof&lt;/code&gt;、&lt;code&gt;instanceof&lt;/code&gt;的，张口就来，但你真的掌握了每一种类型判断，并熟知其原理吗？就比如说&lt;code&gt;Object.prototype.toString.call()&lt;/code&gt;，当面试官问其中的 &lt;code&gt;call&lt;/code&gt;有什么作用时，咱们又该如何游说呢。&lt;/p&gt;
&lt;h2 id="typeof原理"&gt;typeof原理&lt;/h2&gt;
&lt;p&gt;所有的类型判断里当属&lt;code&gt;typeof&lt;/code&gt;最为经典，其最为出名之处就是这玩意不顶用，&lt;code&gt;typeof&lt;/code&gt;居然会将&lt;code&gt;null&lt;/code&gt;判定为&lt;code&gt;object&lt;/code&gt;，但这到底是什么原因？实际上，这就是JS这门编程语言的官方团队造出来的一个bug。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;s&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;123&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nu&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sy&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Symbol&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;big&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1234&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;date&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;f&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;// boolean
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;u&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;// undifined
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;sy&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;// symbol
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;big&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;// bigint
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;nu&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;//将null判断为object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//以下为引用类型，除了function，一律被判断为object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;//object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;//object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;//object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 所有引用类型只能判断function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;//function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;原因就是：&lt;code&gt;typeof&lt;/code&gt;会把所有传进去的值都转成二进制，而当年JS制定的规则便是：原始类型的被转为二进制的前面三个值绝对不为零，而&lt;code&gt;typeof&lt;/code&gt;会把前三位为零的类型全部认定为对象，&lt;code&gt;null&lt;/code&gt;这个类型又是JS语言后来引入的。遵循其他语言的原则，JS语言将&lt;code&gt;null&lt;/code&gt;的二进制值定为一长串的0，因此&lt;code&gt;typeof&lt;/code&gt;在判断时会将其认定为&lt;code&gt;object&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;因此，面试官一般不会询问判断方法 &lt;code&gt;typeof&lt;/code&gt; 的原理。&lt;/p&gt;
&lt;h2 id="手写一个instanceof"&gt;手写一个instanceof&lt;/h2&gt;
&lt;p&gt;相较于&lt;code&gt;typeof&lt;/code&gt;，&lt;code&gt;instanceof&lt;/code&gt;有其优越之处，也有其不足之处，比如，&lt;code&gt;instanceof&lt;/code&gt;只能判断引用类型，并且是通过原型链查找来判断类型。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;s&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;123&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nu&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sy&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Symbol&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;big&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1234&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;date&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; String); &lt;span style="color:#75715e"&gt;// false instanceof 不能判断原始类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 以下为引用类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; Object) ; &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; Object); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; Function); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; Date); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;首先要知道每个类型的原型都不相同。&lt;/p&gt;</description></item><item><title>模版字符串</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-002/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-002/</guid><description>&lt;p&gt;未见过的函数用法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function fun(strings,params1){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(strings);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(params1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fun`params1 = ${333}`
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 输出分别为
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// [&amp;#39;params1 = &amp;#39;, &amp;#39;&amp;#39;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 333
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不知道各位在学习或开发中有没有遇到过这样的函数调用方式呢？秉承着我没遇到的东西就要发文章来分享分享的原则，经过我查阅资料并加以学习，就让本文来带大家了解一下JS中的标签函数吧。&lt;/p&gt;
&lt;h2 id="模板字符串"&gt;模板字符串&lt;/h2&gt;
&lt;p&gt;标签函数的主要作用就是处理模板字符串，所以在了解标签函数之前先了解一下模板字符串（模板字面量）吧。&lt;/p&gt;
&lt;h3 id="基本用法"&gt;基本用法&lt;/h3&gt;
&lt;p&gt;模板字符串是ES6新增的使用模板字面量定义字符串的能力，用反引号```````` 进行分隔。与使用&lt;code&gt;''&lt;/code&gt;或&lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;的定义的字符串字面量不同是模板字面量保留换行字符，可以跨行定义字符串。 例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let str1 = &amp;#39;xxhh\n2233&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let str2 = `xxhh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2233`
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(str1 === str2) // 结果为true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;要注意的是模板字符串中的所有字符都会包含在字符串中，特别在使用缩进的时候，缩进的空格都会包含在字符串中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let str = `
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;h1&amp;gt;xxhh&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(str.length) // 结果为44，包含了缩进所产出的所有空格
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="字符串插值"&gt;字符串插值&lt;/h3&gt;
&lt;p&gt;在没有模板字符串时，我们通常会使用&lt;code&gt;+&lt;/code&gt;加法运算符来进行字符串的拼接，但有了模板字符串后我们并可通过插值占位符&lt;code&gt;${}&lt;/code&gt;来将各字面量、变量或表达式结果来进行拼接，这样可以更容易地创建复杂和动态的字符串，同时保持代码的可读性和简洁性。这是模板字符串最常用的一个特性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let name = &amp;#39;xxhh&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let str1 = &amp;#34;name:&amp;#34;+name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let str2 = `name:${name}`;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(str1,str2) // name:xxhh name:xxhh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(str1 === str2) // true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;要注意的是使用字符串插值的所有插入的值都会使用&lt;code&gt;toString()&lt;/code&gt;强制转型为字符串，而且任何JavaScript 表达式都可以用于插值。&lt;/p&gt;</description></item><item><title>数据类型转换</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-003/</link><pubDate>Mon, 04 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-003/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;JavaScript 是一种非常灵活的编程语言，它允许开发者在代码中进行各种类型的操作和转换。其中，显式和隐式类型转换是 JavaScript 中一个重要而又常见的概念。你是否曾经遇到过 JavaScript 中奇怪的类型转换行为？当你使用加号连接两个不同类型的值时，为什么有时候会得到意料之外的结果？为了更好地理解 JavaScript 中的这些行为，我本篇文章将带大家深入探讨显式和隐式类型转换。&lt;/p&gt;
&lt;h2 id="数据类型"&gt;数据类型&lt;/h2&gt;
&lt;p&gt;首先简单了解下有哪些数据类型。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;原始数据类型：String、Number、Boolean、Symbol、Undefined、Null、BigInt（本文不讨论BigInt、Symbol）&lt;/p&gt;
&lt;p&gt;引用数据类型: Object（引用类型指向一个对象，不是原始值，指向对象的变量是引用变量）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="类型转换"&gt;类型转换&lt;/h2&gt;
&lt;p&gt;数据类型之间的转换可以分为下面三种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;原始数据类型之间的转换。&lt;/li&gt;
&lt;li&gt;原始数据类型转换为对象。&lt;/li&gt;
&lt;li&gt;对象转换为原始数据类型。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="11-原始数据类型转number"&gt;1.1 原始数据类型转Number&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Number(&lt;span style="color:#e6db74"&gt;&amp;#39;123&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 123
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Number(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Number(&lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// NaN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Number(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以直接调用&lt;code&gt;Number()&lt;/code&gt;函数来进行转换。该函数会把&lt;code&gt;undefined&lt;/code&gt;转换为&lt;code&gt;NaN&lt;/code&gt;，将&lt;code&gt;null&lt;/code&gt;转换为&lt;code&gt;0&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;而对于字符串，如果字符串中仅仅包含数字，则将转换为数字，若包含非数字字符，则返回&lt;code&gt;NaN&lt;/code&gt;。我们也可以使用&lt;code&gt;parseInt()&lt;/code&gt;来转换字符串。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(parseInt(&lt;span style="color:#e6db74"&gt;&amp;#39;123&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 123
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(parseInt(&lt;span style="color:#e6db74"&gt;&amp;#39;12.3&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 12
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(parseInt(&lt;span style="color:#e6db74"&gt;&amp;#39;12ds8&amp;#39;&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// 12
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(parseInt(&lt;span style="color:#e6db74"&gt;&amp;#39;ads25&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// NaN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;parseInt()&lt;/code&gt;只解析整数部分，忽略小数部分。&lt;code&gt;parseFloat()&lt;/code&gt;可以将字符串转换为浮点数的函数。&lt;/p&gt;
&lt;h2 id="12-原始数据类型转string"&gt;1.2 原始数据类型转String&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String());&lt;span style="color:#75715e"&gt;//&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String(&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;));&lt;span style="color:#75715e"&gt;//&amp;#39;123&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String(&lt;span style="color:#66d9ef"&gt;NaN&lt;/span&gt;));&lt;span style="color:#75715e"&gt;//NaN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String(&lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;));&lt;span style="color:#75715e"&gt;//undefined
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;));&lt;span style="color:#75715e"&gt;//null
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;));&lt;span style="color:#75715e"&gt;//true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以使用&lt;code&gt;String()&lt;/code&gt; 构造函数将任何类型的数据转换为字符串类型。它将接收到的参数转换为对应的字符串表示形式。&lt;/p&gt;
&lt;h2 id="13-原始数据类型转boolean"&gt;1.3 原始数据类型转Boolean&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean());&lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#e6db74"&gt;&amp;#39;Ywis&amp;#39;&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// tru
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#66d9ef"&gt;NaN&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;调用&lt;code&gt;Boolean()&lt;/code&gt;函数进行转换。在将非布尔值类型转换为布尔值类型时，有一个总结：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;false&lt;/code&gt;：布尔值 false&lt;/li&gt;
&lt;li&gt;&lt;code&gt;undefined&lt;/code&gt;：未定义的值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;null&lt;/code&gt;：空值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;：数字 0&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-0&lt;/code&gt;：负零&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NaN&lt;/code&gt;：非数字值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;''&lt;/code&gt;：空字符串&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;除了以上七个值外，其他值（包括对象、数组、函数等）在转换为布尔值时都会返回 &lt;code&gt;true&lt;/code&gt;。这种规则使得 JS 中的大多数值被视为真值（truthy）。&lt;/p&gt;</description></item><item><title>默认参数</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-003/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-003/</guid><description>&lt;p&gt;一、参数传递&lt;/p&gt;
&lt;p&gt;代码语言：javascript&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function foo(a, b) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log([a, b]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;foo(1, 2); // 输出 [1, 2]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个例子中，a 和 b 属于函数中的局部变量，只能在函数中访问。调用函数时，传递的数据会根据位置来匹配对应，分别赋值给 a 和 b。&lt;/p&gt;
&lt;p&gt;创建函数时，function 函数名 后面括号中设定的参数被称为形参；调用函数时，函数名后面括号中传入的参数被称为实参。上面例子中，a 和 b 是形参，传入的 1 和 2 是实参。&lt;/p&gt;
&lt;p&gt;因为形参是已声明的变量，所以不能再用 let 和 const 重复声明。&lt;/p&gt;
&lt;p&gt;代码语言：javascript&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function foo(a, b) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#f92672"&gt;//&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;报错，&lt;/span&gt;a &lt;span style="color:#960050;background-color:#1e0010"&gt;已声明&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; b &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#f92672"&gt;//&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;报错，&lt;/span&gt;b &lt;span style="color:#960050;background-color:#1e0010"&gt;已声明&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;JavaScript 中所有函数传递都是按值传递的，不会按引用传递。所谓的值，就是指直接保存在变量上的值，如果把对象作为参数传递，那么这个值就是这个对象的引用，而不是对象本身。这里实际上是一个隐式的赋值过程，所以给函数传递参数时，相当于从一个变量赋值到另一个变量。&lt;/p&gt;
&lt;p&gt;原始值：&lt;/p&gt;
&lt;p&gt;代码语言：javascript&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function add(num) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return num + 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let count = 5;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let result = add(count); // 此处参数传递的过程可以看作是 num = count
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(count); // 5
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(result); // 6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;引用值：&lt;/p&gt;</description></item><item><title>内存空间</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/image-01.webp"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因为JavaScript具有自动垃圾回收机制，所以对于前端开发来说，内存空间并不是一个经常被提及的概念，很容易被大家忽视。特别是很多不是计算机专业的朋友在进入到前端之后，会对内存空间的认知比较模糊，甚至有些人干脆就是一无所知。&lt;/p&gt;
&lt;p&gt;当然也包括我自己。在很长一段时间里认为内存空间的概念在JS的学习中并不是那么重要。可是后我当我回过头来重新整理JS基础时，发现由于对它们的模糊认知，导致了很多东西我都理解得并不明白。比如最基本的引用数据类型和引用传递到底是怎么回事儿？比如浅复制与深复制有什么不同？还有闭包，原型等等。&lt;/p&gt;
&lt;p&gt;因此后来我才渐渐明白，想要对JS的理解更加深刻，就必须对内存空间有一个清晰的认知。&lt;/p&gt;
&lt;p&gt;在学习内存空间之前，我们需要对三种数据结构有一个直观的认知。他们分别是&lt;strong&gt;堆(heap)，栈(stack)与队列(queue)&lt;/strong&gt;。&lt;/p&gt;
&lt;h5 id="一栈数据结构"&gt;一、栈数据结构&lt;/h5&gt;
&lt;p&gt;与C/C++不同，JavaScript中并没有严格意义上区分栈内存与堆内存。因此我们可以简单粗暴的理解为JavaScript的所有数据都保存在堆内存中。但是在某些场景，我们仍然需要基于堆栈数据结构的思维来实现一些功能，比如JavaScript的执行上下文（关于执行上下文我会在下一篇文章中总结）。执行上下文的执行顺序借用了栈数据结构的存取方式。(也就是后面我们会经常提到的函数调用栈)。因此理解栈数据结构的原理与特点十分重要。&lt;/p&gt;
&lt;p&gt;要简单理解栈的存取方式，我们可以通过类比乒乓球盒子来分析。如下图左侧。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;这种乒乓球的存放方式与栈中存取数据的方式如出一辙。处于盒子中最顶层的乒乓球5，它一定是最后被放进去，但可以最先被使用。而我们想要使用底层的乒乓球1，就必须将上面的4个乒乓球取出来，让乒乓球1处于盒子顶层。这就是栈空间&lt;strong&gt;先进后出，后进先出&lt;/strong&gt;的特点。图中已经详细的表明了栈空间的存储原理。&lt;/p&gt;
&lt;h5 id="二堆数据结构"&gt;二、堆数据结构&lt;/h5&gt;
&lt;p&gt;堆数据结构是一种树状结构。它的存取数据的方式，则与书架与书非常相似。&lt;/p&gt;
&lt;p&gt;书虽然也整齐的存放在书架上，但是我们只要知道书的名字，我们就可以很方便的取出我们想要的书，而不用像从乒乓球盒子里取乒乓一样，非得将上面的所有乒乓球拿出来才能取到中间的某一个乒乓球。好比在JSON格式的数据中，我们存储的&lt;code&gt;key-value&lt;/code&gt;是可以无序的，因为顺序的不同并不影响我们的使用，我们只需要关心书的名字。&lt;/p&gt;
&lt;h4 id="三队列"&gt;三、队列&lt;/h4&gt;
&lt;p&gt;在JavaScript中，理解队列数据结构的目的主要是为了清晰的明白事件循环（Event Loop）的机制到底是怎么回事。在后续的章节中我会详细分析事件循环机制。&lt;/p&gt;
&lt;p&gt;队列是一种先进先出（FIFO）的数据结构。正如排队过安检一样，排在队伍前面的人一定是最先过检的人。用以下的图示可以清楚的理解队列的原理。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/image-03.webp"&gt;&lt;/p&gt;
&lt;h5 id="四变量对象与基础数据类型"&gt;四、变量对象与基础数据类型&lt;/h5&gt;
&lt;p&gt;JavaScript的执行上下文生成之后，会创建一个叫做变量对象的特殊对象（具体会在下一篇文章与执行上下文一起总结），JavaScript的基础数据类型往往都会保存在变量对象中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;严格意义上来说，变量对象也是存放于堆内存中，但是由于变量对象的特殊职能，我们在理解时仍然需要将其于堆内存区分开来。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;基础数据类型都是一些简单的数据段，JavaScript中有5中基础数据类型，分别是&lt;code&gt;Undefined、Null、Boolean、Number、String&lt;/code&gt;。基础数据类型都是按值访问，因为我们可以直接操作保存在变量中的实际的值。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ES6中新加了一种基础数据类型Symbol，可以先不用考虑他&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5 id="五引用数据类型与堆内存"&gt;五、引用数据类型与堆内存&lt;/h5&gt;
&lt;p&gt;与其他语言不同，JS的引用数据类型，比如数组Array，它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JavaScript不允许直接访问堆内存中的位置，因此我们不能直接操作对象的堆内存空间。在操作对象时，实际上是在操作对象的引用而不是实际的对象。因此，引用类型的值都是按引用访问的。这里的引用，我们可以理解为保存在变量对象中的一个地址，该地址与堆内存的实际值相关联。&lt;/p&gt;
&lt;p&gt;为了更好的搞懂变量对象与堆内存，我们可以结合以下例子与图解进行理解。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;this is string&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a3&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; }; &lt;span style="color:#75715e"&gt;// 变量b存在于变量对象中，{m: 20} 作为对象存在于堆内存中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 变量c存在于变量对象中，[1, 2, 3] 作为对象存在于堆内存中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;因此当我们要访问堆内存中的引用数据类型时，实际上我们首先是从变量对象中获取了该对象的地址引用（或者地址指针），然后再从堆内存中取得我们需要的数据。&lt;/p&gt;
&lt;p&gt;理解了JS的内存空间，我们就可以借助内存空间的特性来验证一下引用类型的一些特点了。&lt;/p&gt;
&lt;p&gt;在前端面试中我们常常会遇到这样一个类似的题目&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo01.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 这时a的值是多少？
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo02.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 这时m.a的值是多少
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在变量对象中的数据发生复制行为时，系统会自动为新的变量分配一个新值。&lt;code&gt;var b = a&lt;/code&gt;执行之后，a与b虽然值都等于20，但是他们其实已经是相互独立互不影响的值了。具体如图。所以我们修改了b的值以后，a的值并不会发生变化。&lt;/p&gt;</description></item><item><title>箭头函数</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-004/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-004/</guid><description>&lt;h2 id="一箭头函数的特点"&gt;一、箭头函数的特点&lt;/h2&gt;
&lt;h3 id="1-相比普通函数箭头函数有更加简洁的语法"&gt;1. 相比普通函数，箭头函数有更加简洁的语法。&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;普通函数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function add(num) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return num + 10
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;箭头函数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; add &lt;span style="color:#f92672"&gt;=&lt;/span&gt; num &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; num &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-箭头函数不绑定this会捕获其所在上下文的this作为自己的this"&gt;2. 箭头函数不绑定this，会捕获其所在上下文的this，作为自己的this。&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;这句话需要注意的是，箭头函数的外层如果有普通函数，那么箭头函数的this就是这个外层的普通函数的this，箭头函数的外层如果没有普通函数，那么箭头函数的this就是全局变量。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;下面这个例子是箭头函数的外层有普通函数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let obj = {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fn:function(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(&amp;#39;我是普通函数&amp;#39;,this === obj) // true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return ()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(&amp;#39;我是箭头函数&amp;#39;,this === obj) // true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(obj.fn()())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;下面这个例子是箭头函数的外层没有普通函数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let obj = {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fn:()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(this === window);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(obj.fn())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-箭头函数是匿名函数不能作为构造函数不可以使用new命令否则后抛出错误"&gt;3. 箭头函数是匿名函数，不能作为构造函数，不可以使用new命令，否则后抛出错误。&lt;/h3&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-004/image-01.webp"&gt;&lt;/p&gt;</description></item><item><title>执行上下文</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-01.webp"&gt;&lt;br&gt;
我们在JS学习初期或者面试的时候常常会遇到考核变量提升的思考题。比如先来一个简单一点的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 这里会打印出什么？
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;暂时先不管这个例子，我们先引入一个JavaScript中最基础，但同时也是最重要的一个概念&lt;strong&gt;执行上下文（Execution Context）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;每次当控制器转到可执行代码的时候，就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境，它会形成一个作用域。JavaScript中的运行环境大概包括三种情况。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全局环境：JavaScript代码运行起来会首先进入该环境&lt;/li&gt;
&lt;li&gt;函数环境：当函数被调用执行时，会进入当前函数中执行代码&lt;/li&gt;
&lt;li&gt;eval（不建议使用，可忽略）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此在一个JavaScript程序中，必定会产生多个执行上下文，在我的上一篇文章中也有提到，JavaScript引擎会以栈的方式来处理它们，这个栈，我们称其为函数调用栈(call stack)。栈底永远都是全局上下文，而栈顶就是当前正在执行的上下文。&lt;/p&gt;
&lt;p&gt;当代码在执行过程中，遇到以上三种情况，都会生成一个执行上下文，放入栈中，而处于栈顶的上下文执行完毕之后，就会自动出栈。为了更加清晰的理解这个过程，根据下面的例子，结合图示给大家展示。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;执行上下文可以理解为函数执行的环境，每一个函数执行时，都会给对应的函数创建这样一个执行环境。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;blue&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;changeColor&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;anotherColor&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;red&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;swapColors&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tempColor&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;anotherColor&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;anotherColor&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tempColor&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;swapColors&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;changeColor&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们用ECStack来表示处理执行上下文组的堆栈。我们很容易知道，第一步，首先是全局上下文入栈。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;全局上下文入栈之后，其中的可执行代码开始执行，直到遇到了&lt;code&gt;changeColor()&lt;/code&gt; ，这一句激活函数&lt;code&gt;changeColor&lt;/code&gt;创建它自己的执行上下文，因此第二步就是changeColor的执行上下文入栈。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;changeColor的上下文入栈之后，控制器开始执行其中的可执行代码，遇到&lt;code&gt;swapColors()&lt;/code&gt;之后又激活了一个执行上下文。因此第三步是swapColors的执行上下文入栈。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;在swapColors的可执行代码中，再没有遇到其他能生成执行上下文的情况，因此这段代码顺利执行完毕，swapColors的上下文从栈中弹出。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;swapColors的执行上下文弹出之后，继续执行changeColor的可执行代码，也没有再遇到其他执行上下文，顺利执行完毕之后弹出。这样，ECStack中就只身下全局上下文了。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;全局上下文在浏览器窗口关闭后出栈。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：函数中，遇到return能直接终止可执行代码的执行，因此会直接将当前上下文弹出栈。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-07.webp"&gt;&lt;/p&gt;
&lt;p&gt;详细了解了这个过程之后，我们就可以对执行上下文总结一些结论了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单线程&lt;/li&gt;
&lt;li&gt;同步执行，只有栈顶的上下文处于执行中，其他上下文需要等待&lt;/li&gt;
&lt;li&gt;全局上下文只有唯一的一个，它在浏览器关闭时出栈&lt;/li&gt;
&lt;li&gt;函数的执行上下文的个数没有限制&lt;/li&gt;
&lt;li&gt;每次某个函数被调用，就会有个新的执行上下文为其创建，即使是调用的自身函数，也是如此。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了巩固一下执行上下文的理解，我们再来绘制一个例子的演变过程，这是一个简单的闭包例子。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f1&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;999&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f2&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;alert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;f1&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 999
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因为f1中的函数f2在f1的可执行代码中，并没有被调用执行，因此执行f1时，f2不会创建新的上下文，而直到result执行时，才创建了一个新的。具体演变过程如下。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-08.webp"&gt;&lt;/p&gt;
&lt;p&gt;最后留一个简单的例子，大家可以自己脑补一下这个例子在执行过程中执行上下文的变化情况。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;window&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Perter&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 利用变量保存的方式保证其访问的是p对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;_name&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;执行上下文的定义&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;什么是执行上下文？它在 JavaScript 中有哪些类型？&lt;/li&gt;
&lt;li&gt;执行上下文在代码执行时是如何被创建和销毁的？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;执行上下文的生命周期&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;执行上下文的创建和执行过程有哪些阶段？（例如，创建阶段和执行阶段）&lt;/li&gt;
&lt;li&gt;请描述执行上下文在创建阶段进行的三个步骤：变量对象的创建、作用域链的建立、&lt;code&gt;this&lt;/code&gt; 的绑定。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;变量对象（Variable Object）&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;什么是变量对象？它在执行上下文中的作用是什么？&lt;/li&gt;
&lt;li&gt;变量提升是如何与变量对象关联的？在函数声明和变量声明时有何不同？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;作用域链&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;执行上下文是如何通过作用域链来访问变量的？&lt;/li&gt;
&lt;li&gt;请解释在嵌套函数的情况下，作用域链是如何建立的？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;this&lt;/code&gt; 绑定&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;在不同的执行上下文中，&lt;code&gt;this&lt;/code&gt; 的值是如何确定的？（例如，全局上下文、函数上下文、箭头函数）&lt;/li&gt;
&lt;li&gt;如何解释在不同函数调用方式下 &lt;code&gt;this&lt;/code&gt; 的指向差异？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="6"&gt;
&lt;li&gt;&lt;strong&gt;执行上下文栈&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;什么是执行上下文栈？它如何管理代码执行的顺序？&lt;/li&gt;
&lt;li&gt;JavaScript 引擎如何利用执行上下文栈来实现函数的嵌套调用和返回？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="7"&gt;
&lt;li&gt;&lt;strong&gt;块级作用域的影响&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;ES6 中引入的 &lt;code&gt;let&lt;/code&gt; 和 &lt;code&gt;const&lt;/code&gt; 是如何影响执行上下文的？&lt;/li&gt;
&lt;li&gt;如何解释块级作用域在执行上下文中的特殊处理？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="8"&gt;
&lt;li&gt;&lt;strong&gt;常见问题与调试&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;如何通过理解执行上下文来排查变量未定义、&lt;code&gt;this&lt;/code&gt; 指向错误等常见问题？&lt;/li&gt;
&lt;li&gt;请解释某个你遇到的实际问题，以及如何通过分析执行上下文来解决它的。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>解构赋值</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/</guid><description>&lt;h2 id="解构赋值概念"&gt;解构赋值概念&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;解构赋值&lt;/strong&gt;语法是一种 Javascript 表达式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过解构赋值，可以将属性/值从对象/数组中取出,赋值给其他变量。&lt;/li&gt;
&lt;li&gt;解构赋值是通过将结构中的各元素复制到变量中来达到“解构”的目的。但对象/数组本身不会被修改。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="数组解构"&gt;数组解构&lt;/h2&gt;
&lt;h3 id="基本使用"&gt;基本使用&lt;/h3&gt;
&lt;p&gt;📖 可以在定义变量的同时，使用解构进行赋值&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let [one, two, three] = foo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;//等同于
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let one = foo[0];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let two = foo[1];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let three = foo[2];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;📖 也可以先声明变量，在进行解构赋值&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="设置默认值"&gt;设置默认值&lt;/h3&gt;
&lt;p&gt;当【左边≠右边】时，可以先设置一个默认值，否则取不到值的变量会变成undefined&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-03.webp"&gt;&lt;/p&gt;
&lt;h3 id="剩余值处理"&gt;剩余值处理&lt;/h3&gt;
&lt;p&gt;可以使用三个点 &lt;code&gt;&amp;quot;...&amp;quot;&lt;/code&gt;+ 参数来接收剩余的所有元素，变量名称随意，必须在最后一个参数的位置上&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-04.webp"&gt;&lt;/p&gt;
&lt;h3 id="进阶用法"&gt;进阶用法&lt;/h3&gt;
&lt;p&gt;🎨 可以和&lt;code&gt;split&lt;/code&gt; 函数结合使用，比如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let [Mother,Father] = &amp;#34;judy,pete&amp;#34;.split(&amp;#39;,&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(Mother) //judy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(Father) //pete
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;🎨 可以使用逗号忽略元素，比如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let [name1,,name3] = [&amp;#34;Julius01&amp;#34;, &amp;#34;Caesar02&amp;#34;, &amp;#34;Consul03&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;🎨 可以直接赋值给对象的属性，比如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let user = {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[user.name, user.surname] = [&amp;#34;Ilya&amp;#34;,&amp;#34;Kantor&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-06.webp"&gt;&lt;/p&gt;</description></item><item><title>变量对象</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-006/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-006/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-006/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;这篇文章要给大家介绍的是变量对象。&lt;/p&gt;
&lt;p&gt;在JavaScript中，我们肯定不可避免的需要声明变量和函数，可是JS解析器是如何找到这些变量的呢？我们还得对执行上下文有一个进一步的了解。&lt;/p&gt;
&lt;p&gt;在知识点《执行上下文》中，我们已经知道，当调用一个函数时（激活），一个新的执行上下文就会被创建。而一个执行上下文的生命周期可以分为两个阶段。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;创建阶段&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在这个阶段中，执行上下文会分别创建变量对象，建立作用域链，以及确定this的指向。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;代码执行阶段&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;创建完成之后，就会开始执行代码，这个时候，会完成变量赋值，函数引用，以及执行其他代码。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-006/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;从这里我们就可以看出详细了解执行上下文极为重要，因为其中涉及到了变量对象，作用域链，this等很多人没有怎么弄明白，但是却极为重要的概念，它关系到我们能不能真正理解JavaScript。在后面的文章中我们会一一详细总结，这里我们先重点了解变量对象。&lt;/p&gt;
&lt;h5 id="变量对象variable-object"&gt;变量对象（Variable Object）&lt;/h5&gt;
&lt;p&gt;变量对象的创建，依次经历了以下几个过程。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;建立arguments对象。检查当前上下文中的参数，建立该对象下的属性与属性值。&lt;/li&gt;
&lt;li&gt;检查当前上下文的函数声明，也就是使用function关键字声明的函数。在变量对象中以函数名建立一个属性，属性值为指向该函数所在内存地址的引用。如果函数名的属性已经存在，那么该属性将会被新的引用所覆盖。&lt;/li&gt;
&lt;li&gt;检查当前上下文中的变量声明，每找到一个变量声明，就在变量对象中以变量名建立一个属性，属性值为undefined。如果该变量名的属性已经存在，为了防止同名的函数被修改为undefined，则会直接跳过，原属性值不会被修改。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;许多读者在阅读到这的时候会因为下面的这样场景对于“跳过”一词产生疑问。既然变量声明的foo遇到函数声明的foo会跳过，可是为什么最后foo的输出结果仍然是被覆盖了？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() { &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function foo&amp;#39;&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实只是大家在阅读的时候不够仔细，因为上面的三条规则仅仅适用于变量对象的创建过程。也就是执行上下文的创建过程。而&lt;code&gt;foo = 20&lt;/code&gt;是在执行上下文的执行过程中运行的，输出结果自然会是20。对比下例。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// function foo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() { &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function foo&amp;#39;&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 上栗的执行顺序为
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 首先将所有函数声明放入变量对象中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() { &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function foo&amp;#39;&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 其次将所有变量声明放入变量对象中，但是因为foo已经存在同名函数，因此此时会跳过undefined的赋值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// var foo = undefined;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 然后开始执行阶段代码的执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// function foo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-006/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;根据这个规则，理解变量提升就变得十分简单了。在很多文章中虽然提到了变量提升，但是具体是怎么回事还真的很多人都说不出来，以后在面试中用变量对象的创建过程跟面试官解释变量提升，保证瞬间提升逼格。&lt;/p&gt;
&lt;p&gt;在上面的规则中我们看出，function声明会比var声明优先级更高一点。为了帮助大家更好的理解变量对象，我们结合一些简单的例子来进行探讨。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上例中，我们直接从test()的执行上下文开始理解。全局作用域中运行&lt;code&gt;test()&lt;/code&gt;时，test()的执行上下文开始创建。为了便于理解，我们用如下的形式来表示&lt;/p&gt;</description></item><item><title>展开运算符</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-006/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-006/</guid><description>&lt;p&gt;ES6 新增了很多特性，扩展运算符就是其中一个。简单的三个点号，让原本繁琐的代码瞬间变得简洁、优雅。就让我们看看它有哪些常见用法吧。&lt;/p&gt;
&lt;h2 id="让函数的-apply-调用方式成为过去"&gt;让函数的 Apply 调用方式成为过去&lt;/h2&gt;
&lt;p&gt;有时候我们需要通过 &lt;code&gt;Function.prototype.apply&lt;/code&gt; 来调用函数，参数就放在一个数组里。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function doStuff (x, y, z) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; args &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;//&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;调用函数并传参&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doStuff&lt;span style="color:#f92672"&gt;.&lt;/span&gt;apply(null, args);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在有了展开运算符，我们可以完全避免使用 &lt;code&gt;apply&lt;/code&gt;，只需在调用函数时在数组前加上展开运算符：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doStuff(...args);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码变得更短、更简洁，也不需要一个毫无用处的 &lt;code&gt;null&lt;/code&gt;！&lt;/p&gt;
&lt;h2 id="合并数组"&gt;合并数组&lt;/h2&gt;
&lt;p&gt;合并数组有各种方式，但是展开运算符为我们提供了一种新思路：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arr1.push(...arr2) // 在数组后面添加 arr2 里的元素
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arr1.unshift(...arr2) //在数组前面添加 arr2 里的元素
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你想合并两个数组，并且想把元素放到数组中的任何位置，你可以这么做：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; arr1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;two&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;three&amp;#39;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; arr2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;one&amp;#39;&lt;/span&gt;, &lt;span style="color:#f92672"&gt;...&lt;/span&gt;arr1, &lt;span style="color:#e6db74"&gt;&amp;#39;four&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;five&amp;#39;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;//&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;one&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;two&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;three&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;four&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;five&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码少了很多，还可以随意控制位置！&lt;/p&gt;
&lt;h2 id="拷贝数组"&gt;拷贝数组&lt;/h2&gt;
&lt;p&gt;拷贝数组是个常见的任务，过去我们使用 &lt;code&gt;Array.prototype.slice&lt;/code&gt;&lt;br&gt;
来完成，但现在我们可以通过展开运算符得到数组的副本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; arr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; arr2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#f92672"&gt;...&lt;/span&gt;arr]; &lt;span style="color:#f92672"&gt;//&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;等同于&lt;/span&gt; arr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;slice()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arr2&lt;span style="color:#f92672"&gt;.&lt;/span&gt;push(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里要注意，数组里的对象仍然是引用类型的，因此实际上并不是所有内容都被“拷贝”了。&lt;/p&gt;
&lt;h2 id="将参数或-nodelist-转成数组"&gt;将参数或 NodeList 转成数组&lt;/h2&gt;
&lt;p&gt;跟拷贝数组类似，我们用 &lt;code&gt;Array.Prototype.slice&lt;/code&gt; 将 &lt;code&gt;NodeList&lt;/code&gt;和 &lt;code&gt;arguments&lt;/code&gt; 对象转成真正的数组，但是现在我们可以使用展开运算符完成这个任务：&lt;/p&gt;</description></item><item><title>export/import</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/export-import/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/export-import/</guid><description>&lt;h2 id="exportimport-是什么"&gt;export，import 是什么&lt;/h2&gt;
&lt;p&gt;我们知道，JS 模块导入导出，使用 &lt;code&gt;import&lt;/code&gt; , &lt;code&gt;export&lt;/code&gt; 这两个关键字&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;export&lt;/strong&gt; 用于对外输出本模块&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;import&lt;/strong&gt; 用于导入模块&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;也就是说使用 export 导出一个模块之后，其它文件就可以使用 import 导入相应的模块了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面我们具体看看， import 和 export 到底怎么用？怎么导出模块（比如变量，函数，类，对象等）&lt;/p&gt;
&lt;h3 id="1-导出单个变量"&gt;1 导出单个变量&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//a.js 导出一个变量，语法如下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;site&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;www.helloworld.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//b.js 中使用import 导入上面的变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;site&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/.a.js&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;//路径根据你的实际情况填写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;site&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//输出： www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-导出多个变量"&gt;2 导出多个变量&lt;/h3&gt;
&lt;p&gt;上面的例子是导出单个变量，那么如何导出多个变量呢&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//a.js 中定义两个变量，并导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;www.helloworld.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;helloworld开发者社区&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//将上面的变量导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt; ,&lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// b.js 中使用这两个变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt; , &lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/.a.js&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;//路径根据你的实际情况填写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//输出： www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//输出： helloworld开发者社区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;### 3 导出函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;导出函数和导出变量一样，需要添加`&lt;/span&gt;{ }&lt;span style="color:#e6db74"&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;````js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//a.js 中定义并导出一个函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;function sum(a, b) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; return a + b
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//将函数sum导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;export { sum }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//b.js 中导入函数并使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;import { sum } from &amp;#34;/.a.js&amp;#34; //路径根据你的实际情况填写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;console.log( sum(4,6) ) //输出： 10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;###&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;导出对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;js中一切皆对象&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;所以对象一定是可以导出的&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;并且有两种写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;####&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4.1&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;第一种写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;使用&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`export default`&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;关键字导出&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;如下&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;````&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;js&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//a.js 中，定义对象并导出, 注意，使用export default 这两个关键字导出一个对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;www.helloworld.net&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;helloworld开发者社区&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//b.js 中导入并使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./a.js&amp;#39;&lt;/span&gt; &lt;span style="color:#75715e"&gt;//路径根据你的实际情况填写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//输出：www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//输出：helloworld开发者社区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;#### 4.2 第二种写法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;同样是使用`&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;&lt;span style="color:#e6db74"&gt;` 关键字，如下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;````js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//a.js 中定义对象，并在最后导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;var obj = {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; siteUrl:&amp;#39;www.helloworld.net&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; siteName:&amp;#39;helloworld开发者社区&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;export default obj //导出对象obj
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//b.js 中导入并使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;import obj from &amp;#39;./a.js&amp;#39; //路径根据你的实际情况填写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;console.log(obj.siteUrl) //输出：www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;console.log(obj.siteName) //输出：helloworld开发者社区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;###&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;导出类&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;导出类与上面的导出对象类似&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;同样是用&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`export default`&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;关键字&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;同样有两种写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;####&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5.1&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;第一种写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;````&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;js&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//a.js 中定义一个类并直接导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//类的属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;site&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;www.helloworld.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//类的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;show&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;site&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//b.js 中导入并使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//导入类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./a.js&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//创建类的一个对象person
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//调用类的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;person&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;show&lt;/span&gt;() &lt;span style="color:#75715e"&gt;//输出：www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;#### 5.2 第二种写法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;````js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//a.js 中定义一个类，最后导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;class Person {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; //类的属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; site = &amp;#34;www.helloworld.net&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; //类的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; show(){
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; console.log(this.site)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//导出这个类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;export default Person
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//b.js 中导入并使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//导入类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;import Person from &amp;#39;./a.js&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//创建类的一个对象person
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;let person = new Person()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//调用类的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;person.show() //输出：www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;###&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;下面我们简单总结一下&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;`export`&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;与&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`export default`&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;的区别&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;export与export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default均可用于导出常量&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;函数&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;文件&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;模块等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;可以在其它文件或模块中通过import&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;常量&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;函数&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;文件&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;模块&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;名的方式&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;将其导入&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;以便能够对其进行使用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default后面不能跟const或let的关键词&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;export&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;import可以有多个&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default仅有一个&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;通过export方式导出&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;在导入时要加&lt;/span&gt; { }&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default则不需要&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;export具名导出xxx&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default匿名&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;区别在于导入的时候&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;export需要一样的名称才能匹配&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;后者无论取什么名都可以&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;模块化管理中一个文件就是一个模块&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;export可以导出多个方法和变量&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default只能导出当前模块&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;一个js文件中只支持出现一个&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;对于&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`import`&lt;/span&gt; ,&lt;span style="color:#e6db74"&gt;`export`&lt;/span&gt; , &lt;span style="color:#e6db74"&gt;`export default`&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;他们的用法上面的例子已经很详细的列出了&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;忘记的时候&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;可以当作参考看看&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;最重要的还是要明白为什么要这么写&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;实在不明白记住就行了&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;h3 id="1"&gt;&lt;strong&gt;1. &lt;code&gt;export&lt;/code&gt; 的基本使用&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;export&lt;/code&gt; 用于导出模块中的内容（如变量、函数、类等），使得其他模块能够导入这些内容。&lt;/p&gt;</description></item><item><title>作用域链与闭包</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/image-01.png"&gt;&lt;br&gt;
初学JavaScript的时候，我在学习闭包上，走了很多弯路。而这次重新回过头来对基础知识进行梳理，要讲清楚闭包，也是一个非常大的挑战。&lt;/p&gt;
&lt;p&gt;闭包有多重要？如果你是初入前端的朋友，我没有办法直观的告诉你闭包在实际开发中的无处不在，但是我可以告诉你，&lt;strong&gt;前端面试，必问闭包&lt;/strong&gt;。面试官们常常用对闭包的了解程度来判定面试者的基础水平，保守估计，10个前端面试者，至少5个都死在闭包上。&lt;/p&gt;
&lt;p&gt;可是为什么，闭包如此重要，还是有那么多人没有搞清楚呢？是因为大家不愿意学习吗？还真不是，而是我们通过搜索找到的大部分讲解闭包的中文文章，都没有清晰明了的把闭包讲解清楚。要么浅尝辄止，要么高深莫测，要么干脆就直接乱说一通。包括我自己曾经也写过一篇关于闭包的总结，回头一看，不忍直视[捂脸]。&lt;/p&gt;
&lt;p&gt;因此本文的目的就在于，能够清晰明了得把闭包说清楚，让读者朋友们看了之后，就把闭包给彻底学会了，而不是似懂非懂。&lt;/p&gt;
&lt;h5 id="一作用域与作用域链"&gt;一、作用域与作用域链&lt;/h5&gt;
&lt;p&gt;在详细讲解作用域链之前，我默认你已经大概明白了JavaScript中的下面这些重要概念。这些概念将会非常有帮助。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基础数据类型与引用数据类型&lt;/li&gt;
&lt;li&gt;内存空间&lt;/li&gt;
&lt;li&gt;垃圾回收机制&lt;/li&gt;
&lt;li&gt;执行上下文&lt;/li&gt;
&lt;li&gt;变量对象与活动对象&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你暂时还没有明白，可以去看本系列的前三篇文章，本文文末有目录链接。为了讲解闭包，已经为大家做好了基础知识的铺垫哦。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;作用域&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在JavaScript中，我们可以将作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称进行变量查找。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;这里的标识符，指的是变量名或者函数名&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript中只有全局作用域与函数作用域(因为eval我们平时开发中几乎不会用到它，这里不讨论)。&lt;/li&gt;
&lt;li&gt;作用域与执行上下文是完全不同的两个概念。我知道很多人会混淆他们，但是一定要仔细区分。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;JavaScript代码的整个执行过程，分为两个阶段，代码编译阶段与代码执行阶段。编译阶段由编译器完成，将代码翻译成可执行代码，这个阶段作用域规则会确定。执行阶段由引擎完成，主要任务是执行可执行代码，执行上下文在这个阶段创建。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;作用域链&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;回顾一下，我们分析过的执行上下文的生命周期，如下图： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/image-03.png"&gt;&lt;/p&gt;
&lt;p&gt;我们知道函数在调用激活时，会开始创建对应的执行上下文，在执行上下文生成的过程中，变量对象，作用域链，以及this的值会分别被确定。之前一篇文章我们详细说明了变量对象，而这里，我们将详细说明作用域链。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;作用域链，是由当前环境与上层环境的一系列变量对象组成，它保证了当前执行环境对符合访问权限的变量和函数的有序访问。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了帮助大家理解作用域链，我我们先结合一个例子，以及相应的图示来说明。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;innerTest&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;innerTest&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上面的例子中，全局，函数test，函数innerTest的执行上下文先后创建。我们设定他们的变量对象分别为VO(global)，VO(test), VO(innerTest)。而innerTest的作用域链，则同时包含了这三个变量对象，所以innerTest的执行上下文可如下表示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;innerTestEC&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;VO&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {...}, &lt;span style="color:#75715e"&gt;// 变量对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;scopeChain&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;VO&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;innerTest&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;VO&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;VO&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;global&lt;/span&gt;)], &lt;span style="color:#75715e"&gt;// 作用域链
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以直接用一个数组来表示作用域链，数组的第一项scopeChain[0]为作用域链的最前端，而数组的最后一项，为作用域链的最末端，所有的最末端都为全局变量对象。&lt;/p&gt;
&lt;p&gt;很多人会误解为当前作用域与上层作用域为包含关系，但其实并不是。以最前端为起点，最末端为终点的单方向通道我认为是更加贴切的形容。如图。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/image-04.png"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意，因为变量对象在执行上下文进入执行阶段时，就变成了活动对象，这一点在上一篇文章中已经讲过，因此图中使用了AO来表示。Active Object&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;是的，作用域链是由一系列变量对象组成，我们可以在这个单向通道中，查询变量对象中的标识符，这样就可以访问到上一层作用域中的变量了。&lt;/p&gt;
&lt;h5 id="二闭包"&gt;二、闭包&lt;/h5&gt;
&lt;p&gt;对于那些有一点 JavaScript 使用经验但从未真正理解闭包概念的人来说，理解闭包可以看作是某种意义上的重生，突破闭包的瓶颈可以使你功力大增。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;闭包是一种特殊的对象。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;它由两部分组成。执行上下文(代号A)，以及在该执行上下文中创建的函数（代号B）。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;当B执行时，如果访问了A中变量对象中的值，那么闭包就会产生。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在大多数理解中，包括许多著名的书籍，文章里都以函数B的名字代指这里生成的闭包。而在chrome中，则以执行上下文A的函数名代指闭包。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;因此我们只需要知道，一个闭包对象，由A、B共同组成，在以后的篇幅中，我将以chrome的标准来称呼。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的例子，首先有执行上下文foo，在foo中定义了函数bar，而通过对外返回bar的方式让bar得以执行。当bar执行时，访问了foo内部的变量a，b。因此这个时候闭包产生。&lt;/p&gt;</description></item><item><title>全方位解读this</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-008/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-008/</guid><description>&lt;p&gt;我们在学习JavaScript的过程中，由于对一些概念理解得不是很清楚，但是又想要通过一些方式把它记下来，于是就很容易草率的给这些概念定下一些方便自己记忆的有偏差的结论。&lt;/p&gt;
&lt;p&gt;危害比较大的是，有的不准确的结论在网上还广为流传。&lt;/p&gt;
&lt;p&gt;比如对于this指向的理解中，有这样一种说法：谁调用它，this就指向谁。在我刚开始学习this的时候，我是非常相信这句话的。因为在一些情况下，这样理解也还算说得通。可是我常常会在开发中遇到一些不一样的情况，一个由于this的错误调用，可以让我懵逼一整天。那个时候我也查资料，在群里问大神，可是我仍然搞不清楚“我特么到底错哪里了”。其实只是因为我心中有一个不太准确的结论。&lt;/p&gt;
&lt;p&gt;所以，我认为需要有这样一篇文章，来帮助大家全方位的解读this。让大家对this，有一个正确的，全面的认知。&lt;/p&gt;
&lt;p&gt;在这之前，我们需要来回顾一下执行上下文。&lt;/p&gt;
&lt;p&gt;在前面的几篇文章中，我有好几个地方都提到执行上下文的生命周期，为了防止大家没有记住，再次来回顾一下，如下图。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-008/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;在执行上下文的创建阶段，会分别生成变量对象，建立作用域链，确定this指向。其中变量对象与作用域链我们都已经仔细总结过了，而这里的关键，就是确定this指向。&lt;/p&gt;
&lt;p&gt;首先我们需要得出一个非常重要一定要牢记于心的结论，**this的指向，是在函数被调用的时候确定的。**也就是执行上下文被创建时确定的。因此，一个函数中的this指向，可以是非常灵活的。比如下面的例子中，同一个函数由于调用方式的不同，this指向了不一样的对象。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;除此之外，&lt;strong&gt;在函数执行过程中，this一旦被确定，就不可更改了。&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 这句话试图修改this，运行后会报错
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;一、全局对象中的this&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;关于全局对象的this，我之前在总结变量对象的时候提到过，它是一个比较特殊的存在。全局环境中的this，指向它本身。因此，这也相对简单，没有那么多复杂的情况需要考虑。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 通过this绑定到全局对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 通过声明绑定到变量对象，但在全局环境中，变量对象就是它自身
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 仅仅只有赋值操作，标识符会隐式绑定到全局对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;a3&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 输出结果会全部符合预期
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id="二函数中的this"&gt;二、函数中的this&lt;/h5&gt;
&lt;p&gt;在总结函数中this指向之前，我想我们有必要通过一些奇怪的例子，来感受一下函数中this的捉摸不定。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo02
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo03
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这几个例子需要花点时间仔细感受一下，如果你暂时没想明白怎么回事，也不用着急，我们一点一点来分析。&lt;/p&gt;</description></item><item><title>Promise</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/promise/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/promise/</guid><description>&lt;p&gt;Promise 是在 ES6 出现的新功能，并且是用来优化过去回调函式 callback 的写法。这篇面试详解中会讨论到， promise 是什么、为什么需要有 Promise，以及延伸到 async/await 相关问题。&lt;/p&gt;
&lt;h2 id="为什么要使用-promise"&gt;为什么要使用 Promise？&lt;/h2&gt;
&lt;p&gt;在探讨 Promise 之前，我们先来看一下为什么需要它的出现。&lt;/p&gt;
&lt;p&gt;JavaScript 中有一个重要概念 - 异步 (async)，它允许我们在执行耗时任务时，不必等待程式完成，而是继续执行下面的代码，直到任务完成再通知。常用的异步操作有：文件操作、数据库操作、AJAX 以及定时器等。&lt;/p&gt;
&lt;p&gt;JavaScript 有两种实现异步的方式：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一种：回调函式 callback function&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在 ES6 promise 出现之前，通常使用回调函式 (callback) 实现异步操作。但使用回调函式 callback 存在一个明显的缺点，当需要执行多个异步操作时，代码会不断往内嵌套，这种情况通常被称为「callback 地狱」(callback hell)。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而为了解决这种问题，就出现了第二种方法 - promise。&lt;/p&gt;
&lt;h2 id="什么是-promise"&gt;什么是 Promise？&lt;/h2&gt;
&lt;p&gt;上一段提到 Promise 出现的原因，这一段我们来看那到底 Promise 是什么。&lt;/p&gt;</description></item><item><title>Generator</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/generator/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/generator/</guid><description>&lt;h2 id="聊聊-for-of"&gt;聊聊 &lt;code&gt;for of&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;说起 &lt;code&gt;for of&lt;/code&gt; 相信每个写过 &lt;code&gt;JavaScript&lt;/code&gt; 的人都用过 &lt;code&gt;for of&lt;/code&gt; ，平时我们用它做什么呢？大多数情况应该就是遍历数组了，当然，更多时候，我们也会用 &lt;code&gt;map()&lt;/code&gt; 或者 &lt;code&gt;filer()&lt;/code&gt; 来遍历一个数组。 但是就像我们标题里面说的，它跟 &lt;code&gt;Generator&lt;/code&gt; 能扯上什么关系呢？&lt;/p&gt;
&lt;p&gt;首先我们想一个问题，为什么使用 &lt;code&gt;for of&lt;/code&gt; 或者 &lt;code&gt;map()&lt;/code&gt;/&lt;code&gt;filer()&lt;/code&gt; 方法就可以遍历一个数组 (或者类数组对象: &lt;code&gt;Strings&lt;/code&gt; , &lt;code&gt;Maps&lt;/code&gt; , &lt;code&gt;Sets&lt;/code&gt; , &lt;code&gt;arguments&lt;/code&gt; ) 呢？ 为什么不能用他们来遍历一个对象呢？&lt;/p&gt;
&lt;h2 id="你能学到什么"&gt;你能学到什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;对 &lt;code&gt;for of&lt;/code&gt; 更深入的理解&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iterator&lt;/code&gt; 到底是何方神圣?&lt;/li&gt;
&lt;li&gt;数组也是对象，为什么不能用 &lt;code&gt;for of&lt;/code&gt; 来遍历对象呢？&lt;/li&gt;
&lt;li&gt;如何实现对象的 &lt;code&gt;for of&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Generator&lt;/code&gt; 又是何方神圣？他有什么用呢？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="类数组对象的玄机"&gt;类数组对象的玄机&lt;/h2&gt;
&lt;p&gt;在真正揭开谜底之前，站在 &lt;code&gt;for of&lt;/code&gt; 的角度想一下，现在让你去遍历一个数组，你需要知道什么信息呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对应下标的值&lt;/li&gt;
&lt;li&gt;是否遍历结束的标志&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;带着这样的思考，我们打印一个数组来看看这里面的玄机：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;numbersArray&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dir&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;numbersArray&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/generator/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;数组 (或者类数组对象: &lt;code&gt;Strings&lt;/code&gt; , &lt;code&gt;Maps&lt;/code&gt; , &lt;code&gt;Sets&lt;/code&gt; , &lt;code&gt;arguments&lt;/code&gt; ) 的原型中都实现了一个方法 &lt;code&gt;Symbol.iterator&lt;/code&gt;，问题来了，那么这个 &lt;code&gt;Symbol.iterator&lt;/code&gt; 又有什么用呢？ 拿出来试一下就知道了：&lt;/p&gt;</description></item><item><title>函数与函数式编程</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-009/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-009/</guid><description>&lt;p&gt;纵观JavaScript中所有必须需要掌握的重点知识中，函数是我们在初学的时候最容易忽视的一个知识点。在学习的过程中，可能会有很多人、很多文章告诉你面向对象很重要，原型很重要，可是却很少有人告诉你，面向对象中所有的重点难点，几乎都与函数息息相关。&lt;/p&gt;
&lt;p&gt;包括之前几篇文章介绍的执行上下文，变量对象，闭包，this等，都是围绕函数的细节来展开。&lt;/p&gt;
&lt;p&gt;很多人在学习中，很急切的希望自己快一点开始学习面向对象，学习模块，学习流行框架，然后迅速成为高手。但是我可以很负责的告诉你，关于函数的这些基础东西没理解到一定程度，那么你的学习进展一定是举步维艰的。&lt;/p&gt;
&lt;p&gt;所以，大家一定要重视函数！&lt;/p&gt;
&lt;p&gt;当然，关于函数的重点，难点在前面几篇文章都已经说得差不多了，这篇文章主要总结一下函数的基础知识，并初步学习函数式编程的思维。&lt;/p&gt;
&lt;h5 id="一函数声明函数表达式匿名函数与自执行函数"&gt;一、函数声明、函数表达式、匿名函数与自执行函数&lt;/h5&gt;
&lt;p&gt;关于函数在实际开发中的应用，大体可以总结为函数声明、函数表达式、匿名函数、自执行函数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;函数声明&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们知道，JavaScript中，有两种声明方式，一个是使用&lt;code&gt;var&lt;/code&gt;的变量声明，另一个是使用&lt;code&gt;function&lt;/code&gt;的函数声明。&lt;/p&gt;
&lt;p&gt;在前端基础进阶（三）：变量对象详解中我有提到过，变量对象的创建过程中，函数声明比变量声明具有更为优先的执行顺序，即我们常常提到的函数声明提前。因此我们在执行上下文中，无论在什么位置声明了函数，我们都可以在同一个执行上下文中直接使用该函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;函数表达式&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;与函数声明不同，函数表达式使用了var进行声明，那么我们在确认他是否可以正确使用的时候就必须依照var的规则进行判断，即变量声明。我们知道使用var进行变量声明，其实是进行了两步操作。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 变量声明
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 实际执行顺序
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量声明，初始值undefined，变量提升，提升顺序次于function声明
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量赋值，该操作不会提升
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同样的道理，当我们使用变量声明的方式来声明函数时，就是我们常常说的函数表达式。函数表达的提升方式与变量声明一致。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 报错
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上例子的执行顺序为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量声明提升
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 执行报错
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() { &lt;span style="color:#75715e"&gt;// 赋值操作，此时将后边函数的引用赋值给fn
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;因此，由于声明方式的不同，导致了函数声明与函数表达式在使用上的一些差异需要我们注意，除此之外，这两种形式的函数在使用上并无不同。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;关于上面例子中，函数表达式中的赋值操作，在其他一些地方也会被经常使用，我们清楚其中的关系即可。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;在构造函数中添加方法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;age&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 在构造函数内部中添加方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getAge&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 给原型添加方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在对象中添加方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;getM&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;匿名函数&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Async/Await</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/async-await/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/async-await/</guid><description>&lt;h2 id="asyncawait用法"&gt;async/await用法&lt;/h2&gt;
&lt;p&gt;其实你要实现一个东西之前，最好是先搞清楚这两样东西&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这个东西有什么用？&lt;/li&gt;
&lt;li&gt;这个东西是怎么用的？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="有什么用"&gt;有什么用？&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;async/await&lt;/code&gt;的用处就是：&lt;strong&gt;用同步方式，执行异步操作&lt;/strong&gt;，怎么说呢？举个例子&lt;/p&gt;
&lt;p&gt;比如我现在有一个需求：先请求完&lt;code&gt;接口1&lt;/code&gt;，再去请求&lt;code&gt;接口2&lt;/code&gt;，我们通常会这么做&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// 模拟接口请求
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Promise(&lt;span style="color:#a6e22e"&gt;resolve&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;resolve&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;num&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 1秒后 输出 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 2秒后 输出 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者我现在又有一个需求：先请求完&lt;code&gt;接口1&lt;/code&gt;，再拿&lt;code&gt;接口1&lt;/code&gt;返回的数据，去当做&lt;code&gt;接口2&lt;/code&gt;的请求参数，那我们也可以这么做&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 1秒后 输出 10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 2秒后 输出 20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实这么做是没问题的，但是如果嵌套的多了，不免有点不雅观，这个时候就可以用&lt;code&gt;async/await&lt;/code&gt;来解决了&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 2秒后输出 20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="是怎么用"&gt;是怎么用？&lt;/h3&gt;
&lt;p&gt;还是用刚刚的例子&lt;/p&gt;</description></item><item><title>函数柯里化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-010/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-010/</guid><description>&lt;p&gt;柯里化是函数的一个比较高级的应用，想要理解它并不简单。&lt;/p&gt;
&lt;p&gt;通过《函数与函数式编程》的学习，我们知道，接收函数作为参数的函数，都可以叫做高阶函数。我们常常利用高阶函数来封装一些公共的逻辑。&lt;/p&gt;
&lt;p&gt;我们接下来要学习的柯里化，其实就是高阶函数的一种特殊用法。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;柯里化是指这样一个函数(假设叫做createCurry)，他接收函数A作为参数，运行后能够返回一个新的函数。并且这个新的函数能够处理函数A的剩余参数。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这样的定义可能不太好理解，我们可以通过下面的例子配合理解。&lt;/p&gt;
&lt;p&gt;假如有一个接收三个参数的函数A。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;A&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// do something
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;又假如我们有一个已经封装好了的柯里化通用函数createCurry。他接收bar作为参数，能够将A转化为柯里化函数，返回结果就是这个被转化之后的函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_A&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createCurry&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;A&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么_A作为createCurry运行的返回函数，他能够处理A的剩余参数。因此下面的运行结果都是等价的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_A&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_A&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_A&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_A&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;A&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;函数A被createCurry转化之后得到柯里化函数_A，_A能够处理A的所有剩余参数。因此柯里化也被称为部分求值。&lt;/p&gt;
&lt;p&gt;在简单的场景下，我们可以不用借助柯里化通用式来转化得到柯里化函数，我们可以凭借眼力自己封装。&lt;/p&gt;
&lt;p&gt;例如有一个简单的加法函数，他能够将自身的三个参数加起来并返回计算结果。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么add函数的柯里化函数_add则可以如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_add&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因此下面的运算方式是等价的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_add&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当然，柯里化通用式具备更加强大的能力，我们靠眼力自己封装的柯里化函数则自由度偏低。因此我们仍然需要知道自己如何去封装这样一个柯里化的通用式。&lt;/p&gt;
&lt;p&gt;首先通过_add可以看出，柯里化函数的运行过程其实是一个参数的收集过程，我们将每一次传入的参数收集起来，并在最里层里面处理。因此我们在实现createCurry时，可以借助这个思路来进行封装。&lt;/p&gt;
&lt;p&gt;封装如下:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 简单实现，参数只能从右到左传递
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createCurry&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;func&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arity&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;func&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; [];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_args&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [].&lt;span style="color:#a6e22e"&gt;slice&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arguments&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [].&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;_args&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 如果参数个数小于最初的func.length，则递归调用，继续收集参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;_args&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arity&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createCurry&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;func&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;_args&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 参数收集完毕，则执行func
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;func&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;_args&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;尽管我已经做了足够详细的注解，但是我想理解起来也并不是那么容易，因此建议大家用点耐心多阅读几遍。这个createCurry函数的封装借助闭包与递归，实现了一个参数收集，并在收集完毕之后执行所有参数的一个过程。&lt;/p&gt;</description></item><item><title>Class</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/class/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/class/</guid><description>&lt;h2 id="class-的基本语法"&gt;Class 的基本语法&lt;/h2&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;h3 id="类的由来"&gt;类的由来&lt;/h3&gt;
&lt;p&gt;JavaScript 语言中，生成实例对象的传统方法是通过构造函数。下面是一个例子。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;(&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;, &amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面这种写法跟传统的面向对象语言（比如 C++ 和 Java）差异很大，很容易让新学习这门语言的程序员感到困惑。&lt;/p&gt;
&lt;p&gt;ES6 提供了更接近传统语言的写法，引入了 Class（类）这个概念，作为对象的模板。通过&lt;code&gt;class&lt;/code&gt;关键字，可以定义类。&lt;/p&gt;
&lt;p&gt;基本上，ES6 的&lt;code&gt;class&lt;/code&gt;可以看作只是一个语法糖，它的绝大部分功能，ES5 都可以做到，新的&lt;code&gt;class&lt;/code&gt;写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用 ES6 的&lt;code&gt;class&lt;/code&gt;改写，就是下面这样。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;(&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;, &amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面代码定义了一个“类”，可以看到里面有一个&lt;code&gt;constructor()&lt;/code&gt;方法，这就是构造方法，而&lt;code&gt;this&lt;/code&gt;关键字则代表实例对象。这种新的 Class 写法，本质上与本章开头的 ES5 的构造函数&lt;code&gt;Point&lt;/code&gt;是一致的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Point&lt;/code&gt;类除了构造方法，还定义了一个&lt;code&gt;toString()&lt;/code&gt;方法。注意，定义&lt;code&gt;toString()&lt;/code&gt;方法的时候，前面不需要加上&lt;code&gt;function&lt;/code&gt;这个关键字，直接把函数定义放进去了就可以了。另外，方法与方法之间不需要逗号分隔，加了会报错。&lt;/p&gt;
&lt;p&gt;ES6 的类，完全可以看作构造函数的另一种写法。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt; &lt;span style="color:#75715e"&gt;// &amp;#34;function&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt; &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面代码表明，类的数据类型就是函数，类本身就指向构造函数。&lt;/p&gt;
&lt;p&gt;使用的时候，也是直接对类使用&lt;code&gt;new&lt;/code&gt;命令，跟构造函数的用法完全一致。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Bar&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;doStuff&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;stuff&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Bar&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;doStuff&lt;/span&gt;() &lt;span style="color:#75715e"&gt;// &amp;#34;stuff&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;构造函数的&lt;code&gt;prototype&lt;/code&gt;属性，在 ES6 的“类”上面继续存在。事实上，类的所有方法都定义在类的&lt;code&gt;prototype&lt;/code&gt;属性上面。&lt;/p&gt;</description></item><item><title>原型链与继承</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/</guid><description>&lt;p&gt;&lt;code&gt;JavaScript&lt;/code&gt; 中没有类的概念的，主要通过原型链来实现继承。通常情况下，继承意味着复制操作，然而 &lt;code&gt;JavaScript&lt;/code&gt; 默认并不会复制对象的属性，相反，&lt;code&gt;JavaScript&lt;/code&gt; 只是在两个对象之间创建一个关联（原型对象指针），这样，一个对象就可以通过委托访问另一个对象的属性和函数，所以与其叫继承，委托的说法反而更准确些。&lt;/p&gt;
&lt;h2 id="原型"&gt;原型&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;当我们 &lt;code&gt;new&lt;/code&gt; 了一个新的对象实例，明明什么都没有做，就直接可以访问 &lt;code&gt;toString&lt;/code&gt; 、&lt;code&gt;valueOf&lt;/code&gt; 等原生方法。那么这些方法是从哪里来的呢？答案就是原型。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;在控制台打印一个空对象时，我们可以看到，有很多方法，已经“初始化”挂载在内置的 &lt;code&gt;__proto__&lt;/code&gt; 对象上了。这个内置的 &lt;code&gt;__proto__&lt;/code&gt; 是一个指向原型对象的指针，它会在创建一个新的引用类型对象时（显示或者隐式）自动创建，并挂载到新实例上。当我们尝试访问实例对象上的某一属性 / 方法时，如果实例对象上有该属性 / 方法时，就返回实例属性 / 方法，如果没有，就去 &lt;code&gt;__proto__&lt;/code&gt; 指向的原型对象上查找对应的属性 / 方法。这就是为什么我们尝试访问空对象的 &lt;code&gt;toString&lt;/code&gt; 和 &lt;code&gt;valueOf&lt;/code&gt; 等方法依旧能访问到的原因，&lt;strong&gt;&lt;code&gt;JavaScript&lt;/code&gt; 正式以这种方式为基础来实现继承的。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="构造函数"&gt;构造函数&lt;/h2&gt;
&lt;p&gt;如果说实例的 &lt;code&gt;__proto__&lt;/code&gt; 只是一个指向原型对象的指针，那就说明在此之前原型对象就已经创建了，那么原型对象是什么时候被创建的呢？这就要引入&lt;strong&gt;构造函数&lt;/strong&gt;的概念。&lt;/p&gt;
&lt;p&gt;其实构造函数也就只是一个普通的函数而已，如果这个函数可以使用 &lt;code&gt;new&lt;/code&gt; 关键字来创建它的实例对象，那么我们就把这种函数称为 &lt;strong&gt;构造函数&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 普通函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt; () {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 构造函数，函数首字母通常大写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; () {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;原型对象正是在构造函数被声明时一同创建的。构造函数被申明时，原型对象也一同完成创建，然后挂载到构造函数的 &lt;code&gt;prototype&lt;/code&gt; 属性上：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;原型对象被创建时，会自动生成一个 &lt;code&gt;constructor&lt;/code&gt; 属性，指向创建它的构造函数。这样它俩的关系就被紧密地关联起来了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;细心的话，你可能会发现，原型对象也有自己的 &lt;code&gt;__proto__&lt;/code&gt; ，这也不奇怪，毕竟万物皆对象嘛。原型对象的 &lt;strong&gt;proto&lt;/strong&gt; 指向的是 &lt;code&gt;Object.prototype&lt;/code&gt;。那么 &lt;code&gt;Object.prototype.__proto__&lt;/code&gt; 存不存在呢？其实是不存在的，打印的话会发现是 &lt;code&gt;null&lt;/code&gt; 。这也证明了 &lt;code&gt;Object&lt;/code&gt; 是 &lt;code&gt;JavaScript&lt;/code&gt; 中数据类型的起源。&lt;/p&gt;</description></item><item><title>Map与Set</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-012/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-012/</guid><description>&lt;p&gt;每当去学习ES6的时候，我都会不由自主的打开阮一峰老师的&lt;a href="http://es6.ruanyifeng.com/#docs/set-map"&gt;《ES6入门》&lt;/a&gt;去学习和查找用法，相信大多数同学也都和我一样看过阮老师写的文章。&lt;/p&gt;
&lt;p&gt;当然大家也都知道ES6里常用的API就那么些，不多不少，用在项目中也是刚刚好。&lt;/p&gt;
&lt;p&gt;不过在每次读到Set和Map数据结构那一章的时候，总是有点不知所措，因为我不明白实现这样的数据结构，目的是什么，意义又是什么呢&lt;/p&gt;
&lt;p&gt;Set和Map主要的应用场景在于&lt;strong&gt;数组去重&lt;/strong&gt;和&lt;strong&gt;数据存储&lt;/strong&gt;，幸运的是在读了关于数据结构和算法之类的书籍后，恍然大悟的发现&lt;/p&gt;
&lt;p&gt;原来Set是一种叫做&lt;strong&gt;集合&lt;/strong&gt;的数据结构，Map是一种叫做&lt;strong&gt;字典&lt;/strong&gt;的数据结构&lt;/p&gt;
&lt;p&gt;那么下面就来了解下这两种数据结构，最后来亲手实现的一个ES6中的Set和Map吧&lt;/p&gt;
&lt;h3 id="集合"&gt;集合&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;集合是由一组无序且唯一(即不能重复)的项组成的，可以想象成集合是一个既没有重复元素，也没有顺序概念的数组&lt;/li&gt;
&lt;li&gt;ES6提供了新的数据结构Set。它类似于数组，但是成员的值都是唯一的，没有重复的值&lt;/li&gt;
&lt;li&gt;Set 本身是一个构造函数，用来生成 Set 数据结构&lt;/li&gt;
&lt;li&gt;这里说的Set其实就是我们所要讲到的集合，先来看下基础用法&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const s &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new Set&lt;span style="color:#f92672"&gt;()&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2, 3, 5, 4, 5, 2, 2&lt;span style="color:#f92672"&gt;]&lt;/span&gt;.forEach&lt;span style="color:#f92672"&gt;(&lt;/span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; s.add&lt;span style="color:#f92672"&gt;(&lt;/span&gt;x&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;let i of s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;i&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; // &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 去除数组的重复成员
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let array &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1,2,1,4,5,3&lt;span style="color:#f92672"&gt;]&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;...new Set&lt;span style="color:#f92672"&gt;(&lt;/span&gt;array&lt;span style="color:#f92672"&gt;)]&lt;/span&gt; // &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1, 2, 4, 5, 3&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;具体用法如果还有不清楚的，这里我会在后面一一细说。现在还是来看一下以ES6中Set类(数据结构)为基础实现的集合吧&lt;/p&gt;
&lt;h4 id="set实例的属性和方法"&gt;Set实例的属性和方法&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Set的属性：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;size：返回集合所包含元素的数量&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set的方法：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;操作方法&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;add(value)：向集合添加一个新的项&lt;/li&gt;
&lt;li&gt;delete(value)：从集合中移除一个值&lt;/li&gt;
&lt;li&gt;has(value)：如果值在集合中存在，返回true,否则false&lt;/li&gt;
&lt;li&gt;clear(): 移除集合里所有的项&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;遍历方法&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;keys()：返回一个包含集合中所有键的数组&lt;/li&gt;
&lt;li&gt;values()：返回一个包含集合中所有值的数组&lt;/li&gt;
&lt;li&gt;entries：返回一个包含集合中所有键值对的数组(感觉没什么用就不实现了)&lt;/li&gt;
&lt;li&gt;forEach()：用于对集合成员执行某种操作，没有返回值&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="创建一个集合"&gt;创建一个集合&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; Set&lt;span style="color:#f92672"&gt;(&lt;/span&gt;arr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;[])&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; // 可以传入数组
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let items &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; this.size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0; // 记录集合中成员的数量
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;module.exports &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Set;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里用{}对象来表示集合，也是因为对象不允许一个键指向两个不同的属性，保证了集合里的元素都是唯一的&lt;/p&gt;</description></item><item><title>高阶函数</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-012/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-012/</guid><description>&lt;p&gt;高阶函数是指那些可以接受函数作为参数或者返回函数作为结果的函数。这种特性使得JavaScript的函数变得异常灵活和强大，为开发者提供了丰富的工具和手段来编写更加简洁、可重用和模块化的代码。&lt;/p&gt;
&lt;p&gt;本文将详细介绍JavaScript高阶函数的概念、特性、常见用法以及在实际开发中的应用。&lt;/p&gt;
&lt;h4 id="一高阶函数的概念"&gt;一、高阶函数的概念&lt;/h4&gt;
&lt;p&gt;高阶函数是函数式编程中的一个核心概念。在JavaScript中，函数是一等公民，这意味着函数可以像其他数据类型（如数字、字符串、对象等）一样被传递和操作。高阶函数正是利用了这一特性，使得函数可以作为参数传递给其他函数，或者作为其他函数的返回值。&lt;/p&gt;
&lt;h4 id="二高阶函数的特性"&gt;二、高阶函数的特性&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;函数作为参数&lt;/strong&gt;：高阶函数可以接受一个或多个函数作为参数。这使得我们可以将特定的行为（即函数）作为参数传递给高阶函数，从而实现更加灵活和可重用的代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数作为返回值&lt;/strong&gt;：高阶函数可以返回一个函数作为结果。这种特性允许我们创建可以动态生成新函数的函数，这些新函数可以根据需要执行不同的行为。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;闭包&lt;/strong&gt;：闭包是高阶函数的一个重要特性。闭包允许函数访问其外部作用域中的变量，即使该函数在其外部作用域之外执行。这使得高阶函数可以捕获和存储状态，从而创建更加复杂和强大的函数行为。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="三高阶函数的常见用法"&gt;三、高阶函数的常见用法&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数组方法&lt;/strong&gt;：JavaScript中的数组方法（如&lt;code&gt;map&lt;/code&gt;、&lt;code&gt;filter&lt;/code&gt;、&lt;code&gt;reduce&lt;/code&gt;等）都是高阶函数的典型例子。这些方法接受一个函数作为参数，并对数组中的每个元素执行该函数，从而返回一个新的数组或单一结果。&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;map&lt;/code&gt;方法：用于创建一个新数组，其结果是该数组中的每个元素调用一个提供的函数后返回的结果。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;filter&lt;/code&gt;方法：创建一个新数组，其包含通过所提供函数实现的测试的所有元素。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reduce&lt;/code&gt;方法：对数组中的每个元素执行一个由您提供的reducer函数(升序执行)，将其结果汇总为单个返回值。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;函数组合&lt;/strong&gt;：函数组合是指将多个函数组合在一起形成一个新的函数。通过高阶函数，我们可以轻松地将多个函数组合在一起，从而创建一个更加复杂和强大的函数。这种技术在实际开发中非常有用，特别是当我们需要处理一系列转换或操作时。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;柯里化&lt;/strong&gt;：柯里化是一种将接收多个参数的函数转换为一系列接收单一参数的函数的技术。虽然柯里化本身不是高阶函数，但高阶函数在实现柯里化时扮演着重要角色。通过高阶函数，我们可以创建一个接受原始函数作为参数的柯里化函数，并返回一个新的函数来处理单一参数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创建高阶函数&lt;/strong&gt;：我们可以编写自己的高阶函数来实现特定的行为。例如，我们可以编写一个高阶函数来接受一个函数和一个数组作为参数，并返回该数组中应用该函数后的结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="四高阶函数在实际开发中的应用"&gt;四、高阶函数在实际开发中的应用&lt;/h4&gt;
&lt;h4 id="1-数据转换"&gt;1. 数据转换&lt;/h4&gt;
&lt;p&gt;高阶函数非常适合用于数据的转换和映射。例如，我们可以使用&lt;code&gt;Array.prototype.map&lt;/code&gt;方法将一个数组中的每个元素转换为另一种形式。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 定义一个高阶函数，它接受一个转换函数和一个数组作为参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transformArray&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;transformFn&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;array&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;array&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;map&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;transformFn&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 定义一个简单的转换函数，将数字转换为它的平方
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;square&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; =&amp;gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用高阶函数和转换函数来处理数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;numbers&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;squaredNumbers&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transformArray&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;square&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;numbers&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;squaredNumbers&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 输出: [1, 4, 9, 16, 25]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个例子中，&lt;code&gt;transformArray&lt;/code&gt;是一个高阶函数，它接受一个转换函数&lt;code&gt;transformFn&lt;/code&gt;和一个数组&lt;code&gt;array&lt;/code&gt;作为参数。然后，它使用&lt;code&gt;Array.prototype.map&lt;/code&gt;方法来遍历数组，并对每个元素应用转换函数。&lt;/p&gt;
&lt;h4 id="2-事件处理"&gt;2. 事件处理&lt;/h4&gt;
&lt;p&gt;在Web开发中，事件处理是一个常见的任务。通过高阶函数，我们可以创建更加灵活和可重用的事件处理器。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 定义一个高阶函数，它接受一个事件处理函数和一个事件类型作为参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createEventHandler&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;handlerFn&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;eventType&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;type&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eventType&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handlerFn&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 定义一个简单的事件处理函数，用于打印事件信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;logEvent&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt; =&amp;gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`Event type: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Target: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 创建一个点击事件处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handleClick&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createEventHandler&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;logEvent&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 假设我们有一个DOM元素，我们可以为它添加事件监听器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// const button = document.querySelector(&amp;#39;button&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// button.addEventListener(&amp;#39;click&amp;#39;, handleClick);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 为了演示，我们直接调用处理器并传递一个模拟的事件对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mockEvent&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;body&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;handleClick&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;mockEvent&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 输出: Event type: click, Target: [object HTMLBodyElement]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个例子中，&lt;code&gt;createEventHandler&lt;/code&gt;是一个高阶函数，它接受一个事件处理函数&lt;code&gt;handlerFn&lt;/code&gt;和一个事件类型&lt;code&gt;eventType&lt;/code&gt;作为参数，并返回一个新的函数。这个新的函数会检查传入的事件对象的类型是否与指定的事件类型匹配，如果匹配，则调用事件处理函数。&lt;/p&gt;</description></item><item><title>WeakMap 和 WeakSet</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/</guid><description>&lt;h2 id="1-什么是-weakset"&gt;1. 什么是 WeakSet&lt;/h2&gt;
&lt;p&gt;WeakSet 结构与 Set 类似，也是不重复的值的集合，具备&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;WeakSet.prototype.add(value)&lt;/strong&gt; ：向 WeakSet 实例添加一个新成员。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WeakSet.prototype.delete(value)&lt;/strong&gt; ：清除 WeakSet 实例的指定成员。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WeakSet.prototype.has(value)&lt;/strong&gt; ：返回一个布尔值，表示某个值是否在 WeakSet 实例之中。 这三个方法。但是，它与 Set 有两个区别。&lt;/li&gt;
&lt;/ul&gt;
&lt;h6 id="区别一weakset-的成员只能是对象和symbol类型而不能是其他类型的值我们用代码演示一下"&gt;区别一：WeakSet 的成员只能是对象和Symbol类型，而不能是其他类型的值，我们用代码演示一下&lt;/h6&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;从代码中可以看到，想像Set一样直接往 WeakSet 中添加原始类型化会报错，只能添加对象和Symbol&lt;/p&gt;
&lt;h6 id="区别二这是核心-weakset-中的对象都是弱引用即垃圾回收机制不考虑-weakset-对该对象的引用也就是说如果其他对象都不再引用该对象那么垃圾回收机制会自动回收该对象所占用的内存不考虑该对象还存在于-weakset-之中"&gt;区别二&lt;code&gt;(这是核心)&lt;/code&gt;： WeakSet 中的对象都是弱引用，即垃圾回收机制不考虑 WeakSet 对该对象的引用，也就是说，如果其他对象都不再引用该对象，那么垃圾回收机制会自动回收该对象所占用的内存，不考虑该对象还存在于 WeakSet 之中。&lt;/h6&gt;
&lt;p&gt;（这句解释来自&lt;code&gt;ECMAScript 6 入门&lt;/code&gt;,第一眼看到这句话这话会觉得有点晦涩，我们来解释一下）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;弱引用&lt;/strong&gt;：垃圾回收机制有一套自己的回收算法，我们都知道一个函数执行完成后该函数在调用栈中创建的执行上下文会被销毁，这里说的销毁，其实指的就是执行上下文中环境变量、词法变量中的数据存储所占据的内存空间被垃圾回收机制所回收，那么&lt;code&gt;垃圾回收机制不考虑 WeakSet 对该对象的引用&lt;/code&gt;是不是就意味着垃圾回收机制不会回收 WeakSet 对象里面的数据所占据的内存呢？不！不是的！代码是最好的解释&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;我们用 ws 中存放一个对象，然后再将该对象置为null，（这里要说明一下，一个变量被置为null，就意味着这个变量的内存可以被回收了）看着这个打印结果有没有突然明白了点什么，对！没错！只要 WeakSet 结构中的对象不再需要被引用，那么 WeakSet 就直接为空了，这不就意味着WeakSet中的数据所占据的内存被释放了吗。好的，你或许还会有疑问，难道不用 WeakSet 存储数据，结果就不是这样的吗，来打消你的疑虑&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/image-03.webp"&gt; 不使用 WeakSet 存放数据，当变量obj为null时，fistName依旧是有值的，对比这段代码，我们可以清晰的看出, WeakSet中 - &lt;code&gt;垃圾回收机制会自动回收该对象所占用的内存&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="2-这里有bug"&gt;2. 这里有&amp;rsquo;BUG'&lt;/h2&gt;
&lt;p&gt;可能已经有小伙伴拔出了他40米长的大剑了，上图二中的代码其实有问题，真实的打印应该是&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;各位手中的长剑收一收，先别急，其实我们前面聊的没有问题，为什么这里真是打印能出来结果呢？这个问题在国外某技术论坛上也是一度出现在 WeakSet 话题榜首位，&lt;strong&gt;解释为：因为浏览器的垃圾回收机制是不受我们控制的，我们无法知道垃圾回收机制什么时候执行，之所以打印能出现内容，其实是因为打印的时候垃圾回收机制没有启动。所以我们可以认为，上图二中的打印在垃圾回收启动之后，它就是空的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们可以这样来证明它:&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;如果这样你觉得依旧不够睡服你自己的话，我们把这段代码搬到node中：&lt;/p&gt;</description></item><item><title>异步编程</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-013/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-013/</guid><description>&lt;p&gt;浏览器中的JavaScript程序是典型的事件驱动型程序，即它们会等待用户触发后才真正的执行，而基于的JavaScript的服务器通常要等待客户端通过网络发送请求，然后才能执行。这种异步编程在JavaScript是很常见的，下面就来介绍几个异步编程的重要特性，它们可以使编写异步代码更容易。&lt;/p&gt;
&lt;p&gt;本文将按照异步编程方式的出现时间来归纳整理： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-013/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="一什么是异步"&gt;一、什么是异步&lt;/h2&gt;
&lt;p&gt;下面先来看看同步和异步的概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;同步：&lt;/strong&gt; 在执行某段代码时，在没有得到返回结果之前，其他代码暂时是无法执行的，但是一旦执行完成拿到返回值，即可执行其他代码。也就是说，在此段代码执行完未返回结果之前，会阻塞之后的代码执行，这样的情况称为同步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步：&lt;/strong&gt; 当某一代码执行异步过程调用发出后，这段代码不会立刻得到返回结果。而是在异步调用发出之后，一般通过回调函数处理这个调用之后拿到结果。异步调用发出后，不会影响阻塞后面的代码执行，这样的情况称为异步。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面来看一个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 同步
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;syncAdd&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;syncAdd&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 立即得到结果：3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异步
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;asyncAdd&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  }, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;asyncAdd&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 1s后打印结果：3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里定义了同步函数 syncAdd 和异步函数 asyncAdd，调用 syncAdd(1, 2) 函数时会等待得到结果之后再执行后面的代码。而调用 asyncAdd(1, 2) 时则会在得到结果之前继续执行，直到 1 秒后得到结果并打印。&lt;/p&gt;
&lt;p&gt;我们知道，JavaScript 是单线程的，如果代码同步执行，就可能会造成阻塞；而如果使用异步则不会阻塞，不需要等待异步代码执行的返回结果，可以继续执行该异步任务之后的代码逻辑。因此，在 JavaScript 编程中，会大量使用异步。&lt;/p&gt;
&lt;p&gt;那为什么单线程的JavaScript还能实现异步呢，其实也没有什么魔法，只是把一些操作交给了其他线程处理，然后采用了&lt;strong&gt;事件循环&lt;/strong&gt;的机制来处理返回结果。&lt;/p&gt;
&lt;h2 id="二回调函数"&gt;二、回调函数&lt;/h2&gt;
&lt;p&gt;在最基本的层面上，JavaScript的异步编程式通过回调实现的。回调的是函数，可以传给其他函数，而其他函数会在满足某个条件时调用这个函数。下面就来看看常见的不同形式的基于回调的异步编程。&lt;/p&gt;
&lt;h3 id="1-定时器"&gt;1. 定时器&lt;/h3&gt;
&lt;p&gt;一种最简单的异步操作就是在一定时间之后运行某些代码。如下面代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;asyncAdd&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;), &lt;span style="color:#ae81ff"&gt;8000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;setTimeout()&lt;/code&gt;方法的第一个参数是一个函数，第二个参数是以毫秒为单位的时间间隔。&lt;code&gt;asyncAdd()&lt;/code&gt;方法可能是一个回调函数，而&lt;code&gt;setTimeout()&lt;/code&gt;方法就是注册回调函数的函数。它还代指在什么异步条件下调用回调函数。&lt;code&gt;setTimeout()&lt;/code&gt;方法只会调用一次回调函数。&lt;/p&gt;
&lt;h3 id="2-事件监听"&gt;2. 事件监听&lt;/h3&gt;
&lt;p&gt;给目标 DOM 绑定一个监听函数，用的最多的是 &lt;code&gt;addEventListener&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;#myDiv&amp;#39;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;我被点击了&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过给 id 为 &lt;code&gt;myDiv&lt;/code&gt; 的一个元素绑定了点击事件的监听函数，把任务的执行时机推迟到了点击这个动作发生时。此时，&lt;strong&gt;任务的执行顺序与代码的编写顺序无关，只与点击事件有没有被触发有关&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>defineProperty 与 proxy</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-014/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-014/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;我们或多或少都听过“数据绑定”这个词，“数据绑定”的关键在于监听数据的变化，可是对于这样一个对象：&lt;code&gt;var obj = {value: 1}&lt;/code&gt;，我们该怎么知道 obj 发生了改变呢？&lt;/p&gt;
&lt;h2 id="definepropety"&gt;definePropety&lt;/h2&gt;
&lt;p&gt;ES5 提供了 Object.defineProperty 方法，该方法可以在一个对象上定义一个新属性，或者修改一个对象的现有属性，并返回这个对象。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;语法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Object.defineProperty(obj, prop, descriptor)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; 要在其上定义属性的对象。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;prop&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; 要定义或修改的属性的名称。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;descriptor&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; 将被定义或修改的属性的描述符。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;举个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Object.&lt;span style="color:#a6e22e"&gt;defineProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;num&amp;#34;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;writable&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;enumerable&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;configurable&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 对象 obj 拥有属性 num，值为 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然我们可以直接添加属性和值，但是使用这种方式，我们能进行更多的配置。&lt;/p&gt;
&lt;p&gt;函数的第三个参数 descriptor 所表示的属性描述符有两种形式：&lt;strong&gt;数据描述符和存取描述符&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;两者均具有以下两种键值&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;configurable&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-arduino" data-lang="arduino"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;当且仅当该属性的&lt;/span&gt; configurable &lt;span style="color:#960050;background-color:#1e0010"&gt;为&lt;/span&gt; true &lt;span style="color:#960050;background-color:#1e0010"&gt;时，该属性描述符才能够被改变，也能够被删除。默认为&lt;/span&gt; false&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;enumerable&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-arduino" data-lang="arduino"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;当且仅当该属性的&lt;/span&gt; enumerable &lt;span style="color:#960050;background-color:#1e0010"&gt;为&lt;/span&gt; true &lt;span style="color:#960050;background-color:#1e0010"&gt;时，该属性才能够出现在对象的枚举属性中。默认为&lt;/span&gt; false&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;数据描述符同时具有以下可选键值&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;value&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;该属性对应的值&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;可以是任何有效的&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;JavaScript&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;值&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;（&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;数值&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;对象&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;函数等&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;）。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;默认为&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;writable&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-arduino" data-lang="arduino"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;当且仅当该属性的&lt;/span&gt; writable &lt;span style="color:#960050;background-color:#1e0010"&gt;为&lt;/span&gt; true &lt;span style="color:#960050;background-color:#1e0010"&gt;时，该属性才能被赋值运算符改变。默认为&lt;/span&gt; false&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;存取描述符同时具有以下可选键值&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;get&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;一个给属性提供&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getter&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;的方法&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;如果没有&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getter&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;则为&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;该方法返回值被用作属性值&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;默认为&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;set&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;一个给属性提供&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setter&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;的方法&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;如果没有&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setter&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;则为&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;该方法将接受唯一参数&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;并将该参数的新值分配给该属性&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;默认为&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;值得注意的是：&lt;/p&gt;</description></item><item><title>事件循环</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-014/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-014/</guid><description>&lt;h2 id="单线程的-javascript"&gt;单线程的 JavaScript&lt;/h2&gt;
&lt;h3 id="同步与异步"&gt;同步与异步&lt;/h3&gt;
&lt;p&gt;JavaScript 在设计之初是作为&lt;strong&gt;浏览器脚本语言&lt;/strong&gt;，主要用于与用户进行&lt;strong&gt;页面交互&lt;/strong&gt;和&lt;strong&gt;操纵 DOM&lt;/strong&gt;。因此，为避免由不可预测的用户操作可能带来的复杂的并发问题，JavaScript 只能设计成&lt;strong&gt;单线程&lt;/strong&gt;的，这也是这门语言的核心特征之一。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JS 的宿主环境通过仅提供一个线程运行 JS 来保证 JS 代码的单线程运行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;单线程意味着 JS 引擎在同一时间只能做一件事情，即&lt;strong&gt;同步&lt;/strong&gt;地执行代码。但在代码执行过程中不可避免地会遇到一些&lt;strong&gt;无法立即执行&lt;/strong&gt;的任务，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;计时器到达时间后要执行的任务 &amp;mdash; &lt;code&gt;setInterval&lt;/code&gt;、&lt;code&gt;setTimeout&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;网络请求完成后要执行的任务 &amp;mdash; &lt;code&gt;XMLHttpRequest&lt;/code&gt;、&lt;code&gt;Fetch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;监听到用户操作后要执行的任务 &amp;mdash; &lt;code&gt;addEventListener&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;hellip; &amp;hellip; &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果让执行 JS 的线程去处理这些任务，就会导致该线程处于&lt;strong&gt;长期阻塞&lt;/strong&gt;的状态，而宿主环境中的 JS 执行线程往往还承担着极其重要的工作。例如，在浏览器中，如果执行 JS 的线程长期阻塞，就会导致浏览器卡死！&lt;/p&gt;
&lt;p&gt;为避免上述情况发生，JS 的宿主环境使用了&lt;strong&gt;异步&lt;/strong&gt;的方式来处理这种无法立即执行的任务。&lt;/p&gt;
&lt;p&gt;当遇到异步任务时，宿主环境会将其交给&lt;strong&gt;其他线程&lt;/strong&gt;处理，执行 JS 的线程则会立即结束当前任务转而去执行后续代码。&lt;/p&gt;
&lt;h3 id="事件循环"&gt;事件循环&lt;/h3&gt;
&lt;p&gt;事件循环是宿主环境处理 JS 异步操作，让其能够&lt;strong&gt;非阻塞式运行&lt;/strong&gt;的机制。&lt;/p&gt;
&lt;p&gt;不同宿主环境对事件循环的实现方式有所不同，不过在核心机制上大同小异。&lt;/p&gt;
&lt;p&gt;接下来，本文将详细描述 JavaScript 在&lt;strong&gt;浏览器&lt;/strong&gt;和 &lt;strong&gt;Node.js&lt;/strong&gt; 这两个宿主环境中的事件循环机制。&lt;/p&gt;
&lt;h2 id="浏览器事件循环"&gt;浏览器事件循环&lt;/h2&gt;
&lt;h3 id="浅谈浏览器"&gt;浅谈浏览器&lt;/h3&gt;
&lt;p&gt;聊浏览器的事件循环之前，我们先说说浏览器本身。&lt;/p&gt;
&lt;p&gt;现代浏览器是一个&lt;strong&gt;多进程多线程&lt;/strong&gt;的应用程序，内部工作极其复杂，其程度直逼操作系统。它拥有数个功能模块，为避免单个模块崩溃牵连其他模块，导致连锁反应，使浏览器彻底崩溃。浏览器在启动时，会开启多个进程，把不同的功能模块放在&lt;strong&gt;不同的进程&lt;/strong&gt;里。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-014/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;浏览器进程众多，其中比较&lt;strong&gt;重要&lt;/strong&gt;的有：&lt;/p&gt;
&lt;p&gt;📚 浏览器进程&lt;/p&gt;
&lt;p&gt;浏览器进程是浏览器的&lt;strong&gt;主进程&lt;/strong&gt;，无论打开多少浏览器窗口，它仅有&lt;strong&gt;一个&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它主要负责浏览器&lt;strong&gt;界面显示&lt;/strong&gt;、&lt;strong&gt;用户交互&lt;/strong&gt;和&lt;strong&gt;进程管理&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里说的界面和交互，不是视窗内的网站界面。而是指浏览器本身自带的部分，如导航栏、书签栏、刷新按钮等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;刚打开浏览器的时候只有一个浏览器进程，其他进程都是它创建的。&lt;/p&gt;
&lt;p&gt;📚 网络进程&lt;/p&gt;
&lt;p&gt;网络进程主要负责处理网站的&lt;strong&gt;数据请求和响应&lt;/strong&gt;，通常情况下，它与&lt;strong&gt;渲染进程&lt;/strong&gt;的交互最为密切。每当网站需要进行资源请求，渲染进程就会将任务交给网络进程处理，网络进程取得响应结果后再返回给渲染进程。&lt;/p&gt;
&lt;p&gt;网络进程内部会开启多个线程，以实现&lt;strong&gt;多网络请求&lt;/strong&gt;的&lt;strong&gt;异步化处理&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;📚 渲染进程&lt;/p&gt;
&lt;p&gt;渲染进程负责控制和显示&lt;strong&gt;视窗&lt;/strong&gt;部分（网站页面）的所有内容，主要是解析 HTML、CSS、JS 和其他资源，并生成渲染树、执行布局和绘制等操作。&lt;/p&gt;</description></item><item><title>Reflect</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/reflect/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/reflect/</guid><description>&lt;h3 id="一reflect有什么用"&gt;一、Reflect有什么用？&lt;/h3&gt;
&lt;p&gt;一句话，Reflect没什么用，除了装装逼，让人看起来高大上以外，并不具有什么牛逼之处。&lt;/p&gt;
&lt;p&gt;准确讲应该是这样的，Reflect更像是一种语法变体，其挂在的所有方法都能找到对应的原始语法，也就是Reflect的替代性非常强。&lt;/p&gt;
&lt;p&gt;其实从Reflect这个单词本身字面意思就能体会出Reflect的神韵，Reflect的中文意思是“反射”，阳光照在镜子上反射，其实光子还是那些光子，只是变化了方向。&lt;/p&gt;
&lt;p&gt;举例说明：&lt;/p&gt;
&lt;p&gt;Reflect对象挂载了很多静态方法，所谓静态方法，就是和&lt;code&gt;Math.round()&lt;/code&gt;这样，不需要new就可以直接使用的方法。&lt;/p&gt;
&lt;p&gt;比较常用的两个方法就是&lt;code&gt;get()&lt;/code&gt;和&lt;code&gt;set()&lt;/code&gt;方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Reflect&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;propertyKey&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;[, &lt;span style="color:#a6e22e"&gt;receiver&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Reflect&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;propertyKey&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;[, &lt;span style="color:#a6e22e"&gt;receiver&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就作用而言，等同于：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;propertyKey&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;propertyKey&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;比方说页面上有个输入框，其DOM对象变量是&lt;code&gt;input&lt;/code&gt;，平时我们对整个输入框赋值使用的语句多半是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;zhangxinxu&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就可以直接使用&lt;code&gt;Reflect.set()&lt;/code&gt;方法代替：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Reflect&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;zhangxinxu&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;效果是一模一样的。&lt;/p&gt;
&lt;p&gt;又例如，我们希望对&lt;code&gt;input&lt;/code&gt;的&lt;code&gt;value&lt;/code&gt;属性重新定义，使该输入框&lt;code&gt;value&lt;/code&gt;属性发生变化的时候可以同时触发&lt;code&gt;'change'&lt;/code&gt;事件，下面是使用大家普遍比较熟悉的&lt;code&gt;Object.defineProperty()&lt;/code&gt;方法实现的示意：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Object.&lt;span style="color:#a6e22e"&gt;getOwnPropertyDescriptor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Object.&lt;span style="color:#a6e22e"&gt;defineProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ...&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;oldv&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 手动触发change事件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;oldv&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dispatchEvent&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CustomEvent&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;change&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述代码我们完全可以使用Reflect对象实现，具体的JavaScript代码如下所示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Reflect&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getOwnPropertyDescriptor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HTMLInputElement&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Reflect&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;defineProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ...&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;oldv&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 手动触发change事件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;oldv&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dispatchEvent&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CustomEvent&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;change&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以测试下，假设页面HTML如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;input&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试代码为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;change&amp;#39;&lt;/span&gt;, () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.&lt;span style="color:#a6e22e"&gt;body&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;append&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;变化啦~&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;zhangxinxu&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此时，就可以看到页面上出现了“变化啦~”文字&lt;/p&gt;</description></item><item><title>模块化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-015/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-015/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;在JavaScript发展初期就是为了实现简单的页面交互逻辑，寥寥数语即可；如今CPU、浏览器性能得到了极大的提升，很多页面逻辑迁移到了客户端（表单验证等），随着web2.0时代的到来，Ajax技术得到广泛应用，jQuery等前端库层出不穷，前端代码日益膨胀，此时在JS方面就会考虑使用模块化规范去管理。 本文内容主要有理解模块化，为什么要模块化，模块化的优缺点以及模块化规范,并且介绍下开发中最流行的CommonJS, AMD, ES6、CMD规范。&lt;/p&gt;
&lt;p&gt;本文试图站在小白的角度，用通俗易懂的笔调介绍这些枯燥无味的概念，希望诸君阅读后，对模块化编程有个全新的认识和理解！&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-015/image-01.png"&gt;&lt;/p&gt;
&lt;h2 id="一模块化的理解"&gt;一、模块化的理解&lt;/h2&gt;
&lt;h3 id="1什么是模块"&gt;1.什么是模块?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起&lt;/li&gt;
&lt;li&gt;块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2模块化的进化过程"&gt;2.模块化的进化过程&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;全局function模式 : 将不同的功能封装成不同的全局函数&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;编码: 将不同的功能封装成不同的全局函数&lt;/li&gt;
&lt;li&gt;问题: 污染全局命名空间, 容易引起命名冲突或数据不安全，而且模块成员之间看不出直接关系&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; m1&lt;span style="color:#f92672"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; m2&lt;span style="color:#f92672"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;namespace模式 : 简单对象封装&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;作用: 减少了全局变量，解决命名冲突&lt;/li&gt;
&lt;li&gt;问题: 数据不安全(外部可以直接修改模块内部的数据)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let myModule &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data: &lt;span style="color:#e6db74"&gt;&amp;#39;www.baidu.com&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;this.data&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bar&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;bar&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;this.data&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;myModule.data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;other data&amp;#39;&lt;/span&gt; //能直接修改模块内部的数据
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;myModule.foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; // foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; other data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样的写法会暴露所有模块成员，内部状态可以被外部改写。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IIFE模式：匿名函数自调用(闭包)&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;作用: 数据是私有的, 外部只能通过暴露的方法操作&lt;/li&gt;
&lt;li&gt;编码: 将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口&lt;/li&gt;
&lt;li&gt;问题: 如果当前这个模块依赖另一个模块怎么办?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// index.html文件
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;script type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt; src&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;module.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;script type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myModule.foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myModule.bar&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;myModule.data&lt;span style="color:#f92672"&gt;)&lt;/span&gt; //undefined 不能访问模块内部数据
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myModule.data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xxxx&amp;#39;&lt;/span&gt; //不是修改的模块内部的data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myModule.foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; //没有改变
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// module.js文件
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;window&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;www.baidu.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //操作数据的函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //用于暴露有函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;data&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; bar&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //用于暴露有函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;bar&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;data&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; otherFun&lt;span style="color:#f92672"&gt;()&lt;/span&gt; //内部调用
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; otherFun&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //内部私有的函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;otherFun()&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //暴露行为
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; window.myModule &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; foo, bar &lt;span style="color:#f92672"&gt;}&lt;/span&gt; //ES6写法
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;})(&lt;/span&gt;window&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后得到的结果：&lt;/p&gt;</description></item><item><title>数组扩展</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-016/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-016/</guid><description>&lt;p&gt;ES6（ECMAScript 2015）为JavaScript数组引入了多项扩展功能，这些功能不仅简化了数组操作，还提高了代码的可读性和效率。本文将详细介绍ES6数组扩展的主要功能和用法。&lt;/p&gt;
&lt;h4 id="一扩展运算符"&gt;一、扩展运算符（&amp;hellip;）&lt;/h4&gt;
&lt;p&gt;扩展运算符可以用于数组的赋值、合并、解构赋值以及将字符串转为数组。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;赋值数组&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;, [&lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;]];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [...&lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 浅拷贝
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;400&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 不受影响
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;][&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 受影响（只拷贝了一层）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;合并数组&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;([...[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;], ...[&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;]]); &lt;span style="color:#75715e"&gt;// [1, 2, 3, 4, 5, 6]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;解构赋值&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, ...&lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, ...[&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;]];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [&amp;#34;a&amp;#34;, &amp;#34;b&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;将字符串转为数组&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;([...&lt;span style="color:#e6db74"&gt;&amp;#34;str&amp;#34;&lt;/span&gt;]); &lt;span style="color:#75715e"&gt;// [&amp;#34;s&amp;#34;, &amp;#34;t&amp;#34;, &amp;#34;r&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="二arrayfrom"&gt;二、Array.from()&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Array.from()&lt;/code&gt;方法用于将类数组对象或可迭代对象转换为真正的数组。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arrLike&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;内容&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;内容2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;内容3&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Array.&lt;span style="color:#a6e22e"&gt;from&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arrLike&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// [&amp;#34;内容&amp;#34;, &amp;#34;内容2&amp;#34;, &amp;#34;内容3&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此外，&lt;code&gt;Array.from()&lt;/code&gt;还可以接受一个回调函数，用于对数组中的每个元素进行处理。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Array.&lt;span style="color:#a6e22e"&gt;from&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; }, () =&amp;gt; &lt;span style="color:#e6db74"&gt;&amp;#34;jack&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [&amp;#34;jack&amp;#34;, &amp;#34;jack&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="三arrayof"&gt;三、Array.of()&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Array.of()&lt;/code&gt;方法用于将一组值转换为数组，与Array构造函数的行为不同，Array.of()不会把一个参数作为数组的长度。&lt;/p&gt;</description></item><item><title>垃圾回收</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-016/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-016/</guid><description>&lt;h2 id="写在前面"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;我们知道垃圾回收机制是引擎来做的，JS引擎有很多种（各个浏览器都不同），其垃圾回收机制在一些细节及优化上略有不同，本文我们以一些通用的回收算法作为切入，再由 V8 引擎发展至今对该机制的优化为例（为什么以 V8 为例？因为它市场占有率大 😄 ），一步一步深入来助我们了解垃圾回收机制，因为只有真正了解垃圾回收机制，后面才能理解内存泄漏的问题以及手动预防和优化&lt;/p&gt;
&lt;p&gt;JavaScript 是门魅力无限的语言，关于它的 GC（垃圾回收）方面，你了解多少呢？想来大部分人是因为面试才去看一些面试题从而了解的垃圾回收，那在正式开始之前，给大家列几个小问题，大家可以先想一下答案，带着问题及答案再去看文章，最后读完此文如果你的答案可以优化，即有收获&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;什么是垃圾回收机制？&lt;/li&gt;
&lt;li&gt;垃圾是怎样产生的？&lt;/li&gt;
&lt;li&gt;为什么要进行垃圾回收？&lt;/li&gt;
&lt;li&gt;垃圾回收是怎样进行的？&lt;/li&gt;
&lt;li&gt;V8 引擎对垃圾回收进行了哪些优化？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，我们可不仅仅是为了面试，其目的是一次性彻底搞懂 GC！&lt;/p&gt;
&lt;h2 id="gc是什么"&gt;GC是什么&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;GC&lt;/code&gt; 即 &lt;code&gt;Garbage Collection&lt;/code&gt; ，程序工作过程中会产生很多 &lt;code&gt;垃圾&lt;/code&gt;，这些垃圾是程序不用的内存或者是之前用过了，以后不会再用的内存空间，而 &lt;code&gt;GC&lt;/code&gt; 就是负责回收垃圾的，因为他工作在引擎内部，所以对于我们前端来说，&lt;code&gt;GC&lt;/code&gt; 过程是相对比较无感的，这一套引擎执行而对我们又相对无感的操作也就是常说的 &lt;code&gt;垃圾回收机制&lt;/code&gt; 了&lt;/p&gt;
&lt;p&gt;当然也不是所有语言都有 &lt;code&gt;GC&lt;/code&gt;，一般的高级语言里面会自带 &lt;code&gt;GC&lt;/code&gt;，比如 &lt;code&gt;Java、Python、JavaScript&lt;/code&gt; 等，也有无 &lt;code&gt;GC&lt;/code&gt; 的语言，比如 &lt;code&gt;C、C++&lt;/code&gt; 等，那这种就需要我们程序员手动管理内存了，相对比较麻烦&lt;/p&gt;
&lt;h2 id="垃圾产生为何回收"&gt;垃圾产生&amp;amp;为何回收&lt;/h2&gt;
&lt;p&gt;我们知道写代码时创建一个基本类型、对象、函数……都是需要占用内存的，但是我们并不关注这些，因为这是引擎为我们分配的，我们不需要显式手动的去分配内存&lt;/p&gt;
&lt;p&gt;但是，你有没有想过，当我们不再需要某个东西时会发生什么？JavaScript 引擎又是如何发现并清理它的呢？&lt;/p&gt;
&lt;p&gt;我们举个简单的例子&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;isboyjc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;test&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如上所示，我们假设它是一个完整的程序代码&lt;/p&gt;
&lt;p&gt;我们知道 &lt;code&gt;JavaScript&lt;/code&gt; 的引用数据类型是保存在堆内存中的，然后在栈内存中保存一个对堆内存中实际对象的引用，所以，&lt;code&gt;JavaScript&lt;/code&gt; 中对引用数据类型的操作都是操作对象的引用而不是实际的对象。可以简单理解为，栈内存中保存了一个地址，这个地址和堆内存中的实际值是相关的&lt;/p&gt;
&lt;p&gt;那上面代码首先我们声明了一个变量 &lt;code&gt;test&lt;/code&gt;，它引用了对象 &lt;code&gt;{name: 'isboyjc'}&lt;/code&gt;，接着我们把这个变量重新赋值了一个数组对象，也就变成了该变量引用了一个数组，那么之前的对象引用关系就没有了，如下图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-016/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;没有了引用关系，也就是无用的对象，这个时候假如任由它搁置，一个两个还好，多了的话内存也会受不了，所以就需要被清理（回收）&lt;/p&gt;
&lt;p&gt;用官方一点的话说，程序的运行需要内存，只要程序提出要求，操作系统或者运行时就必须提供内存，那么对于持续运行的服务进程，必须要及时释放内存，否则，内存占用越来越高，轻则影响系统性能，重则就会导致进程崩溃&lt;/p&gt;
&lt;h2 id="垃圾回收策略"&gt;垃圾回收策略&lt;/h2&gt;
&lt;p&gt;在 JavaScript 内存管理中有一个概念叫做 &lt;code&gt;可达性&lt;/code&gt;，就是那些以某种方式可访问或者说可用的值，它们被保证存储在内存中，反之不可访问则需回收&lt;/p&gt;
&lt;p&gt;至于如何回收，其实就是怎样发现这些不可达的对象（垃圾）它并给予清理的问题， &lt;code&gt;JavaScript&lt;/code&gt; 垃圾回收机制的原理说白了也就是定期找出那些不再用到的内存（变量），然后释放其内存&lt;/p&gt;</description></item><item><title>尾部优化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-017/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-017/</guid><description>&lt;p&gt;ES6 引入了&lt;strong&gt;尾调用优化（Tail Call Optimization，TCO）&lt;strong&gt;的规范，但它的实现依赖于 &lt;strong&gt;JavaScript 引擎的支持&lt;/strong&gt;（比如 V8 并未开启 TCO），所以这是一个&lt;/strong&gt;理论上重要、实践中需要谨慎对待&lt;/strong&gt;的考点。&lt;/p&gt;
&lt;h2 id="一什么是尾调用tail-call"&gt;一、什么是尾调用（Tail Call）？&lt;/h2&gt;
&lt;p&gt;尾调用是指：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;函数的最后一步是调用另一个函数&lt;/strong&gt;，并直接返回这个函数的执行结果。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// bar 是 foo 的尾调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;尾调用意味着：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当前函数的&lt;strong&gt;调用栈帧&lt;/strong&gt;不需要再做任何事。&lt;/li&gt;
&lt;li&gt;调用栈可以复用，&lt;strong&gt;不需要为当前函数保留栈帧&lt;/strong&gt;，从而节省内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二什么是尾调用优化tco"&gt;二、什么是尾调用优化（TCO）？&lt;/h2&gt;
&lt;p&gt;尾调用优化的目标是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当一个函数的最后一步是调用另一个函数，JS 引擎可以不再保留当前函数的调用记录，&lt;strong&gt;直接跳转执行被调用函数，复用当前栈帧&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不会形成函数调用嵌套的“栈帧链”；&lt;/li&gt;
&lt;li&gt;可以避免&lt;strong&gt;函数递归导致的栈溢出（stack overflow）&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="三尾调用成立的条件"&gt;三、尾调用成立的条件&lt;/h2&gt;
&lt;p&gt;必须同时满足以下三个条件：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;条件&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. 在严格模式下&lt;/td&gt;
&lt;td&gt;TCO 只在 strict mode 下才可能被引擎开启&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. 是函数的最后一步调用&lt;/td&gt;
&lt;td&gt;return 后没有任何操作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. 返回调用结果&lt;/td&gt;
&lt;td&gt;return bar(x) 形式，不能是 &lt;code&gt;bar(x); return y&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;✅ 尾调用示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;use strict&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;g&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 最后一步是返回 g(x)，符合尾调用优化条件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;❌ 非尾调用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;g&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 不是直接返回函数调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="四尾调用优化应用场景尾递归"&gt;四、尾调用优化应用场景：&lt;strong&gt;尾递归&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;递归调用时，若能做到尾调用，就能避免栈溢出。&lt;/p&gt;</description></item><item><title>DOM操作</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-017/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-017/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-017/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="1dom基本概念"&gt;1、DOM基本概念&lt;/h2&gt;
&lt;h3 id="11domdom节点与dom树"&gt;1.1、DOM、DOM节点与DOM树&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://developer.mozilla.org/zh-CN/docs/Glossary/DOM"&gt;DOM&lt;/a&gt;&lt;/strong&gt;：(&lt;strong&gt;D&lt;/strong&gt;ocument &lt;strong&gt;O&lt;/strong&gt;bject &lt;strong&gt;M&lt;/strong&gt;odel, 文档对象模型)是文档内容（HTML或XML）在编程语言上的抽象模型，它建模了文档的内容和结构，并提供给编程语言一套完整的操纵文档的API。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;本文面向HTML，不讨论XML等文档，下文中“文档===HTML”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DOM节点&lt;/strong&gt;：简称节点（Node），是DOM模型的组成单元。HTML的基本单元是标签，节点&lt;strong&gt;常常&lt;/strong&gt;与标签对应，但连续的文本内容也是一个&lt;strong&gt;文本标签&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DOM树&lt;/strong&gt;：DOM树是DOM结构的表示形式，DOM把文档的每个节点根据父子关系连接，形成DOM树。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12节点节点类型和节点类"&gt;1.2、节点、节点类型和节点类&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;节点&lt;/strong&gt;：前面提过，节点是DOM树的组成单元。在JS看来，一个节点就是JS对象。下面用&lt;code&gt;node&lt;/code&gt;表示任意的节点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Node/nodeType"&gt;节点类型&lt;/a&gt;&lt;/strong&gt;：并非所有的节点都是一样的，DOM规定文档中有12种节点类型，分别用常量&lt;code&gt;1 ~ 12&lt;/code&gt;（有与之对应的常量名称&lt;code&gt;Node.XXX_NODE&lt;/code&gt;）表示，可以通过&lt;code&gt;node.nodeType&lt;/code&gt;属性获取节点的类型常量。 现在，有些类型的节点已经弃用了，常见到的只有几种类型的节点，包括：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;元素节点&lt;/strong&gt;: 类型常量为&lt;code&gt;Node.ELEMENT_NODE&lt;/code&gt;或&lt;code&gt;1&lt;/code&gt;。最常见的一类节点，对应文档中的元素。大部分DOM操作都是在元素节点层次的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文本节点&lt;/strong&gt;：类型常量为&lt;code&gt;Node.TEXT_NODE&lt;/code&gt;或&lt;code&gt;2&lt;/code&gt;。对应文档中的文本，&lt;strong&gt;任何文档内容都有对应的文本节点，即使空格和换行符&lt;/strong&gt;。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;空格和换行不会对页面内容产生影响，但它们确实以文本节点的形式存在于DOM树中。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Document节点&lt;/strong&gt;：类型常量为&lt;code&gt;Node.DOCUMENT_NODE&lt;/code&gt;或&lt;code&gt;9&lt;/code&gt;。它不对应文档的内容，而是作为文档的入口节点，每个文档都有且仅有一个入口，因为这种独特性，赋予一个特殊的变量名称&lt;code&gt;document&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注释节点&lt;/strong&gt;：类型常量为&lt;code&gt;Node.COMMENT_NODE&lt;/code&gt;或&lt;code&gt;8&lt;/code&gt;。它对应文档中的注释标签，文档的注释内容也是可读取和修改的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;节点类&lt;/strong&gt;：DOM内置许多节点类，类之间存在继承关系，形成一套节点类框架。每个节点对象都属于节点类，拥有该类和其父类的方法与属性，这使得操作节点十分简单。节点类框架的一部分大概如图： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-017/image-02.webp"&gt; 这些节点上有丰富的属性和方法，是继承的结果，可以看到，一个HTML标签元素至少有四层的继承关系。 以&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;标签为例，它属于&lt;code&gt;HTMLAnchorElement&lt;/code&gt;类，获得了&lt;code&gt;a.target&lt;/code&gt;，&lt;code&gt;a.download&lt;/code&gt;等属性，接着继承了&lt;code&gt;HTMLElement&lt;/code&gt;类上的&lt;code&gt;title&lt;/code&gt;, &lt;code&gt;hidden&lt;/code&gt;等属性和&lt;code&gt;click()&lt;/code&gt;等方法，又从&lt;code&gt;Element&lt;/code&gt;类继承了&lt;code&gt;tagName&lt;/code&gt;, &lt;code&gt;className&lt;/code&gt;等属性和&lt;code&gt;getAttribute()&lt;/code&gt;, &lt;code&gt;setAttribute()&lt;/code&gt;等方法，再从&lt;code&gt;Node&lt;/code&gt;类继承了&lt;code&gt;nodeType&lt;/code&gt;(前面说过的节点类型), &lt;code&gt;appenChild()&lt;/code&gt;, &lt;code&gt;removeChild()&lt;/code&gt;等方法，最后从&lt;code&gt;EventTarget&lt;/code&gt;类中继承了事件相关的属性和方法。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;不要混淆节点类型和节点类这两个概念&lt;/strong&gt;。前者是一个生活中的&lt;strong&gt;类别&lt;/strong&gt;，后者是编程意义上的&lt;strong&gt;类&lt;/strong&gt;。节点对象的&lt;code&gt;nodeType&lt;/code&gt;属性表示了它的类型，而节点类是该节点的从属的类。因为&lt;code&gt;Dode&lt;/code&gt;是一个抽象类，所以，如果知道了某个节点从属的类，我们就知道它的节点类型。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;区分节点与元素节点&lt;/strong&gt;。我们经常关心元素节点（简称元素），因为这是一类最常使用的节点，但是并非所有节点都是元素。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="13探索dom结构"&gt;1.3、探索DOM结构&lt;/h3&gt;
&lt;p&gt;前面的说法太抽象了，让我们用实际的例子看看文档、DOM树与节点的关系。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A...#"&gt;Live DOM Viewer&lt;/a&gt;是一个可以根据HTML文档实时查看DOM树的网站。你把下面的例子复制过去，或者自己去探索。&lt;/p&gt;
&lt;p&gt;一个简单的HTML文档：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE HTML&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A simple text.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;ol&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;title&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;this is a title&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;czpcalm&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- comment --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;ol&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它对应的DOM图（颜色区分了节点类型）：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-017/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;留意这个图，你要注意几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;总共有4种类型的节点，分别是&lt;code&gt;标签节点&lt;/code&gt;（红色）,&lt;code&gt;文本节点&lt;/code&gt;（灰色），&lt;code&gt;注释节点&lt;/code&gt;(黄色)和&lt;code&gt;DOCTYPE节点&lt;/code&gt;（紫色）。&lt;/li&gt;
&lt;li&gt;文档没有&lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;标签却出现了&lt;code&gt;HEAD&lt;/code&gt;节点。这是因为HTML必然存在&lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;标签，不存在时会自动补上。顺便一提，当出现&lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;标签时，也一定会有&lt;code&gt;&amp;lt;tbody&amp;gt;&lt;/code&gt;标签。&lt;/li&gt;
&lt;li&gt;文档中的文本都会形成文本节点的内容，包括&lt;code&gt;空格␣&lt;/code&gt;和&lt;code&gt;换行↵&lt;/code&gt;。第一,&lt;code&gt;单独的空格和换行都会形成对应的文本节点&lt;/code&gt;；第二，有内容的文本节点的值包含前导和后继的空白。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;不是说HTML中的空白字符都被忽略吗？怎么这里又说全都是有效的字符？&lt;/p&gt;
&lt;p&gt;在从文档解析生成DOM树的过程中，HTML中的任何字符都是有效的；不过，在接下去的页面渲染的过程中，空白内容被忽略。所以从文档到页面的整过过程中，空白确实被忽略了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;理解DOM树中的父子关系对应文档中的包含（嵌套）关系。一个极佳的类比是文件树，把元素看做文件夹，文本看做文件，文件夹中可以存放文件和新的文件夹，然后一层层深入下去，DOM树也是如此。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;几个原则可以帮我们快速理解这个DOM树的构建：&lt;/p&gt;</description></item><item><title>事件冒泡、事件捕获、事件委托</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/</guid><description>&lt;p&gt;&lt;code&gt;DOM&lt;/code&gt;事件流（&lt;code&gt;event flow&lt;/code&gt; ）存在三个阶段：事件捕获阶段、处于目标阶段、事件冒泡阶段。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Dom&lt;/code&gt;标准事件流的触发的先后顺序为：先捕获再冒泡。即当触发&lt;code&gt;dom&lt;/code&gt;事件时，会先进行事件捕获，捕获到事件源之后通过事件传播进行事件冒泡。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;addEventListener的第三个参数&lt;/strong&gt;&lt;br&gt;
在我们平常用的&lt;code&gt;addEventListener&lt;/code&gt;方法中，一般只会用到两个参数，一个是需要绑定的事件，另一个是触发事件后要执行的函数，然而&lt;code&gt;addEventListener&lt;/code&gt;还可以传入第三个参数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;element&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;useCapture&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第三个参数默认值是&lt;code&gt;false&lt;/code&gt;，表示在事件冒泡阶段调用事件处理函数;如果参数为&lt;code&gt;true&lt;/code&gt;，则表示在事件捕获阶段调用处理函数。如果不写第三个参数则默认在事件冒泡阶段调用事件处理函数。&lt;/p&gt;
&lt;p&gt;下面先介绍事件冒泡：&lt;/p&gt;
&lt;h2 id="1-事件冒泡"&gt;1. 事件冒泡&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;事件冒泡（dubbed bubbling）&lt;/code&gt;：当一个元素接收到事件的时候，会把他接收到的事件传给自己的父级，一直到 &lt;code&gt;window&lt;/code&gt; （注意这里传递的仅仅是事件，例如&lt;code&gt;click、focus&lt;/code&gt;等等这些事件， 并不传递所绑定的事件函数。）&lt;/p&gt;
&lt;p&gt;事件源 =&amp;gt;根节点（由内到外）进行事件传播。&lt;/p&gt;
&lt;p&gt;举例说明：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;给三个盒子依次绑定点击事件，当点击盒子的时候，会依次触发父级元素的点击事件。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click center box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click big box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;如果父元素没有绑定点击事件则只会触发点击盒子的事件。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-07.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-08.webp"&gt;&lt;/p&gt;
&lt;p&gt;如果子元素（&lt;code&gt;small&lt;/code&gt;）的点击事件去掉，当我们点击&lt;code&gt;small&lt;/code&gt;的时候会把当前操作的点击事件传递给父元素（因为父元素绑定了点击函数） &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-09.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-10.webp"&gt;&lt;/p&gt;
&lt;p&gt;有些时候我们不希望产生事件冒泡，所以可以 &lt;strong&gt;在子事件中加入e.stopPropagation()&lt;/strong&gt; 取消冒泡 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-11.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-12.webp"&gt;&lt;/p&gt;
&lt;h2 id="2-事件捕获"&gt;2. 事件捕获&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;事件捕获（event capturing）&lt;/code&gt;： 当鼠标点击或者触发&lt;code&gt;dom&lt;/code&gt;事件时（被触发&lt;code&gt;dom&lt;/code&gt;事件的这个元素被叫作事件源），浏览器会从根节点 =&amp;gt;事件源（由外到内）进行事件传播。&lt;/p&gt;
&lt;p&gt;事件捕获与事件冒泡是比较类似的，最大的不同在于事件传播的方向。&lt;/p&gt;
&lt;p&gt;还是举上面的例子： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-13.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-14.webp"&gt;&lt;/p&gt;
&lt;h2 id="3-事件委托"&gt;3. 事件委托&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;事件委托&lt;/code&gt;也称为&lt;code&gt;事件代理&lt;/code&gt;。就是利用&lt;code&gt;事件冒泡&lt;/code&gt;，把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡，那么委托就无法实现。&lt;/p&gt;
&lt;p&gt;原理实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;不是每个子节点单独设置事件监听器&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;而是事件监听器设置在其父节点上&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;然后利用冒泡原理影响设置每个子节点&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应用场景：&lt;code&gt;1000&lt;/code&gt;个&lt;code&gt;button&lt;/code&gt;需要注册点击事件&lt;/p&gt;
&lt;p&gt;如果循环给每个按钮添加点击事件，那么会增加内存损耗，影响性能 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-15.webp"&gt;&lt;/p&gt;
&lt;p&gt;此时可以给&lt;code&gt;button&lt;/code&gt;的父元素添加点击事件 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-16.webp"&gt;&lt;/p&gt;
&lt;p&gt;这时相当于每个按钮都绑定了点击事件&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-17.webp"&gt;&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;替代循环绑定事件的操作，减少内存消耗，提高性能。比如：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;在&lt;code&gt;table&lt;/code&gt;上代理所有&lt;code&gt;td&lt;/code&gt;的&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;li&gt;在&lt;code&gt;ul&lt;/code&gt;上代理所有&lt;code&gt;li&lt;/code&gt;的&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;简化了&lt;code&gt;dom&lt;/code&gt;节点更新时，相应事件的更新。比如：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;不用在新添加的&lt;code&gt;li&lt;/code&gt;上绑定&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;li&gt;当删除某个&lt;code&gt;li&lt;/code&gt;时，不用移解绑上面的&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;</description></item><item><title>call、apply和bind</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/call-apply-bind/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/call-apply-bind/</guid><description>&lt;h2 id="apply-和-call简介"&gt;&lt;code&gt;apply&lt;/code&gt; 和 &lt;code&gt;call&lt;/code&gt;简介&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;javascript&lt;/code&gt; 中，&lt;code&gt;call&lt;/code&gt; 和 &lt;code&gt;apply&lt;/code&gt; 都是为了改变某个函数运行时的上下文（&lt;code&gt;context&lt;/code&gt;）而存在的，换句话说，就是为了改变函数体内部 &lt;code&gt;this&lt;/code&gt; 的指向。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;JavaScript&lt;/code&gt; 的一大特点是，函数存在「&lt;code&gt;定义时上下文&lt;/code&gt;」和「&lt;code&gt;运行时上下文&lt;/code&gt;」以及「&lt;code&gt;上下文是可以改变的&lt;/code&gt;」这样的概念。&lt;/p&gt;
&lt;p&gt;比如 &lt;code&gt;A&lt;/code&gt; 对象有一个方法，而 &lt;code&gt;B&lt;/code&gt; 对象因为某种原因，也需要用到同样的方法，那么这时候不用单独为 &lt;code&gt;B&lt;/code&gt; 对象扩展一个方法，可以直接借用 A 对象的方法。这样既完成了需求，又减少了内存的占用。&lt;/p&gt;
&lt;p&gt;直接来看个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plain" data-lang="plain"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function fruits() {} fruits.prototype = { color: &amp;#34;red&amp;#34;, say: function() { console.log(&amp;#34;My color is &amp;#34; + this.color); }} var apple = new fruits();apple.say(); //My color is red
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是如果我们有一个对象 &lt;code&gt;banana= {color : &amp;quot;yellow&amp;quot;}&lt;/code&gt; ,我们不想对它重新定义 &lt;code&gt;say&lt;/code&gt; 方法，那么我们可以通过 &lt;code&gt;call&lt;/code&gt; 或 &lt;code&gt;apply&lt;/code&gt; 用 &lt;code&gt;apple&lt;/code&gt; 的 &lt;code&gt;say&lt;/code&gt; 方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plain" data-lang="plain"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;banana = { color: &amp;#34;yellow&amp;#34;}apple.say.call(banana); //My color is yellowapple.say.apply(banana); //My color is yellow
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="applycall-的区别"&gt;apply、call 的区别&lt;/h2&gt;
&lt;p&gt;对于 apply、call 二者而言，作用完全一样，只是接受参数的方式不太一样。例如，有一个函数定义如下：&lt;/p&gt;</description></item><item><title>深拷贝/浅拷贝</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-020/</link><pubDate>Thu, 07 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-020/</guid><description>&lt;p&gt;浅拷贝和深拷贝都是对于JS中的引用类型而言的，浅拷贝就只是复制对象的引用，如果拷贝后的对象发生变化，原对象也会发生变化。只有深拷贝才是真正地对对象的拷贝。&lt;/p&gt;
&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;说到深浅拷贝，必须先提到的是JavaScript的数据类型，大家可以看前面的知识点，这里不多说了。&lt;/p&gt;
&lt;p&gt;初学前端的同学，需要知道的一点就是：JavaScript的数据类型分为基本数据类型和引用数据类型。&lt;/p&gt;
&lt;p&gt;对于基本数据类型的拷贝，并没有深浅拷贝的区别，我们所说的深浅拷贝都是对于引用数据类型而言的。&lt;/p&gt;
&lt;h2 id="浅拷贝"&gt;浅拷贝&lt;/h2&gt;
&lt;p&gt;浅拷贝的意思就是只复制引用，而未复制真正的值。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;originArray&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;originObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;],&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;dd&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;dd&amp;#39;&lt;/span&gt;}};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cloneArray&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;originArray&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cloneObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;originObj&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cloneArray&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [1,2,3,4,5]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;originObj&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// {a:&amp;#39;a&amp;#39;,b:&amp;#39;b&amp;#39;,c:Array[3],d:{dd:&amp;#39;dd&amp;#39;}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;cloneArray&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;cloneObj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&lt;span style="color:#a6e22e"&gt;aa&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cloneArray&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [1,2,3,4,5,6]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;originArray&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [1,2,3,4,5,6]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cloneObj&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// {a:{aa:&amp;#39;aa&amp;#39;},b:&amp;#39;b&amp;#39;,c:Array[3],d:{dd:&amp;#39;dd&amp;#39;}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;originArray&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// {a:{aa:&amp;#39;aa&amp;#39;},b:&amp;#39;b&amp;#39;,c:Array[3],d:{dd:&amp;#39;dd&amp;#39;}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的代码是最简单的利用 &lt;code&gt;=&lt;/code&gt; 赋值操作符实现了一个浅拷贝，可以很清楚的看到，随着 &lt;code&gt;cloneArray&lt;/code&gt; 和 &lt;code&gt;cloneObj&lt;/code&gt; 改变，&lt;code&gt;originArray&lt;/code&gt; 和 &lt;code&gt;originObj&lt;/code&gt; 也随着发生了变化。&lt;/p&gt;
&lt;h2 id="深拷贝"&gt;深拷贝&lt;/h2&gt;
&lt;p&gt;深拷贝就是对目标的完全拷贝，不像浅拷贝那样只是复制了一层引用，就连值也都复制了。&lt;/p&gt;
&lt;p&gt;只要进行了深拷贝，它们老死不相往来，谁也不会影响谁。&lt;/p&gt;
&lt;p&gt;目前实现深拷贝的方法不多，主要是两种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;利用 &lt;code&gt;JSON&lt;/code&gt; 对象中的 &lt;code&gt;parse&lt;/code&gt; 和 &lt;code&gt;stringify&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;利用递归来实现每一层都重新创建对象并赋值&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="jsonstringifyparse的方法"&gt;JSON.stringify/parse的方法&lt;/h3&gt;
&lt;p&gt;先看看这两个方法吧：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The JSON.stringify() method converts a JavaScript value to a JSON string.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;JSON.stringify&lt;/code&gt; 是将一个 &lt;code&gt;JavaScript&lt;/code&gt; 值转成一个 &lt;code&gt;JSON&lt;/code&gt; 字符串。&lt;/p&gt;</description></item><item><title>字符串常见方法</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-021/</link><pubDate>Fri, 08 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-021/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-021/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="1-获取字符串长度"&gt;1. 获取字符串长度&lt;/h3&gt;
&lt;p&gt;JavaScript中的字符串有一个length属性，该属性可以用来获取字符串的长度：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 输出结果：5
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-获取字符串指定位置的值"&gt;2. 获取字符串指定位置的值&lt;/h3&gt;
&lt;p&gt;charAt()和charCodeAt()方法都可以通过索引来获取指定位置的值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;charAt() 方法获取到的是指定位置的字符；&lt;/li&gt;
&lt;li&gt;charCodeAt()方法获取的是指定位置字符的Unicode值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="1charat"&gt;（1）charAt()&lt;/h4&gt;
&lt;p&gt;charAt() 方法可以返回指定位置的字符。其语法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;charAt&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;index&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;index表示字符在字符串中的索引值：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;charAt&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 输出结果：e
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们知道，字符串也可以通过索引值来直接获取对应字符，那它和charAt()有什么区别呢？来看例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;charAt&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 输出结果：e
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#75715e"&gt;// 输出结果：e
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;charAt&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 输出结果：&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;] &lt;span style="color:#75715e"&gt;// 输出结果：undefined
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到，当index的取值不在str的长度范围内时，str[index]会返回undefined，而charAt(index)会返回空字符串；除此之外，str[index]不兼容ie6-ie8，charAt(index)可以兼容。&lt;/p&gt;
&lt;h4 id="2charcodeat"&gt;（2）charCodeAt()&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;charCodeAt()&lt;/code&gt;：该方法会返回指定索引位置字符的 Unicode 值，返回值是 0 - 65535 之间的整数，表示给定索引处的 UTF-16 代码单元，如果指定位置没有字符，将返回 &lt;strong&gt;NaN&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;abcdefg&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;charCodeAt&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// &amp;#34;b&amp;#34; --&amp;gt; 98
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过这个方法，可以获取字符串中指定Unicode编码值范围的字符。比如，数字0～9的Unicode编码范围是: 48～57，可以通过这个方法来筛选字符串中的数字，当然如果你更熟悉正则表达式，会更方便。&lt;/p&gt;
&lt;h3 id="3-检索字符串是否包含特定序列"&gt;3. 检索字符串是否包含特定序列&lt;/h3&gt;
&lt;p&gt;这5个方法都可以用来检索一个字符串中是否包含特定的序列。其中前两个方法得到的指定元素的索引值，并且只会返回第一次匹配到的值的位置。后三个方法返回的是布尔值，表示是否匹配到指定的值。&lt;/p&gt;
&lt;p&gt;注意：这5个方法都对大小写敏感！&lt;/p&gt;
&lt;h4 id="1indexof"&gt;（1）indexOf()&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;indexOf()&lt;/code&gt;：查找某个字符，&lt;strong&gt;有则返回第一次匹配到的位置&lt;/strong&gt;，否则返回-1，其语法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;indexOf&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;searchvalue&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;fromindex&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该方法有两个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;searchvalue：必需，规定需检索的字符串值；&lt;/li&gt;
&lt;li&gt;fromindex：可选的整数参数，规定在字符串中开始检索的位置。它的合法取值是 0 到 string.length - 1。如省略该，则从字符串的首字符开始检索。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;abcdefgabc&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;indexOf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 输出结果：0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;indexOf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;z&amp;#34;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 输出结果：-1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;indexOf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;c&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;// 输出结果：9
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="2lastindexof"&gt;（2）lastIndexOf()&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;lastIndexOf()&lt;/code&gt;：查找某个字符，有则返回最后一次匹配到的位置，否则返回-1&lt;/p&gt;</description></item><item><title>数组常用方法</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-022/</link><pubDate>Fri, 08 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-022/</guid><description>&lt;p&gt;数组是 js 中最常用到的数据集合，其内置的方法有很多，熟练掌握这些方法，可以有效的提高我们的工作效率，同时对我们的代码质量也是有很大影响。&lt;/p&gt;
&lt;h2 id="一创建数组"&gt;一、创建数组&lt;/h2&gt;
&lt;h2 id="1使用数组字面量表示法"&gt;1.使用数组字面量表示法&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr4&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []; &lt;span style="color:#75715e"&gt;//创建一个空数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr5&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 创建一个包含1项数据为20的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr6&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;lily&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lucy&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Tom&amp;#34;&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 创建一个包含3个字符串的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="2使用-array-构造函数"&gt;2.使用 Array 构造函数&lt;/h2&gt;
&lt;h3 id="无参构造"&gt;无参构造&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Array(); &lt;span style="color:#75715e"&gt;//创建一个空数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="带参构造"&gt;带参构造&lt;/h3&gt;
&lt;p&gt;如果只传一个数值参数，则表示创建一个初始长度为指定数值的空数组&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Array(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 创建一个包含20项的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果传入一个非数值的参数或者参数个数大于 1，则表示创建一个包含指定元素的数组&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr3&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Array(&lt;span style="color:#e6db74"&gt;&amp;#34;lily&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lucy&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Tom&amp;#34;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 创建一个包含3个字符串的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array4&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Array(&lt;span style="color:#e6db74"&gt;&amp;#39;23&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [&amp;#34;23&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="3arrayof-方法创建数组es6-新增"&gt;3.Array.of 方法创建数组(es6 新增)&lt;/h2&gt;
&lt;p&gt;ES6 为数组新增创建方法的目的之一，是帮助开发者在使用 Array 构造器时避开 js 语言的一个怪异点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Array.of()方法总会创建一个包含所有传入参数的数组，而不管参数的数量与类型。&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Array.&lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Array.&lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]);&lt;span style="color:#75715e"&gt;//3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Array.&lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]);&lt;span style="color:#75715e"&gt;//&amp;#39;2&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4arrayfrom-方法创建数组es6-新增"&gt;4.Array.from 方法创建数组(es6 新增)&lt;/h2&gt;
&lt;p&gt;在 js 中将&lt;strong&gt;非数组对象转换为真正的数组&lt;/strong&gt;是非常麻烦的。在 ES6 中，将可迭代对象或者类数组对象作为第一个参数传入，Array.from()就能返回一个数组。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arga&lt;/span&gt;(...&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;//...args剩余参数数组,由传递给函数的实际参数提供
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Array.&lt;span style="color:#a6e22e"&gt;from&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;arga&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;arr1&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;from&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [&amp;#39;arr1&amp;#39;,26,&amp;#39;from&amp;#39;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="映射转换"&gt;映射转换&lt;/h3&gt;
&lt;p&gt;如果你想实行进一步的数组转换，你可以向 Array.from()方法传递一个映射用的函数作为第二个参数。此函数会将数组对象的每一个值转换为目标形式，并将其存储在目标数组的对应位置上。&lt;/p&gt;</description></item><item><title>正则表达式</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-023/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-023/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;正则表达式使用单个[字符串]来描述、匹配一系列匹配某个[句法规则]的字符串，通常被用来检索、替换那些符合某个模式（规则）的文本。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="创建"&gt;创建&lt;/h2&gt;
&lt;h2 id="1构造函数创建"&gt;1.构造函数创建&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;new RegExp(&amp;lsquo;正则表达式&amp;rsquo;,&amp;lsquo;修饰符&amp;rsquo;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; RegExp(&lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;igm&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="2直接直面量创建"&gt;2.直接直面量创建&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;/正则表达式/修饰符&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/hello/igm&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="字符分类"&gt;字符分类&lt;/h2&gt;
&lt;h2 id="1普通字符"&gt;1.普通字符&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;字母、数字、下划线、汉字、没有特殊含义的符号（,;!@等）&lt;/p&gt;
&lt;p&gt;实际上不是特殊字符的字符都是普通字符&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="2特殊字符"&gt;2.特殊字符&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;\：将特殊字符转义成普通字符&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="3模式修饰符"&gt;3.模式修饰符&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;i：ignoreCase，匹配时忽视大小写&lt;/p&gt;
&lt;p&gt;m：multiline，多行匹配&lt;/p&gt;
&lt;p&gt;g：global，全局匹配&lt;/p&gt;
&lt;p&gt;字面量创建正则时，模式修饰符写在一对反斜线后&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="实例方法"&gt;实例方法&lt;/h2&gt;
&lt;h2 id="1exec"&gt;1.exec()&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;用来匹配字符串中符合正则表达式的字符串&lt;/p&gt;
&lt;p&gt;如果匹配到，返回值是一个result数组:&lt;/p&gt;
&lt;p&gt;[匹配的内容，index: 在str中匹配的起始位置，input: 参数字符串，groups: undefined]&lt;/p&gt;
&lt;p&gt;否则返回null&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello world javascript hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; RegExp(&lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;igm&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;exec&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;输出结果为&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;index&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello world javascript hello&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;groups&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="2test"&gt;2.test()&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;用来测试待检测的字符串中是否有可以匹配到正则表达式的字符串&lt;/p&gt;
&lt;p&gt;如果有返回true，否则返回false&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/hello/&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello world&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;//true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="3tosting-tolocalestring"&gt;3.toSting() toLocaleString()&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;把正则表达式的内容转化成&lt;strong&gt;字面量形式字符串&lt;/strong&gt;/有本地特色的字符串&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/hello/&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello world&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt;(),&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt;()); &lt;span style="color:#75715e"&gt;// /hello/ string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toLocaleString&lt;/span&gt;(),&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toLocaleString&lt;/span&gt;()); &lt;span style="color:#75715e"&gt;// /hello/ string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4valueof"&gt;4.valueOf()&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;返回正则表达式本身&lt;/p&gt;</description></item><item><title>跨域</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-024/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-024/</guid><description>&lt;h2 id="一什么是跨域"&gt;一、什么是跨域？&lt;/h2&gt;
&lt;p&gt;在前端领域中，跨域是指浏览器允许向服务器发送跨域请求，从而克服Ajax只能&lt;strong&gt;同源&lt;/strong&gt;使用的限制。&lt;/p&gt;
&lt;h3 id="什么是同源策略"&gt;什么是同源策略？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;同源策略&lt;/strong&gt;是一种约定，由Netscape公司1995年引入浏览器，它是浏览器最核心也最基本的安全功能，如果缺少了同源策略，浏览器很容易受到XSS、CSFR等攻击。所谓同源是指&amp;quot;协议+域名+端口&amp;quot;三者相同，即便两个不同的域名指向同一个ip地址，也非同源。&lt;/p&gt;
&lt;p&gt;同源策略限制以下几种行为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cookie、LocalStorage 和 IndexDB 无法读取&lt;/li&gt;
&lt;li&gt;DOM和JS对象无法获得&lt;/li&gt;
&lt;li&gt;AJAX 请求不能发送&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二常见的跨域场景"&gt;二、常见的跨域场景&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;是否允许通信&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/"&gt;www.domain.com/&lt;/a&gt;a.js&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/"&gt;www.domain.com/&lt;/a&gt;b.js&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/"&gt;www.domain.com/&lt;/a&gt;lab/c.js&lt;/td&gt;
&lt;td&gt;同一域名，不同文件或路径&lt;/td&gt;
&lt;td&gt;允许&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/"&gt;www.domain.com&lt;/a&gt;:8000/a.js&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/b.js"&gt;www.domain.com/b.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;同一域名，不同端口&lt;/td&gt;
&lt;td&gt;不允许&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/a.js"&gt;http://www.domain.com/a.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.domain.com/b.js"&gt;https://www.domain.com/b.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;同一域名，不同协议&lt;/td&gt;
&lt;td&gt;不允许&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/a.js"&gt;http://www.domain.com/a.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://192.168.4.12/b.js"&gt;http://192.168.4.12/b.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;域名和域名对应相同ip&lt;/td&gt;
&lt;td&gt;不允许&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/a.js"&gt;http://www.domain.com/a.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://x.domain.com/b.js"&gt;http://x.domain.com/b.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://domain.com/c.js"&gt;http://domain.com/c.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;主域相同，子域不同&lt;/td&gt;
&lt;td&gt;不允许&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain1.com/a.js"&gt;http://www.domain1.com/a.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain2.com/b.js"&gt;http://www.domain2.com/b.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;不同域名&lt;/td&gt;
&lt;td&gt;不允许&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="三9种跨域解决方案"&gt;三、9种跨域解决方案&lt;/h2&gt;
&lt;h3 id="1jsonp跨域"&gt;1、JSONP跨域&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;jsonp&lt;/strong&gt;的原理就是利用&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;标签没有跨域限制，通过&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;标签src属性，发送带有callback参数的GET请求，服务端将接口返回数据拼凑到callback函数中，返回给浏览器，浏览器解析执行，从而前端拿到callback函数返回的数据。&lt;br&gt;
1）原生JS实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; var script &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.createElement&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; script.type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;text/javascript&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; // 传参一个回调函数名给后端，方便后端返回时执行这个在前端定义的回调函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; script.src &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;http://www.domain2.com:8080/login?user=admin&amp;amp;callback=handleCallback&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.head.appendChild&lt;span style="color:#f92672"&gt;(&lt;/span&gt;script&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; // 回调执行函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; handleCallback&lt;span style="color:#f92672"&gt;(&lt;/span&gt;res&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; alert&lt;span style="color:#f92672"&gt;(&lt;/span&gt;JSON.stringify&lt;span style="color:#f92672"&gt;(&lt;/span&gt;res&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;服务端返回如下（返回时即执行全局函数）：&lt;/p&gt;</description></item><item><title>前端存储</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/</guid><description>&lt;h2 id="什么是前端存储"&gt;什么是前端存储&lt;/h2&gt;
&lt;p&gt;开门见山。前端存储就是通过前端技术来存储一段信息，然后在同源下的不同页面中都可以获取到已存储信息的一种策略。&lt;/p&gt;
&lt;h2 id="前端存储的作用"&gt;前端存储的作用&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;方便网页的加载，避免了在发送请求收到响应前页面的空白期&lt;/li&gt;
&lt;li&gt;可以在非强制性要求实时更新时减少向服务端的请求，加快渲染速度&lt;/li&gt;
&lt;li&gt;在网络不佳或无网时仍有离线数据可以查看&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="有哪些前端存储方案"&gt;有哪些前端存储方案&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;如图，一共有5种前端存储方案。大致可以分为3类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cookie&lt;/li&gt;
&lt;li&gt;WebStorage：LocalStorage、SessionStorage&lt;/li&gt;
&lt;li&gt;数据库存储：IndexedDB、WebSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;先做一个简单对比：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;下面我们详细介绍。&lt;/p&gt;
&lt;h2 id="cookie"&gt;Cookie&lt;/h2&gt;
&lt;p&gt;Cookie 的工作流程：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;Cookie 的构成：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;域、路径、失效时间和安全性都是服务器给浏览器的指示，它们不会随着请求发送给服务器，&lt;strong&gt;发送给服务器的只有名称与值的键值对&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Cookie 的生命周期：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果设定了 Cookie 的过期时间，那么 Cookie 会在到期时自动失效&lt;/li&gt;
&lt;li&gt;如果没有设定过期时间，那么 Cookie 就是 session 级别的，即浏览器关闭时 Cookie 自动消失&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cookie 的优缺点：&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以控制过期时间，不会永久有效，有一定的安全保障&lt;/li&gt;
&lt;li&gt;可进行扩展，可跨域共享&lt;/li&gt;
&lt;li&gt;通过加密与安全传输技术，可以减少 Cookie 被破解的可能性&lt;/li&gt;
&lt;li&gt;有较高的兼容性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存储大小最多4KB&lt;/li&gt;
&lt;li&gt;存储数量根据浏览器或浏览器版本的不同而不同，并且每个域最多20条&lt;/li&gt;
&lt;li&gt;请求头上的数据容易被拦截攻击&lt;/li&gt;
&lt;li&gt;存储的数据只能是字符串类型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;操作 Cookie：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置 Cookie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Cookie 值必须是字符串类型，并且不支持分号、逗号以及空格，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 所以有时需要先使用 encodeURIComponent() 进行编码，或者使用 JSON.stringify() 进行序列化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;cookie&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;键1=值1;键2=值2;键n=值n&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 读取 Cookie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 有时需要使用 decodeURIComponent() 或者 JSON.parse()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;cookie&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修改 Cookie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 如果键不存在，就新增；否则就修改
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;cookie&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;已经存储过的键=新值&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 删除 Cookie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;cookie&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;要删除的键=任意值;max-age=0&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="webstorage"&gt;WebStorage&lt;/h2&gt;
&lt;p&gt;WebStorage 是 HTML5 新加的，WebStorage（Web 存储） 分为 LocalStorage（本地存储） 和 SessionStorage（会话存储）。&lt;/p&gt;</description></item><item><title>WebWorker</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/webworker/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/webworker/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;先来聊聊单线程的Javascript&lt;/p&gt;
&lt;p&gt;众所周知，js最初设计是运行在浏览器中的，为了防止多个线程同时操作DOM，带来渲染冲突问题，所以js执行器被设计成单线程。但随着前端技术的发展，js能力远不止如此，当我们遇到需要大量计算的场景时（比如图像处理、视频解码等），js线程往往会被长时间阻塞，甚至造成页面卡顿，影响用户体验。为了解决单线程带来的这一弊端，Web Worker 应运而生。&lt;/p&gt;
&lt;h2 id="1-web-worker"&gt;1. Web Worker&lt;/h2&gt;
&lt;h3 id="11-web-worker-是什么"&gt;1.1 &lt;code&gt;Web Worker&lt;/code&gt; 是什么&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Web Worker&lt;/code&gt; 是 HTML5 标准的一部分，这一规范定义了一套 API，允许我们在 js 主线程之外开辟新的 Worker 线程，并将一段 js 脚本运行其中，它赋予了开发者利用 js 操作多线程的能力。&lt;/p&gt;
&lt;p&gt;因为是独立的线程，Worker 线程与 js 主线程能够同时运行，互不阻塞。所以，在我们有大量运算任务时，可以把运算任务交给 Worker 线程去处理，当 Worker 线程计算完成，再把结果返回给 js 主线程。这样，js 主线程只用专注处理业务逻辑，不用耗费过多时间去处理大量复杂计算，从而减少了阻塞时间，也提高了运行效率，页面流畅度和用户体验自然而然也提高了。&lt;/p&gt;
&lt;h3 id="12-web-worker-能干些什么"&gt;1.2 &lt;code&gt;Web Worker&lt;/code&gt; 能干些什么&lt;/h3&gt;
&lt;p&gt;虽然 Worker 线程是在浏览器环境中被唤起，但是它与当前页面窗口运行在不同的全局上下文中，我们常用的顶层对象 &lt;code&gt;window&lt;/code&gt;，以及 &lt;code&gt;parent&lt;/code&gt; 对象在 Worker 线程上下文中是不可用的。另外，在 Worker 线程上下文中，操作 DOM 的行为也是不可行的，&lt;code&gt;document&lt;/code&gt;对象也不存在。但是，&lt;code&gt;location&lt;/code&gt;和&lt;code&gt;navigator&lt;/code&gt;对象可以以可读方式访问。除此之外，绝大多数 Window 对象上的方法和属性，都被共享到 Worker 上下文全局对象 &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope"&gt;WorkerGlobalScope&lt;/a&gt; 中。同样，Worker 线程上下文也存在一个顶级对象 &lt;code&gt;self&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;详细信息请参考：&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers"&gt;Functions and classes available to Web Workers&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="2-web-worker-使用"&gt;2. Web Worker 使用&lt;/h2&gt;
&lt;h3 id="21-创建-worker"&gt;2.1 创建 &lt;code&gt;worker&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;创建 &lt;code&gt;worker&lt;/code&gt; 只需要通过 &lt;code&gt;new&lt;/code&gt; 调用 &lt;code&gt;Worker()&lt;/code&gt; 构造函数即可，它接收两个参数&lt;/p&gt;</description></item><item><title>Service Worker</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/service-worker/</link><pubDate>Fri, 08 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/service-worker/</guid><description>&lt;h2 id="引言"&gt;引言&lt;/h2&gt;
&lt;p&gt;我们经常可以听到 &lt;strong&gt;Worker&lt;/strong&gt; 这个名词，比如本文要介绍的 &lt;strong&gt;ServiceWorker&lt;/strong&gt; 后面就带着一个 &lt;strong&gt;Worker&lt;/strong&gt; 的单词，那么 &lt;strong&gt;Worker&lt;/strong&gt; 实际上指的是什么呢？&lt;/p&gt;
&lt;p&gt;在介绍 &lt;strong&gt;Worker&lt;/strong&gt; 的定义之前，先来回忆一下浏览器的渲染原理。&lt;/p&gt;
&lt;p&gt;在一个 tab 打开的时候，浏览器会给这个 tab 创建一个新的渲染进程（renderer process），如下图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/service-worker/image-01.webp"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;图1：Chrome 浏览器的多进程架构&lt;/p&gt;
&lt;p&gt;图片来源：&lt;a href="https://developer.chrome.com/blog/inside-browser-part1/"&gt;developer.chrome.com/blog/inside…&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在每一个渲染进程中，都会有一个主线程（Main Thread），负责 JavaScript 的执行以及浏览器的渲染（JavaScript 的执行与 UI 渲染是一个互相阻塞的流程）。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/service-worker/image-02.webp"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;图2：浏览器一帧的剖析&lt;/p&gt;
&lt;p&gt;图片来源：&lt;a href="https://aerotwist.com/blog/the-anatomy-of-a-frame/"&gt;aerotwist.com/blog/the-an…&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果 JavaScript 执行时间过久（比如超过 33.33 ms），那么一帧内留给 UI 渲染的时间不多，如果这时候网页有正在执行的动画，那么用户就会感受到卡顿。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;10 FPS：能够达成基本的视觉残留（参考：定格动画至少需要 12 帧每秒以上）&lt;/p&gt;
&lt;p&gt;30 FPS以下：让人感觉到明显的卡顿和不适感&lt;/p&gt;
&lt;p&gt;30-50 FPS：因人而异&lt;/p&gt;
&lt;p&gt;50-60 FPS：流畅&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一个 Worker，指的是一个可以在后台独立执行 JavaScript 脚本。它存在于一个单独的 worker 线程，即使执行一些长任务也不会阻塞主线程响应用户操作（如鼠标点击、动画等）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;另外 Worker 也指使用 &lt;code&gt;new Worker()&lt;/code&gt; 构造函数创建的一个对象，可以用在主线程与 worker 线程的通信&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/service-worker/image-03.webp"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;图3：worker 线程独立于主线程之外&lt;/p&gt;
&lt;p&gt;图片来源：&lt;a href="https://developer.chrome.com/blog/inside-browser-part3/"&gt;developer.chrome.com/blog/inside…&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Worker 与 主线程之间可以通过 &lt;code&gt;postMessage&lt;/code&gt; 进行通信：&lt;/p&gt;</description></item><item><title>WebSocket</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/websocket/</link><pubDate>Fri, 08 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/websocket/</guid><description>&lt;h2 id="一什么是websocket"&gt;一、什么是WebSocket&lt;/h2&gt;
&lt;p&gt;WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单，允许服务端主动向客户端推送数据。&lt;/p&gt;
&lt;p&gt;在 WebSocket API 中，浏览器和服务器只需要完成一次握手，两者之间就直接可以创建持久性的连接， 并进行双向数据传输。（维基百科）&lt;/p&gt;
&lt;p&gt;WebSocket本质上一种&lt;code&gt;计算机网络应用层的协议&lt;/code&gt;，用来弥补http协议在持久通信能力上的不足。&lt;/p&gt;
&lt;p&gt;WebSocket 协议在2008年诞生，2011年成为国际标准。现在最新版本浏览器都已经支持了。&lt;/p&gt;
&lt;p&gt;它的最大特点就是，服务器可以主动向客户端推送信息，客户端也可以主动向服务器发送信息，是真正的双向平等对话，属于&lt;a href="https://en.wikipedia.org/wiki/Push_technology"&gt;服务器推送技术&lt;/a&gt;的一种。&lt;/p&gt;
&lt;p&gt;WebSocket 的其他特点包括：&lt;/p&gt;
&lt;p&gt;（1）建立在 TCP 协议之上，服务器端的实现比较容易。&lt;/p&gt;
&lt;p&gt;（2）与 HTTP 协议有着良好的兼容性。默认端口也是80和443，并且握手阶段采用 HTTP 协议，因此握手时不容易屏蔽，能通过各种 HTTP 代理服务器。&lt;/p&gt;
&lt;p&gt;（3）数据格式比较轻量，性能开销小，通信高效。&lt;/p&gt;
&lt;p&gt;（4）可以发送文本，也可以发送二进制数据。&lt;/p&gt;
&lt;p&gt;（5）没有同源限制，客户端可以与任意服务器通信。&lt;/p&gt;
&lt;p&gt;（6）协议标识符是&lt;code&gt;ws&lt;/code&gt;（如果加密，则为&lt;code&gt;wss&lt;/code&gt;），服务器网址就是 URL。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ws&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#75715e"&gt;//example.com:80/some/path
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/websocket/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="为什么需要-websocket"&gt;为什么需要 WebSocket？&lt;/h3&gt;
&lt;p&gt;我们已经有了 HTTP 协议，为什么还需要另一个协议？它能带来什么好处？&lt;/p&gt;
&lt;p&gt;因为 HTTP 协议有一个缺陷：通信只能由客户端发起，不具备服务器推送能力。&lt;/p&gt;
&lt;p&gt;举例来说，我们想了解查询今天的实时数据，只能是客户端向服务器发出请求，服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/websocket/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;这种单向请求的特点，注定了如果服务器有连续的状态变化，客户端要获知就非常麻烦。我们只能使用&lt;a href="https://www.pubnub.com/blog/2014-12-01-http-long-polling/"&gt;&amp;ldquo;轮询&amp;rdquo;&lt;/a&gt;：每隔一段时候，就发出一个询问，了解服务器有没有新的信息。最典型的场景就是聊天室。轮询的效率低，非常浪费资源（因为必须不停连接，或者 HTTP 连接始终打开）。&lt;/p&gt;
&lt;p&gt;在 WebSocket 协议出现以前，创建一个和服务端进双通道通信的 web 应用，需要依赖HTTP协议，进行不停的轮询，这会导致一些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务端被迫维持来自每个客户端的大量不同的连接&lt;/li&gt;
&lt;li&gt;大量的轮询请求会造成高开销，比如会带上多余的header，造成了无用的数据传输。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;http协议本身是没有持久通信能力的，但是我们在实际的应用中，是很需要这种能力的，所以，为了解决这些问题，WebSocket协议由此而生，于2011年被IETF定为标准RFC6455，并被RFC7936所补充规范。&lt;/p&gt;
&lt;p&gt;并且在HTML5标准中增加了有关WebSocket协议的相关api，所以只要实现了HTML5标准的客户端，就可以与支持WebSocket协议的服务器进行全双工的持久通信了。&lt;/p&gt;
&lt;h3 id="websocket-与-http-的区别"&gt;WebSocket 与 HTTP 的区别&lt;/h3&gt;
&lt;p&gt;WebSocket 与 HTTP的关系图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/websocket/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;相同点：&lt;/strong&gt; 都是一样基于TCP的，都是可靠性传输协议。都是应用层协议。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;联系：&lt;/strong&gt; WebSocket在建立握手时，数据是通过HTTP传输的。但是建立之后，在真正传输时候是不需要HTTP协议的。&lt;/p&gt;
&lt;p&gt;下面一张图说明了 HTTP 与 WebSocket 的主要区别：&lt;/p&gt;</description></item><item><title>设计模式</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-029/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-029/</guid><description>&lt;p&gt;说到设计模式，大家想到的就是六大原则，23种模式。这么多模式，并非都要记住，但作为前端开发，对于前端出现率高的设计模式还是有必要了解并掌握的，浅浅掌握9种模式后，整理了这份文章。&lt;/p&gt;
&lt;p&gt;那么，我们先了解六大原则&lt;/p&gt;
&lt;h2 id="六大原则"&gt;六大原则：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;依赖倒置原则(Dependence Inversion Principle)：高层(业务层)不应该直接调用底层(基础层)模块&lt;/li&gt;
&lt;li&gt;开闭原则(Open Close Principle)：单模块对拓展开放、对修改关闭&lt;/li&gt;
&lt;li&gt;单一原则(Single Responsibility Principle)：单模块负责的职责必须是单一的&lt;/li&gt;
&lt;li&gt;迪米特法则(Law of Demeter)：对外暴露接口应该简单&lt;/li&gt;
&lt;li&gt;接口隔离原则(Interface Segregation Principle)：单个接口(类)都应该按业务隔离开&lt;/li&gt;
&lt;li&gt;里氏替换原则(Liskov Substitution Principle)：子类可以替换父类&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;六大原则也可以用六个字替换：高内聚低耦合。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;高&lt;/strong&gt;层不直接依赖底层：依赖倒置原则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内&lt;/strong&gt;部修改关闭，外部开放扩展：开闭原则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;聚&lt;/strong&gt;合单一功能：单一原则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;低&lt;/strong&gt;知识接口，对外接口简单：迪米特法则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;耦&lt;/strong&gt;合多个接口，不如隔离拆分：接口隔离原则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;合&lt;/strong&gt;并复用，子类可以替换父类：里氏替换原则&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们采用模式编写时，要尽可能遵守这六大原则&lt;/p&gt;
&lt;h2 id="23-种设计模式分为创建型行为型和结构型"&gt;23 种设计模式分为“创建型”、“行为型”和“结构型”&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-029/image-01.png"&gt;&lt;/p&gt;
&lt;h2 id="前端九种设计模式"&gt;前端九种设计模式&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-029/image-02.webp"&gt;&lt;/p&gt;
&lt;h2 id="一创建型"&gt;一、创建型&lt;/h2&gt;
&lt;p&gt;创建型从功能上来说就是创建元素，目标是规范元素创建步骤&lt;/p&gt;
&lt;h3 id="1构造器模式抽象了对象实例的变与不变变的是属性值不变的是属性名"&gt;1.构造器模式：抽象了对象实例的变与不变(变的是属性值，不变的是属性名)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 需求：给公司员工创建线上基本信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 单个员工创建，可以直接使用创建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;张三&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;20&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;department&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;人力资源部门&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 可员工的数量过于多的时候，一个个创建不可行，那么就可以使用构造器模式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;age&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;department&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;department&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-工厂模式为创建一组相关或相互依赖的对象提供一个接口且无须指定它们的具体类"&gt;2. 工厂模式：为创建一组相关或相互依赖的对象提供一个接口，且无须指定它们的具体类&lt;/h3&gt;
&lt;p&gt;即隐藏创建过程、暴露共同接口。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 需求：公司员工创建完信息后需要为每一个员工创建一个信息名片
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setPerson&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;pesonObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;creatCard&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//创建信息名片
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;otherFynction&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setPerson&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;card&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;creatCard&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;张三&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;20&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;department&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;人力资源部门&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-单例模式全局只有一个实例避免重复创建对象优化性能"&gt;3. 单例模式：全局只有一个实例，避免重复创建对象，优化性能&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 需求：判断一款应用的开闭状态，根据不同状态给出不同提示
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationStation&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;off&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;play&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;on&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;已打开&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;on&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;shutdown&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;off&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;已关闭&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;off&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;window.&lt;span style="color:#a6e22e"&gt;applicationStation&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationStation&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// applicationStation.instance = undefined
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// applicationStation.getInstance = function() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// return function() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// if (!applicationStation.instance) { // 如果全局没有实例再创建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// applicationStation.instance = new applicationStation()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// return applicationStation.instance
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// }()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// application1和application2拥有同一个applicationStation对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;application1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; window.&lt;span style="color:#a6e22e"&gt;applicationStation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;application2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; window.&lt;span style="color:#a6e22e"&gt;applicationStation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="二结构型"&gt;二、结构型&lt;/h2&gt;
&lt;p&gt;结构型从功能上来说就是给元素添加行为的，目标是优化结构的实现方式&lt;/p&gt;</description></item><item><title>JavaScript 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/javascript/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/javascript/</guid><description>&lt;p&gt;共 407 道 JavaScript 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-f142c5fe-17fd-444e-8daf-bd03d085ce69"&gt;1. &lt;code&gt;requestAnimationFrame&lt;/code&gt; 与 &lt;code&gt;requestIdleCallback&lt;/code&gt; 在渲染优化中的执行时机差异？谁优先触发？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;requestAnimationFrame&lt;/code&gt; 在浏览器即将进行下一帧渲染之前执行，用于动画与视觉更新，优先级高于渲染阶段后的任务。&lt;code&gt;requestIdleCallback&lt;/code&gt; 只会在当前帧所有渲染任务完成且仍有剩余时间时触发，属于低优先级空闲调度机制。因此在同一帧中，rAF 必然先于 rIC 执行。rAF 用于保证帧同步，rIC 用于利用空闲时间执行非关键任务。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题本质是理解 &lt;strong&gt;浏览器一帧的调度模型&lt;/strong&gt;。
不搞清楚一帧里发生了什么，很容易回答成“谁快谁慢”这种表层结论。&lt;/p&gt;
&lt;p&gt;核心结论先给出：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在有下一帧渲染需求的情况下，&lt;code&gt;requestAnimationFrame&lt;/code&gt; 一定优先于 &lt;code&gt;requestIdleCallback&lt;/code&gt; 执行。
&lt;code&gt;requestIdleCallback&lt;/code&gt; 只会在当前帧还有“空闲时间”时才会触发。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面从浏览器帧模型拆解。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="一浏览器一帧的基本流程"&gt;一、浏览器一帧的基本流程&lt;/h1&gt;
&lt;p&gt;以 60fps 为例，一帧约 16.6ms。&lt;/p&gt;
&lt;p&gt;一次完整渲染循环大致是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;执行宏任务（例如 setTimeout）&lt;/li&gt;
&lt;li&gt;清空微任务队列&lt;/li&gt;
&lt;li&gt;触发 requestAnimationFrame 回调&lt;/li&gt;
&lt;li&gt;进行样式计算（Style）&lt;/li&gt;
&lt;li&gt;布局计算（Layout）&lt;/li&gt;
&lt;li&gt;绘制（Paint）&lt;/li&gt;
&lt;li&gt;合成（Composite）&lt;/li&gt;
&lt;li&gt;如果还有时间 → 执行 requestIdleCallback&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;需要明确一点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rAF 是“下一帧渲染前”的回调&lt;/li&gt;
&lt;li&gt;rIC 是“当前帧剩余时间”的回调&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1 id="二requestanimationframe-的执行时机"&gt;二、requestAnimationFrame 的执行时机&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;requestAnimationFrame&lt;/code&gt; 的设计目标是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在浏览器即将进行下一次重绘之前执行回调。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每帧最多执行一次&lt;/li&gt;
&lt;li&gt;与刷新率同步&lt;/li&gt;
&lt;li&gt;在样式计算之前触发&lt;/li&gt;
&lt;li&gt;如果标签页不可见，会暂停&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;执行时机可以理解为：&lt;/p&gt;</description></item></channel></rss>