<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss/feed.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>(╹ڡ╹ ) 的博客</title><description>Wala li longla ~~~</description><link>https://wine-congee.vercel.app</link><item><title>WebScoket</title><link>https://wine-congee.vercel.app/post/WebScoket</link><guid isPermaLink="false">WebScoket</guid><description>在 Web 应用早期，浏览器和服务器之间的通信几乎完全依赖 HTTP 请求。用户点击按钮，浏览器发起请求，服务器返回响应。这种模式简单、可靠，也非常适合传统页面加载和表单提交。
但随着聊天系统、在线协作、实时行情、多人游戏、消息通知等场景出现，传统 HTTP</description><pubDate>Fri, 12 Jun 2026 13:50:23 GMT</pubDate><content:encoded>&lt;p&gt;在 Web 应用早期，浏览器和服务器之间的通信几乎完全依赖 HTTP 请求。用户点击按钮，浏览器发起请求，服务器返回响应。这种模式简单、可靠，也非常适合传统页面加载和表单提交。&lt;/p&gt;
&lt;p&gt;但随着聊天系统、在线协作、实时行情、多人游戏、消息通知等场景出现，传统 HTTP 的“一问一答”模式开始显得笨重。客户端想要知道服务器有没有新消息，就必须不断轮询服务器。轮询不仅浪费带宽，也增加服务器压力，实时性还不够理想。&lt;/p&gt;
&lt;p&gt;WebSocket 正是在这种背景下出现的。它让浏览器和服务器之间建立一条持久的双向通信通道，使双方都可以随时主动发送消息。&lt;/p&gt;
&lt;h2&gt;一、WebSocket 是什么？&lt;a href=&quot;#一websocket-是什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WebSocket 是一种基于 TCP 的全双工通信协议。它允许客户端和服务器在一次连接建立后，持续保持通信通道，并且双方都能主动向对方发送数据。&lt;/p&gt;
&lt;p&gt;简单来说，HTTP 更像是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;客户端：你有新消息吗？&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;服务器：没有。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;客户端：你有新消息吗？&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;服务器：没有。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;客户端：你有新消息吗？&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;服务器：有，给你。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;WebSocket 更像是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;客户端：我们建立一个长期连接吧。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;服务器：可以。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;服务器：有新消息了，直接发给你。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;客户端：收到。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种模式非常适合实时性要求较高的业务。&lt;/p&gt;
&lt;h2&gt;二、WebSocket 和 HTTP 的关系&lt;a href=&quot;#二websocket-和-http-的关系&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WebSocket 并不是 HTTP 的替代品，而是对 HTTP 通信能力的一种补充。&lt;/p&gt;
&lt;p&gt;WebSocket 的连接通常从一个 HTTP 请求开始。客户端会发送一个带有 &lt;code&gt;Upgrade&lt;/code&gt; 头的 HTTP 请求，告诉服务器：“我想把这个连接升级成 WebSocket。”&lt;/p&gt;
&lt;p&gt;示意请求如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;GET&lt;/span&gt;&lt;span&gt; /chat &lt;/span&gt;&lt;span&gt;HTTP&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;1.1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Host&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; example.com&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Upgrade&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; websocket&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Connection&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Upgrade&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Sec-WebSocket-Key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; xxx&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Sec-WebSocket-Version&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 13&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果服务器支持 WebSocket，就会返回类似响应：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;HTTP&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;1.1&lt;/span&gt;&lt;span&gt; 101&lt;/span&gt;&lt;span&gt; Switching Protocols&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Upgrade&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; websocket&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Connection&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Upgrade&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Sec-WebSocket-Accept&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; xxx&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;状态码 &lt;code&gt;101 Switching Protocols&lt;/code&gt; 表示协议切换成功。之后，这条连接就不再按照普通 HTTP 请求响应模式通信，而是进入 WebSocket 双向通信阶段。&lt;/p&gt;
&lt;h2&gt;三、为什么不用 HTTP 轮询？&lt;a href=&quot;#三为什么不用-http-轮询&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在 WebSocket 普及之前，实时通信常见方案主要有三种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;短轮询
&lt;ol&gt;
&lt;li&gt;短轮询最简单，客户端每隔几秒请求一次服务器。但如果大多数请求都没有新数据，就会造成大量无效请求。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;长轮询
&lt;ol&gt;
&lt;li&gt;长轮询比短轮询稍好。客户端发送请求后，服务器如果没有新数据，会暂时挂起请求，直到有数据或超时再返回。它减少了一些无效请求，但本质上仍然是 HTTP 请求响应模型。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Server-Sent Events
&lt;ol&gt;
&lt;li&gt;Server-Sent Events，简称 SSE，允许服务器持续向客户端推送事件。但它主要是单向通信：服务器推给客户端。如果客户端也要频繁发送消息，仍然需要 HTTP 请求配合。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;WebSocket 的优势在于，它是真正的双向通信。客户端和服务器都可以主动发送数据，通信开销更低，实时性更好。&lt;/p&gt;
&lt;h2&gt;四、WebSocket 的核心特点&lt;a href=&quot;#四websocket-的核心特点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 全双工通信&lt;a href=&quot;#1-全双工通信&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WebSocket 最大的特点是全双工。连接建立后，客户端和服务器可以同时发送和接收消息，不需要等待对方先发起请求。这对聊天、直播弹幕、在线游戏、协作文档等场景非常重要。&lt;/p&gt;
&lt;h3&gt;2. 持久连接&lt;a href=&quot;#2-持久连接&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WebSocket 建立后会保持连接，除非客户端、服务器或网络主动断开。相比 HTTP 每次请求都要携带大量头部信息，WebSocket 后续数据帧更轻量。&lt;/p&gt;
&lt;h3&gt;3. 低延迟&lt;a href=&quot;#3-低延迟&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;由于连接已经建立，后续通信不需要重复握手。服务器有数据时可以立刻推送给客户端，因此延迟通常比轮询方案更低。&lt;/p&gt;
&lt;h3&gt;4. 支持文本和二进制数据&lt;a href=&quot;#4-支持文本和二进制数据&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WebSocket 可以传输文本，也可以传输二进制数据，比如图片片段、音视频数据、协议缓冲区数据等。&lt;/p&gt;
&lt;h2&gt;五、WebSocket 适合哪些场景？&lt;a href=&quot;#五websocket-适合哪些场景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WebSocket 不是所有业务都需要，但在以下场景中非常有价值：&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;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;判断是否需要 WebSocket，可以问一个简单问题：“服务器是否需要在客户端没有请求时，主动把数据推给客户端？”，如果答案是肯定的，WebSocket 很可能是合适方案。&lt;/p&gt;
&lt;h2&gt;六、浏览器中如何使用 WebSocket？&lt;a href=&quot;#六浏览器中如何使用-websocket&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;由于浏览器原生支持 WebSocket API，使用非常简单。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; socket&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; WebSocket&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;wss://example.com/socket&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;socket.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;open&quot;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;WebSocket connected&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  socket.&lt;/span&gt;&lt;span&gt;send&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;({ type: &lt;/span&gt;&lt;span&gt;&quot;hello&quot;&lt;/span&gt;&lt;span&gt; }));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;socket.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;message&quot;&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;parse&lt;/span&gt;&lt;span&gt;(event.data);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Received:&quot;&lt;/span&gt;&lt;span&gt;, data);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;socket.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;close&quot;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;WebSocket closed&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;socket.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;error&quot;&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;WebSocket error:&quot;&lt;/span&gt;&lt;span&gt;, error);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ws://&lt;/code&gt; 类似 HTTP&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wss://&lt;/code&gt; 类似 HTTPS，表示加密 WebSocket 连接&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;生产环境中应优先使用 &lt;code&gt;wss://&lt;/code&gt;，避免通信被窃听或篡改。&lt;/p&gt;
&lt;h2&gt;七、服务端简单示例&lt;a href=&quot;#七服务端简单示例&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;以 Node.js 的 &lt;code&gt;ws&lt;/code&gt; 库为例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { WebSocketServer } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &quot;ws&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; wss&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; WebSocketServer&lt;/span&gt;&lt;span&gt;({ port: &lt;/span&gt;&lt;span&gt;8080&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;wss.&lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;connection&quot;&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;socket&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;client connected&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  socket.&lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;message&quot;&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;received:&quot;&lt;/span&gt;&lt;span&gt;, message.&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    socket.&lt;/span&gt;&lt;span&gt;send&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      type: &lt;/span&gt;&lt;span&gt;&quot;echo&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      payload: message.&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  socket.&lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;close&quot;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;client disconnected&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个例子中，服务器接收客户端消息后，会原样返回一条 echo 消息。&lt;/p&gt;
&lt;p&gt;真实业务中，服务端通常还需要处理身份认证、房间管理、消息广播、心跳检测、限流、断线重连等问题。&lt;/p&gt;
&lt;h2&gt;八、WebSocket 的常见问题&lt;a href=&quot;#八websocket-的常见问题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 身份认证&lt;a href=&quot;#1-身份认证&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WebSocket 连接建立后不像普通 HTTP 请求那样每次都携带完整请求上下文，因此认证需要提前设计。&lt;/p&gt;
&lt;p&gt;常见方式有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在连接 URL 中携带短期 token&lt;/li&gt;
&lt;li&gt;在 WebSocket 子协议中传递认证信息&lt;/li&gt;
&lt;li&gt;连接建立后发送认证消息&lt;/li&gt;
&lt;li&gt;借助 Cookie 和服务端 Session&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; socket&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; WebSocket&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;wss://example.com/socket?token=xxx&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不过 URL 中的 token 可能出现在日志里，因此更推荐使用短期、可撤销、权限有限的 token。&lt;/p&gt;
&lt;h3&gt;2. 心跳检测&lt;a href=&quot;#2-心跳检测&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;网络连接可能因为代理、NAT、防火墙或移动网络切换而悄悄断开。客户端和服务器不能只依赖 &lt;code&gt;close&lt;/code&gt; 事件判断连接是否还活着，因此通常需要心跳机制。一种常见方式是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;客户端定时发送 ping&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;服务器收到后返回 pong&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;如果连续多次没有 pong，客户端主动重连&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;服务端也可以主动发送 ping，用于清理已经失效的连接。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3. 断线重连&lt;a href=&quot;#3-断线重连&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WebSocket 是长连接，但长连接并不意味着永远连接。网络抖动、服务重启、页面休眠、移动端切网都可能导致断开。客户端应该实现重连机制，并且最好使用指数退避，避免大量客户端同时重连压垮服务器。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 示意逻辑：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; retryCount &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; connect&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; socket&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; WebSocket&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;wss://example.com/socket&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  socket.&lt;/span&gt;&lt;span&gt;onopen&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    retryCount &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  socket.&lt;/span&gt;&lt;span&gt;onclose&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; delay&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt; **&lt;/span&gt;&lt;span&gt; retryCount, &lt;/span&gt;&lt;span&gt;30000&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    retryCount &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    setTimeout&lt;/span&gt;&lt;span&gt;(connect, delay);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;connect&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 消息可靠性&lt;a href=&quot;#4-消息可靠性&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WebSocket 只负责传输，不天然保证业务层消息一定被正确处理。如果业务对可靠性要求高，比如订单状态、交易通知、协作文档操作，就需要设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消息 ID&lt;/li&gt;
&lt;li&gt;ACK 确认机制&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;id&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;msg_123&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;type&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;chat.message&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;payload&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &quot;text&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务器处理后返回：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;type&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;ack&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;id&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;msg_123&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样客户端才能知道这条消息是否真正被服务端接收。&lt;/p&gt;
&lt;h3&gt;5. 水平扩展&lt;a href=&quot;#5-水平扩展&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;单机 WebSocket 很容易理解，但真实生产环境往往是多台服务器。问题在于：用户 A 连接在服务器 1，用户 B 连接在服务器 2。如果 A 给 B 发消息，服务器 1 需要某种方式把消息转给服务器 2。&lt;/p&gt;
&lt;p&gt;常见解决方案包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 Redis Pub/Sub&lt;/li&gt;
&lt;li&gt;使用 Kafka、RabbitMQ、NATS 等消息系统&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;Client A -&amp;gt; WebSocket Server 1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Client B -&amp;gt; WebSocket Server 2&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Server 1 -&amp;gt; Message Broker -&amp;gt; Server 2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;消息系统在这里承担跨实例广播和解耦的作用。&lt;/p&gt;
&lt;h2&gt;九、WebSocket 和 SSE 怎么选？&lt;a href=&quot;#九websocket-和-sse-怎么选&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;如果业务只是服务器向客户端单向推送，比如通知流、日志流、状态更新，SSE 可能更简单。&lt;/li&gt;
&lt;li&gt;如果业务需要客户端和服务器频繁双向通信，比如聊天、游戏、协作编辑，WebSocket 更合适。&lt;/li&gt;
&lt;/ul&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;WebSocket&lt;/th&gt;&lt;th&gt;SSE&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&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;/td&gt;&lt;td&gt;独立协议，HTTP Upgrade 后切换&lt;/td&gt;&lt;td&gt;基于 HTTP&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&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;/td&gt;&lt;td&gt;支持&lt;/td&gt;&lt;td&gt;不直接支持&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&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;/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&gt;十、生产环境最佳实践&lt;a href=&quot;#十生产环境最佳实践&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;使用 WebSocket 时，建议遵循这些原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;生产环境使用 &lt;code&gt;wss://&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;设计清晰的消息协议&lt;/li&gt;
&lt;li&gt;每条重要消息带唯一 ID&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;/li&gt;
&lt;li&gt;避免把 WebSocket 当成数据库同步工具滥用&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;一个成熟的 WebSocket 系统，难点通常不在“建立连接”，而在连接之后的治理。&lt;/p&gt;
&lt;h2&gt;十一、一个推荐的消息格式&lt;a href=&quot;#十一一个推荐的消息格式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;为了让 WebSocket 通信更可维护，建议定义统一消息结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;id&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;msg_001&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;type&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;chat.message&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;timestamp&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1710000000000&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;payload&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &quot;roomId&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;room_1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &quot;content&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;Hello WebSocket&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id&lt;/code&gt; 用于追踪和去重&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt; 用于区分消息类型&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timestamp&lt;/code&gt; 用于排序和调试&lt;/li&gt;
&lt;li&gt;&lt;code&gt;payload&lt;/code&gt; 存放业务数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;错误消息也应标准化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;type&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;error&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;code&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;UNAUTHORIZED&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;message&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;Authentication failed&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样前后端就能围绕协议协作，而不是在大量零散字段中互相猜测。&lt;/p&gt;
&lt;h2&gt;十二、总结&lt;a href=&quot;#十二总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WebSocket 解决的是 Web 应用中的实时双向通信问题。它通过一次握手建立持久连接，让客户端和服务器可以低延迟、低开销地互相发送消息。&lt;/p&gt;
&lt;p&gt;它非常适合聊天、协作、游戏、实时看板和行情推送等场景。但 WebSocket 不是简单地“连上就完事”。真正的工程重点在于认证、心跳、重连、消息可靠性、水平扩展和监控治理。&lt;/p&gt;
&lt;p&gt;如果只是单向推送，SSE 可能更轻量；如果需要频繁双向通信，WebSocket 通常是更好的选择。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;WebSocket 让 Web 从“客户端主动询问”走向了“服务端实时对话”，但要把它用好，需要的不只是协议能力，更是完整的实时系统设计。&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>category:网络通信</category><category>tag:网络通信</category><category>tag:前端</category><category>tag:后端</category></item><item><title>Agent Client Protocol 初学习</title><link>https://wine-congee.vercel.app/post/Agent-Client-Protocol</link><guid isPermaLink="false">Agent-Client-Protocol</guid><description>认识 Agent Client Protocol
什么是 Agent Client Protocol？
Agent Client Protocol（简称 ACP）是一种专门用于 AI Agent 与客户端（编辑器、IDE、终端、Web 应用等）之间通信的开放协议，用来规范 AI</description><pubDate>Sat, 06 Jun 2026 04:36:08 GMT</pubDate><content:encoded>&lt;h2&gt;认识 Agent Client Protocol&lt;a href=&quot;#认识-agent-client-protocol&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;什么是 Agent Client Protocol？&lt;a href=&quot;#什么是-agent-client-protocol&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Agent Client Protocol（简称 ACP）是一种专门用于 &lt;strong&gt;AI Agent 与客户端（编辑器、IDE、终端、Web 应用等）之间通信的开放协议&lt;/strong&gt;，用来规范 AI 编码智能体与代码编辑器 / IDE 等客户端之间如何交互、同步状态和下发命令。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;简单来说，ACP 定义了一套统一的通信标准，让任何支持 ACP 的编辑器都可以连接任何支持 ACP 的 AI Agent。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ACP 的核心目标，是让&lt;strong&gt;任何代码编辑器可以连接任何 AI 编码智能体&lt;/strong&gt;，通过一套统一协议完成会话管理、能力协商、状态同步和操作执行，解决的就是 &lt;strong&gt;“编辑器如何与 AI 编码代理通信”&lt;/strong&gt; 的问题。&lt;/p&gt;
&lt;p&gt;例如 VS Code、Cursor、Windsurf、JetBrains IDE、自研 IDE 等等类似的产品都属于 &lt;strong&gt;Client（客户端）&lt;/strong&gt;，而 Claude Code、OpenAI Codex Agent、Gemini CLI、Aider、自研 Coding Agent 都属于 &lt;strong&gt;Agent&lt;/strong&gt;，ACP 就是他们之间通信连接的“通用语言”。&lt;/p&gt;
&lt;h3&gt;为什么会产生 Agent Client Protocol？&lt;a href=&quot;#为什么会产生-agent-client-protocol&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在 ACP 出现之前：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;VS Code   &amp;lt;--私有协议--&amp;gt;  Claude Code&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Cursor    &amp;lt;--私有协议--&amp;gt;  Claude Code&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;JetBrains &amp;lt;--私有协议--&amp;gt;  Claude Code&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Windsurf  &amp;lt;--私有协议--&amp;gt;  Claude Code&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一个编辑器都要单独适配 Claude Code、单独适配 Codex、单独适配 Gemini …，而每个 Agent 也要：单独支持 VS Code、单独支持 Cursor、单独支持 JetBrains …，产生出 N × M 个适配问题，可以想象如果没有一个统一的通信协议，这些 Client（客户端）和 Agent 之间通信连接的建立与维护，成本都是极高的。&lt;/p&gt;
&lt;p&gt;同时，AI 智能体任务越来越长时、多步、需要频繁读写文件、调用终端，缺少统一协议会导致过程不可观测、结果不可复现、权限控制混乱，就难以满足企业落地和团队协作的需求。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以上这些问题正是 ACP 产生的根本原因：&lt;/p&gt;
&lt;p&gt;AI 编码智能体越来越强大，而编辑器与智能体之间缺少统一标准，导致生态割裂、重复适配成本高。ACP 通过定义 Agent 与 Client 的标准通信协议，实现 “任意客户端连接任意 Agent” 的互操作能力。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;理解 Agent Client Protocol&lt;a href=&quot;#理解-agent-client-protocol&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;理解 ACP，最重要的不是把所有 method 名背下来，而是抓住它的&lt;strong&gt;几个核心概念和流程&lt;/strong&gt;。&lt;/p&gt;
&lt;h3&gt;Client 和 Agent：谁负责什么？&lt;a href=&quot;#client-和-agent谁负责什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在 ACP 的世界里有两个角色：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Client（客户端）
&lt;ul&gt;
&lt;li&gt;典型角色：VS Code、JetBrains、Zed、Neovim 插件、自研 Web IDE、命令行工具等。&lt;/li&gt;
&lt;li&gt;职责：
&lt;ul&gt;
&lt;li&gt;与用户交互（UI、输入输出）。&lt;/li&gt;
&lt;li&gt;掌控本地能力：文件系统、终端/命令执行、网络访问、弹窗等。&lt;/li&gt;
&lt;li&gt;决定是否给 Agent 授权执行某些操作，并记录日志做审计。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Agent（智能体）
&lt;ul&gt;
&lt;li&gt;典型角色：一个使用大模型的编码助手服务，可以运行在本地进程或远程服务器。&lt;/li&gt;
&lt;li&gt;职责：
&lt;ul&gt;
&lt;li&gt;理解用户需求、分析代码、规划修改方案。&lt;/li&gt;
&lt;li&gt;通过 ACP 请求 Client 提供所需的环境能力（读文件、写文件、运行测试等）。&lt;/li&gt;
&lt;li&gt;以流式消息、事件形式把思考过程和结果反馈给 Client。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两者之间通过 ACP 交流，一端发 &lt;strong&gt;JSON‑RPC&lt;/strong&gt; 请求/通知，一端响应或推回事件，形成一个完整的事件流。&lt;/p&gt;
&lt;h4&gt;JSON‑RPC 是什么？&lt;a href=&quot;#jsonrpc-是什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;h5&gt;JSON‑RPC 的核心概念&lt;a href=&quot;#jsonrpc-的核心概念&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;JSON‑RPC（JavaScript Object Notation Remote Procedure Call）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是一种&lt;u&gt;基于 JSON 的远程过程调用协议&lt;/u&gt;，&lt;strong&gt;本质是用 JSON 来描述“调用某个远程函数”的请求和结果&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;它不规定我们调用时必须用什么传输层（可以是 HTTP、WebSocket、TCP、自定义管道甚至标准输入输出），只规定&lt;strong&gt;消息的格式&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;目标是让两个进程/服务之间的通信&lt;strong&gt;看起来就像是本地函数调用&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;指定方法名（method）&lt;/li&gt;
&lt;li&gt;传入参数（params）&lt;/li&gt;
&lt;li&gt;得到返回值（result 或 error）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们可以把它当成&lt;strong&gt;用 JSON 写的 RPC 协议&lt;/strong&gt;，和 REST 那种&lt;u&gt;资源 + HTTP 动词&lt;/u&gt;风格不太一样，它更偏向&lt;strong&gt;直接调用函数&lt;/strong&gt;。&lt;/p&gt;
&lt;h5&gt;JSON‑RPC 的三种消息类型&lt;a href=&quot;#jsonrpc-的三种消息类型&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;在 JSON‑RPC 2.0 里，有三种核心消息形式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;请求（Request）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;有 &lt;code&gt;id&lt;/code&gt; 字段。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结构大致是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;jsonrpc&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;2.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;id&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;method&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;someMethod&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;params&quot;&lt;/span&gt;&lt;span&gt;: { &lt;/span&gt;&lt;span&gt;&quot;foo&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;bar&quot;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;含义：我要调用你那边名为 &lt;code&gt;someMethod&lt;/code&gt; 的方法，参数是 &lt;code&gt;params&lt;/code&gt;，请给我一个响应。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;响应（Response）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;必须带上对应请求的 &lt;code&gt;id&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;成功时包含 &lt;code&gt;result&lt;/code&gt;，失败时包含 &lt;code&gt;error&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;jsonrpc&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;2.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;id&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;result&quot;&lt;/span&gt;&lt;span&gt;: { &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;jsonrpc&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;2.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;id&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;error&quot;&lt;/span&gt;&lt;span&gt;: { &lt;/span&gt;&lt;span&gt;&quot;code&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-32602&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;message&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;Invalid params&quot;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通知（Notification）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;没有 &lt;code&gt;id&lt;/code&gt;，表示&lt;strong&gt;不需要响应&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结构类似请求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;jsonrpc&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;2.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;method&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;log&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;params&quot;&lt;/span&gt;&lt;span&gt;: { &lt;/span&gt;&lt;span&gt;&quot;level&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;info&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;message&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;hello&quot;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;场景：发日志、发进度事件、发状态变更，不需要对方回一个响应。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;JSON‑RPC 的几个特点&lt;a href=&quot;#jsonrpc-的几个特点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;轻量：消息就是 JSON，易读易调试。&lt;/li&gt;
&lt;li&gt;无状态：协议层不强制会话概念（像 ACP 这样需要会话，会自己在 &lt;code&gt;params&lt;/code&gt; 里带 &lt;code&gt;sessionId&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;双向：只要底层连接是双向（如 WebSocket / stdio），双方都可以当「客户端」发请求，对方当「服务端」响应。&lt;/li&gt;
&lt;li&gt;支持批量调用：可以一次发一个 JSON 数组，里面多个请求一起处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;初始化与能力协商&lt;a href=&quot;#初始化与能力协商&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ACP 一切交互的起点是 &lt;code&gt;initialize&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;当 Client 启动并连接到一个 ACP Agent 时，它会先发送一个 &lt;code&gt;initialize&lt;/code&gt; 请求，用来协商：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;协议版本（protocolVersion）&lt;/li&gt;
&lt;li&gt;彼此支持的能力和扩展&lt;/li&gt;
&lt;li&gt;协商身份验证方法&lt;/li&gt;
&lt;li&gt;一些基础元信息（客户端名称、Agent 名称等）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这一步的意义在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;避免版本不兼容：比如 Client 是 v1，Agent 是 v2，就可以在这里检测并处理。&lt;/li&gt;
&lt;li&gt;让双方提前知道对方支持哪些扩展功能，比如是否支持某种文件系统 API、是否支持多 Agent 协作等。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;写在代码层，我们基本可以抽象成一个 &lt;code&gt;acpClient.initialize()&lt;/code&gt; 的高层调用，之后所有方法都建立在这一步成功的前提下。&lt;/p&gt;
&lt;p&gt;这其实就是相当于在让客户端和智能体建立连接，连接建立后，我们可以进行身份认证，然后创建会话并开始与智能体的对话。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;更详细信息的可查看官方文档：&lt;a href=&quot;https://agentclientprotocol.com/protocol/v1/initialization&quot;&gt;https://agentclientprotocol.com/protocol/v1/initialization&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;会话管理：session 是一条「长期关系」&lt;a href=&quot;#会话管理session-是一条长期关系&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ACP 里有一个非常重要的概念：&lt;strong&gt;session（会话）&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Client 会调用 &lt;code&gt;session/new&lt;/code&gt; 创建一个新的会话，通常会附带一些上下文信息，比如当前工作目录、项目路径、打开的文件列表等。&lt;/li&gt;
&lt;li&gt;返回的 &lt;code&gt;sessionId&lt;/code&gt; 用来标识接下来的一整段交互（类似一个长期聊天频道），后续的所有 prompt、工具调用、状态更新都挂在这个 session 下面。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以这样类比：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果说 HTTP 请求偏向于&lt;strong&gt;一次性的动作交换&lt;/strong&gt;，那么 ACP 的 session 更像是&lt;strong&gt;一个长期的工作房间&lt;/strong&gt;，你和 Agent 在同一个房间里做很多轮对话和修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在代码设计上，我们可以把 session 映射为一个对象，比如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; session&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; acpClient.&lt;/span&gt;&lt;span&gt;newSession&lt;/span&gt;&lt;span&gt;({ cwd: projectPath });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 后续所有与这个项目相关的提示都用 session.id&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样我们的 UI 或后端可以轻松地把某个项目或某个 tab 绑定到一个 session 上面。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;详细内容可见官方文档：&lt;a href=&quot;https://agentclientprotocol.com/protocol/v1/session-setup&quot;&gt;https://agentclientprotocol.com/protocol/v1/session-setup&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;一次完整交互：prompt turn&lt;a href=&quot;#一次完整交互prompt-turn&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在 session 之上，ACP 定义了&lt;strong&gt;一次完整往返&lt;/strong&gt;的单位：&lt;strong&gt;prompt turn&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;官方的定义是：一次 &lt;strong&gt;prompt turn&lt;/strong&gt; 是从用户发出一条消息开始，到 Agent 完成这一轮响应（或被终止）为止的完整交互周期。&lt;/p&gt;
&lt;p&gt;官方文档：&lt;a href=&quot;https://agentclientprotocol.com/protocol/v1/prompt-turn&quot;&gt;https://agentclientprotocol.com/protocol/v1/prompt-turn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在我们的真实项目中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Client 通过 &lt;code&gt;session/prompt&lt;/code&gt; 发起一次 prompt turn：
&lt;ul&gt;
&lt;li&gt;指定 &lt;code&gt;sessionId&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;带上当前这一轮的用户消息（可以是文本、代码片段等富内容）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Agent 收到后开始工作，在这一轮期间会以事件流的方式不断往回推：
&lt;ul&gt;
&lt;li&gt;流式输出 token / 分段消息（让你实现「打字机」效果）。&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;/li&gt;
&lt;li&gt;当 Agent 觉得这轮结束了，会发一个「完成」的事件，该轮 turn 宣告结束，下一轮 prompt 可以开始。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;我的理解就是，&lt;code&gt;session/prompt&lt;/code&gt; 是 ACP 的&lt;strong&gt;函数调用&lt;/strong&gt;，而 prompt turn 是&lt;strong&gt;这次调用从开始到结束的整个生命周期&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;为什么使用函数调用来打比方，是因为 ACP（以及底层的 JSON‑RPC）本质上就是：&lt;strong&gt;一端给另一端发 我要调用你某个方法 的请求，对方执行完再把结果返回&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这个模式和我们在代码里写 &lt;code&gt;someFunction(params)&lt;/code&gt; 很像，所以用&lt;strong&gt;函数调用&lt;/strong&gt;来帮助理解&lt;strong&gt;协议里的一次请求与响应&lt;/strong&gt;是什么关系。&lt;/p&gt;
&lt;p&gt;所以，我们可以暂时先忘掉高级 AI 概念，只把 ACP 当作&lt;strong&gt;两段程序之间远程互相调函数&lt;/strong&gt;的规则。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;工具调用、文件系统和权限&lt;a href=&quot;#工具调用文件系统和权限&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;强大的 Agent 必须能够操作环境：读写文件、运行测试、调用外部服务。ACP 在这里提供了一个统一的&lt;strong&gt;工具调用&lt;/strong&gt;接口层，典型能力包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文件系统（fs）相关方法：
&lt;ul&gt;
&lt;li&gt;读取文件内容、列目录、写入或创建文件等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;终端 / 命令执行：
&lt;ul&gt;
&lt;li&gt;运行 &lt;code&gt;npm test&lt;/code&gt;、&lt;code&gt;pytest&lt;/code&gt;、编译命令等，把 stdout/stderr 结果回给 Agent。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;权限请求：
&lt;ul&gt;
&lt;li&gt;Agent 不直接「悄悄改文件」，而是通过类似 &lt;code&gt;session/request_permission&lt;/code&gt; 请求，告知我想修改 A、B、C 这几个文件，由 Client 弹窗给用户确认，然后再执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这一层是 ACP 特别适合企业和团队场景的原因之一，它安全、可控、可审计，而不是让 Agent 获得完全不受控的本地能力。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;官方文档：&lt;/p&gt;
&lt;div&gt;
  &lt;a href=&quot;https://agentclientprotocol.com/protocol/v1/tool-calls&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          &lt;img src=&quot;https://agentclientprotocol.com/mintlify-assets/_mintlify/favicons/zed-685ed6d6/FRQhP3nE5XCe1eY2/_generated/favicon/android-chrome-192x192.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;
          &lt;span&gt;agentclientprotocol.com&lt;/span&gt;
        &lt;/div&gt;
        &lt;h3&gt;Tool Calls - Agent Client Protocol&lt;/h3&gt;
        &lt;p&gt;How Agents report tool call execution&lt;/p&gt;
        &lt;div&gt;
          &lt;span&gt;https://agentclientprotocol.com/protocol/v1/tool-calls&lt;/span&gt;
           
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;&lt;img src=&quot;https://zed.dev/img/acp/og-dark.webp&quot; alt=&quot;Tool Calls - Agent Client Protocol&quot; loading=&quot;lazy&quot; /&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
  &lt;a href=&quot;https://agentclientprotocol.com/protocol/v1/file-system&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          &lt;img src=&quot;https://agentclientprotocol.com/mintlify-assets/_mintlify/favicons/zed-685ed6d6/FRQhP3nE5XCe1eY2/_generated/favicon/android-chrome-192x192.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;
          &lt;span&gt;agentclientprotocol.com&lt;/span&gt;
        &lt;/div&gt;
        &lt;h3&gt;File System - Agent Client Protocol&lt;/h3&gt;
        &lt;p&gt;Client filesystem access methods&lt;/p&gt;
        &lt;div&gt;
          &lt;span&gt;https://agentclientprotocol.com/protocol/v1/file-system&lt;/span&gt;
           
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;&lt;img src=&quot;https://zed.dev/img/acp/og-dark.webp&quot; alt=&quot;File System - Agent Client Protocol&quot; loading=&quot;lazy&quot; /&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;h2&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;以上知识我在看 Agent Client Protocol 文档，了解学习 ACP 的一次初学习理解记录，如果想要深入，还是应该动手先跑一遍最小 demo，再实际中学习基础用法，然后再考虑将它落实道自己最熟悉的应用形态里面。但是以上提到的 ession + prompt turn + 事件流 + 工具调用，算是 ACP 的一个主线流程，我们可以先理解这个，再慢慢在实践中进行深入学习。&lt;/p&gt;</content:encoded><category>category:AI</category><category>tag:AI</category></item><item><title>双Token校验机制</title><link>https://wine-congee.vercel.app/post/dual-token</link><guid isPermaLink="false">dual-token</guid><description>为什么需要双 Token？


单 Token 模型通常存在一个核心矛盾：安全性与用户体验难以兼顾。


如果 Token 过期时间很短：安全性高，但用户频繁掉线


如果 Token 过期时间很长：用户体验好，但一旦泄露风险极大




双 Token</description><pubDate>Sat, 23 May 2026 06:04:04 GMT</pubDate><content:encoded>&lt;h2&gt;为什么需要双 Token？&lt;a href=&quot;#为什么需要双-token&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;单 Token 模型通常存在一个核心矛盾：安全性与用户体验难以兼顾。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果 Token 过期时间很短：安全性高，但用户频繁掉线&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果 Token 过期时间很长：用户体验好，但一旦泄露风险极大&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;双 Token 的核心思路是：把“短期访问权限”和“长期刷新能力”拆开。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Access Token：短期有效（例如 5~30 分钟），用于接口请求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Refresh Token：长期有效（例如 7~30 天），用于换取新的 Access Token&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样一来，即使 Access Token 被窃取，攻击窗口也被压缩在较短时间内。&lt;/p&gt;
&lt;h2&gt;双 Token 的核心原理&lt;a href=&quot;#双-token-的核心原理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;双 Token 机制包含两个核心令牌：&lt;strong&gt;Access Token（访问令牌）&lt;strong&gt;和&lt;/strong&gt;Refresh Token（刷新令牌）&lt;/strong&gt;，二者有效期、用途、存储方式完全不同，可以精准解决单 Token 的所有痛点。&lt;/p&gt;
&lt;h3&gt;双令牌核心差异对比&lt;a href=&quot;#双令牌核心差异对比&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;特性维度&lt;/th&gt;&lt;th&gt;Access Token（访问令牌）&lt;/th&gt;&lt;th&gt;Refresh Token（刷新令牌）&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;核心用途&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;用于所有业务接口鉴权，证明用户实时身份&lt;/td&gt;&lt;td&gt;仅用于刷新 Access Token，&lt;strong&gt;不参与任何业务请&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;有效期&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;短期有效，建议 15~30 分钟&lt;/td&gt;&lt;td&gt;长期有效，建议 7~30 天&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;安全级别&lt;/strong&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;strong&gt;存储方式&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;前端内存/普通存储，随请求携带&lt;/td&gt;&lt;td&gt;优先 HttpOnly Cookie，杜绝 XSS 窃取&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;通俗化理解&lt;a href=&quot;#通俗化理解&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;可以把双 Token 机制类比为「景区通行体系」：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Access Token = 一次性入园门票&lt;/strong&gt;：有效期短，只能用于游玩参观（访问业务接口），过期立即失效，丢了也影响不大&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refresh Token = 次卡（可以凭次卡换取入园门票）&lt;/strong&gt;：有效期长，不能直接入园游玩，但可以凭此免费兑换新的一次性入园门票（刷新 Access Token）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这套机制的核心逻辑：&lt;strong&gt;用短期令牌承担高频业务风险，用长期令牌保障登录连续性，从而达到风险隔离&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;双 Token 基本业务流程&lt;a href=&quot;#双-token-基本业务流程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;完整的双 Token 登录、鉴权、刷新流程，覆盖用户从登录到退出的全生命周期，是实现&lt;strong&gt;无感刷新&lt;/strong&gt;的核心依据。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;首次登录流程&lt;a href=&quot;#首次登录流程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;用户输入账号密码，前端提交登录请求至后端&lt;/li&gt;
&lt;li&gt;后端校验账号密码无误后，&lt;strong&gt;同时生成两个 Token&lt;/strong&gt;：短期 Access Token、长期 Refresh Token&lt;/li&gt;
&lt;li&gt;后端返回双 Token 给前端，同时将 Refresh Token 关联用户信息存入 Redis（用于失效管控）&lt;/li&gt;
&lt;li&gt;前端接收令牌：Access Token 存入内存/本地存储，Refresh Token 写入 HttpOnly Cookie&lt;/li&gt;
&lt;li&gt;登录成功，跳转首页，后续所有业务请求携带 Access Token 鉴权&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;正常业务请求流程&lt;a href=&quot;#正常业务请求流程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;前端发起接口请求，请求头自动携带 Access Token&lt;/li&gt;
&lt;li&gt;后端校验 Token 有效性（是否过期、签名是否正确）&lt;/li&gt;
&lt;li&gt;校验通过，正常返回业务数据；校验失败，返回对应状态码 401&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;核心：Token 过期无感刷新流程&lt;a href=&quot;#核心token-过期无感刷新流程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当 Access Token 过期、Refresh Token 未过期时，触发&lt;strong&gt;无感刷新&lt;/strong&gt;，用户全程无感知，无需重新登录：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;前端请求接口，后端检测 Access Token 过期，返回 &lt;strong&gt;401 Token 过期&lt;/strong&gt;状态码&lt;/li&gt;
&lt;li&gt;前端拦截器捕获 401 错误，暂停当前所有业务请求，防止重复报错&lt;/li&gt;
&lt;li&gt;前端携带 Refresh Token，单独发起&lt;strong&gt;刷新 Token 专用请求&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;后端校验 Refresh Token 有效且未过期，生成&lt;strong&gt;全新的 Access Token&lt;/strong&gt;返回前端&lt;/li&gt;
&lt;li&gt;前端更新本地 Access Token，重新发起之前失败的业务请求&lt;/li&gt;
&lt;li&gt;请求成功，用户正常操作，全程无弹窗、无跳转&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;注意点&lt;a href=&quot;#注意点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;双 Token 不是万能方案，若存储和使用不当，依然存在安全漏洞。&lt;/p&gt;
&lt;h3&gt;令牌存储安全区分&lt;a href=&quot;#令牌存储安全区分&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Access Token&lt;/strong&gt;：推荐存入 &lt;strong&gt;localStorage/sessionStorage + 内存&lt;/strong&gt;，不长期留存，即使被 XSS 窃取，短时间过期风险低&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refresh Token&lt;/strong&gt;：&lt;strong&gt;禁止存入本地存储&lt;/strong&gt;，必须存入 &lt;strong&gt;HttpOnly + Secure Cookie&lt;/strong&gt;，杜绝 XSS 攻击窃取，仅允许后端读取&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;前端逻辑容错优化&lt;a href=&quot;#前端逻辑容错优化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;增加&lt;strong&gt;请求锁机制&lt;/strong&gt;：避免多个接口同时 401，重复发起刷新 Token 请求，造成接口冗余&lt;/li&gt;
&lt;li&gt;失败请求队列缓存：刷新 Token 期间的所有请求排队等待，刷新成功后批量重试，保证业务不中断&lt;/li&gt;
&lt;li&gt;主动过期预判：前端可在 Access Token 过期前 5 分钟主动触发刷新，规避用户操作卡顿&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:前端</category><category>tag:前端</category></item><item><title>Chrome DevTools MCP</title><link>https://wine-congee.vercel.app/post/Chrome-DevTools-MCP</link><guid isPermaLink="false">Chrome-DevTools-MCP</guid><description>前言
最近读到一篇关于 Chrome DevTools MCP 的博客，文章系统介绍了 Claude Code 配合 Chrome DevTools MCP 做页面抓取、前端调试等的使用。看完感觉这个功能确实还挺好的，所以决定在自己的项目里试一试 Chrome DevTools MCP</description><pubDate>Sat, 16 May 2026 13:50:03 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;a href=&quot;#前言&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;最近读到一篇关于 Chrome DevTools MCP 的博客，文章系统介绍了 Claude Code 配合 Chrome DevTools MCP 做页面抓取、前端调试等的使用。看完感觉这个功能确实还挺好的，所以决定在自己的项目里试一试 Chrome DevTools MCP 的“抓取页面学习在线文档”以及“前端调试”的功能。&lt;/p&gt;
&lt;h2&gt;一、Chrome DevTools MCP 到底是什么&lt;a href=&quot;#一chrome-devtools-mcp-到底是什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在展开实践之前，先简单说一下这个工具的本质。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chrome DevTools MCP&lt;/strong&gt; 是一个 MCP（Model Context Protocol）服务，它让 Claude Code 获得了操控 Chrome 浏览器的能力。装上它之后，Claude Code 不再只是”在终端里和你对话”，而是可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;打开任意网页&lt;/li&gt;
&lt;li&gt;读取页面上的 DOM 结构和文本内容&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;claude&lt;/span&gt;&lt;span&gt; mcp&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; chrome-devtools&lt;/span&gt;&lt;span&gt; --&lt;/span&gt;&lt;span&gt; npx&lt;/span&gt;&lt;span&gt; chrome-devtools-mcp@latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装完成后在 Claude Code 里输入 &lt;code&gt;claude mcp list&lt;/code&gt;，确认 &lt;code&gt;chrome-devtools&lt;/code&gt; 出现在工具列表里就行了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键点在于&lt;/strong&gt;：它复用的是你当前已经打开的 Chrome 浏览器会话。这意味着，如果你已经在浏览器里登录了某个系统，Claude Code 通过这个 MCP 就能直接访问你需要登录才能看到的页面——这一点对”自动学习在线文档”场景非常重要，因为很多内部文档系统是需要登录的。&lt;/p&gt;
&lt;h2&gt;二、配合 Claude Code，这套组合能做什么&lt;a href=&quot;#二配合-claude-code这套组合能做什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Chrome DevTools MCP 给 Claude Code 增加了一个维度的能力：&lt;strong&gt;从”理解代码”扩展到”理解网页”&lt;/strong&gt;。配合 Claude Code 本身的代码理解和生成能力，可以做的事情非常多。&lt;/p&gt;
&lt;p&gt;下面是我实际用过或者验证过的场景：&lt;/p&gt;
&lt;h3&gt;2.1 页面数据抓取&lt;a href=&quot;#21-页面数据抓取&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;这是最直观的用途。用自然语言告诉 Claude Code 你要从哪个页面抓什么数据，它会自动打开页面、分析 DOM、提取信息并以结构化格式返回。&lt;/p&gt;
&lt;p&gt;比如你可以说：“帮我打开 XX 后台的运营数据页面，把今天的核心指标（UV、PV、转化率）抓出来。“它不需要你写任何选择器或爬虫脚本。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;和传统爬虫的区别&lt;/strong&gt;：传统爬虫需要你分析页面结构、写选择器、处理反爬机制。Chrome DevTools MCP 走的是”像人一样浏览”的路线，它复用你的真实浏览器会话，所以登录态、Cookie、JavaScript 渲染的内容都能正常获取。&lt;/p&gt;
&lt;h3&gt;2.2 前端问题诊断&lt;a href=&quot;#22-前端问题诊断&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当页面出现异常时，你可以让 Claude Code 直接打开页面，帮你做一轮”AI 版的前端排查”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查控制台有没有报错&lt;/li&gt;
&lt;li&gt;看网络请求有没有失败的&lt;/li&gt;
&lt;li&gt;分析 DOM 结构是否符合预期&lt;/li&gt;
&lt;li&gt;检查某些关键元素是否渲染出来了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它会把排查结果整理成报告，告诉你”哪里有问题、可能的原因是什么、建议怎么修”。&lt;/p&gt;
&lt;h3&gt;2.3 UI 还原度检查&lt;a href=&quot;#23-ui-还原度检查&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;设计稿交付之后，前端同学写完了页面，怎么确认还原度？可以让 Claude Code 同时打开设计稿页面和开发页面，对比两者的布局、间距、颜色等视觉差异。虽然不能完全替代人工 review，但能快速发现明显的不一致。&lt;/p&gt;
&lt;h3&gt;2.4 自动化回归&lt;a href=&quot;#24-自动化回归&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;代码改完之后，你可以让 Claude Code 自动打开页面、执行一系列操作（比如点击按钮、填写表单、提交请求），然后检查结果是否符合预期。这相当于一个”自然语言驱动的 E2E 测试”。&lt;/p&gt;
&lt;h3&gt;2.5 多站点信息对比&lt;a href=&quot;#25-多站点信息对比&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;如果你需要对比同一类信息在不同站点上的展示差异（比如竞品分析），可以让 Claude Code 同时打开多个页面，提取关键信息并做横向对比。&lt;/p&gt;
&lt;h3&gt;2.6 自动学习在线文档&lt;a href=&quot;#26-自动学习在线文档&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;让 AI 帮你系统阅读文档站，把关键知识提炼出来，再带着这些知识修改项目，要比自己一点一点去看要快速并且准确很多。&lt;/p&gt;
&lt;h2&gt;三、前端调试&lt;a href=&quot;#三前端调试&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;3.1 传统前端调试的痛点&lt;a href=&quot;#31-传统前端调试的痛点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;关于前端调试，对于我自己来说，真正耗时间的其实不是”看报错”本身，而是&lt;strong&gt;看完报错之后的分析和修复过程&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;举个例子：页面上一个组件渲染异常，Console 里报了一个 &lt;code&gt;Cannot read properties of undefined&lt;/code&gt;。传统排查流程是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;看报错堆栈，定位到某一行代码&lt;/li&gt;
&lt;li&gt;打断点或加 &lt;code&gt;console.log&lt;/code&gt;，看变量的值&lt;/li&gt;
&lt;li&gt;发现某个 props 没传对，去查父组件的逻辑&lt;/li&gt;
&lt;li&gt;父组件的数据来自一个 API，去查 API 返回格式&lt;/li&gt;
&lt;li&gt;API 返回格式和文档描述不一致，去翻文档确认&lt;/li&gt;
&lt;li&gt;最后发现是自己对某个参数的理解有误&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个流程里，&lt;strong&gt;第 5 步和第 6 步才是真正决定修复方向的关键&lt;/strong&gt;，但它们也是最耗时间的——因为你需要在浏览器、IDE、文档站点之间来回切换。&lt;/p&gt;
&lt;p&gt;当然，现在借助于 AI 可能找错误要比上面流程要快速简单很多，但是还是免不了要在不同页面进行切换，并且面对复杂一些的报错问题，可能还是需要自己去翻文档。&lt;/p&gt;
&lt;h3&gt;3.2 用 Chrome DevTools MCP 做”调试 + 文档”一体化排查&lt;a href=&quot;#32-用-chrome-devtools-mcp-做调试--文档一体化排查&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Chrome DevTools MCP 的价值不只是让 AI 能”看页面”，更在于它能让 AI &lt;strong&gt;在同一个上下文里完成”看报错 → 查文档 → 给方案”的完整闭环&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我实际使用中的典型流程大概是类似于这样的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;我项目里 src/views/order/OrderDetail.vue 页面，&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;订单详情里的商品列表渲染不出来，页面白了一块。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;请使用 Chrome DevTools 打开 http://localhost:3000/order/123，&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;帮我排查问题。如果涉及到第三方组件库的用法，&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;请同时打开对应的文档页面确认正确用法。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个工具在这里主要的作用其实就在最后一句话，&lt;strong&gt;“如果涉及到第三方组件库的用法，请同时打开对应的文档页面确认正确用法”&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;AI 收到这个指令后，会做以下事情：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;打开页面，截图查看当前状态&lt;/strong&gt; — 确认”白了一块”具体是哪个区域&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;查看 Console 报错&lt;/strong&gt; — 发现有 &lt;code&gt;TypeError: Cannot read properties of undefined (reading &apos;map&apos;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;查看 Network 请求&lt;/strong&gt; — 确认 API 返回的数据结构&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读取项目代码&lt;/strong&gt; — 定位到 &lt;code&gt;OrderDetail.vue&lt;/code&gt; 里渲染商品列表的逻辑&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;打开组件库文档&lt;/strong&gt; — 确认 Table 组件的 &lt;code&gt;dataSource&lt;/code&gt; 格式要求&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交叉比对&lt;/strong&gt; — 发现 API 返回的商品列表字段名是 &lt;code&gt;items&lt;/code&gt;，但代码里写的是 &lt;code&gt;list&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;整个过程 AI 就是在&lt;strong&gt;一个连贯的思维链&lt;/strong&gt;里完成的，不需要像人一样在浏览器、IDE、文档之间来回跳转，所以分析速度更快，也更不容易遗漏线索。&lt;/p&gt;
&lt;h3&gt;3.3 调试过程中 AI 能做到的事&lt;a href=&quot;#33-调试过程中-ai-能做到的事&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;总结一下，在前端调试场景中，Chrome DevTools MCP 让 Claude Code 能做到这些：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;看得到&lt;/strong&gt;：打开页面、截图、查看 DOM 结构、读取元素属性、查看 Console 输出、检查 Network 请求。&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;/ol&gt;
&lt;h3&gt;3.4 踩过的坑和经验教训&lt;a href=&quot;#34-踩过的坑和经验教训&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在使用这个工具的过程中，我也踩过一些坑，总结出来供参考：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;文档页面有动态加载，AI 读到的内容不完整&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;有些文档站点使用了懒加载或者需要交互才能展开内容（比如点击”展开详情”按钮）。这种情况下，AI 第一次打开页面可能只能看到首屏内容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决办法&lt;/strong&gt;：在指令里明确告诉 AI “如果页面有展开/折叠的内容，都要点开看一遍”。或者先手动打开页面，把需要关注的部分展开，再让 AI 来读。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;文档版本和项目依赖版本不一致&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;关于版本的问题，如果它读的是最新版（v5），但我的项目还在用 v3。结果 AI 给出的修改建议全部是基于 v5 的 API，直接用了就会报错。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决办法&lt;/strong&gt;：在指令里明确指定文档版本，比如”请阅读 v3 版本的文档”。或者先确认自己项目的依赖版本，再告诉 AI 对应去读哪个版本的文档。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AI 给出的代码修改建议缺乏上下文&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AI 读完文档后给出的修改建议，有时候会忽略项目里已有的封装。比如项目里已经对某个 API 做了二次封装，但 AI 不知道，直接用了原生 API 的写法。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决办法&lt;/strong&gt;：在指令里补充项目上下文。比如”我的项目在 src/utils/request.ts 里对 axios 做了封装，所有 HTTP 请求都要走这个文件”。上下文给得越充分，AI 的修改建议就越准确。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;所以其实,我们自己对于给 AI 的条件和约束也是很重要的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;四、一些进阶用法&lt;a href=&quot;#四一些进阶用法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;4.1 让 AI 帮你写文档&lt;a href=&quot;#41-让-ai-帮你写文档&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;不只是”读文档”，也可以让 AI 通过 Chrome DevTools MCP 参考其他项目的文档风格，帮我们写自己项目的文档：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;请使用 Chrome DevTools 打开 Element Plus 的组件文档&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;（地址：https://element-plus.org/zh-CN/component/button.html），&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;学习它的文档结构和写作方式，&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;然后为我项目 src/components/MyButton.vue 这个组件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;写一份同样风格的 API 文档。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.2 让 AI 帮你做竞品分析&lt;a href=&quot;#42-让-ai-帮你做竞品分析&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;如果我们想了解某个竞品的某个功能是怎么实现的，可以让 AI 打开竞品的页面，分析它的 DOM 结构和交互逻辑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;请使用 Chrome DevTools 打开 [竞品URL]，&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;分析它的 [功能名称] 是怎么实现的：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;- 页面结构是什么样的&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;- 交互流程是怎样的&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;- 有哪些细节设计值得参考&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;整理成一份分析报告。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.3 调试 + 文档驱动的”反向验证”&lt;a href=&quot;#43-调试--文档驱动的反向验证&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;有时候我们想验证某个第三方库的文档是否准确。可以让 AI 读完文档后，直接在项目里按文档的写法试一下，然后用浏览器看看效果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;请使用 Chrome DevTools 阅读 [SDK] 的 [某功能] 文档，&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;然后在我项目里按照文档的示例写一个最小可运行的例子，&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;用浏览器打开看看文档里的写法是否真的能工作。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;如果效果不对，帮我分析是文档写错了还是我理解错了。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;五、总结&lt;a href=&quot;#五总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Chrome DevTools MCP 给 Claude Code 增加了”浏览器”这个维度的能力，让它从一个”代码助手”进化成了一个”全栈助手”。&lt;/p&gt;
&lt;p&gt;这两个能力的结合的核心价值在于三个字：&lt;strong&gt;省切换 - 省时间&lt;/strong&gt;。省掉了”浏览器和 IDE 之间的切换”、省掉了”读文档和写代码之间的切换”、省掉了”查 API 和用 API 之间的切换”、省掉了”看报错和查文档之间的切换”。&lt;/p&gt;
&lt;p&gt;而且，在我们想要学习某个网址的文档的时候，可以直接读取这个网址的文档，直接为我们总结大纲、重点，帮助我们去快速的了解学习，从而可以给我们节省很多时间。&lt;/p&gt;</content:encoded><category>category:AI</category><category>tag:AI</category></item><item><title>如何在浏览器中存储数据</title><link>https://wine-congee.vercel.app/post/data-storage</link><guid isPermaLink="false">data-storage</guid><description>
在前端开发中，“让浏览器记住一些东西”几乎是所有稍微复杂一点的应用都会遇到的需求：保存用户登录状态、记录偏好设置、缓存接口数据、支持离线应用等。浏览器本地存储做得好，可以显著减少网络请求、提升页面性能和用户体验；做不好，则会很容易出现数据混乱、XSS</description><pubDate>Sat, 02 May 2026 09:38:17 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;在前端开发中，“让浏览器记住一些东西”几乎是所有稍微复杂一点的应用都会遇到的需求：保存用户登录状态、记录偏好设置、缓存接口数据、支持离线应用等。浏览器本地存储做得好，可以显著减少网络请求、提升页面性能和用户体验；做不好，则会很容易出现数据混乱、XSS 泄露隐私等问题。之前我只是对着其中的一两个用的比较多，熟悉一些，其他的只是知道，所以我现在就想做一个全面一些的对比总结。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;一、为什么需要浏览器本地存储？&lt;a href=&quot;#一为什么需要浏览器本地存储&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;传统 Web 模式下，所有状态都由服务端维护，浏览器只是一个“渲染终端”。但随着前端单页应用、PWA 和离线应用的兴起，越来越多状态被下放到客户端管理，典型需求包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;记住登录状态（Token、用户信息、权限等）&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;基于以上这些需求，我们就需要对传统的 Web 模式进行改进优化，即诞生了可以在&lt;strong&gt;客户端持久化数据&lt;/strong&gt;，以减少对服务端的依赖，提高用户体验。&lt;/p&gt;
&lt;h2&gt;二、浏览器常见存储方式总览&lt;a href=&quot;#二浏览器常见存储方式总览&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;目前主流浏览器中，前端常用的存储方案主要有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Cookie&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;localStorage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sessionStorage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IndexedDB&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;（以及更偏缓存方向的 &lt;code&gt;Cache API&lt;/code&gt;，文末会顺带提一下）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以从几个维度来对比这些方案：容量、生命周期、是否参与网络请求、安全性和易用性。&lt;/p&gt;
&lt;p&gt;一个常见的理解是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;少量、与服务端强相关、需要随请求发送 → &lt;strong&gt;Cookie&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;少量、长期存在、只在前端用 → &lt;strong&gt;localStorage&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;少量、只在当前标签页会话内有效 → &lt;strong&gt;sessionStorage&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;大量、结构化、需要查询/索引/事务 → &lt;strong&gt;IndexedDB&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;三、前置核心：浏览器存储的基石 —— 同源策略&lt;a href=&quot;#三前置核心浏览器存储的基石--同源策略&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在介绍这四种方法前，我们需要对一个前置知识点进行介绍。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;所有浏览器存储方案都严格受&lt;strong&gt;同源策略&lt;/strong&gt;约束，这是浏览器安全的核心规则。同源指的是「协议 + 域名 + 端口」三者完全一致，不同源的站点之间，存储数据完全隔离，无法互相访问。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;唯一的例外是 Cookie，可通过 &lt;code&gt;Domain&lt;/code&gt; 属性配置实现父子域名间的数据共享，其余存储方案均不支持跨子域名访问，这是选型时必须先明确的前提。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;四、Cookie：最传统也最“重”的方案&lt;a href=&quot;#四cookie最传统也最重的方案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. Cookie 的特点&lt;a href=&quot;#1-cookie-的特点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Cookie 是最早的浏览器存储方式之一，最初就是为了解决“HTTP 是无状态的”这一问题，用来在客户端和服务端之间共享一小段状态信息，维持客户端与服务端的会话状态，是唯一能自动在前后端同步的存储方案。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;核心原理&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cookie 是服务端通过 &lt;code&gt;Set-Cookie&lt;/code&gt; 响应头发送到浏览器、并保存在本地的小块数据，浏览器下次向同一服务端发起符合规则的请求时，会自动将 Cookie 携带在&lt;code&gt;Cookie&lt;/code&gt;请求头中，回传给服务端。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;典型特征&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;容量很小：单个域名下总容量大约几 KB 级别&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;会自动随着同域 HTTP 请求发送给服务器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以设置过期时间（Session Cookie / Persistent Cookie）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以通过属性控制安全性（如 &lt;code&gt;HttpOnly&lt;/code&gt;、&lt;code&gt;Secure&lt;/code&gt;、&lt;code&gt;SameSite&lt;/code&gt;）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 设置和读取 Cookie 的方式&lt;a href=&quot;#2-设置和读取-cookie-的方式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;我们可以通过两种方式操作 Cookie：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过 &lt;code&gt;document.cookie&lt;/code&gt; 在浏览器端直接读写&lt;/li&gt;
&lt;li&gt;通过服务端响应头 &lt;code&gt;Set-Cookie&lt;/code&gt; 下发&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;典型示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 写入 Cookie&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;document.cookie &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;theme=dark; max-age=3600; path=/&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 读取 Cookie（简单解析）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; getCookie&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; pattern&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; RegExp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;(?:^|; )&apos;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; encodeURIComponent&lt;/span&gt;&lt;span&gt;(name) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &apos;=([^;]*)&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; match&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.cookie.&lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt;(pattern);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; match &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; decodeURIComponent&lt;/span&gt;&lt;span&gt;(match[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; theme&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; getCookie&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;theme&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;推荐在项目中封装一层 Cookie 工具函数，避免到处拼字符串&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3. Cookie 的适用场景与注意事项&lt;a href=&quot;#3-cookie-的适用场景与注意事项&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;适用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;会话标识（Session ID）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;短小的鉴权 Token（更推荐 HttpOnly + Secure）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;简单的跨页面偏好设置（如果需要服务端也感知）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;注意事项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不要在 Cookie 中存放敏感的明文信息（如密码、完整个人信息）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Token 建议使用 &lt;code&gt;HttpOnly&lt;/code&gt;，避免被 XSS 通过 JS 读取&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;过多、过大的 Cookie 会拖累所有同域请求的性能&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;五、localStorage：最常用的“持久储物柜”&lt;a href=&quot;#五localstorage最常用的持久储物柜&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 特点与限制&lt;a href=&quot;#1-特点与限制&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;localStorage&lt;/code&gt; 是 HTML5 引入的 &lt;code&gt;Web Storage API&lt;/code&gt; 中的一部分，它提供了一个简单的键值对存储空间，有如下特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;与域名绑定，通常容量在 5MB 左右&lt;/li&gt;
&lt;li&gt;数据持久存在，除非显式清除或用户清理浏览器数据&lt;/li&gt;
&lt;li&gt;不随 HTTP 请求发送，仅在前端可见&lt;/li&gt;
&lt;li&gt;API 简单、同步执行（阻塞主线程）&lt;/li&gt;
&lt;li&gt;仅支持字符串类型，需要手动处理序列化和反序列化&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 基本用法示例&lt;a href=&quot;#2-基本用法示例&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 写入&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;localStorage.&lt;/span&gt;&lt;span&gt;setItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;token&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;xxx-yyy-zzz&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 读取&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; token&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; localStorage.&lt;/span&gt;&lt;span&gt;getItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;token&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 删除某个 key&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;localStorage.&lt;/span&gt;&lt;span&gt;removeItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;token&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 清空所有&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;localStorage.&lt;/span&gt;&lt;span&gt;clear&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果要存对象，需要配合 &lt;code&gt;JSON.stringify&lt;/code&gt; 和 &lt;code&gt;JSON.parse&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; user&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; { id: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, name: &lt;/span&gt;&lt;span&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span&gt;, role: &lt;/span&gt;&lt;span&gt;&apos;admin&apos;&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;localStorage.&lt;/span&gt;&lt;span&gt;setItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;user&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;(user));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; raw&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; localStorage.&lt;/span&gt;&lt;span&gt;getItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;user&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; userObj&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; raw &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;parse&lt;/span&gt;&lt;span&gt;(raw) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 使用场景与最佳实践&lt;a href=&quot;#3-使用场景与最佳实践&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;常见场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;存放 UI 层配置（主题色、布局、语言）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缓存一些非敏感的接口数据（如字典项、热门列表）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;记录用户上次访问的状态（如当前 Tab、分页页码）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实践建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;避免把敏感信息（Access Token、用户隐私）长期明文放在 localStorage 中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;封装统一的 Storage 工具，集中管理 key 名、版本号、过期策略&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;考虑数据膨胀对性能的影响，大量字符串读写会阻塞主线程&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;六、sessionStorage：会话级的临时存储&lt;a href=&quot;#六sessionstorage会话级的临时存储&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 特点&lt;a href=&quot;#1-特点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sessionStorage&lt;/code&gt; 与 &lt;code&gt;localStorage&lt;/code&gt; API 几乎完全相同，但它的生命周期和作用范围不同：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;只在当前标签页有效，标签页关闭即销毁&lt;/li&gt;
&lt;li&gt;同一浏览器同一域名下的不同标签页互不共享&lt;/li&gt;
&lt;li&gt;容量通常与 localStorage 相近（约 5MB）&lt;/li&gt;
&lt;li&gt;同样是同步 API，字符串键值对存储&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2. 典型用法示例&lt;a href=&quot;#2-典型用法示例&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 保存表单草稿&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; saveDraft&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;formId&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; form&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`#${&lt;/span&gt;&lt;span&gt;formId&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Object.&lt;/span&gt;&lt;span&gt;fromEntries&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; FormData&lt;/span&gt;&lt;span&gt;(form).&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sessionStorage.&lt;/span&gt;&lt;span&gt;setItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;form-draft&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;(data));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; restoreDraft&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;formId&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; form&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`#${&lt;/span&gt;&lt;span&gt;formId&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; draftStr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sessionStorage.&lt;/span&gt;&lt;span&gt;getItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;form-draft&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;draftStr) &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; draft&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;parse&lt;/span&gt;&lt;span&gt;(draftStr);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  Object.&lt;/span&gt;&lt;span&gt;keys&lt;/span&gt;&lt;span&gt;(draft).&lt;/span&gt;&lt;span&gt;forEach&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; input&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; form.elements.&lt;/span&gt;&lt;span&gt;namedItem&lt;/span&gt;&lt;span&gt;(key);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (input) input.value &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; draft[key];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 使用场景&lt;a href=&quot;#3-使用场景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;临时表单数据防丢（刷新页面不丢，关闭标签页就清）&lt;/li&gt;
&lt;li&gt;页内导航时的数据中转（不想暴露在 URL 上）&lt;/li&gt;
&lt;li&gt;某些只在当前会话内生效的状态（如一次性的向导步骤）&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;七、IndexedDB：浏览器内的“小型数据库”&lt;a href=&quot;#七indexeddb浏览器内的小型数据库&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;如果某一应用需要存储大量数据（比如离线缓存大量列表、图片缩略图、聊天记录等），或者需要复杂的查询能力，仅靠 localStorage 就不够用了，我们需要另一个解决方法，即 IndexeDB。&lt;/p&gt;
&lt;h3&gt;1. IndexedDB 的特点&lt;a href=&quot;#1-indexeddb-的特点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IndexedDB 是浏览器内置的 NoSQL 数据库，有以下能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;支持存储大量数据，只受磁盘空间限制&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;支持二进制（Blob、ArrayBuffer）等任意 JS 对象&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;支持索引、范围查询、游标、事务等数据库特性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;异步 API，不阻塞主线程&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;和域名绑定，安全隔离&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;对于传统的 客户端-服务器 应用，以上的这些功能通常是没有必要的。IndexedDB 适用于离线应用，可与 ServiceWorkers 和其他技术相结合使用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2. 基本使用流程概览&lt;a href=&quot;#2-基本使用流程概览&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;本文不在于详细解释教会每一个方法的使用，所以我也不过多的去介绍用法，只是简单说一下步骤。&lt;/p&gt;
&lt;p&gt;详细介绍与使用方法推荐在下面的文章学习，写的都很好:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://zh.javascript.info/indexeddb&quot;&gt;https://zh.javascript.info/indexeddb&lt;/a&gt;
&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API&quot;&gt;https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IndexedDB 的 API 相对繁琐，一般包含几个步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;打开数据库（&lt;code&gt;indexedDB.open&lt;/code&gt;），指定名称和版本&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;onupgradeneeded&lt;/code&gt; 中创建对象存储（类似表）和索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;onsuccess&lt;/code&gt; 中拿到数据库实例&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;发起读写事务（&lt;code&gt;db.transaction&lt;/code&gt;），执行增删改查&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 适用场景&lt;a href=&quot;#3-适用场景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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&gt;八、如何选择合适的存储方式？&lt;a href=&quot;#八如何选择合适的存储方式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;我们可以从这几个问题倒推，然后结合选择方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据大小有多大？&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;几 KB：Cookie、Web Storage 都可以&lt;/li&gt;
&lt;li&gt;几百 KB～MB：localStorage、sessionStorage&lt;/li&gt;
&lt;li&gt;更大、甚至几十 MB：IndexedDB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要被服务端感知吗？&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;需要：Cookie（随请求发送）&lt;/li&gt;
&lt;li&gt;不需要：localStorage / sessionStorage / IndexedDB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据的生命周期是怎样的？&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;只在当前会话/标签页内：sessionStorage&lt;/li&gt;
&lt;li&gt;长期保留，用户下次访问还需使用：localStorage / IndexedDB&lt;/li&gt;
&lt;li&gt;按过期时间控制，并服务端参与：Cookie&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;是否包含敏感信息？&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;敏感信息优先考虑存服务器 + 短期 Token，配合 HttpOnly Cookie&lt;/li&gt;
&lt;li&gt;尽量避免在 localStorage 中长期存放敏感明文数据&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一个常见的组合实践：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;认证凭证：短期 Token 放在 HttpOnly Cookie 中（前端无权读），前端只负责根据“是否登录”调整 UI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UI 偏好/非敏感配置：localStorage&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;临时表单数据：sessionStorage&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;大批量列表缓存、离线功能：IndexedDB&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;九、安全与性能注意事项&lt;a href=&quot;#九安全与性能注意事项&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. XSS 与数据泄露&lt;a href=&quot;#1-xss-与数据泄露&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;无论是 Cookie、localStorage 还是 IndexedDB，只要能被 JS 读写，就有可能在发生 XSS 时被攻击者窃取。建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对用户可输入的内容严格做 XSS 防御（转义、CSP 等）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不在可被 JS 读到的存储中保存高价值敏感数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对关键数据做加密/签名（虽然前端加密本身也需要谨慎看待）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 存储配额与异常处理&lt;a href=&quot;#2-存储配额与异常处理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不同浏览器的实际存储配额、策略有所不同：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;超出配额时，写入会抛出异常&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用户可能随时清理站点数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;隐身模式下的行为可能不同&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;因此实际使用时就需要考虑到这些，采取一些应对措施，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;封装一层安全读写：捕获异常、做降级处理&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对关键数据设计“缺失时如何恢复”的逻辑（例如重新拉取接口）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 同步 API 的阻塞问题&lt;a href=&quot;#3-同步-api-的阻塞问题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;localStorage&lt;/code&gt; / &lt;code&gt;sessionStorage&lt;/code&gt; 的读写是同步的，在大量或高频操作时可能造成主线程卡顿。建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不在高频事件（如 &lt;code&gt;scroll&lt;/code&gt;、&lt;code&gt;mousemove&lt;/code&gt;）里直接操作 Storage&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;尽量合并多次写入，做节流/防抖&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于大规模读写，考虑使用 IndexedDB 这种异步方案&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:前端</category><category>tag:前端</category><category>tag:JavaScript</category><category>tag:数据存储</category></item><item><title>flipbook体验文档</title><link>https://wine-congee.vercel.app/post/flipbook</link><guid isPermaLink="false">flipbook</guid><description>flipbook 工具的产品介绍、基本使用方法与使用它生成的一些图片展示</description><pubDate>Fri, 01 May 2026 12:40:51 GMT</pubDate><content:encoded>&lt;h2&gt;完全 AI 实时生成的无限可视化探索工具&lt;a href=&quot;#完全-ai-实时生成的无限可视化探索工具&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;一、产品核心概览&lt;a href=&quot;#一产品核心概览&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Flipbook 是一款&lt;strong&gt;完全由 AI 实时按需生成的无限可视化探索工具&lt;/strong&gt;， 它的核心交互逻辑是：点击画面里的任意元素 / 区域，AI 就会立即生成全新的画面，对该内容进行无限深度的拆解与探索，真正实现无边界的可视化信息浏览。&lt;/p&gt;
&lt;p&gt;通俗来说，是一个用 AI 生成「可点击的插画信息图」来回答问题的网页工具。你输入一个问题，它不会给你一大段文字，而是生成一张带说明的插画/信息图；你点图里的任何区域，它会围绕那个部分继续生成下一张图，像翻页一样，让你一步步「看懂」一个知识点。&lt;/p&gt;
&lt;h3&gt;二、核心产品理念与特点&lt;a href=&quot;#二核心产品理念与特点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;1. 从「文字答案」变成「视觉答案」&lt;a href=&quot;#1-从文字答案变成视觉答案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;传统 AI 问答：输入问题 → 返回一大段文字，理解成本在用户自己。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Flipbook：输入问题 → 返回一张完整的视觉页面（信息图）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这张图的特点是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;图里包含标题、小模块、箭头、标注等元素，整体像一张 PPT 或信息海报。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;所有这些都是 AI 直接生成的图片，而不是传统网页的 HTML+CSS 元素。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;文本、图形、卡片都融合在一张图里，看起来像「设计好的讲解海报」。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 通过「点击图」来继续提问&lt;a href=&quot;#2-通过点击图来继续提问&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;想继续和 Flipbook 交互我们当然可以和传统的 AI 问答一样，继续再输入框中输入内容，让它生成图片。但是，如果只是这样的话，我也不会想要继续了解它，我感觉它比较吸引我的，就是它后续的交互可以不是在输入框里追问，而是直接点击你感兴趣的图像区域。&lt;/p&gt;
&lt;p&gt;交互过程大致是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;输入一个问题，比如「帮我解释一下智能手机的各个硬件部件都做什么」。&lt;/li&gt;
&lt;li&gt;系统生成一张信息图，标出屏幕、电池、CPU、摄像头等部分，并附简单说明。&lt;/li&gt;
&lt;li&gt;你对「摄像头」感兴趣，就直接点图中摄像头那块区域。&lt;/li&gt;
&lt;li&gt;系统再生成一张新的图，只讲「手机摄像头」，可能继续拆分为：传感器、镜头组、防抖模块等。&lt;/li&gt;
&lt;li&gt;一直点击，一直往下钻，像在翻一本无限延伸的「知识图解书」。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，「翻页」指的是：你每点击一次，系统就为你「多画一页」，而不是打开一个新的网页链接。所以，虽然这个交互过程中还有不尽人意的地方，但这个已经足够吸引我了。&lt;/p&gt;
&lt;h3&gt;三、核心功能与核心特性&lt;a href=&quot;#三核心功能与核心特性&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;无限可视化深度探索&lt;/td&gt;&lt;td&gt;每一个页面都是 AI 实时生成的专属图像，点击画面内任意你感兴趣的元素、文字、区域，都会生成全新的页面，对该内容进行深度拆解，可无限延伸探索路径&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;全像素无代码架构&lt;/td&gt;&lt;td&gt;界面内所有内容（包括全部文字）均由图像模型渲染为像素，无 HTML、无硬编码链接、无固定表单字段，彻底摆脱代码对界面的限制&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;双源信息供给&lt;/td&gt;&lt;td&gt;画面内的信息来自「Agent 智能联网搜索」+「图像模型自身的世界知识」，事实准确度与 ChatGPT、Gemini、Claude 等主流大模型处于同一水平&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;实验性实时视频流&lt;/td&gt;&lt;td&gt;可一键开启 Live Video Stream 功能，将静态生成的图片转为连续视频流，为画面添加动态效果，同时实现页面间的无缝转场；该功能由定制优化的视频生成模型与图像生成系统联合驱动&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;四、3 分钟快速上手（零门槛使用步骤）&lt;a href=&quot;#四3-分钟快速上手零门槛使用步骤&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;1. 访问入口&lt;a href=&quot;#1-访问入口&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;打开浏览器，访问 &lt;a href=&quot;https://flipbook.page/&quot;&gt;flipbook.page&lt;/a&gt;。&lt;/li&gt;
&lt;li&gt;页面上方会有一个明显的输入框，让你输入想要了解的问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不需要注册账号即可体验基础功能（以当前公开原型为准，未来可能有变更）。&lt;/p&gt;
&lt;h4&gt;2. 输入问题&lt;a href=&quot;#2-输入问题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;在页面顶部输入框中，输入一句你想了解的话题，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;「用图解方式教我 HTTP 是怎么工作的。」&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;ul&gt;
&lt;li&gt;
&lt;p&gt;建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;把问题问得稍微具体一点，例如「帮我拆解 iPhone 里的主要硬件组成」比「手机」更容易出图。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当作是在对一个「会画信息图的老师」提问，而不是搜索引擎。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/weekly/weekly-aitools/%E4%BB%A5%E5%A4%AA%E9%98%B3%E7%B3%BB%E6%98%9F%E7%B3%BB%E5%9B%BE%E4%B8%BA%E4%BE%8B.png&quot; alt=&quot;太阳系星系图&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;太阳系星系图&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h4&gt;3. 理解第一页内容&lt;a href=&quot;#3-理解第一页内容&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;几秒之后，可以看到一张全屏的视觉页面。整体结构通常类似于一张架构图/流程图/信息海报：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;上方：标题，概括你提问的主题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;中间：多个模块、卡片、图形，代表不同的子部分。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;旁边或下方：简短文字说明，帮助你理解每一个块代表什么。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;此时可以先把整张图扫一遍，确认：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;大致结构是否合理（有无明显偏题）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;是否出现出我们真正关心的那几个部分。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果感觉不对，可以回到顶部输入框重提问题，或调整提问方式再来一次。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;4. 点击图中感兴趣的区域&lt;a href=&quot;#4-点击图中感兴趣的区域&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Flipbook 的&lt;strong&gt;关键体验是「点图继续深入」&lt;/strong&gt;，不是只看一页。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;操作方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;将鼠标移动到你感兴趣的模块上（例如「水星」区域）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;点击该区域，系统会把这个点击理解为「请详细展开讲这个部分」。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;随后生成一个新的页面，专门用一张新图解释这个子主题。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重复这个流程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;从「太阳系整体图」→ 点「水星」→ 进入「水星内部详细构造」→ 再点「陨石坑」，继续往下钻。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;知识结构会像树一样不断展开，每一页都是一层更细的图解。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/weekly/weekly-aitools/%E6%B0%B4%E6%98%9F%E8%AF%A6%E6%83%85%E5%9B%BE.png&quot; alt=&quot;水星详情图&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;水星详情图&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/weekly/weekly-aitools/%E5%8D%A1%E6%B4%9B%E9%87%8C%E7%9B%86%E5%9C%B0.png&quot; alt=&quot;卡洛里盆地&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;卡洛里盆地&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h4&gt;5. 在「翻页」中构建知识路径&lt;a href=&quot;#5-在翻页中构建知识路径&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;每一次点击都会带来一张新图，这种使用过程会像下面的这样的一条视觉路径：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;起点：原始问题（第一页）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;展开：对某个组件/概念感兴趣，点击它&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;深入：进入下一个细分概念的专页&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以继续向下深挖，也可以退回上层重新选择其他分支（根据浏览器的返回操作）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;注意：回退后新生成的图片会覆盖此图片后面的图片，如果需要注意保存&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这和传统网页「超链接跳转」的差别在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;传统：点链接 → 跳到别人写好的另一篇文章。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Flipbook：点图块 → AI 现画一张新的解释图，继续沿着你的兴趣生长。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;五、产品定位&lt;a href=&quot;#五产品定位&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;1. 面向谁？&lt;a href=&quot;#1-面向谁&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&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;/ul&gt;
&lt;h4&gt;2. 解决了什么痛点？&lt;a href=&quot;#2-解决了什么痛点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;它解决的核心痛点是：「文字太抽象时，知识很难在脑子里形成结构」。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Flipbook 用一张张信息图来替代长文本：&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;/ul&gt;
&lt;h3&gt;六、使用场景&lt;a href=&quot;#六使用场景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;场景推荐&lt;a href=&quot;#场景推荐&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&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&gt;第一次使用的建议提问模版&lt;a href=&quot;#第一次使用的建议提问模版&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;为了让第一次体验更顺畅，我们其实可以从下面这种问题开始尝试：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;「用图解方式向小白解释一下 X 是什么」&lt;/li&gt;
&lt;li&gt;「帮我拆解 XX 系统的主要组成部分并画图说明」&lt;/li&gt;
&lt;li&gt;「请画一张图讲清楚从 A 到 B 的完整流程」&lt;/li&gt;
&lt;li&gt;「用信息图的方式解释一下 XX 产品的核心模块和数据流向」&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;主题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;技术类：HTTP 请求流程、数据库读写流程、前后端交互过程。&lt;/li&gt;
&lt;li&gt;硬件类：智能手机内部结构、电脑硬件组成。&lt;/li&gt;
&lt;li&gt;商业/产品类：一个产品从需求到上线的流程、某个商业模式的运作逻辑。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;六、使用注意事项&lt;a href=&quot;#六使用注意事项&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;u&gt;目前&lt;/u&gt; Flipbook 还是一个&lt;strong&gt;相对实验性的产品原型&lt;/strong&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;
&lt;ul&gt;
&lt;li&gt;把图当做灵感/草稿，再人工复刻一版（PPT、Figma、Keynote 等）。&lt;/li&gt;
&lt;li&gt;人工审阅所有关键信息，以免出现误导或不准确的描述。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;太阳系星系图&lt;a href=&quot;#太阳系星系图&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;关于我自己在太阳系星系图方面的尝试,有几个我还挺喜欢的，展示一下吧！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/weekly/weekly-aitools/%E6%B5%B7%E7%8E%8B%E6%98%9F.png&quot; alt=&quot;海王星&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;海王星&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/weekly/weekly-aitools/%E6%B5%B7%E7%8E%8B%E6%98%9F%E5%A4%A7%E9%BB%91%E6%96%91.png&quot; alt=&quot;海王星大黑斑&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;海王星大黑斑&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/weekly/weekly-aitools/%E5%A4%A9%E7%8E%8B%E6%98%9F.png&quot; alt=&quot;天王星&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;天王星&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/weekly/weekly-aitools/%E5%B7%A8%E5%A4%A7%E5%86%B0%E8%B4%A8%E5%9C%B0%E5%B9%94.png&quot; alt=&quot;天王星内部结构&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;天王星内部结构&lt;/figcaption&gt;&lt;/figure&gt;</content:encoded><category>category:周刊</category><category>category:AI工具</category><category>tag:AI tools</category><category>tag:周刊系列</category></item><item><title>NotebookLM 介绍与基本使用</title><link>https://wine-congee.vercel.app/post/NotebookLM</link><guid isPermaLink="false">NotebookLM</guid><description>NotebookLM 工具的产品介绍，界面基本格式与基本使用方法</description><pubDate>Sat, 25 Apr 2026 02:37:41 GMT</pubDate><content:encoded>&lt;h2&gt;一、产品核心定位：不是普通聊天 AI，是「带资料工作的智能笔记本」&lt;a href=&quot;#一产品核心定位不是普通聊天-ai是带资料工作的智能笔记本&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;一句话定位：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NotebookLM 是谷歌推出的「专属 AI 研究助理」，只基于你上传的资料回答、总结、生成内容，杜绝幻觉，帮你快速吃透文档、整理知识、产出结构化成果&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1. 本质是什么&lt;a href=&quot;#1-本质是什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;NotebookLM 是 Google 基于 Gemini 大模型打造的&lt;strong&gt;私有知识库 AI 工具&lt;/strong&gt;，核心逻辑是：&lt;strong&gt;先喂资料 → AI 消化 → 只基于这些资料回答 / 生成 → 带原文引用，不瞎编&lt;/strong&gt;。 它和 ChatGPT、Claude 等通用 AI 最大区别：&lt;strong&gt;不依赖互联网 / 模型记忆，只信任你上传的本地 / 私有资料&lt;/strong&gt;，解决 AI 幻觉、信息不可靠、上下文太长读不完的痛点。&lt;/p&gt;
&lt;h3&gt;2. 它不是什么&lt;a href=&quot;#2-它不是什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;h3&gt;3. 解决的核心痛点&lt;a href=&quot;#3-解决的核心痛点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;读长文档 / 文献 / 报告慢、抓不住重点&lt;/li&gt;
&lt;li&gt;AI 回答经常胡编、找不到依据、不可信&lt;/li&gt;
&lt;li&gt;多份资料（论文、会议纪要、竞品报告）难以整合、对比、提炼&lt;/li&gt;
&lt;li&gt;知识整理、做摘要、写提纲、做复习材料效率低&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. 核心受众&lt;a href=&quot;#4-核心受众&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;学生（读论文、备考）、科研 / 职场人（文献综述、会议纪要、项目复盘）、内容创作者（资料整理、大纲生成）、产品 / 运营（竞品分析、报告提炼）&lt;/p&gt;
&lt;h2&gt;二、核心功能详解（看懂它能做什么）&lt;a href=&quot;#二核心功能详解看懂它能做什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 多模态资料导入（构建专属知识库）&lt;a href=&quot;#1-多模态资料导入构建专属知识库&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;支持几乎所有常用资料格式，一个笔记本最多添加 50 个来源、单来源上限 50 万字：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文件：PDF、Word、TXT、Markdown、PPT、Google Docs/Sheets/Slides&lt;/li&gt;
&lt;li&gt;链接：网页 URL、YouTube 视频链接（自动提取字幕 / 文本）&lt;/li&gt;
&lt;li&gt;其他：音频文件、直接粘贴文本、Google Drive 导入&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 智能对话与精准问答（基于资料的深度交互）&lt;a href=&quot;#2-智能对话与精准问答基于资料的深度交互&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;精准问答：提问只检索你上传的资料，&lt;strong&gt;所有回答带原文引用标注&lt;/strong&gt;（点击可跳转到对应文档位置），完全杜绝幻觉&lt;/li&gt;
&lt;li&gt;深度分析：支持跨文档对比、找矛盾、提炼共性、梳理逻辑链&lt;/li&gt;
&lt;li&gt;追问引导：自动生成关键问题，帮你挖掘资料里没注意到的信息&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 一键生成结构化成果（Studio 工作区）&lt;a href=&quot;#3-一键生成结构化成果studio-工作区&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;不用手动排版，直接从资料输出可用内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文本类：全文摘要、核心要点、FAQ、学习指南、汇报提纲、论文大纲&lt;/li&gt;
&lt;li&gt;可视化：思维导图、信息图、PPT、闪卡、知识测验&lt;/li&gt;
&lt;li&gt;音频类：&lt;strong&gt;音频概览（双人播客风格）&lt;/strong&gt;，把长文档转成可听的内容，通勤 / 走路学习&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. 隐私与安全&lt;a href=&quot;#4-隐私与安全&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;你的上传资料&lt;strong&gt;不会用于 Google 模型训练&lt;/strong&gt;，仅在你的账号内处理&lt;/li&gt;
&lt;li&gt;支持私有笔记本，仅自己可见，符合个人 / 企业数据安全要求&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;三、快速上手：3 步就能用（零门槛）&lt;a href=&quot;#三快速上手3-步就能用零门槛&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;准备条件&lt;a href=&quot;#准备条件&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;可用 Google 账号&lt;/li&gt;
&lt;li&gt;能访问 &lt;a href=&quot;https://notebooklm.google.com&quot;&gt;notebooklm.google.com&lt;/a&gt;（需科学上网）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 1：创建笔记本（建立专属知识库）&lt;a href=&quot;#step-1创建笔记本建立专属知识库&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;打开官网 &lt;a href=&quot;https://notebooklm.google.com&quot;&gt;notebooklm.google.com&lt;/a&gt;，用 Google 账号登录&lt;/li&gt;
&lt;li&gt;点击「New Notebook」，输入名称（如「XX 论文研读」「竞品分析」），选择用途（研究 / 学习 / 工作）&lt;/li&gt;
&lt;li&gt;进入三栏主界面：左侧「Sources（来源）」、中间「Chat（对话）」、右侧「Studio（生成）」&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Step 2：添加资料（喂给 AI）&lt;a href=&quot;#step-2添加资料喂给-ai&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;左侧 Sources 点「Add source」&lt;/li&gt;
&lt;li&gt;选择上传方式：上传本地文件、粘贴网页 / YouTube 链接、导入 Google Docs、粘贴文本&lt;/li&gt;
&lt;li&gt;等待 AI 解析（几秒到几分钟，看文件大小），解析完成后资料会显示在左侧列表&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Step 3：开始使用（两种核心用法）&lt;a href=&quot;#step-3开始使用两种核心用法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;用法 A：对话提问（吃透资料）&lt;a href=&quot;#用法-a对话提问吃透资料&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;中间 Chat 框输入问题，比如：
&lt;ol&gt;
&lt;li&gt;「总结这份报告的 3 个核心结论」&lt;/li&gt;
&lt;li&gt;「对比这两篇论文的研究方法差异」&lt;/li&gt;
&lt;li&gt;「这份文档里提到的关键数据有哪些」&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;AI 回答会标注引用（如 [Source 1, Page 5]），点击可直接查看原文&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;用法 B：Studio 一键生成（快速出成果）&lt;a href=&quot;#用法-bstudio-一键生成快速出成果&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;右侧 Studio 选择要生成的类型：Summary（摘要）、Outline（大纲）、Mind Map（思维导图）、Audio Overview（音频）、Flashcards（闪卡）&lt;/li&gt;
&lt;li&gt;选择参考的资料来源，点击生成，直接导出 / 复制使用&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;这个其实出了自己创建笔记本，还同步接入了我们在 Gemini 大模型对话里面创建的笔记本，Gemini 笔记本里面的内容直接回在这里创建一个 NotebookLM 笔记本，并将你在大模型里面与 Ai 的对话以及上传的资料同步到你，你可在 NotebookLM 中直接打开使用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;基础结构&lt;a href=&quot;#基础结构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/weekly/weekly-aitools/%E5%9F%BA%E6%9C%AC%E7%BB%93%E6%9E%84.png&quot; alt=&quot;基本结构&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;基本结构&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/weekly/weekly-aitools/%E7%AC%94%E8%AE%B0%E6%9C%AC%E5%86%85%E9%83%A8%E5%9F%BA%E6%9C%AC%E7%BB%93%E6%9E%84.png&quot; alt=&quot;笔记本内部格式&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;笔记本内部格式&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/weekly/weekly-aitools/%E4%BD%BF%E7%94%A8%E5%B1%95%E7%A4%BA.png&quot; alt=&quot;使用展示&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;使用展示&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;四、最佳使用场景（怎么用最香）&lt;a href=&quot;#四最佳使用场景怎么用最香&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 文献 / 长文档精读（学生 / 科研）&lt;a href=&quot;#1-文献--长文档精读学生--科研&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;上传多篇论文 → 让 AI 总结核心观点、对比差异、生成研究框架 → 做复习闪卡 / 音频 → 高效完成文献综述&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 会议 / 报告整理（职场）&lt;a href=&quot;#2-会议--报告整理职场&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;上传会议录音转写、项目报告 → 生成会议纪要、待办清单、核心决策 → 快速输出可分发文档&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 知识沉淀与学习（个人）&lt;a href=&quot;#3-知识沉淀与学习个人&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;收集课程资料、行业文章 → 生成学习指南、思维导图 → 转音频，碎片化时间复习&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. 竞品 / 内容分析（产品 / 运营）&lt;a href=&quot;#4-竞品--内容分析产品--运营&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;上传竞品官网、报告 → 提炼核心卖点、设计亮点、功能差异 → 生成分析简报&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;五、使用注意事项（避坑）&lt;a href=&quot;#五使用注意事项避坑&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&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;li&gt;复杂资料分多次上传、分步骤提问（先总结、再细节、再对比）&lt;/li&gt;
&lt;li&gt;导出成果后再二次编辑，贴合自己的需求&lt;/li&gt;
&lt;/ul&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;/ul&gt;
&lt;h2&gt;六、总结&lt;a href=&quot;#六总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;NotebookLM 的核心价值，是把「零散资料 → 结构化知识 → 可复用成果」的流程自动化，让 AI 真正成为你的「专属研究助理」，而不是泛泛的聊天工具。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;推荐使用场景：如果你经常要读长文档、整理资料、做知识输出，它能帮你节省 60% 以上的信息处理时间，还能保证内容准确、有据可查。&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>category:周刊</category><category>category:AI工具</category><category>tag:AI tools</category><category>tag:周刊系列</category></item><item><title>跨域</title><link>https://wine-congee.vercel.app/post/Cross-Origin</link><guid isPermaLink="false">Cross-Origin</guid><description>一、跨域问题的本质：同源策略与安全边界
1.1 什么是跨域？
跨域（Cross-Origin）的核心根源，是浏览器内置的同源策略，指的是浏览器出于安全考虑，限制一个源（Origin）的脚本访问另一个源的资源。这里的”源”由三个要素组成，所谓「同源」，要求两个 URL 的以下三个要素完全一致：</description><pubDate>Fri, 24 Apr 2026 13:05:36 GMT</pubDate><content:encoded>&lt;h2&gt;一、跨域问题的本质：同源策略与安全边界&lt;a href=&quot;#一跨域问题的本质同源策略与安全边界&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1.1 什么是跨域？&lt;a href=&quot;#11-什么是跨域&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;跨域（Cross-Origin）的核心根源，是浏览器内置的&lt;strong&gt;同源策略&lt;/strong&gt;，指的是&lt;strong&gt;浏览器&lt;/strong&gt;出于安全考虑，限制一个源（Origin）的脚本访问另一个源的资源。这里的”源”由三个要素组成，所谓「同源」，要求两个 URL 的以下三个要素&lt;strong&gt;完全一致&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;协议&lt;/strong&gt;（http vs https）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;域名&lt;/strong&gt;（example.com vs api.example.com）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;端口&lt;/strong&gt;（80 vs 8080）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;只要三者中任一不同，即构成跨域。举个直观的例子，以 &lt;code&gt;http://www.example.com:80&lt;/code&gt; 为基准，同源判定结果如下：&lt;/p&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;code&gt;https://www.example.com&lt;/code&gt;&lt;/td&gt;&lt;td&gt;否&lt;/td&gt;&lt;td&gt;协议不同（http→https）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;http://api.example.com&lt;/code&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;code&gt;http://www.example.com:3000&lt;/code&gt;&lt;/td&gt;&lt;td&gt;否&lt;/td&gt;&lt;td&gt;端口不同（80→3000）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;http://www.example.com/user&lt;/code&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;blockquote&gt;
&lt;p&gt;补充：&lt;/p&gt;
&lt;p&gt;核心定义&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;主域（注册域名）&lt;/strong&gt;：是用户通过域名注册商合法申请、拥有完整所有权与管理权的最小独立域名单元，格式为「自定义主体 + 顶级域」，比如 &lt;code&gt;example.com&lt;/code&gt;、&lt;code&gt;example.com.cn&lt;/code&gt;。主域是域名所有权的核心载体，必须付费注册，可自主创建所有下级子域。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;子域&lt;/strong&gt;：是主域持有者在主域基础上，免费自主配置的下级从属域名，无需额外注册。比如主域 &lt;code&gt;example.com&lt;/code&gt; 的子域包括 &lt;code&gt;www.example.com&lt;/code&gt;、&lt;code&gt;api.example.com&lt;/code&gt;、&lt;code&gt;admin.example.com&lt;/code&gt; 等，子域完全依附于主域，可独立配置解析指向不同服务，但无独立所有权。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.2 一个必须纠正的核心误区&lt;a href=&quot;#12-一个必须纠正的核心误区&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;跨域是浏览器的单向限制，不是服务器拒绝了你的请求&lt;/strong&gt;&lt;/p&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;浏览器收到响应后，检查响应头的 CORS 规则，判定是否允许当前源访问&lt;/li&gt;
&lt;li&gt;若规则不匹配，浏览器直接拦截响应，抛出 CORS 报错，前端无法拿到任何响应数据&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;简单说：请求发出去了，服务器也正常返回了，只是浏览器把数据「扣下了」。这也是为什么你在 Network 面板能看到请求的状态码是 200，却拿不到响应体的核心原因。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.3 同源策略到底限制了什么？&lt;a href=&quot;#13-同源策略到底限制了什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;同源策略就像浏览器给每个页面加了一道「安全隔离墙」，主要限制三类行为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据存储访问&lt;/strong&gt;：禁止读取 / 修改非同源页面的 Cookie、LocalStorage、IndexedDB 等存储数据&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DOM 操作&lt;/strong&gt;：禁止获取非同源页面的 DOM 元素，防止恶意页面篡改嵌入的第三方页面&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络请求&lt;/strong&gt;：限制 XMLHttpRequest、Fetch API 发起的跨域 AJAX 请求，这也是我们最常遇到的跨域场景&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;但有一个关键例外：&lt;strong&gt;HTML 的资源嵌入标签不受同源策略限制&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;比如&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;等标签，可以正常加载跨域资源，这也是 JSONP、图片打点等方案的底层原理。&lt;/p&gt;
&lt;h3&gt;1.4 为什么会有同源策略？&lt;a href=&quot;#14-为什么会有同源策略&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;同源策略是浏览器的&lt;strong&gt;核心安全机制&lt;/strong&gt;，主要防范：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;XSS 攻击&lt;/strong&gt;：恶意脚本窃取用户数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CSRF 攻击&lt;/strong&gt;：伪造用户身份进行恶意操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数据泄露&lt;/strong&gt;：敏感信息被未授权访问&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;举两个最直观的风险场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;没有同源策略，你打开的恶意钓鱼网站，可以直接读取你网银页面的 Cookie，轻松盗取你的账户信息，发起转账操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;没有同源策略，恶意页面可以嵌入你的电商支付页面，篡改 DOM 元素的支付金额，诱导你完成超额付款&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;同源策略的核心意义，就是&lt;strong&gt;隔离不同站点的资源，防止恶意网站窃取用户的敏感数据，从根源上阻断绝大多数 CSRF、XSS 衍生的攻击行为&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;二、主流跨域解决方案&lt;a href=&quot;#二主流跨域解决方案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.1 CORS：跨域资源共享的核心机制&lt;a href=&quot;#21-cors跨域资源共享的核心机制&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;2.1.1 CORS 工作原理&lt;a href=&quot;#211-cors-工作原理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;CORS（Cross-Origin Resource Sharing）是 W3C 标准，通过&lt;strong&gt;HTTP 响应头&lt;/strong&gt;告知浏览器是否允许跨域访问。其核心流程分为两类：&lt;/p&gt;
&lt;h5&gt;&lt;strong&gt;简单请求（Simple Request）&lt;/strong&gt;&lt;a href=&quot;#简单请求simple-request&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;满足以下条件的请求为简单请求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方法仅限 &lt;code&gt;GET&lt;/code&gt;、&lt;code&gt;HEAD&lt;/code&gt;、&lt;code&gt;POST&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Content-Type&lt;/code&gt; 为 &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;、&lt;code&gt;multipart/form-data&lt;/code&gt;、&lt;code&gt;text/plain&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;无自定义请求头&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;简单请求&lt;strong&gt;直接发送&lt;/strong&gt;，无需预检。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;&lt;strong&gt;非简单请求（Preflight Request）&lt;/strong&gt;&lt;a href=&quot;#非简单请求preflight-request&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;复杂请求会触发浏览器的&lt;strong&gt;预检机制&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;浏览器先使用 &lt;code&gt;OPTIONS&lt;/code&gt; 方法发起一个「预检请求」，携带三个核心请求头：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Origin&lt;/code&gt;：请求的来源域&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Request-Method&lt;/code&gt;：正式请求要使用的方法&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Request-Headers&lt;/code&gt;：正式请求要携带的自定义头&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 预检请求示例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;OPTIONS&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt;api&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;data &lt;/span&gt;&lt;span&gt;HTTP&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;1.1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Origin&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;https&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;//www.example.com&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Access&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Control&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Request&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Method&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;PUT&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Access&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Control&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Request&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Headers&lt;/span&gt;&lt;span&gt;: Authorization, Content&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Type&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;服务器接收预检请求，校验后返回对应的 CORS 响应头，明确是否允许该请求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;浏览器校验预检响应通过后，才会发起正式的 HTTP 请求；校验失败则直接拦截，正式请求永远不会发出&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;2.1.2 核心 CORS 响应头&lt;a href=&quot;#212-核心-cors-响应头&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;服务器的 CORS 配置，本质就是正确设置以下 HTTP 响应头，每一个都有明确的作用，不可乱配：&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;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;code&gt;Access-Control-Allow-Origin&lt;/code&gt;&lt;/td&gt;&lt;td&gt;必需&lt;/td&gt;&lt;td&gt;指定允许访问的源，值可以是单个具体源、&lt;code&gt;null&lt;/code&gt;，或通配符&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;非公开 API 严禁使用&lt;code&gt;*&lt;/code&gt;；携带凭据时，必须为具体源，绝对不能用&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Access-Control-Allow-Methods&lt;/code&gt;&lt;/td&gt;&lt;td&gt;预检必需&lt;/td&gt;&lt;td&gt;指定正式请求允许的 HTTP 方法，多个用逗号分隔&lt;/td&gt;&lt;td&gt;按需开放，不要全量开放&lt;code&gt;GET,POST,PUT,DELETE,PATCH&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt;&lt;/td&gt;&lt;td&gt;预检必需&lt;/td&gt;&lt;td&gt;指定正式请求允许携带的自定义请求头&lt;/td&gt;&lt;td&gt;按需开放，比如仅开放&lt;code&gt;Content-Type,Authorization&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Access-Control-Allow-Credentials&lt;/code&gt;&lt;/td&gt;&lt;td&gt;可选&lt;/td&gt;&lt;td&gt;指定是否允许请求携带 Cookie、HTTP 认证等身份凭证，值只能是&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;&lt;td&gt;开启后，&lt;code&gt;Allow-Origin&lt;/code&gt;不能为&lt;code&gt;*&lt;/code&gt;，前端必须设置&lt;code&gt;withCredentials: true&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Access-Control-Max-Age&lt;/code&gt;&lt;/td&gt;&lt;td&gt;可选&lt;/td&gt;&lt;td&gt;指定预检请求的缓存时间（秒），缓存期内不会重复发起预检&lt;/td&gt;&lt;td&gt;建议设置合理值（如 86400 秒 = 1 天），减少 OPTIONS 请求开销&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 使用示例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Access&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Control&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Allow&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Origin&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; https&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;//www.example.com  # 必须，允许的源&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Access&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Control&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Allow&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Methods&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; GET, POST, PUT, DELETE   # 允许的HTTP方法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Access&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Control&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Allow&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Headers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Content&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Type, Authorization  # 允许的请求头&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Access&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Control&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Allow&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Credentials&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;span&gt;  # 是否允许发送Cookie&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Access&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Control&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Max&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Age&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 86400&lt;/span&gt;&lt;span&gt;  # 预检请求缓存时间（秒）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Access&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Control&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Expose&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Headers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; X&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Total&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;Count  # 允许客户端访问的响应头&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2.2 服务端 CORS 配置（生产环境首选）&lt;a href=&quot;#22-服务端-cors-配置生产环境首选&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Node.js/Express 方案&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; express&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;express&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; cors&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;cors&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; express&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 方案1：使用cors中间件（推荐）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;app.&lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cors&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  origin: &lt;/span&gt;&lt;span&gt;&apos;https://www.example.com&apos;&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;// 精确指定源&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  methods: [&lt;/span&gt;&lt;span&gt;&apos;GET&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;POST&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;PUT&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;DELETE&apos;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  credentials: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;// 允许携带Cookie&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  maxAge: &lt;/span&gt;&lt;span&gt;86400&lt;/span&gt;&lt;span&gt;,      &lt;/span&gt;&lt;span&gt;// 预检缓存24小时&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 方案2：手动配置（更灵活）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;app.&lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;req&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;res&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; allowedOrigins&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;&apos;https://www.example.com&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;https://app.example.com&apos;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; req.headers.origin;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (allowedOrigins.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(origin)) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    res.&lt;/span&gt;&lt;span&gt;setHeader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Access-Control-Allow-Origin&apos;&lt;/span&gt;&lt;span&gt;, origin);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    res.&lt;/span&gt;&lt;span&gt;setHeader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Access-Control-Allow-Credentials&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;true&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  res.&lt;/span&gt;&lt;span&gt;setHeader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Access-Control-Allow-Methods&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;GET, POST, PUT, DELETE, OPTIONS&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  res.&lt;/span&gt;&lt;span&gt;setHeader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Access-Control-Allow-Headers&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;Content-Type, Authorization, X-Requested-With&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  res.&lt;/span&gt;&lt;span&gt;setHeader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Access-Control-Max-Age&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;86400&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (req.method &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &apos;OPTIONS&apos;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; res.&lt;/span&gt;&lt;span&gt;sendStatus&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  next&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Spring Boot 4.0 方案&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Configuration&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; CorsConfig&lt;/span&gt;&lt;span&gt; implements&lt;/span&gt;&lt;span&gt; WebMvcConfigurer&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    @&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    public&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; addCorsMappings&lt;/span&gt;&lt;span&gt;(CorsRegistry &lt;/span&gt;&lt;span&gt;registry&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        registry.&lt;/span&gt;&lt;span&gt;addMapping&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;/api/**&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                .&lt;/span&gt;&lt;span&gt;allowedOrigins&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;https://www.example.com&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;https://app.example.com&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                .&lt;/span&gt;&lt;span&gt;allowedMethods&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;GET&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;POST&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;PUT&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;DELETE&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;OPTIONS&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                .&lt;/span&gt;&lt;span&gt;allowedHeaders&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;Authorization&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;X-Requested-With&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                .&lt;/span&gt;&lt;span&gt;allowCredentials&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                .&lt;/span&gt;&lt;span&gt;maxAge&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;86400&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// 24小时&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 或使用@CrossOrigin注解&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    @&lt;/span&gt;&lt;span&gt;RestController&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    @&lt;/span&gt;&lt;span&gt;RequestMapping&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;/api&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    @&lt;/span&gt;&lt;span&gt;CrossOrigin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;origins&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;https://www.example.com&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;maxAge&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 86400&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    public&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; ApiController&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // ...&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;FastAPI 方案&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; fastapi &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; FastAPI&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; fastapi.middleware.cors &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; CORSMiddleware&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;app &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; FastAPI()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# 配置CORS中间件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;app.add_middleware(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    CORSMiddleware,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    allow_origins&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&quot;https://www.example.com&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;https://app.example.com&quot;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    allow_credentials&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;True&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    allow_methods&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&quot;*&quot;&lt;/span&gt;&lt;span&gt;],  &lt;/span&gt;&lt;span&gt;# 或指定具体方法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    allow_headers&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&quot;*&quot;&lt;/span&gt;&lt;span&gt;],  &lt;/span&gt;&lt;span&gt;# 或指定具体头&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    max_age&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;86400&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;# 预检缓存24小时&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.2 代理方案&lt;a href=&quot;#22-代理方案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;代理方案的核心原理，直击同源策略的本质：&lt;strong&gt;同源策略仅限制浏览器与服务器之间的通信，服务器与服务器之间的 HTTP 通信，没有任何跨域限制&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我们只需要搭建一个「代理中转服务器」，让浏览器把请求发给同源的代理服务器，再由代理服务器转发给真实的后端接口，就能彻底绕开跨域问题 —— 对浏览器来说，请求是发给同源的代理服务，不存在跨域；对后端来说，请求来自正常的服务器，无需做任何 CORS 配置。其中，代理方案分为开发环境和生产环境两类。&lt;/p&gt;
&lt;h4&gt;开发环境代理&lt;a href=&quot;#开发环境代理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Vite/Vue3 配置&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// vite.config.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; defineConfig&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  server: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    proxy: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &apos;/api&apos;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        target: &lt;/span&gt;&lt;span&gt;&apos;https://api.example.com&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        changeOrigin: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        rewrite&lt;/span&gt;&lt;span&gt;: (&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; path.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;^&lt;/span&gt;&lt;span&gt;\/&lt;/span&gt;&lt;span&gt;api&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        secure: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;// 不验证SSL证书&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        ws: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,       &lt;/span&gt;&lt;span&gt;// 代理WebSocket&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Webpack DevServer 配置&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// webpack.config.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;exports&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  devServer: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    proxy: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &apos;/api&apos;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        target: &lt;/span&gt;&lt;span&gt;&apos;https://api.example.com&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        pathRewrite: { &lt;/span&gt;&lt;span&gt;&apos;^/api&apos;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        changeOrigin: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        headers: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          Connection: &lt;/span&gt;&lt;span&gt;&apos;keep-alive&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;配置完成后，前端只需把请求地址写成&lt;code&gt;/api/xxx&lt;/code&gt;，开发服务器会自动把请求转发到&lt;code&gt;http://localhost:3000/xxx&lt;/code&gt;，浏览器全程认为是同源请求，不会有任何跨域问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Nginx 反向代理（生产环境推荐）&lt;a href=&quot;#nginx-反向代理生产环境推荐&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;生产环境中，我们通常使用 Nginx 作为静态资源服务器和反向代理服务器，实现和开发代理完全一致的效果，同时还能兼顾负载均衡、静态资源缓存等能力。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;server&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    listen &lt;/span&gt;&lt;span&gt;80&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    server_name &lt;/span&gt;&lt;span&gt;www.example.com;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # 前端静态资源&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    location&lt;/span&gt;&lt;span&gt; / &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        root &lt;/span&gt;&lt;span&gt;/var/www/frontend;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        index &lt;/span&gt;&lt;span&gt;index.html;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        try_files &lt;/span&gt;&lt;span&gt;$uri $uri/ /index.html;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # API代理，解决跨域&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    location&lt;/span&gt;&lt;span&gt; /api/ &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        proxy_pass &lt;/span&gt;&lt;span&gt;https://api.example.com/;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        proxy_set_header &lt;/span&gt;&lt;span&gt;Host $host;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        proxy_set_header &lt;/span&gt;&lt;span&gt;X-Real-IP $remote_addr;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        proxy_set_header &lt;/span&gt;&lt;span&gt;X-Forwarded-For $proxy_add_x_forwarded_for;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        # CORS相关头&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        add_header &lt;/span&gt;&lt;span&gt;&apos;Access-Control-Allow-Origin&apos;&lt;/span&gt;&lt;span&gt; &apos;https://www.example.com&apos;&lt;/span&gt;&lt;span&gt; always;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        add_header &lt;/span&gt;&lt;span&gt;&apos;Access-Control-Allow-Methods&apos;&lt;/span&gt;&lt;span&gt; &apos;GET, POST, PUT, DELETE, OPTIONS&apos;&lt;/span&gt;&lt;span&gt; always;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        add_header &lt;/span&gt;&lt;span&gt;&apos;Access-Control-Allow-Headers&apos;&lt;/span&gt;&lt;span&gt; &apos;Content-Type, Authorization&apos;&lt;/span&gt;&lt;span&gt; always;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        add_header &lt;/span&gt;&lt;span&gt;&apos;Access-Control-Allow-Credentials&apos;&lt;/span&gt;&lt;span&gt; &apos;true&apos;&lt;/span&gt;&lt;span&gt; always;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        # 处理预检请求&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt; ($request_method &lt;/span&gt;&lt;span&gt;= &lt;/span&gt;&lt;span&gt;&apos;OPTIONS&apos;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            add_header &lt;/span&gt;&lt;span&gt;&apos;Access-Control-Max-Age&apos;&lt;/span&gt;&lt;span&gt; 86400&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            add_header &lt;/span&gt;&lt;span&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span&gt; &apos;text/plain; charset=utf-8&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            add_header &lt;/span&gt;&lt;span&gt;&apos;Content-Length&apos;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            return&lt;/span&gt;&lt;span&gt; 204&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;配置完成后，用户访问 &lt;code&gt;https://www.example.com&lt;/code&gt; 加载前端页面，所有 &lt;code&gt;/api&lt;/code&gt; 开头的请求都会被 Nginx 转发到后端服务，前端和接口处于完全同源的状态，从根源上彻底消除了跨域问题，无需后端做任何 CORS 配置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.3 JSONP：仅兼容老旧浏览器的古董方案&lt;a href=&quot;#23-jsonp仅兼容老旧浏览器的古董方案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;JSONP 是早期前端解决跨域的方案，核心原理是利用&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;标签不受同源策略限制的特性，通过动态创建 script 标签，请求后端返回一个「函数调用」，把数据作为参数传入，前端在全局定义该函数，从而拿到跨域数据。&lt;/p&gt;
&lt;h3&gt;2.4 postMessage：跨窗口 /iframe 通信专属方案&lt;a href=&quot;#24-postmessage跨窗口-iframe-通信专属方案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;postMessage 是 HTML5 提供的 API，专门用于解决「不同源的页面之间」的通信问题，最常见的场景：主页面与嵌入的跨域 iframe 通信、同一浏览器打开的多个跨域标签页通信。&lt;/p&gt;
&lt;h3&gt;2.5 WebSocket：全双工通信无跨域限制&lt;a href=&quot;#25-websocket全双工通信无跨域限制&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WebSocket 协议本身不受浏览器同源策略限制，只要服务器支持，前端可以和任意源的 WebSocket 服务建立连接，实现全双工通信，是实时通信场景的最优解。&lt;/p&gt;
&lt;h3&gt;2.3 跨域解决方案对比与选型建议&lt;a href=&quot;#23-跨域解决方案对比与选型建议&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;方案&lt;/th&gt;&lt;th&gt;适用场景&lt;/th&gt;&lt;th&gt;优点&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;strong&gt;服务端 CORS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;生产环境&lt;/td&gt;&lt;td&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;strong&gt;Nginx 代理&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;生产环境&lt;/td&gt;&lt;td&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;strong&gt;开发代理&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;开发环境&lt;/td&gt;&lt;td&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;strong&gt;JSONP&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;传统项目&lt;/td&gt;&lt;td&gt;兼容性好&lt;/td&gt;&lt;td&gt;仅支持 GET、有安全风险&lt;/td&gt;&lt;td&gt;★☆☆☆☆&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;WebSocket&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;实时通信&lt;/td&gt;&lt;td&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;h4&gt;&lt;strong&gt;选型建议&lt;/strong&gt;&lt;a href=&quot;#选型建议&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;生产环境&lt;/strong&gt;：优先选择 Nginx 反向代理或服务端 CORS 配置&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开发环境&lt;/strong&gt;：使用 Webpack/Vite 内置代理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;遗留系统&lt;/strong&gt;：考虑 WebSocket 或服务端代理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;移动端/小程序&lt;/strong&gt;：服务端统一代理，避免前端跨域问题&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:前端</category><category>tag:前端</category><category>tag:JavaScript</category><category>tag:网络通信</category></item><item><title>Agent Skill 与 MCP</title><link>https://wine-congee.vercel.app/post/skill-mcp</link><guid isPermaLink="false">skill-mcp</guid><description>关于 Agent Skill 与 MCP 的组内分享会文档</description><pubDate>Fri, 17 Apr 2026 09:35:00 GMT</pubDate><content:encoded>&lt;h2&gt;Agent Skill&lt;a href=&quot;#agentskill&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;什么是 Agent Skill&lt;a href=&quot;#什么是agentskill&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;专业概念&lt;/strong&gt;：Agent Skill（智能体技能）是一种&lt;strong&gt;模块化&lt;/strong&gt;的能力扩展包，用于增强通用 AI 智能体的功能。它&lt;strong&gt;封装了特定领域的指令&lt;/strong&gt;、元数据和可选资源文件（如脚本、模板、文档），让 AI 在遇到匹配场景时能自动调用这些专业能力，完成特定任务&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;通俗解释&lt;/strong&gt;：就是大模型可以随时翻阅的&lt;strong&gt;说明文档&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;例子&lt;/strong&gt;：比如，我现在想让大模型作为我的智能客服，那么我就可以一个“智能客服 Skill”，或者我又想要让大模型为我做一个会议总结，那么我又可以写一个“会议总结 Skill”，这样一来我就不用每次对话都去重复粘贴这一长串的要求，大模型自己翻翻这个说明文档就知道该怎么干活了&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/sharedocs/skill-mcp/Skill%E9%80%9A%E4%BF%97%E7%A4%BA%E4%BE%8B.png&quot; alt=&quot;Skill通俗示例&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;Skill通俗示例&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;当然，说明文档只是一个简单通俗的说法，Skill 的功能要远比这个强大的多，后面会进行介绍，这里只是方便初步理解使用&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;怎么使用 Agent Skill&lt;a href=&quot;#怎么使用agentskill&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;以 trae 为例：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;步骤：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在项目根目录下创建 &lt;code&gt;.trae&lt;/code&gt; 文件夹&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;.trae&lt;/code&gt; 文件夹内创建 &lt;code&gt;skills&lt;/code&gt; 文件夹&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;skills&lt;/code&gt; 文件夹内创建你的技能文件夹（例如：&lt;code&gt;skill-reviewer&lt;/code&gt;）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在技能文件夹内创建核心文件 &lt;code&gt;SKILL.md&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;目录结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;skill-name/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── SKILL.md           # 必需：核心指令文件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── references/        # 可选：参考文档目录&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── assets/            # 可选：模板和资源目录  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── scripts/           # 可选：可执行脚本目录&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── templates/         # 可选：可复用的模板目录&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;核心文件 &lt;code&gt;SKILL.md&lt;/code&gt; 的必要内容：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;元数据&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;这个 skill 叫什么&lt;/li&gt;
&lt;li&gt;它做什么&lt;/li&gt;
&lt;li&gt;什么时候应该使用&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;主说明书（指令）&lt;/strong&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;li&gt;哪些边界需要注意&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;格式模板如下&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;name: template-skill&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;description: 请在此处替换为该技能的描述，以及 trae 应在何时使用它。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# 在下方插入指令&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;注意：&lt;code&gt;name：name&lt;/code&gt; 名字要求与 &lt;code&gt;skill&lt;/code&gt; 文件夹名字一致&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Agent Skill 的核心机制&lt;a href=&quot;#agentskill的核心机制&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;核心机制：按需加载&lt;/strong&gt;，指系统或模型仅在识别到特定任务需求时，才加载、激活或调用相关的代码库、功能模块或提示词指令&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/sharedocs/skill-mcp/Skill%E6%A0%B8%E5%BF%83%E6%9C%BA%E5%88%B6.png&quot; alt=&quot;Skill核心机制&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;Skill核心机制&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3&gt;进阶用法&lt;a href=&quot;#进阶用法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;核心机制：按需加载中的按需加载&lt;/strong&gt;，类似于模块化分离出去，核心 &lt;code&gt;SKILL.md&lt;/code&gt; 文件在需要的时候才进行引入调用，以进一步减少核心文件的体积&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;reference 概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;给大模型准备的可以模块化分离出去的「权威参考资料」，告诉它在执行某个技能时，应该遵循哪些具体规则、标准和规范，这些当然也可以直接写在 &lt;code&gt;SKILL.md&lt;/code&gt; 文件中，但这样核心文件不免越来越大，一些我们暂时没有用到的规范将会在我们这次的对话中浪费资源，因此我们可以将它们模块化的分离出去，核心 &lt;code&gt;SKILL.md&lt;/code&gt; 文件在需要的时候才进行引入调用，以进一步减少核心文件的体积&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/sharedocs/skill-mcp/reference%E6%A6%82%E5%BF%B5%E7%A4%BA%E4%BE%8B.png&quot; alt=&quot;reference概念示例&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;reference概念示例&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;script 概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可执行脚本目录&lt;/strong&gt;，当 skill 不只是“给建议”，还需要执行一些确定性动作时，就可以把这些动作写成脚本放在这里&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;加载机制&lt;a href=&quot;#加载机制&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;渐进式披露&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/sharedocs/skill-mcp/%E6%B8%90%E8%BF%9B%E5%BC%8F%E6%8A%AB%E9%9C%B2%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6.png&quot; alt=&quot;渐进式披露加载机制&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;渐进式披露加载机制&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3&gt;与 prompt 的区别&lt;a href=&quot;#与prompt的区别&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;前面说了这么多，是不是感觉这和 &lt;code&gt;prompt&lt;/code&gt; 提示词还有些相似，那么它俩的区别在哪里呢？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Prompt&lt;/code&gt; 是“给模型的一次性指令表达”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Skill&lt;/code&gt;是把一类可复用的 prompt + 工作流 + 资源约束打包成模块化能力&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Skill&lt;/code&gt; 不是 &lt;code&gt;Prompt&lt;/code&gt; 的对立面，而更像是：&lt;strong&gt;结构化、可复用、可发现、可按需加载&lt;/strong&gt;的 &lt;code&gt;Prompt&lt;/code&gt; 工程产物&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;推荐了解学习视频：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1cGigBQE6n/?spm_id_from=333.1387.favlist.content.click&quot;&gt;https://www.bilibili.com/video/BV1cGigBQE6n/&lt;/a&gt;（本文一些例子与图片也来自与本视频）&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1dz6oBWEWx/?spm_id_from=333.1387.favlist.content.click&amp;amp;vd_source=bacdae271e7d03ff39e0c6deed00cb7c&quot;&gt;https://www.bilibili.com/video/BV1dz6oBWEWx/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;MCP&lt;a href=&quot;#mcp&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;MCP 是什么&lt;a href=&quot;#mcp是什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MCP（Model Context Protocol，模型上下文协议）&lt;/strong&gt; 是一套&lt;strong&gt;开源、标准化、跨平台&lt;/strong&gt;的通信协议，核心目标是&lt;strong&gt;统一大模型、Agent、工具、数据源之间的上下文交互标准&lt;/strong&gt;，解决上下文碎片化、数据隔离、协议不兼容问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;本质上，大模型是一个只能问答的工具，而 MCP 的出现，就等于是让大模型拥有了使用各种外部工具的能力，简单来说，MCP 是让大模型从”只能聊天”升级为”能动手干活”的技术桥梁。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;想象一下，大语言模型（比如我这样的 AI）就像一个特别聪明的大脑，但这个大脑只能”动嘴说话”，不能”动手做事”。比如你想让 AI 帮你整理电脑里的文件、查看数据库、或者操作设计软件，它通常做不到。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MCP 就是解决这个问题的”万能插座”&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;它是一种标准化的连接协议，就像手机的 USB-C 接口一样&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过 MCP，AI 可以安全地连接到你的电脑、数据库、各种软件工具&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;让 AI 不仅能”说”代码，还能”做”事情 - 比如自动读写文件、操作浏览器、调用 API 等&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;举个实际例子&lt;/strong&gt;：
没有 MCP 时：你问 AI “帮我整理上周的会议记录”，AI 只能告诉你方法，不能真的去操作你的文件。有了 MCP 后，通过配置各种 MCP 服务工具，AI 可以直接访问你的文件系统，自动找到并整理那些会议记录文件。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;MCP Server&lt;a href=&quot;#mcpserver&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;MCP Server 就是 AI 的”工具管家”&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;举个例子：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你家有很多工具（文件、数据库、浏览器、计算器等），AI 就是一个新来的小助手，它想帮你做事，但不知道工具放在哪里、怎么用，MCP Server 就是这个管家，它把所有工具整理好，贴上标签，告诉 AI：“想要这个功能，就按这个标准方式来调用我”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一句话来说，&lt;strong&gt;MCP Server = 让 AI 安全地操作你电脑上各种工具的”安全桥梁”，本质是一段程序&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;tool&lt;a href=&quot;#tool&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;MCP Server 内置的一些模块&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;简单解释，一个 tool 其实就是一个编程语言里面的一个函数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;举个例子，一个处理查询天气的 MCP Server ，它内部可能包含两个函数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;figure&gt;&lt;img src=&quot;/img/blog/sharedocs/skill-mcp/tool%E7%A4%BA%E4%BE%8B.png&quot; alt=&quot;tool示例&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;tool示例&lt;/figcaption&gt;&lt;/figure&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;调用 MCP Server 的内部执行机制&lt;a href=&quot;#调用mcpserver的内部执行机制&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/sharedocs/skill-mcp/MCP%E5%86%85%E9%83%A8%E6%89%A7%E8%A1%8C%E6%9C%BA%E5%88%B6.png&quot; alt=&quot;MCP内部执行机制&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;MCP内部执行机制&lt;/figcaption&gt;&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;推荐 MCP 市场：&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;
  &lt;a href=&quot;https://mcp.so/&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          &lt;img src=&quot;https://mcp.so/favicon.ico&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;
          &lt;span&gt;mcp.so&lt;/span&gt;
        &lt;/div&gt;
        &lt;h3&gt;MCP Servers&lt;/h3&gt;
        &lt;p&gt;The largest collection of MCP Servers, including Awesome MCP Servers and Claude MCP integration. Search and discover MCP servers to enhance your AI capabilities.&lt;/p&gt;
        &lt;div&gt;
          &lt;span&gt;https://mcp.so/&lt;/span&gt;
           
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;&lt;img src=&quot;https://mcp.so/logo.png&quot; alt=&quot;MCP Servers&quot; loading=&quot;lazy&quot; /&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
  &lt;a href=&quot;https://mcpmarket.com/zh&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;https://mcpmarket.com/zh&lt;/div&gt;
          &lt;div&gt;mcpmarket.com&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      
        
      
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
  &lt;a href=&quot;https://smithery.ai/&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;smithery.ai&lt;/div&gt;
          &lt;div&gt;https://smithery.ai/&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      
        
      
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Agent Skill 与 Prompt 与 MCP 的区别&lt;a href=&quot;#agentskill与-prompt-与mcp的区别&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;它们看着功能相似，其实本质不在一个层面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Skill 是 AI 的“技能书”或“操作手册”，教 AI 怎么做，增强内在认知和专业能力&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MCP 是 AI 的“手”，让 AI 能够实际操作和连接外部工具，扩展外部操作能力和系统集成&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;一篇很好的关于我以上讲的 Agent Skill 与 Prompt 与 MCP 的关系的文章：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;以下内容也摘自其中&lt;/strong&gt;，&lt;a href=&quot;https://javaguide.cn/ai/agent/skills.html&quot;&gt;https://javaguide.cn/ai/agent/skills.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1. Skills vs Prompt&lt;a href=&quot;#1skillsvsprompt&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;维度&lt;/th&gt;&lt;th&gt;Prompt&lt;/th&gt;&lt;th&gt;Skills&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;本质&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;单次对话的文本指令&lt;/td&gt;&lt;td&gt;可持久化、可发现的&lt;strong&gt;能力单元&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;复用性&lt;/strong&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;strong&gt;加载机制&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;全量载入（挤占 Token）&lt;/td&gt;&lt;td&gt;&lt;strong&gt;延迟加载&lt;/strong&gt;（按需读取正文）&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;：用户即时表达意图的载体（如”分析这份报表”）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Skills&lt;/strong&gt;：包含**元数据（何时使用）+ 正文（如何执行）**的完整方案，通过 &lt;code&gt;load_skill()&lt;/code&gt; 机制按需加载到上下文。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. Skills vs MCP&lt;a href=&quot;#2skillsvsmcp&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;MCP (Model Context Protocol)&lt;/th&gt;&lt;th&gt;Skills&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;核心思路&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;标准化连接&lt;/strong&gt;：通过 JSON-RPC 统一数据格式&lt;/td&gt;&lt;td&gt;&lt;strong&gt;逻辑编排&lt;/strong&gt;：用自然语言描述复杂执行路径&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;定义方式&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;在 Server 端用代码（TS/Python）写死逻辑&lt;/td&gt;&lt;td&gt;在 &lt;code&gt;SKILL.md&lt;/code&gt; 中用自然语言引导模型决策&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;环境依赖&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;需要运行一个 MCP Server 进程&lt;/td&gt;&lt;td&gt;依赖可执行环境（如本地 Shell 或沙箱）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;哲学&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;以协议为中心&lt;/strong&gt;：一次编写，所有 AI 通用&lt;/td&gt;&lt;td&gt;&lt;strong&gt;以模型为中心&lt;/strong&gt;：利用模型推理能力处理不确定性&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MCP 解决的是连通性&lt;/strong&gt; ：它像 USB-C，让 AI 能以统一格式读文件、查数据库。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Skills 解决的是编排逻辑&lt;/strong&gt; ：它像一份说明书，告诉 AI 如何执行复杂任务流——这些任务完全可以包括调用多个 MCP 工具。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;两者的关系&lt;/strong&gt; ：它们解决的是不同层面的问题。MCP 负责把外部系统接入进来，Skills 负责决定什么时候用、怎么组合这些能力。一个高级 Skill 的底层往往就是调用多个 MCP 工具。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:分享会</category><category>tag:前端</category><category>tag:分享会</category><category>tag:JavaScript</category><category>tag:AI</category></item><item><title>clsx和twMerge解决CSS类名冲突问题</title><link>https://wine-congee.vercel.app/post/clsx-twMerge</link><guid isPermaLink="false">clsx-twMerge</guid><description>1. clsx 和 twMerge 与函数解析

以下这段代码是现代前端开发（尤其是使用 Tailwind CSS 和 shadcn/ui 的项目中）的一个工具函数。它通过组合两个强大的库，解决了 CSS 类名合并中的冲突和逻辑判断问题。
import { type ClassValue,</description><pubDate>Sat, 04 Apr 2026 03:22:00 GMT</pubDate><content:encoded>&lt;h3&gt;1. clsx 和 twMerge 与函数解析&lt;a href=&quot;#1-clsx-和-twmerge-与函数解析&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;以下这段代码是现代前端开发（尤其是使用 &lt;strong&gt;Tailwind CSS&lt;/strong&gt; 和 &lt;strong&gt;shadcn/ui&lt;/strong&gt; 的项目中）的一个工具函数。它通过组合两个强大的库，解决了 CSS 类名合并中的冲突和逻辑判断问题。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt; ClassValue, clsx } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;clsx&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { twMerge } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;tailwind-merge&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; cn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; ClassValue&lt;/span&gt;&lt;span&gt;[]) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; twMerge&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;clsx&lt;/span&gt;&lt;span&gt;(inputs));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;h4&gt;导入核心逻辑及类名合并工具&lt;a href=&quot;#导入核心逻辑及类名合并工具&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt; ClassValue, clsx } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;clsx&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { twMerge } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;tailwind-merge&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;clsx&lt;/code&gt;&lt;/strong&gt;: 一个轻量级的 JavaScript 库，用于&lt;strong&gt;条件性地构造类名字符串&lt;/strong&gt;。它能处理对象、数组、布尔值等，自动剔除 &lt;code&gt;false&lt;/code&gt;、&lt;code&gt;null&lt;/code&gt; 或 &lt;code&gt;undefined&lt;/code&gt; 的类。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;type ClassValue&lt;/code&gt;&lt;/strong&gt;: 这是 &lt;code&gt;clsx&lt;/code&gt; 提供的类型定义，确保输入参数符合库要求的格式（字符串、数字、对象、数组等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;twMerge&lt;/code&gt;&lt;/strong&gt;: 专门为 Tailwind CSS 设计的工具，用于&lt;strong&gt;解决类名冲突&lt;/strong&gt;。当同一个 CSS 属性被赋予多个不同的类名时，它会确保最后一个胜出，并删除冲突的旧类。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;&lt;code&gt;cn&lt;/code&gt; 函数&lt;a href=&quot;#cn-函数&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; cn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; ClassValue&lt;/span&gt;&lt;span&gt;[]) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; twMerge&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;clsx&lt;/span&gt;&lt;span&gt;(inputs));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;嵌套调用&lt;/strong&gt;:
&lt;ol&gt;
&lt;li&gt;首先执行 &lt;code&gt;clsx(inputs)&lt;/code&gt;：将复杂的逻辑输入（如&lt;code&gt;{ &apos;bg-red-500&apos;: isActive&lt;/code&gt;）转换成纯字符串。&lt;/li&gt;
&lt;li&gt;最后执行 &lt;code&gt;twMerge(...)&lt;/code&gt;：对转换后的字符串进行“去重和覆盖”处理，确保 Tailwind 类名不冲突。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 为什么要这么写？&lt;a href=&quot;#2-为什么要这么写&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;主要为了解决以下两个问题：&lt;/p&gt;
&lt;h4&gt;A. 条件逻辑混乱 (clsx 解决)&lt;a href=&quot;#a-条件逻辑混乱-clsx-解决&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;在 React 中，我们可能需要根据状态切换类名：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 原生写法：麻烦且容易产生多余空格&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; `px-4 py-2 ${&lt;/span&gt;&lt;span&gt;active&lt;/span&gt;&lt;span&gt; ?&lt;/span&gt;&lt;span&gt; &apos;bg-blue-500&apos;&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span&gt; &apos;bg-gray-200&apos;} ${&lt;/span&gt;&lt;span&gt;disabled&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; &apos;opacity-50&apos;}`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用 cn (内部调用 clsx)：简洁明了&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;cn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;px-4 py-2&apos;&lt;/span&gt;&lt;span&gt;, active &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &apos;bg-blue-500&apos;&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span&gt; &apos;bg-gray-200&apos;&lt;/span&gt;&lt;span&gt;, { &lt;/span&gt;&lt;span&gt;&apos;opacity-50&apos;&lt;/span&gt;&lt;span&gt;: disabled });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;B. Tailwind 类名冲突 (twMerge 解决)&lt;a href=&quot;#b-tailwind-类名冲突-twmerge-解决&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;这是最关键的原因。Tailwind 的类名是平级的，&lt;strong&gt;CSS 后写的类名不一定会覆盖先写的，而是取决于 CSS 文件生成的顺序。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;假设我们封装了一个按钮组件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 基础组件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; Button&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;className&lt;/span&gt;&lt;span&gt; }) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;cn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;px-4 py-2 bg-blue-500&quot;&lt;/span&gt;&lt;span&gt;, className)}&amp;gt;点击&amp;lt;/&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用组件时想更改背景色&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Button&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;bg-red-500&quot;&lt;/span&gt;&lt;span&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;如果没有 &lt;code&gt;twMerge&lt;/code&gt;&lt;/strong&gt;: 最终类名是 &lt;code&gt;px-4 py-2 bg-blue-500 bg-red-500&lt;/code&gt;。由于两个背景色类权重相同，浏览器可能会依然显示蓝色。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有了 &lt;code&gt;twMerge&lt;/code&gt;&lt;/strong&gt;: 它会识别出两者冲突，直接将输出简化为 &lt;code&gt;px-4 py-2 bg-red-500&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;3. 技术点总结&lt;a href=&quot;#3-技术点总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;技术点&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;描述&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TypeScript&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;使用了类型系统（&lt;code&gt;ClassValue[]&lt;/code&gt;），提供强大的代码补全和错误检查。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Tailwind CSS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;该函数几乎是为 Tailwind 这种原子化 CSS 框架量身定做的。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;解构与剩余参数&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;...inputs&lt;/code&gt; 增强了函数的灵活性，支持多种调用方式。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;函数组合&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;将逻辑处理（clsx）与冲突处理（twMerge）组合成一个统一的接口。&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;4. 实际使用示例&lt;a href=&quot;#4-实际使用示例&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;“plain`
// 多种写法混用，依然能完美运行
const isActive = true;
const className = cn(
“base-style”,             // 基础字符串
isActive &amp;amp;&amp;amp; “text-blue”,  // 布尔逻辑
{ “p-4”: true },          // 对象形式
[“m-2”, “rounded”],       // 数组形式
“p-8”                     // 最后的 p-8 会通过 twMerge 覆盖前面的 p-4
);&lt;/p&gt;
&lt;p&gt;// 最终输出: “base-style text-blue m-2 rounded p-8”&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;### 补充：clsx(inputs) 转换逻辑&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;我们可以把 `clsx` 想象成一个**“智能过滤器”**。它的核心逻辑非常简单：**遍历你传入的所有参数，只保留“真值”（truthy）的部分，并把它们拼接成一个干净的字符串。**&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#### 1. 转换逻辑图解&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;`clsx` 会根据你传入的数据类型采取不同的处理策略：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;| **输入类型**  | **转换规则**                    | **示例**                                  | **结果**       |&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;| ------------- | ------------------------------- | ----------------------------------------- | -------------- |&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;| **字符串**    | 直接保留                        | `&apos;px-4&apos;`                                  | `&quot;px-4&quot;`       |&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;| **对象**      | 提取 `key`，前提是 `value` 为真 |``{ &apos;bg-red-500&apos;: true, &apos;hidden&apos;: false`` | `&quot;bg-red-500&quot;` |&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;| **数组**      | 递归处理每个元素                | `[&apos;py-2&apos;, &apos;flex&apos;]`                        | `&quot;py-2 flex&quot;`  |&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;| **布尔/Null** | 直接忽略（过滤掉）              | `false`, `null`, `undefined`              | `&quot;&quot;` (空)      |&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;------&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#### 2. 具体转换过程演练&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;假设我们有以下代码：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;```tsx&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const isActive = true;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const isError = false;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const customClass = &quot;p-8&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const result = clsx(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;base-btn&quot;, &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  { &quot;bg-blue-500&quot;: isActive, &quot;border-red-500&quot;: isError },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  [ &quot;rounded-lg&quot;, isError ? &quot;text-red&quot; : &quot;text-white&quot; ],&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  customClass&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;#####内部执行步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;处理第一个参数 &lt;code&gt;&quot;base-btn&quot;&lt;/code&gt;&lt;/strong&gt;: 字符串，保留。 -&amp;gt; &lt;code&gt;&quot;base-btn&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;处理第二个参数（对象）&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;检查 &lt;code&gt;bg-blue-500&lt;/code&gt;: &lt;code&gt;isActive&lt;/code&gt; 是 &lt;code&gt;true&lt;/code&gt;，保留。&lt;/li&gt;
&lt;li&gt;检查 &lt;code&gt;border-red-500&lt;/code&gt;: &lt;code&gt;isError&lt;/code&gt; 是 &lt;code&gt;false&lt;/code&gt;，丢弃。&lt;/li&gt;
&lt;li&gt;得到 -&amp;gt; &lt;code&gt;&quot;bg-blue-500&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;处理第三个参数（数组）&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;rounded-lg&quot;&lt;/code&gt;: 保留。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isError ? ...&lt;/code&gt;: 三元运算结果为 &lt;code&gt;&quot;text-white&quot;&lt;/code&gt;，保留。&lt;/li&gt;
&lt;li&gt;得到 -&amp;gt; &lt;code&gt;&quot;rounded-lg text-white&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;处理第四个参数&lt;/strong&gt;: 变量 &lt;code&gt;customClass&lt;/code&gt; 是 &lt;code&gt;&quot;p-8&quot;&lt;/code&gt;，保留。 -&amp;gt; &lt;code&gt;&quot;p-8&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;3. 转换后的最终样子&lt;a href=&quot;#3-转换后的最终样子&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;clsx&lt;/code&gt; 将上述所有保留的部分用&lt;strong&gt;空格&lt;/strong&gt;连接起来：&lt;/p&gt;
&lt;p&gt;“plain`
“base-btn bg-blue-500 rounded-lg text-white p-8”&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;------&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;##### 4. 为什么要先经过这一步？&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;因为后面的 `twMerge` 函数**只认字符串**。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;`twMerge` 的工作是处理 CSS 冲突（比如 `p-4` 和 `p-8` 谁留下的问题），它并不理解什么是对象``{ &apos;bg-red-500&apos;: true``。所以 `cn` 函数的逻辑是：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;1. **`clsx`**: 负责把各种花哨的逻辑（对象、数组、条件判断）变成**一段平铺的字符串**。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;2. **`twMerge`**: 拿这段字符串，去剔除里面相互冲突的 Tailwind 类名。&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;如果没有 `clsx` 这一步，你直接传对象给 `twMerge`，它会直接报错或无法处理。这种转换方式让我们在写代码时可以使用非常灵活的逻辑，而最终交给浏览器的永远是规范的类名字符串。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded><category>category:问题</category><category>tag:前端</category><category>tag:JavaScript</category></item><item><title>使用indexOf查找对象结合Pinia持久化引发的问题</title><link>https://wine-congee.vercel.app/post/indexof-pinia</link><guid isPermaLink="false">indexof-pinia</guid><description>1. 问题
最近写代码的时候我遇到一个问题，我在开启了数据持久化的 Pinia 仓库里面写了一个类似“点击切换选中状态”的逻辑：如果数组里没有就 push 进去，有了就 splice 掉。代码如下：
// Pinia 仓库逻辑
const setAddonItems = (addon:</description><pubDate>Sat, 21 Mar 2026 02:22:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. 问题&lt;a href=&quot;#1-问题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;最近写代码的时候我遇到一个问题，我在开启了数据持久化的 &lt;code&gt;Pinia&lt;/code&gt; 仓库里面写了一个类似“点击切换选中状态”的逻辑：如果数组里没有就 &lt;code&gt;push&lt;/code&gt; 进去，有了就 &lt;code&gt;splice&lt;/code&gt; 掉。代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// Pinia 仓库逻辑&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; setAddonItems&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;addon&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; IStep3&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; index&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; addons.value.&lt;/span&gt;&lt;span&gt;indexOf&lt;/span&gt;&lt;span&gt;(addon) &lt;/span&gt;&lt;span&gt;// 查找当前点击的对象是否存在&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (index &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    addons.value.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;(addon) &lt;/span&gt;&lt;span&gt;// 不存在则添加&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    addons.value.&lt;/span&gt;&lt;span&gt;splice&lt;/span&gt;&lt;span&gt;(index, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;// 存在则移除&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这代码单看好像没有什么问题，但是我却遇到一个很奇怪的现象，明明逻辑没问题，为什么刷新页面后 &lt;code&gt;Pinia&lt;/code&gt; 就“失忆”了？当我每次在这个代码运行的页面进行刷新的时候，刷新前存进仓库的数据就好像没了一样，&lt;code&gt;setAddonItems&lt;/code&gt; 函数在调用的时候，却对 &lt;code&gt;addons&lt;/code&gt; 里面存储的数据视而不见，好像里面就是空的一样。我盯着那行 &lt;code&gt;indexOf(addon)&lt;/code&gt; 感觉非常疑惑：&lt;strong&gt;数据明明就在那儿，为什么 JS 却视而不见？&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/questions/indexof-pinia/addons%E6%95%B0%E6%8D%AE.png&quot; alt=&quot;addons数据&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;addons数据&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;以上图片就是我当时 &lt;code&gt;localStorage&lt;/code&gt; 里面 &lt;code&gt;addons&lt;/code&gt; 数据的情况，正确的应该是不论页面刷新几次，内容相同的数据都不会重复出现，但是现在却因为页面刷新而出现了重复。&lt;/p&gt;
&lt;p&gt;这是为什么呢？&lt;/p&gt;
&lt;h2&gt;2. 原因&lt;a href=&quot;#2-原因&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;原因其实很简单，就是 &lt;code&gt;indexOf&lt;/code&gt; 对于数据里面对象数据是否存在的判断规则，以及 &lt;code&gt;Pinia&lt;/code&gt; 持久化把数据存入 &lt;code&gt;localStorage&lt;/code&gt; 时 &lt;code&gt;localStorage&lt;/code&gt; 的反序列化。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;&lt;code&gt;indexOf()&lt;/code&gt; 判断对象数据存在的规则&lt;a href=&quot;#indexof-判断对象数据存在的规则&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;我们都知道，在 JS 中，基本类型是按 &lt;strong&gt;值&lt;/strong&gt; 比较相等的，而对象是按 &lt;strong&gt;内存地址（引用）&lt;/strong&gt; 比较相等的。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; { id: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; { id: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(a &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; b); &lt;/span&gt;&lt;span&gt;// 输出 false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;虽然 &lt;code&gt;a&lt;/code&gt; 和 &lt;code&gt;b&lt;/code&gt; 的内容一模一样，但它们在内存中占据了两个不同的位置。&lt;code&gt;indexOf&lt;/code&gt; 内部使用的是全等运算符（&lt;code&gt;===&lt;/code&gt;），因此它判定这两个对象“不相等”。&lt;/p&gt;
&lt;h3&gt;持久化造成的“孪生兄弟”错觉（&lt;code&gt;localStorage&lt;/code&gt; 反序列化 ）&lt;a href=&quot;#持久化造成的孪生兄弟错觉localstorage-反序列化-&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当我们开启了 &lt;code&gt;persist: true&lt;/code&gt;（&lt;code&gt;Pinia&lt;/code&gt; 持久化），流程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;存储时：&lt;/strong&gt; 插件将内存中的 JS 对象通过 &lt;code&gt;JSON.stringify()&lt;/code&gt; 转化成字符串存入 &lt;code&gt;localStorage&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;刷新页面：&lt;/strong&gt; 插件从 &lt;code&gt;localStorage&lt;/code&gt; 读取字符串，通过 &lt;code&gt;JSON.parse()&lt;/code&gt; 还原成对象。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;关键点就在这里：&lt;/strong&gt; &lt;code&gt;JSON.parse()&lt;/code&gt; 产生的是一个&lt;strong&gt;全新的对象实例&lt;/strong&gt;，这代表这个新的对象实例的引用地址已经和之前的地址不再一样了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;页面中的数据（items.STEP3）：&lt;/strong&gt; 是我们代码里定义的原始对象。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;仓库中的数据（addons）：&lt;/strong&gt; 是从 &lt;code&gt;localStorage&lt;/code&gt; 反序列化回来的新对象。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;即便它们长得一模一样，但在 JS 眼里，它们是住在不同地址的“孪生兄弟”。因此，&lt;code&gt;indexOf(addon)&lt;/code&gt; 永远找不到那个本该存在的对象，导致判断失效。&lt;/p&gt;
&lt;h2&gt;3. 解决办法&lt;a href=&quot;#3-解决办法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;用 &lt;code&gt;id&lt;/code&gt; 判断，而不是对象（简单，改动少）&lt;a href=&quot;#用-id-判断而不是对象简单改动少&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; setAddonItems&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;addon&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; IStep3&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; index&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; addons.value.&lt;/span&gt;&lt;span&gt;findIndex&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    item&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; item.id &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; addon.id&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (index &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    addons.value.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;(addon)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    addons.value.&lt;/span&gt;&lt;span&gt;splice&lt;/span&gt;&lt;span&gt;(index, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;只存 id 数组&lt;a href=&quot;#只存-id-数组&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在大型项目中，为了性能和数据一致性，通常&lt;strong&gt;不建议在状态仓库中存储整个对象列表&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;推荐做法：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;仓库只存储选中的 &lt;code&gt;ID&lt;/code&gt;（例如 &lt;code&gt;string[]&lt;/code&gt; 或 &lt;code&gt;number[]&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;显示逻辑通过 ID 到原始数据源中匹配。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; selectedIds&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ref&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;[]&amp;gt;([])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; toggleAddon&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; index&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; selectedIds.value.&lt;/span&gt;&lt;span&gt;indexOf&lt;/span&gt;&lt;span&gt;(id) &lt;/span&gt;&lt;span&gt;// ID 是基本类型，indexOf 此时是可靠的&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (index &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    selectedIds.value.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;(id)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    selectedIds.value.&lt;/span&gt;&lt;span&gt;splice&lt;/span&gt;&lt;span&gt;(index, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;优点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;节省空间：&lt;/strong&gt; &lt;code&gt;localStorage&lt;/code&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;h2&gt;4. 总结&lt;a href=&quot;#4-总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这个问题的本质是 JavaScript 对象比较机制与数据持久化存储之间的冲突。&lt;strong&gt;刷新页面后，对象引用被重置，导致状态管理失效&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;正确的解决方案是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;避免使用 &lt;code&gt;indexOf&lt;/code&gt; 比较对象&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用唯一标识符（如 ID）进行比较&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在状态管理中只存储必要信息（ID）&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;</content:encoded><category>category:问题</category><category>tag:前端</category><category>tag:JavaScript</category><category>tag:vue</category></item><item><title>Pinia 状态管理</title><link>https://wine-congee.vercel.app/post/pinia-stateManagement</link><guid isPermaLink="false">pinia-stateManagement</guid><description>关于 Pinia 状态管理的组内分享会文档</description><pubDate>Mon, 09 Feb 2026 02:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;一、为什么要讲 Pinia&lt;a href=&quot;#一为什么要讲pinia&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;原因&lt;a href=&quot;#原因&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Vue3 官方推荐的状态管理方案&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用来替代 Vuex（Vuex 5 已停止推进）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更符合 Vue3 中 Composition API 的设计理念&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;比起 Vuex 使用更加方便&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;vuex 与 pinia 对比&lt;a href=&quot;#vuex与pinia对比&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;特性&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Vuex (3/4)&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Pinia&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;核心组成&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;State, Getters, Mutations, Actions&lt;/td&gt;&lt;td&gt;&lt;strong&gt;State, Getters, Actions&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Mutations&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;必须通过它修改 State (繁琐)&lt;/td&gt;&lt;td&gt;&lt;strong&gt;废弃&lt;/strong&gt;，Actions 即可修改 State&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TypeScript&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;支持较弱，需大量额外定义&lt;/td&gt;&lt;td&gt;&lt;strong&gt;原生完美支持&lt;/strong&gt;，类型推断极佳&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;模块化&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;单一 Store 树，需嵌套 Modules&lt;/td&gt;&lt;td&gt;&lt;strong&gt;多 Store 设计&lt;/strong&gt;，扁平化结构，自动拆包&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;体积&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;约 10kb&lt;/td&gt;&lt;td&gt;&lt;strong&gt;约 1kb&lt;/strong&gt; (极度轻量)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;二、什么是状态管理（State Management）&lt;a href=&quot;#二什么是状态管理statemanagement&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;什么是「状态」？&lt;a href=&quot;#什么是状态&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在前端应用中，状态（state）指的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;状态 = 程序运行时”留在内存里、会变化的数据”&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;状态的核心特征&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;特征&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;/td&gt;&lt;td&gt;页面刷新即消失（除非持久化）&lt;/td&gt;&lt;td&gt;用户登录后的 token&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;会随时间变化&lt;/td&gt;&lt;td&gt;用户操作、API 响应会改变它&lt;/td&gt;&lt;td&gt;购物车商品数量增减&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;影响 UI 渲染&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;/td&gt;&lt;td&gt;框架通过响应式系统监控变化&lt;/td&gt;&lt;td&gt;Vue 的 ref/reactive&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;不使用状态管理会遇到什么问题？&lt;a href=&quot;#不使用状态管理会遇到什么问题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当项目变大后，会出现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;父子组件层层传 props&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;兄弟组件通信复杂&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据分散在各个组件，难以维护&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;同一份数据被多处复制，容易不一致&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;为什么需要状态管理？&lt;a href=&quot;#为什么需要状态管理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;状态管理就是&lt;strong&gt;把这些状态从”散落在各个组件里”抽出来，集中存、集中改、集中通知&lt;/strong&gt;，让任何组件都能&lt;strong&gt;同一份数据源、统一规则地读取和更新&lt;/strong&gt;，避免：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;父→子→孙，一层层 &lt;code&gt;props&lt;/code&gt; 传递&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;事件一层层 &lt;code&gt;emit&lt;/code&gt; 回去&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不同组件各自 copy 一份数据，改完互相不一致&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;状态 = 应用运行时需要被框架追踪、会影响视图、且可能被多个组件共享的”活”数据&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;（而状态管理 = 让这些”活”数据变得有序、可控、可预测的工具）&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;三、Pinia 在项目中的定位&lt;a href=&quot;#三pinia在项目中的定位&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;Vue App&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ├─ Components（组件）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ├─ Router（路由）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ├─ Pinia（全局状态）  ← 负责跨组件数据共享&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; └─ Services / API&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;四、Pinia 的核心概念&lt;a href=&quot;#四pinia的核心概念&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Store 是什么&lt;a href=&quot;#store是什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Store 是保存状态 ( state ) 和业务逻辑的实体，它并不与组件树绑定。&lt;/p&gt;
&lt;p&gt;换句话说，它存储着全局的状态数据。&lt;/p&gt;
&lt;h3&gt;一个 Store 由哪几部分组成&lt;a href=&quot;#一个store由哪几部分组成&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;state&lt;/td&gt;&lt;td&gt;定义状态数据&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;getters&lt;/td&gt;&lt;td&gt;类似计算属性（派生状态）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;actions&lt;/td&gt;&lt;td&gt;业务逻辑 / 异步操作&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h3&gt;总结类比&lt;a href=&quot;#总结类比&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可以把 pinia 类比为一个一个中心化的“仓库”。就像一个公司有一个中央档案室，不管哪个 &lt;strong&gt;部门（Vue 组件&lt;/strong&gt;）需要 &lt;strong&gt;看&lt;/strong&gt; 或 &lt;strong&gt;修改&lt;/strong&gt; 某个 &lt;strong&gt;文件（数据）&lt;/strong&gt;，&lt;u&gt;都得去这个档案室拿取&lt;/u&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解释：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;各部门：各个 Vue 组件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;文件：State 数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;看：组件调用 Store 里面 State 状态数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;修改：Store 里面修改 State 状态数据的方法（Actions）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;都得去这个档案室拿取&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我们如果想要在 Vue 组件里面使用 Store 仓库里面的数据与方法，肯定要先在组件里引入使用这个 Store 仓库&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;五、Pinia 的基础使用流程&lt;a href=&quot;#五pinia的基础使用流程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;安装 Pinia&lt;a href=&quot;#安装pinia&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; pinia&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;在 main.ts 中注册 Pinia&lt;a href=&quot;#在maints中注册pinia&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { createApp } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;vue&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { createPinia } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;pinia&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; App &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./App.vue&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; createApp&lt;/span&gt;&lt;span&gt;(App)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;app.&lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;createPinia&lt;/span&gt;&lt;span&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;app.&lt;/span&gt;&lt;span&gt;mount&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#app&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;定义一个 Store&lt;a href=&quot;#定义一个store&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { defineStore } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;pinia&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// &apos;use&apos; 是约定俗成的前缀，便于识别这是一个 store&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// &apos;user&apos; 是 store 的唯一 ID&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; useUserStore&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; defineStore&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;user&apos;&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // Store 配置项&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // state、getter 和 action 都写这里面&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 这里面包含了两种写法，我们会在下面介绍&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}) &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;在组件中使用 Store&lt;a href=&quot;#在组件中使用store&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 1. 导入&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { useUserStore } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@/stores/user&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 2. 调用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; userStore&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; useUserStore&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 3. 获取调用结果里面的数据方法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;userStore.&lt;/span&gt;&lt;span&gt;setToken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;abc&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(userStore.isLogin)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;六、Pinia 的两种写法&lt;a href=&quot;#六pinia的两种写法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. Options Store（类似 Vuex，适合新手）&lt;a href=&quot;#1optionsstore类似vuex适合新手&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 选项式写法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { defineStore } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;pinia&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; useUserStore&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; defineStore&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;user&apos;&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  state&lt;/span&gt;&lt;span&gt;: () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; ({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    token: &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    userInfo: &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  getters: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    isLogin&lt;/span&gt;&lt;span&gt;: (&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; !!&lt;/span&gt;&lt;span&gt;state.token&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  actions: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    setToken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;token&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      this&lt;/span&gt;&lt;span&gt;.token &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; token&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}) &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Setup Store（推荐写法）&lt;a href=&quot;#2setupstore推荐写法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 组合式写法（推荐）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { defineStore } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;pinia&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { ref, computed } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;vue&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; useMainStore&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; defineStore&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;main&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 1. 定义状态 (State) - 使用 ref 或 reactive&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; count&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Eduardo&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; user&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ref&lt;/span&gt;&lt;span&gt;({ name: &lt;/span&gt;&lt;span&gt;&apos;John&apos;&lt;/span&gt;&lt;span&gt;, age: &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 2. 定义计算属性 (Getters) - 使用 computed&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; doubleCount&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; computed&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; count.value &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; isEven&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; computed&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; count.value &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt; ===&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 3. 定义动作 (Actions) - 定义函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  function&lt;/span&gt;&lt;span&gt; increment&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    count.value&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  function&lt;/span&gt;&lt;span&gt; decrement&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    count.value&lt;/span&gt;&lt;span&gt;--&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 可以包含异步操作&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  async&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; fetchUserAge&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // 模拟 API 调用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;resolve&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; setTimeout&lt;/span&gt;&lt;span&gt;(resolve, &lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      user.value.age &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    } &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (error) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Failed to fetch user age:&apos;&lt;/span&gt;&lt;span&gt;, error)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 4. 必须返回你想要暴露给外界的部分&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // State&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    count,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    name,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    user,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // Getters&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    doubleCount,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    isEven,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // Actions&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    increment,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    decrement,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    fetchUserAge&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Setup Store 与 Composition API 思想完全一致&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;七、Pinia 中的数据更新原则&lt;a href=&quot;#七pinia中的数据更新原则&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 可以直接修改 state&lt;a href=&quot;#1可以直接修改state&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 可以在引入 Store 仓库的组件里面直接更改&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 只是通常不建议这么做&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;store.count&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;为什么不推荐&lt;a href=&quot;#为什么不推荐&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;虽然可以直改，但在&lt;strong&gt;中大型项目&lt;/strong&gt;中，如果随处直接修改 Store 数据，会带来如下一些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;业务逻辑碎片化&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果修改数据的逻辑（比如：修改价格前要检查库存、计算折扣、验证权限）散落在 10 个不同的 &lt;code&gt;.vue&lt;/code&gt; 文件里。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;后果&lt;/strong&gt;：当你需要修改这个逻辑时，你得满项目找这 10 个地方。如果写在 &lt;code&gt;action&lt;/code&gt; 里，你只需要改 Store 里的一个函数&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调试与追踪困难&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Pinia 的 Action 像是一个“带名字的事务所”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;直接修改&lt;/strong&gt;：在 DevTools 里，你可能只看到数据变了，但不知道是哪个组件、因为什么逻辑触发的&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Action 修改&lt;/strong&gt;：DevTools 会记录下 Action 的名称和参数，你可以清晰地看到“用户点击了支付按钮 -&amp;gt; 触发了 &lt;code&gt;checkout&lt;/code&gt; Action -&amp;gt; 状态变更”&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 推荐在 actions 中集中修改&lt;a href=&quot;#2推荐在actions中集中修改&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;逻辑集中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;方便调试&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;易于维护&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;八、Pinia 数据持久化&lt;a href=&quot;#八pinia数据持久化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;介绍：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Pinia 数据持久化是指将 Store 中的数据自动保存到浏览器的本地存储&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;localStorage&lt;/code&gt; &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;sessionStorage&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这样即使用户刷新页面或关闭浏览器后再次打开，数据依然能够恢复&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于记住用户的登录状态、购物车内容、主题偏好等场景非常有用&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pinia 官方并没有内置持久化插件，但社区提供了一个非常流行且好用的官方推荐插件&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pinia-plugin-persistedstate&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;pinia-plugin-persistedstate&lt;/code&gt;的使用方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;安装插件：首先，我们需要在我们的项目里面安装 &lt;code&gt;pinia-plugin-persistedstate&lt;/code&gt; 插件&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;npm install pinia&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;plugin&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;persistedstate&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# 或者&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;yarn add pinia&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;plugin&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;persistedstate&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# 或者&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pnpm add pinia&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;plugin&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;persistedstate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在 Pinia 实例中注册插件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// main.js 或 store/index.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { createApp } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;vue&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { createPinia } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;pinia&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; persistedstate &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;pinia-plugin-persistedstate&apos;&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;// 导入插件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; app&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; createApp&lt;/span&gt;&lt;span&gt;(App);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; pinia&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; createPinia&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pinia.&lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt;(persistedstate); &lt;/span&gt;&lt;span&gt;// 注册插件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;app.&lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt;(pinia);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;app.&lt;/span&gt;&lt;span&gt;mount&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#app&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 Store 定义中启用持久化&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在使用 &lt;code&gt;defineStore&lt;/code&gt; 定义 Store 时，通过添加 &lt;code&gt;persist: true&lt;/code&gt; 或一个配置对象来启用持久化&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 示例1：简单的配置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// stores/counter.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { defineStore } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;pinia&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; useCounterStore&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; defineStore&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;counter&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // Store 配置项&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // state、getter 和 action 都写这里面&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  , {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 在这里添加持久化配置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  persist: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; // 最简单的形式，会持久化整个 Store 的 state&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; // ================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 示例 2：更详细的配置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; useUserStore&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; defineStore&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;user&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // Store 配置项&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}, {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  persist: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // key: 自定义存储的键名，默认为 storeId&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    key: &lt;/span&gt;&lt;span&gt;&apos;my_user_store_key&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // storage: 选择存储方式，默认为 localStorage&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    storage: localStorage, &lt;/span&gt;&lt;span&gt;// 或 sessionStorage&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // paths: 指定需要持久化的 state 字段（数组）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 如果不设置，则默认持久化整个 state&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    paths: [&lt;/span&gt;&lt;span&gt;&apos;profile&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;preferences&apos;&lt;/span&gt;&lt;span&gt;], &lt;/span&gt;&lt;span&gt;// 只持久化 profile 和 preferences&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 可选：自定义序列化函数 (serializer)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    serializer: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      serialize: &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.stringify,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      deserialize: &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.parse,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 可选：自定义存储逻辑 (advanced)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 如需要对存储的数据进行加密/解密等操作&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;配置项详解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;persist: true&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最简单的配置，会将整个 Store 的 &lt;code&gt;state&lt;/code&gt;（即 &lt;code&gt;return&lt;/code&gt; 出来的 &lt;code&gt;ref&lt;/code&gt; 和 &lt;code&gt;reactive&lt;/code&gt; 对象）完整地保存到 &lt;code&gt;localStorage&lt;/code&gt; 中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;persist: { ... }&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;key&lt;/code&gt; (string): 指定在浏览器存储中使用的键名。如果不指定，默认使用 &lt;code&gt;defineStore&lt;/code&gt; 时的第一个参数（即 &lt;code&gt;storeId&lt;/code&gt;）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;storage&lt;/code&gt; (Storage): 指定使用的 Web Storage 接口。可以是 &lt;code&gt;localStorage&lt;/code&gt;（数据永久保存，除非手动清除）或 &lt;code&gt;sessionStorage&lt;/code&gt;（数据仅在当前会话期间有效，关闭浏览器标签页/窗口后消失）。默认为 &lt;code&gt;localStorage&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;paths&lt;/code&gt; (Array&amp;lt;string&amp;gt;): 一个字符串数组，用于指定哪些 &lt;code&gt;state&lt;/code&gt; 属性需要被持久化。如果设置了 &lt;code&gt;paths&lt;/code&gt;，则只有列出的属性会被保存，其他属性会被忽略。这对于不想持久化临时数据或敏感信息（如 token）非常有用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;serializer&lt;/code&gt; (object): 允许你自定义数据的序列化和反序列化方式。默认使用 &lt;code&gt;JSON.stringify&lt;/code&gt; 和 &lt;code&gt;JSON.parse&lt;/code&gt;。在某些特殊情况下可能需要自定义。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:分享会</category><category>tag:前端</category><category>tag:分享会</category><category>tag:JavaScript</category></item><item><title>选项式API与组合式API的区别</title><link>https://wine-congee.vercel.app/post/options-composition</link><guid isPermaLink="false">options-composition</guid><description>
Vue 作为前端三大框架之一，从 Vue  2到 Vue  3的迭代不仅带来了性能的飞跃，更在代码组织、逻辑复用等核心层面进行了架构升级。其中，选项式 API（Options API）与组合式 API（Composition</description><pubDate>Fri, 23 Jan 2026 12:57:31 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Vue 作为前端三大框架之一，从 Vue  2到 Vue  3的迭代不仅带来了性能的飞跃，更在代码组织、逻辑复用等核心层面进行了架构升级。其中，选项式 API（Options API）与组合式 API（Composition API）作为两代框架的核心编程范式，承载着不同的设计理念与使用场景。本文将从设计初衷、语法结构、逻辑复用、性能表现等维度，全方位拆解二者的区别，帮助开发者精准把握两种 API 的适用场景，提升 Vue 项目开发效率。。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;一、设计理念：面向对象 vs 函数式组合&lt;a href=&quot;#一设计理念面向对象-vs-函数式组合&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;两种 API 的本质差异源于底层设计理念的不同，这也决定了它们在代码组织方式上的核心区别。。&lt;/p&gt;
&lt;p&gt;###1. 选项式 API（Vue  2默认））
选项式 API 基于面向对象编程（OOP）思想，将组件的功能拆分为一系列预定义选项，如 data、methods、computed、watch、created 等。开发者需将不同逻辑分散到对应选项中，Vue 内部通过整合这些选项构建组件实例。。&lt;/p&gt;
&lt;p&gt;这种方式的优势在于入门门槛低，结构清晰，符合开发者对“对象”的认知习惯——组件就像一个封装好的对象，不同选项对应对象的不同属性和方法。但缺点也十分明显：当组件逻辑复杂时，相关代码会分散在多个选项中，形成“碎片化”代码，难以追踪和维护。&lt;/p&gt;
&lt;p&gt;###2. 组合式 API（Vue  3推荐））
组合式 API 基于于**函数式编程*思想，摒弃了固定的选项划分，允许开发者将相关逻辑封装在独立的函数中，再通过组合这些函数构建组件。核心是通过 setup 函数作为逻辑入口，结合 ref、reactive、computed、watch 等 API，自由组织代码结构。。
这种方式打破了选项式 API 的结构限制，让“相关逻辑聚在一起”，实现了逻辑的模块化拆分与复用，尤其适合复杂组件的开发。同时，函数式的设计也更契合 Vue  3的响应式原理（基于 Proxy），为性能优化提供了更大空间。。&lt;/p&gt;
&lt;h2&gt;二、语法结构：固定选项 vs 自由组合&lt;a href=&quot;#二语法结构固定选项-vs-自由组合&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;语法是设计理念的直接体现，两种 API 的代码结构差异显著，我们通过实现同一个功能（计数器）来直观对比。。&lt;/p&gt;
&lt;p&gt;###1. 选项式 API 实现现
选项式 API 需严格按照预设选项编写代码，逻辑分散在 data、methods、computed 中：：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// Vue2 选项式API 计数器组件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 数据定义&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  data&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      count: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 计算属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  computed: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    doubleCount&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      return&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt;.count &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 方法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  methods: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    increment&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      this&lt;/span&gt;&lt;span&gt;.count&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    decrement&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      this&lt;/span&gt;&lt;span&gt;.count&lt;/span&gt;&lt;span&gt;--&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 生命周期钩子&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  created&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;计数器组件初始化完成，初始值：&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.count)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;特点：代码按 “选项类型” 划分，无需手动管理上下文（this 指向组件实例），但逻辑关联性弱——若需扩展计数器的 “持久化存储” 功能，需在 data 中加存储标识，methods 中加存储方法，created 中加读取逻辑，代码分散在三个不同选项中。。&lt;/p&gt;
&lt;p&gt;###2. 组合式 API 实现现
组合式 API 通过 setup 函数整合所有逻辑，相关功能的代码集中在一起：：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// Vue3 组合式API 计数器组件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { ref, computed, onMounted } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;vue&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  setup&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 数据定义（ref用于基本类型响应式）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; count&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 计算属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; doubleCount&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; computed&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; count.value &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 方法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; increment&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      count.value&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt; // ref对象需通过.value访问/修改&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; decrement&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      count.value&lt;/span&gt;&lt;span&gt;--&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 生命周期钩子（组合式API中钩子前缀为on）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    onMounted&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;计数器组件初始化完成，初始值：&apos;&lt;/span&gt;&lt;span&gt;, count.value)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 暴露给模板使用的内容&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      count,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      doubleCount,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      increment,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      decrement&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;特点：逻辑高度聚合，若需添加持久化功能，可直接在 setup 函数中新增相关逻辑（如使用 localStorage），形成独立的逻辑块。同时，组合式 API 需手动管理响应式数据（ref/reactive）和上下文，无 this 指向问题（setup 函数中 this 为 undefined），避免了选项式 API 中 this 指向混乱的问题。。&lt;/p&gt;
&lt;h2&gt;三、核心差异对比&lt;a href=&quot;#三核心差异对比&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;除了设计理念和语法结构，二者在逻辑复用、响应式原理、生命周期、类型支持等方面也存在显著差异，具体如下：&lt;/p&gt;
&lt;h3&gt;1. 逻辑复用能力&lt;a href=&quot;#1-逻辑复用能力&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;逻辑复用是大型项目开发的核心需求，两种 API 的实现方式差异极大。。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;选项式 APII&lt;/em&gt;：主要通过“混入（mixin）”实现逻辑复用。但 mixin 存在明显缺陷：① 命名冲突：多个 mixin 中的 data、methods 可能重名，覆盖优先级难以控制；② 逻辑模糊：组件中无法清晰判断某个属性/方法来自哪个 mixin，调试难度大；③ 依赖不明确：mixin 与组件间可能存在隐式依赖，维护成本高。。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;组合式 APII&lt;/em&gt;：通过“组合函数（Composable Functions）”实现逻辑复用。将可复用逻辑封装为独立函数，在 setup 中引入并调用，支持参数传递和返回值定制。优势在于：① 无命名冲突：函数返回的内容需手动暴露给组件，命名由开发者自主控制；② 逻辑清晰：组件中可明确看到复用逻辑的来源，调试便捷；③ 依赖透明：函数与组件间的依赖通过参数和返回值显式关联，降低耦合度。。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：封装一个可复用的“鼠标位置监听”逻辑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 组合函数：useMousePosition.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { ref, onMounted, onUnmounted } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;vue&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; useMousePosition&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; updatePosition&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    x.value &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; e.clientX&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    y.value &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; e.clientY&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  onMounted&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    window.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;mousemove&apos;&lt;/span&gt;&lt;span&gt;, updatePosition)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  onUnmounted&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    window.&lt;/span&gt;&lt;span&gt;removeEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;mousemove&apos;&lt;/span&gt;&lt;span&gt;, updatePosition)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; { x, y }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 在组件中使用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { useMousePosition } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./useMousePosition&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  setup&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useMousePosition&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; { x, y }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 响应式原理&lt;a href=&quot;#2-响应式原理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;响应式是 Vue 的核心特性，两种 API 的响应式实现基于不同的底层机制。。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;选项式 APII&lt;/em&gt;*：基于**Object.defineProperty*实现。Vue  2会遍历 data 中的所有属性，通过 Object.defineProperty 为其添加 getter 和 setter，监听属性的读取和修改。但这种方式存在局限性：① 无法监听对象新增/删除的属性；② 无法监听数组的下标修改和长度变化（需通过 Vue.set/Vue.delete 或数组变异方法解决）；③ 对复杂对象的响应式处理成本高，需深度遍历。。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;组合式 APII&lt;/em&gt;*：基于**Proxy*实现。Vue  3通过 Proxy 包裹响应式对象，直接拦截对象的所有操作（读取、修改、新增、删除等），无需深度遍历。优势在于：① 原生支持对象新增/删除属性；② 支持数组下标修改和长度变化；③ 响应式触发更精准，性能更优；④ 提供 ref（基本类型响应式）和 reactive（对象类型响应式）两种 API，适配不同场景。。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 生命周期&lt;a href=&quot;#3-生命周期&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;两种 API 的生命周期钩子名称和使用方式略有差异，核心逻辑一致。。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;选项式 APII&lt;/em&gt;：直接使用生命周期钩子名称作为选项，如 created、mounted、updated、destroyed 等，函数内部 this 指向组件实例。。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;组合式 APII&lt;/em&gt;：生命周期钩子需从 vue 中导入，前缀为“on”，如 onMounted、onUpdated、onUnmounted 等，需在 setup 函数中调用。由于 setup 函数执行时机早于 created（在组件实例创建前执行），因此无需 onCreated 钩子，setup 函数本身即可替代其功能。。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;生命周期对应关系：
选项式 APII 组合式 APII|说明|
|---|---|---|
|beforeCreate|-setup 函数执行前，无对应钩子子|
|created|-setup 函数执行期间，无需单独钩子子|
|beforeMount|onBeforeMount|组件挂载前触发|
|mounted|onMounted|组件挂载完成触发|
|beforeUpdate|onBeforeUpdate|组件更新前触发|
|updated|onUpdated|组件更新完成触发|
|beforeDestroy|onBeforeUnmount|组件卸载前触发（Vue  3更名，语义更准确）|
|destroyed|onUnmounted|组件卸载完成触发||&lt;/p&gt;
&lt;h3&gt;4. 类型支持&lt;a href=&quot;#4-类型支持&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Vue  3对 TypeScript 的支持进行了全面优化，组合式 API 在类型推导上更具优势。。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;选项式 APII&lt;/em&gt;：由于依赖 this 上下文，TypeScript 难以对其进行精准的类型推导。需通过 Vue.extend 或组件选项中的 props 定义来补充类型，配置繁琐，且部分场景（如 mixin 中的类型）无法完美适配。。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;组合式 APII&lt;/em&gt;：基于函数式设计，天然契合 TypeScript 的类型系统。ref 和 reactive 会自动推导数据类型，组合函数的参数和返回值也可通过 TypeScript 明确约束，类型推导更精准、更简洁，无需额外冗余配置，是 Vue3+TS 项目的首选方案。。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. 代码组织与可维护性&lt;a href=&quot;#5-代码组织与可维护性&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;随着组件复杂度的提升，两种 API 的代码可维护性差异会愈发明显。。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;选项式 APII&lt;/em&gt;：适合简单组件（如 UI 组件库中的基础组件），代码结构固定，易上手。但对于复杂组件（如包含表单校验、数据请求、状态管理的页面级组件），逻辑分散在多个选项中，形成“面条代码”，后续修改和扩展难度大。。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;组合式 APII&lt;/em&gt;：适合复杂组件和大型项目，可按“业务逻辑”划分代码块（如表单逻辑、数据请求逻辑、状态管理逻辑），每个逻辑块封装为独立函数，代码结构清晰，可维护性和可扩展性更强。同时，组合式 API 的代码更易压缩，打包体积更优。。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;四、适用场景&lt;a href=&quot;#四适用场景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;两种 API 并非对立关系，Vue  3同时支持两种 API（选项式 API 需通过@vue/composition-api 插件在 Vue  2中使用），开发者需根据项目场景选择合适的方案。。&lt;/p&gt;
&lt;p&gt;###1. 选项式 API 适用场景景&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;小型项目或简单组件，逻辑简单，无需复杂复用；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;-团队成员以 Vue  2开发者为主，学习成本敏感，无需快速迁移到组合式 API；；&lt;/p&gt;
&lt;p&gt;-UI 组件库中的基础组件，结构固定，无需频繁修改。。&lt;/p&gt;
&lt;p&gt;###2. 组合式 API 适用场景景&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;大型项目或复杂组件，逻辑复杂，需要高频复用；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;-使用 TypeScript 开发的项目，追求精准的类型推导；；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要优化性能的场景（如复杂响应式对象、大量数据处理）；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;-新启动的 Vue  3项目，推荐优先使用组合式 API，为项目长期维护奠定基础。。&lt;/p&gt;</content:encoded><category>category:前端</category><category>tag:前端</category><category>tag:JavaScript</category><category>tag:vue</category></item><item><title>JavaScript Promise</title><link>https://wine-congee.vercel.app/post/JavaScript-Promise</link><guid isPermaLink="false">JavaScript-Promise</guid><description>一、为什么需要 Promise？—— 告别回调地狱
在 Promise 出现之前，JavaScript 处理异步操作的主流方式是回调函数。比如我们需要按顺序执行三个异步请求（第一个请求的结果作为第二个的参数，第二个的结果作为第三个的参数），代码会变成这样：

//</description><pubDate>Fri, 26 Dec 2025 12:27:45 GMT</pubDate><content:encoded>&lt;h2&gt;一、为什么需要 Promise？—— 告别回调地狱&lt;a href=&quot;#一为什么需要-promise-告别回调地狱&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在 Promise 出现之前，JavaScript 处理异步操作的主流方式是&lt;strong&gt;回调函数&lt;/strong&gt;。比如我们需要按顺序执行三个异步请求（第一个请求的结果作为第二个的参数，第二个的结果作为第三个的参数），代码会变成这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 回调地狱示例：按顺序执行三个异步请求&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;ajax&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;api/step1&apos;&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;res1&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;第一步完成&apos;&lt;/span&gt;&lt;span&gt;, res1);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ajax&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;api/step2?param=&apos;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; res1, (&lt;/span&gt;&lt;span&gt;res2&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;第二步完成&apos;&lt;/span&gt;&lt;span&gt;, res2);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ajax&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;api/step3?param=&apos;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; res2, (&lt;/span&gt;&lt;span&gt;res3&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;第三步完成&apos;&lt;/span&gt;&lt;span&gt;, res3);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, (&lt;/span&gt;&lt;span&gt;err3&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;第三步失败&apos;&lt;/span&gt;&lt;span&gt;, err3);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }, (&lt;/span&gt;&lt;span&gt;err2&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;第二步失败&apos;&lt;/span&gt;&lt;span&gt;, err2);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}, (&lt;/span&gt;&lt;span&gt;err1&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;第一步失败&apos;&lt;/span&gt;&lt;span&gt;, err1);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种嵌套层级不断加深的代码，被称为“回调地狱”（Callback Hell），它存在三个致命问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可读性差&lt;/strong&gt;：代码横向扩张，逻辑链条被嵌套割裂，后期维护时需要层层拆解才能理清流程；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;错误处理繁琐&lt;/strong&gt;：每个异步操作都要单独处理错误，无法统一捕获，容易遗漏异常；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可维护性低&lt;/strong&gt;：修改某个步骤的逻辑时，需要改动多层嵌套的代码，耦合度极高。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而 Promise 的出现，正是为了解决这些问题。它通过“状态管理”和“链式调用”，将嵌套的回调改为线性的链式代码，同时提供统一的错误处理机制，让异步逻辑变得清晰可控。&lt;/p&gt;
&lt;h2&gt;二、Promise 核心概念：什么是“承诺”？&lt;a href=&quot;#二promise-核心概念什么是承诺&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Promise 字面意思是“承诺”，在 JS 中，它是一个&lt;strong&gt;代表异步操作最终完成或失败的对象&lt;/strong&gt;。我们可以用一个生动的类比理解：&lt;/p&gt;
&lt;p&gt;你去餐厅点餐，服务员给你一个取餐号（Promise 对象）—— 这个取餐号就是餐厅对你的“承诺”：你的餐品正在制作（pending 状态），最终要么做好了叫你取餐（fulfilled 状态），要么因为食材不足等原因制作失败（rejected 状态）。在等待期间，你不需要一直盯着厨房，而是可以自由做其他事（非阻塞），直到承诺兑现或失败。&lt;/p&gt;
&lt;p&gt;从技术角度，Promise 有三个核心特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;它是一个对象，封装了异步操作的结果；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供统一的 API（then/catch/finally 等），让异步操作的处理方式标准化；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;状态一旦确定就不可变，确保行为的确定性。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;三、Promise 三大状态与状态流转&lt;a href=&quot;#三promise-三大状态与状态流转&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Promise 的核心是“状态管理”，它有且只有三种状态，且状态流转不可逆：&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;th&gt;是否可变&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;pending（进行中）&lt;/td&gt;&lt;td&gt;初始状态，异步操作正在执行，既未成功也未失败&lt;/td&gt;&lt;td&gt;是（可转为 fulfilled 或 rejected）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;fulfilled（已成功）&lt;/td&gt;&lt;td&gt;异步操作完成，Promise 兑现了承诺&lt;/td&gt;&lt;td&gt;否（状态凝固，不可再变）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rejected（已失败）&lt;/td&gt;&lt;td&gt;异步操作失败，Promise 未兑现承诺&lt;/td&gt;&lt;td&gt;否（状态凝固，不可再变）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pending（初始） &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ├─ resolve() → fulfilled（成功）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  └─ reject() → rejected（失败）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;关键提醒：状态一旦从 pending 转为 fulfilled 或 rejected，就永远无法改变。比如先调用 resolve() 再调用 reject()，reject() 会失效；反之亦然。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;示例验证状态不可逆：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;resolve&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;reject&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  resolve&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;操作成功&apos;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// 状态转为 fulfilled&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  reject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;操作失败&apos;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// 无效！状态已凝固&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;p.&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;res&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(res)); &lt;/span&gt;&lt;span&gt;// 输出：操作成功&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;p.&lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(err)); &lt;/span&gt;&lt;span&gt;// 不会执行&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;四、Promise 基础用法：从创建到使用&lt;a href=&quot;#四promise-基础用法从创建到使用&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;4.1 创建 Promise 实例&lt;a href=&quot;#41-创建-promise-实例&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;通过 &lt;code&gt;new Promise(executor)&lt;/code&gt; 创建 Promise 实例，executor 是一个立即执行的函数，接收两个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;resolve(value)&lt;/code&gt;：将状态从 pending 转为 fulfilled，并传递成功的结果 value；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;reject(reason)&lt;/code&gt;：将状态从 pending 转为 rejected，并传递失败的原因 reason（通常是 Error 对象）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：创建一个模拟异步请求的 Promise：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 创建 Promise 实例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fetchData&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;resolve&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;reject&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Promise 执行器立即执行&apos;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// 同步执行&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 模拟异步操作（比如接口请求）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  setTimeout&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; success&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;random&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 0.5&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;// 50% 成功概率&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (success) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      resolve&lt;/span&gt;&lt;span&gt;({ code: &lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt;, data: &lt;/span&gt;&lt;span&gt;&apos;请求成功的数据&apos;&lt;/span&gt;&lt;span&gt; }); &lt;/span&gt;&lt;span&gt;// 成功：传递结果&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      reject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; Error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;接口请求超时&apos;&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// 失败：传递错误对象&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }, &lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：Promise 构造函数中的 executor 函数是&lt;strong&gt;同步立即执行&lt;/strong&gt;的，但 resolve/reject 通常在异步操作内部调用，决定最终的状态。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;4.2 三种快捷创建方式&lt;a href=&quot;#42-三种快捷创建方式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;除了 new Promise()，JS 还提供了三个静态方法，快速创建指定状态的 Promise：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Promise.resolve(value)&lt;/strong&gt;：快速创建一个已成功的 Promise（fulfilled 状态）&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 等价于 new Promise(resolve =&amp;gt; resolve(42))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; p1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;resolve&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;42&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;p1.&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;res&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(res)); &lt;/span&gt;&lt;span&gt;// 输出：42&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;适用场景：将非 Promise 值包装成 Promise（便于链式调用）、返回已知成功结果的异步操作。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Promise.reject(reason)&lt;/strong&gt;：快速创建一个已失败的 Promise（rejected 状态）&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 等价于 new Promise((resolve, reject) =&amp;gt; reject(new Error(&apos;失败&apos;)))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; p2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;reject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; Error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;请求失败&apos;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;p2.&lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(err.message)); &lt;/span&gt;&lt;span&gt;// 输出：请求失败&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Promise.all(iterable)&lt;/strong&gt; / &lt;strong&gt;Promise.race(iterable)&lt;/strong&gt;：批量处理多个 Promise（后续进阶部分详解）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4.3 消费 Promise：then/catch/finally&lt;a href=&quot;#43-消费-promisethencatchfinally&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;创建 Promise 后，需要通过 &lt;code&gt;then&lt;/code&gt;、&lt;code&gt;catch&lt;/code&gt;、&lt;code&gt;finally&lt;/code&gt; 这三个核心方法“消费”它的结果，也就是注册状态改变后的回调函数。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;then()：处理成功状态&lt;/strong&gt;接收一个 onFulfilled 回调函数，当 Promise 变为 fulfilled 时执行，参数是 resolve 传递的成功结果。同时，then() 会返回一个新的 Promise，支持链式调用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;catch()：处理失败状态&lt;/strong&gt;接收一个 onRejected 回调函数，当 Promise 变为 rejected 时执行，参数是 reject 传递的失败原因。等价于 &lt;code&gt;then(null, onRejected)&lt;/code&gt;，且能捕获链式调用中任意环节的错误。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;finally()：清理操作&lt;/strong&gt;接收一个无参数的回调函数，无论 Promise 成功还是失败，都会执行。常用于清理资源（比如关闭加载动画、释放内存）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;示例：完整的 Promise 消费流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fetchData&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;res&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;请求成功：&apos;&lt;/span&gt;&lt;span&gt;, res.data);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; res.data.&lt;/span&gt;&lt;span&gt;toUpperCase&lt;/span&gt;&lt;span&gt;(); &lt;/span&gt;&lt;span&gt;// 返回普通值，传递给下一个 then&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;upperData&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;处理后的数据：&apos;&lt;/span&gt;&lt;span&gt;, upperData);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;请求失败：&apos;&lt;/span&gt;&lt;span&gt;, err.message); &lt;/span&gt;&lt;span&gt;// 捕获任意环节的错误&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;finally&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;请求结束，关闭加载动画&apos;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// 无论成败都执行&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;五、进阶特性：链式调用与批量处理&lt;a href=&quot;#五进阶特性链式调用与批量处理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;5.1 链式调用：线性化异步流程&lt;a href=&quot;#51-链式调用线性化异步流程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Promise 最强大的特性之一是“链式调用”，它让多个异步操作按顺序执行变得简单。核心原理是：&lt;strong&gt;then()/catch()/finally() 都会返回一个新的 Promise&lt;/strong&gt;，下一个 then 会接收上一个 then 的返回值，并根据返回值类型决定后续行为：&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;上一个 then 的返回值&lt;/th&gt;&lt;th&gt;下一个 then 接收的值&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;普通值（非 Promise）&lt;/td&gt;&lt;td&gt;直接接收该普通值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Promise 对象&lt;/td&gt;&lt;td&gt;等待该 Promise 状态确定后，接收其 resolve/reject 的值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;抛出错误（throw new Error()）&lt;/td&gt;&lt;td&gt;错误被后续的 catch 捕获&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;示例：用链式调用重构“回调地狱”的三个异步请求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 链式调用：线性流程，清晰可控&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;ajax&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;api/step1&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;res1&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;第一步完成&apos;&lt;/span&gt;&lt;span&gt;, res1);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; ajax&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;api/step2?param=&apos;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; res1); &lt;/span&gt;&lt;span&gt;// 返回新 Promise，等待其完成&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;res2&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;第二步完成&apos;&lt;/span&gt;&lt;span&gt;, res2);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; ajax&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;api/step3?param=&apos;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; res2);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;res3&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;第三步完成&apos;&lt;/span&gt;&lt;span&gt;, res3);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;任意步骤失败：&apos;&lt;/span&gt;&lt;span&gt;, err); &lt;/span&gt;&lt;span&gt;// 统一捕获所有错误&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对比之前的回调地狱，链式调用的代码线性展开，逻辑清晰，错误处理也只需一次 catch 即可。&lt;/p&gt;
&lt;h3&gt;5.2 批量处理：Promise.all 与 Promise.race&lt;a href=&quot;#52-批量处理promiseall-与-promiserace&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;实际开发中，经常需要处理多个异步操作（比如同时加载多个图片、并行请求多个接口），Promise 提供了两个静态方法实现批量处理：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Promise.all(iterable)：并行执行，全成才成&lt;/strong&gt;接收一个可迭代对象（如数组），包含多个 Promise；返回一个新 Promise：适用场景：多个独立的异步操作，需要全部完成后再继续（比如表单提交前，验证多个接口数据）。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 并行请求两个接口&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fetchUser&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;api/user&apos;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;res&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; res.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fetchGoods&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;api/goods&apos;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;res&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; res.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;span&gt;([fetchUser, fetchGoods])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(([&lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;goods&lt;/span&gt;&lt;span&gt;]) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;用户数据：&apos;&lt;/span&gt;&lt;span&gt;, user);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;商品数据：&apos;&lt;/span&gt;&lt;span&gt;, goods);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;任一请求失败：&apos;&lt;/span&gt;&lt;span&gt;, err);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当&lt;strong&gt;所有&lt;/strong&gt;传入的 Promise 都变为 fulfilled 时，新 Promise 才 fulfilled，返回值是所有 Promise resolve 结果的数组（顺序与传入顺序一致）；&lt;/p&gt;
&lt;p&gt;只要&lt;strong&gt;有一个&lt;/strong&gt;传入的 Promise 变为 rejected，新 Promise 立即 rejected，返回值是第一个 rejected 的原因。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Promise.race(iterable)：竞速执行，先成先得&lt;/strong&gt;接收一个可迭代对象，返回一个新 Promise：&lt;strong&gt;哪个 Promise 先改变状态（无论成功或失败），新 Promise 就沿用哪个的状态和结果&lt;/strong&gt;。
适用场景：处理超时逻辑（比如接口请求超过 5 秒就提示超时）、获取最快响应的资源。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 模拟接口请求超时逻辑（5秒超时）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; request&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;api/data&apos;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;res&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; res.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; timeout&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;resolve&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;reject&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  setTimeout&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; reject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; Error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;请求超时&apos;&lt;/span&gt;&lt;span&gt;)), &lt;/span&gt;&lt;span&gt;5000&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;race&lt;/span&gt;&lt;span&gt;([request, timeout])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;请求成功：&apos;&lt;/span&gt;&lt;span&gt;, data))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;错误：&apos;&lt;/span&gt;&lt;span&gt;, err)); &lt;/span&gt;&lt;span&gt;// 先触发的状态决定结果&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;六、实战场景与最佳实践&lt;a href=&quot;#六实战场景与最佳实践&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;6.1 常见实战场景&lt;a href=&quot;#61-常见实战场景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;接口请求处理&lt;/strong&gt;：结合 fetch 或 axios（本质是 Promise 封装）处理 API 请求，统一管理加载状态和错误提示。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;  async&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; getUserData&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;api/user&apos;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// await 是 Promise 的语法糖&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;res.ok) &lt;/span&gt;&lt;span&gt;throw&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;接口返回错误&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; res.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; data;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (err) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;获取用户数据失败：&apos;&lt;/span&gt;&lt;span&gt;, err);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    throw&lt;/span&gt;&lt;span&gt; err; &lt;/span&gt;&lt;span&gt;// 向上抛出，让调用方处理&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;批量资源加载&lt;/strong&gt;：用 Promise.all 并行加载多个图片、脚本，提升页面加载效率。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 并行加载多张图片&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; loadImages&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;urls&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; promises&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; urls.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;resolve&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;reject&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; img&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Image&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      img.&lt;/span&gt;&lt;span&gt;onload&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; resolve&lt;/span&gt;&lt;span&gt;(img);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      img.&lt;/span&gt;&lt;span&gt;onerror&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; reject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; Error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`加载图片失败：${&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      img.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; url;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;span&gt;(promises);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;loadImages&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;&apos;img1.jpg&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;img2.jpg&apos;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;images&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;所有图片加载完成&apos;&lt;/span&gt;&lt;span&gt;, images))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(err));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;异步任务队列&lt;/strong&gt;：用链式调用实现按顺序执行的异步任务队列（比如依次处理多个文件上传）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;6.2 总结&lt;a href=&quot;#62-总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;始终处理错误&lt;/strong&gt;：每个 Promise 链式调用都要加 catch()，或在 async/await 中用 try/catch，避免“静默错误”导致程序异常。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;避免嵌套 Promise&lt;/strong&gt;：即使在 then 中需要新的异步操作，也应返回 Promise 继续链式调用，而非嵌套 new Promise。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;合理使用 Promise.all&lt;/strong&gt;：多个独立异步操作优先用 Promise.all 并行执行，提升效率；但如果操作有依赖，需用链式调用串行执行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;不滥用 Promise&lt;/strong&gt;：同步操作无需包装成 Promise；简单的异步操作（如单个定时器），若逻辑简单，可根据情况选择回调，但复杂场景优先用 Promise。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;用 async/await 简化代码&lt;/strong&gt;：async/await 是 Promise 的语法糖，能让链式调用的代码更像同步代码，可读性更高（本质还是基于 Promise 实现）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:前端</category><category>tag:前端</category><category>tag:JavaScript</category></item><item><title>Vue2中的Vuex</title><link>https://wine-congee.vercel.app/post/vue2-vuex</link><guid isPermaLink="false">vue2-vuex</guid><description>##一、为什么需要 Vuex？？
在 Vue2 项目开发中，如果你遇到以下问题，就该考虑使用 Vuex 了：


多个组件共享同一状态（如用户信息、购物车数据），组件间传参层层嵌套，代码冗余且易出错；


不同组件需要修改同一状态，通过事件总线（Event Bus）会导致数据流向混乱，难以调试；</description><pubDate>Sat, 20 Dec 2025 01:22:27 GMT</pubDate><content:encoded>&lt;p&gt;##一、为什么需要 Vuex？？&lt;/p&gt;
&lt;p&gt;在 Vue2 项目开发中，如果你遇到以下问题，就该考虑使用 Vuex 了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;多个组件共享同一状态（如用户信息、购物车数据），组件间传参层层嵌套，代码冗余且易出错；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不同组件需要修改同一状态，通过事件总线（Event Bus）会导致数据流向混乱，难以调试；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;希望状态变更可追踪，便于定位问题。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Vuex 把组件的共享状态抽取出来，以一个全局单例模式管理，让组件树构成一个巨大的“视图”，不管在哪个组件，都能获取状态或触发行为，同时保证所有状态的变更都遵循统一的规则，使代码可预测。&lt;/p&gt;
&lt;h2&gt;二、Vuex 的核心概念（Vue2 版本）&lt;a href=&quot;#二vuex-的核心概念vue2-版本&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Vuex 的核心由 &lt;strong&gt;State、Getter、Mutation、Action、Module&lt;/strong&gt; 五部分组成，我们先理清每个部分的作用：&lt;/p&gt;
&lt;h3&gt;1. State：唯一数据源&lt;a href=&quot;#1-state唯一数据源&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;State 是 Vuex 存储状态（数据）的地方，相当于组件中的 &lt;code&gt;data&lt;/code&gt;，但它是全局的，所有组件都能访问。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;单一状态树：一个应用只有一个 Store 实例，所有状态集中管理；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;响应式：State 中的数据是响应式的，组件获取后，数据变更会自动更新视图。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. Getter：计算属性&lt;a href=&quot;#2-getter计算属性&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Getter 相当于 Vue 组件中的 &lt;code&gt;computed&lt;/code&gt;，用于对 State 中的数据进行二次处理（如过滤、计算），结果会被缓存，只有依赖的数据变化时才会重新计算。&lt;/p&gt;
&lt;h3&gt;3. Mutation：唯一修改状态的方式&lt;a href=&quot;#3-mutation唯一修改状态的方式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Mutation 是修改 State 的唯一入口，必须是&lt;strong&gt;同步函数&lt;/strong&gt;（异步操作会导致状态变更无法追踪）。每个 Mutation 有一个字符串类型的 &lt;code&gt;type&lt;/code&gt; 和一个 &lt;code&gt;handler&lt;/code&gt; 函数，handler 函数接收 &lt;code&gt;state&lt;/code&gt; 作为第一个参数，可接收第二个参数（载荷 payload）。&lt;/p&gt;
&lt;h3&gt;4. Action：处理异步操作&lt;a href=&quot;#4-action处理异步操作&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Action 用于处理异步逻辑（如接口请求），不能直接修改 State，必须通过提交 Mutation 来修改状态。Action 可以包含任意异步操作，支持提交多个 Mutation。&lt;/p&gt;
&lt;h3&gt;5. Module：模块化管理&lt;a href=&quot;#5-module模块化管理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当项目规模较大时，单一 State 会变得臃肿，Module 允许将 Store 分割成多个模块，每个模块拥有自己的 State、Getter、Mutation、Action，便于维护。&lt;/p&gt;
&lt;h2&gt;三、Vue2 中 Vuex 的使用步骤&lt;a href=&quot;#三vue2-中-vuex-的使用步骤&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 环境准备&lt;a href=&quot;#1-环境准备&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;首先确保项目是 Vue2 环境，安装对应版本的 Vuex（Vue2 对应 Vuex 3.x，Vue3 对应 Vuex 4.x）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# 安装 Vuex 3.x&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;npm install vuex@3 --save&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# 或&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;yarn add vuex@3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 创建 Store 实例&lt;a href=&quot;#2-创建-store-实例&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在项目 &lt;code&gt;src&lt;/code&gt; 目录下新建 &lt;code&gt;store&lt;/code&gt; 文件夹，创建 &lt;code&gt;index.js&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// src/store/index.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import Vue from &apos;vue&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import Vuex from &apos;vuex&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 注册 Vuex&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Vue.use(Vuex)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 定义 Store&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const store = new Vuex.Store({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 1. 状态数据&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  state: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 用户信息&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    userInfo: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      name: &apos;&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      token: &apos;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 购物车列表&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cartList: []&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 2. 计算属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  getters: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 计算购物车商品总数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cartTotalCount: state =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      return state.cartList.reduce((total, item) =&amp;gt; total + item.quantity, 0)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 过滤已选中的购物车商品&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    selectedCartItems: state =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      return state.cartList.filter(item =&amp;gt; item.checked)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 3. 同步修改状态&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mutations: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 设置用户信息&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    SET_USER_INFO(state, payload) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      state.userInfo = { ...state.userInfo, ...payload }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 添加商品到购物车&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ADD_TO_CART(state, goods) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // 先判断商品是否已存在&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      const existItem = state.cartList.find(item =&amp;gt; item.id === goods.id)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      if (existItem) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        existItem.quantity += 1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      } else {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        state.cartList.push({ ...goods, quantity: 1, checked: true })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 清空购物车&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    CLEAR_CART(state) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      state.cartList = []&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 4. 异步操作&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  actions: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 异步获取用户信息（模拟接口请求）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    async fetchUserInfo({ commit }, userId) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      try {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // 模拟接口请求&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        const res = await new Promise(resolve =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          setTimeout(() =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            resolve({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;              name: &apos;张三&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;              token: &apos;abc123456&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          }, 1000)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // 提交 Mutation 修改状态&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        commit(&apos;SET_USER_INFO&apos;, res)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return res&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      } catch (error) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        console.error(&apos;获取用户信息失败：&apos;, error)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        throw error&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 异步清空购物车（模拟接口+修改状态）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    async clearCart({ commit }) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      try {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // 模拟调用清空购物车接口&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        await new Promise(resolve =&amp;gt; setTimeout(resolve, 500))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // 提交 Mutation&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        commit(&apos;CLEAR_CART&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      } catch (error) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        console.error(&apos;清空购物车失败：&apos;, error)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export default store&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 在 Vue 项目中挂载 Store&lt;a href=&quot;#3-在-vue-项目中挂载-store&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;修改 &lt;code&gt;src/main.js&lt;/code&gt;，将 Store 挂载到 Vue 实例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// src/main.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import Vue from &apos;vue&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import App from &apos;./App.vue&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import store from &apos;./store&apos; // 引入 Store&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;new Vue({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  el: &apos;#app&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  store, // 挂载到Vue实例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  render: h =&amp;gt; h(App)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 组件中使用 Vuex&lt;a href=&quot;#4-组件中使用-vuex&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;（1）获取 State 数据&lt;a href=&quot;#1获取-state-数据&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;有两种方式：直接通过 &lt;code&gt;this.$store.state&lt;/code&gt; 访问，或使用 &lt;code&gt;mapState&lt;/code&gt; 辅助函数（推荐，简化代码）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;user-info&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;用户名：{{ userInfo.name }}&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;购物车商品数：{{ cartList.length }}&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { mapState } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;vuex&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  computed: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 方式1：直接访问&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // userInfo() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    //   return this.$store.state.userInfo&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // cartList() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    //   return this.$store.state.cartList&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 方式2：mapState 辅助函数（推荐）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;span&gt;mapState&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;&apos;userInfo&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;cartList&apos;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;（2）使用 Getter&lt;a href=&quot;#2使用-getter&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;同理，可通过 &lt;code&gt;this.$store.getters&lt;/code&gt; 或 &lt;code&gt;mapGetters&lt;/code&gt; 辅助函数：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;cart&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;购物车总数：{{ cartTotalCount }}&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;已选中商品：{{ selectedCartItems.length }} 件&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { mapGetters } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;vuex&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  computed: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;span&gt;mapGetters&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;&apos;cartTotalCount&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;selectedCartItems&apos;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;（3）提交 Mutation 修改状态&lt;a href=&quot;#3提交-mutation-修改状态&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Mutation 必须通过 &lt;code&gt;commit&lt;/code&gt; 触发，支持 &lt;code&gt;this.$store.commit&lt;/code&gt; 或 &lt;code&gt;mapMutations&lt;/code&gt; 辅助函数：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; @click&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;addGoods&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;添加商品到购物车&amp;lt;/&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { mapMutations } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;vuex&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  methods: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    addGoods&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // 方式1：直接 commit&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // this.$store.commit(&apos;ADD_TO_CART&apos;, { id: 1, name: &apos;Vue实战教程&apos;, price: 99 })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // 方式2：mapMutations 辅助函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ADD_TO_CART&lt;/span&gt;&lt;span&gt;({ id: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, name: &lt;/span&gt;&lt;span&gt;&apos;Vue实战教程&apos;&lt;/span&gt;&lt;span&gt;, price: &lt;/span&gt;&lt;span&gt;99&lt;/span&gt;&lt;span&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;span&gt;mapMutations&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;&apos;ADD_TO_CART&apos;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;（4）触发 Action 处理异步&lt;a href=&quot;#4触发-action-处理异步&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Action 通过 &lt;code&gt;dispatch&lt;/code&gt; 触发，支持 &lt;code&gt;this.$store.dispatch&lt;/code&gt; 或 &lt;code&gt;mapActions&lt;/code&gt; 辅助函数：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; @click&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;getUserInfo&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;获取用户信息&amp;lt;/&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; @click&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;clearCart&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;清空购物车&amp;lt;/&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { mapActions } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;vuex&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  methods: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    async&lt;/span&gt;&lt;span&gt; getUserInfo&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // 方式1：直接 dispatch&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // await this.$store.dispatch(&apos;fetchUserInfo&apos;, 1001)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // 方式2：mapActions 辅助函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fetchUserInfo&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1001&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;用户信息已获取：&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.userInfo)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    async&lt;/span&gt;&lt;span&gt; clearCart&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;clearCart&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;购物车已清空&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;span&gt;mapActions&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;&apos;fetchUserInfo&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;clearCart&apos;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  computed: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    userInfo&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      return&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt;.$store.state.userInfo&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. 模块化（Module）实战&lt;a href=&quot;#5-模块化module实战&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当项目复杂时，拆分 Store 为多个模块，例如拆分 &lt;code&gt;user&lt;/code&gt; 和 &lt;code&gt;cart&lt;/code&gt; 模块：&lt;/p&gt;
&lt;h4&gt;步 骤1：创建模块文件&lt;a href=&quot;#步-骤1创建模块文件&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// src/store/modules/user.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export default {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  namespaced: true, // 开启命名空间，避免模块间命名冲突&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  state: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    userInfo: { name: &apos;&apos;, token: &apos;&apos; }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  getters: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    isLogin: state =&amp;gt; !!state.userInfo.token&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mutations: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    SET_USER_INFO(state, payload) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      state.userInfo = { ...state.userInfo, ...payload }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  actions: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    async fetchUserInfo({ commit }, userId) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      const res = await new Promise(resolve =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        setTimeout(() =&amp;gt; resolve({ name: &apos;张三&apos;, token: &apos;abc123&apos; }), 1000)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      commit(&apos;SET_USER_INFO&apos;, res)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// src/store/modules/cart.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export default {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  namespaced: true,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  state: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cartList: []&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  getters: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cartTotalCount: state =&amp;gt; state.cartList.reduce((t, i) =&amp;gt; t + i.quantity, 0)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mutations: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ADD_TO_CART(state, goods) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      const exist = state.cartList.find(i =&amp;gt; i.id === goods.id)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      exist ? exist.quantity++ : state.cartList.push({ ...goods, quantity: 1 })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  actions: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    async clearCart({ commit }) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      await new Promise(resolve =&amp;gt; setTimeout(resolve, 500))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      commit(&apos;CLEAR_CART&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;步 骤2：整合模块到 Store&lt;a href=&quot;#步-骤2整合模块到-store&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// src/store/index.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import Vue from &apos;vue&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import Vuex from &apos;vuex&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import user from &apos;./modules/user&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import cart from &apos;./modules/cart&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Vue.use(Vuex)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export default new Vuex.Store({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  modules: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    user,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cart&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;步 骤3：组件中使用命名空间模块&lt;a href=&quot;#步-骤3组件中使用命名空间模块&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;用户名：{{ userInfo.name }}&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;购物车总数：{{ cartTotalCount }}&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { mapState, mapGetters, mapActions } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;vuex&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  computed: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 方式1：带命名空间的 mapState&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;span&gt;mapState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;user&apos;&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span&gt;&apos;userInfo&apos;&lt;/span&gt;&lt;span&gt;]),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 方式2：直接访问&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // userInfo() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    //   return this.$store.state.user.userInfo&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;span&gt;mapGetters&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;cart&apos;&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span&gt;&apos;cartTotalCount&apos;&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  methods: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;span&gt;mapActions&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;user&apos;&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span&gt;&apos;fetchUserInfo&apos;&lt;/span&gt;&lt;span&gt;]),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ...&lt;/span&gt;&lt;span&gt;mapActions&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;cart&apos;&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span&gt;&apos;clearCart&apos;&lt;/span&gt;&lt;span&gt;]),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    async&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fetchUserInfo&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1001&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  created&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;四、Vuex 使用&lt;a href=&quot;#四vuex-使用&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 严格模式&lt;a href=&quot;#1-严格模式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;开启严格模式后，任何不是通过 Mutation 修改 State 的操作都会抛出错误，便于调试（生产环境建议关闭）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const store = new Vuex.Store({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  strict: process.env.NODE_ENV !== &apos;production&apos;, // 仅开发环境开启&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // ...其他配置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 避免直接修改 State&lt;a href=&quot;#2-避免直接修改-state&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;永远不要在组件中直接修改 &lt;code&gt;this.$store.state.xxx&lt;/code&gt;，必须通过 Mutation 或 Action 提交 Mutation，否则状态变更无法追踪。&lt;/p&gt;
&lt;h3&gt;3. 合理拆分模块&lt;a href=&quot;#3-合理拆分模块&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;按业务域拆分模块（如 user、cart、order），每个模块独立维护；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;开启 &lt;code&gt;namespaced: true&lt;/code&gt;，避免命名冲突；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;复杂模块可进一步拆分（如 cart 下拆分子模块 cartItem、cartPrice）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. 异步逻辑统一放在 Action&lt;a href=&quot;#4-异步逻辑统一放在-action&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;所有异步操作（接口请求、定时器、Promise）都放在 Action 中，Mutation 只做同步的状态修改，保证状态变更可追踪。&lt;/p&gt;
&lt;h3&gt;5. 数据持久化&lt;a href=&quot;#5-数据持久化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Vuex 状态刷新后会丢失，可结合 &lt;code&gt;vuex-persistedstate&lt;/code&gt; 实现本地存储持久化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;npm install vuex-persistedstate@3 --save # 适配 Vuex 3.x&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// src/store/index.js&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import createPersistedState from &apos;vuex-persistedstate&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const store = new Vuex.Store({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // ...其他配置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  plugins: [&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    createPersistedState({&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      key: &apos;vue2-vuex-demo&apos;, // 本地存储的key&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      paths: [&apos;user.userInfo&apos;, &apos;cart.cartList&apos;] // 需要持久化的状态路径&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. 避免过度使用 Vuex&lt;a href=&quot;#6-避免过度使用-vuex&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;并非所有数据都要放入 Vuex，只有&lt;strong&gt;跨组件共享、全局使用&lt;/strong&gt;的状态（如用户信息、购物车、全局配置）才适合，组件内部的私有状态（如表单临时值）直接用组件 &lt;code&gt;data&lt;/code&gt; 即可。&lt;/p&gt;
&lt;h2&gt;五、常见问题与解决方案&lt;a href=&quot;#五常见问题与解决方案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 模块中获取根状态/根 Getter&lt;a href=&quot;#1-模块中获取根状态根-getter&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在模块的 Getter/Action 中，可通过第二个参数获取根状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 模块中的 Getter&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;getters: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // rootState 访问根状态，rootGetters 访问根 Getter&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  cartTotalPrice: (state, getters, rootState, rootGetters) =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return state.cartList.reduce((t, i) =&amp;gt; t + i.price * i.quantity, 0)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 模块中的 Action&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;actions: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  async updateCart({ commit, rootState }) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 访问根状态的 user 信息&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const token = rootState.user.userInfo.token&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    await api.updateCart(token, state.cartList)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 辅助函数简化命名空间写法&lt;a href=&quot;#2-辅助函数简化命名空间写法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;可通过绑定命名空间的方式简化代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;import { createNamespacedHelpers } from &apos;vuex&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const { mapState, mapActions } = createNamespacedHelpers(&apos;cart&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export default {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  computed: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ...mapState([&apos;cartList&apos;])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  methods: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ...mapActions([&apos;addToCart&apos;])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;六、总结&lt;a href=&quot;#六总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Vuex 是 Vue2 中解决&lt;strong&gt;跨组件共享状态&lt;/strong&gt;的核心方案，核心是“单向数据流”：View → Dispatch Action → Commit Mutation → Modify State → Update View；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vuex 3.x 适配 Vue2，核心概念包括 State（状态）、Getter（计算）、Mutation（同步修改）、Action（异步）、Module（模块化）；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;“异步逻辑放 Action，同步修改放 Mutation”，复杂项目拆分模块并开启命名空间，结合 &lt;code&gt;vuex-persistedstate&lt;/code&gt; 实现状态持久化；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;避免过度使用 Vuex，仅管理全局共享状态，组件私有状态仍用 &lt;code&gt;data&lt;/code&gt; 维护。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</content:encoded><category>category:前端</category><category>tag:前端</category><category>tag:JavaScript</category><category>tag:vue</category></item><item><title>捕获、冒泡和事件委托</title><link>https://wine-congee.vercel.app/post/capture-bubbling-eventDelegation</link><guid isPermaLink="false">capture-bubbling-eventDelegation</guid><description>关于捕获、冒泡和事件委托的组内分享会文档</description><pubDate>Sat, 15 Nov 2025 03:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;一、DOM 和 DOM 树&lt;a href=&quot;#一dom-和-dom-树&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;DOM&lt;a href=&quot;#dom&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;概念&lt;/strong&gt;：DOM（Document Object Model —— 文档对象模型）是一种将 HTML、XML 文档结构转化为树状对象的编程&lt;strong&gt;接口&lt;/strong&gt;。它把文档里的元素、文本、属性等都变成可操作的 “节点对象”，让编程语言（比如 JavaScript）能方便地访问、修改文档的内容、结构和样式，是实现网页动态交互的基础&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;：开发网页内容特效和实现用户交互&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;DOM 树&lt;a href=&quot;#dom-树&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;概念&lt;/strong&gt;：DOM 树是 DOM（文档对象模型）对 HTML 或 XML 文档结构的一种树状&lt;strong&gt;可视化表示&lt;/strong&gt;。它将文档中的所有内容（元素、文本、属性、注释等）抽象为 “节点”，并按照它们在文档中的层级关系组织成类似树的结构&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DOM 树的核心特点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;根节点&lt;/strong&gt;：整个树的起点是 &lt;code&gt;document&lt;/code&gt; 对象（代表整个文档），其直接子节点通常是 HTML 文档的 &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; 元素&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;层级关系&lt;/strong&gt;：每个节点有明确的父子、兄弟关系。例如，&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;head&amp;gt;&lt;/code&gt; 和 &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; 互为兄弟节点&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;节点类型&lt;/strong&gt;：树中包含多种节点（如元素节点 &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;、文本节点 “Hello”、属性节点 &lt;code&gt;class=&quot;box&quot;&lt;/code&gt; 等），共同构成文档的完整结构&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**作用：**DOM 树直观的体现了标签与标签之间的关系&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DOM&lt;/strong&gt;：为我们提供了一套专门用来操作网页内容的接口，这时候他是一种抽象的模型概念，看不见摸不着。它本质是一套规范和接口（比如 “如何获取元素” “如何修改文本” 的规则），定义了操作文档的方式，但本身不是一个可见的实体，更像是一种 “协议” 或 “逻辑框架”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DOM 树&lt;/strong&gt;：将这个模型概念给具体化可视化了，变成我们能看见画出来的一种树状结构。是对 DOM 模型的直观呈现，通过树状结构把文档的层级关系（父子、兄弟节点）画出来，让抽象的 “节点关系” 变成了能看懂的图形，帮助理解 DOM 的结构逻辑&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;一张概览图&lt;a href=&quot;#一张概览图&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/sharedocs/capture-bubbling-eventDelegation/1.png&quot; alt=&quot;DOM树&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;DOM树&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3&gt;二、事件流&lt;a href=&quot;#二事件流&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;为什么要先介绍 DOM 和 DOM 树：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DOM、DOM 树跟事件流有很紧密的关联，简单说：&lt;strong&gt;DOM 是基础接口，DOM 树是结构载体，事件流是基于 DOM 树的事件传播规则&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;什么是事件流：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事件完整执行过程中的流动路径&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用一个比喻理解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;把 DOM 树看作一棵 “网页树”，树上的每个枝桠、每片叶子（对应 DOM 节点，如按钮、文本）都是可能被 “触碰”（触发事件，如点击）的对象&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当我们触碰一片叶子（比如点击一个按钮），这个 “触碰信号” 不会直接就到达被触碰的目标叶子上，也不会到达之后一直就停留再目标叶子上 —— 它会先从树根（document）出发，沿着树干、树枝向下 “找”，一路 “找” 到被触碰的叶子上；等到达叶子（目标节点）后，信号又会沿着原来的树枝、树干向上 “返”，一路回到树根。这个 “从根向下找、再从目标向上返” 的完整信号传播路径和规则，就是事件流&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;事件流有三个阶段&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;事件捕获&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;目标阶段&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事件到达实际触发事件的目标节点（比如被点击的按钮），触发该节点上绑定的事件处理函数的阶段&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;事件冒泡&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过上面的比喻，简单来说，捕获阶段是从父到子，冒泡阶段是从子到父&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个流程图&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/sharedocs/capture-bubbling-eventDelegation/2.png&quot; alt=&quot;事件流&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;事件流&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h4&gt;事件捕获&lt;a href=&quot;#事件捕获&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;概念&lt;/strong&gt;：事件从 DOM 树的根节点（document）向下逐层寻找目标节点的过程（一个由上到下的过程）。如果这个从上到下的过程中遇到的节点有绑定与你的触发动作（我点击了一下）相同的事件监听（有一个点击的事件监听），就会先执行该节点上对应的事件处理函数，等所有上层节点的事件执行完，才到目标节点本身&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;一个比喻理解：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把 DOM 树当成一棵大树，我们要触碰的叶子（比如点击按钮，即目标节点）是最终要找的 “目的地”。事件捕获就像 “信号从树根出发，沿着树干、大枝桠、小枝桠，一步步向下找到那片被触碰的叶子”—— 沿途每经过一个节点（树干、大枝桠、小枝桠），如果这个节点绑定了 “捕获阶段” 的事件监听，就会先触发这个监听函数，再继续往下走，直到抵达目标叶子&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：事件捕获需要写对应代码才能看到效果&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;代码：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;DOM元素.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(事件类型，事件处理函数，是否使用捕获机制)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;代码参数说明：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; &lt;code&gt;addEventListener&lt;/code&gt; 第三个参数传入 &lt;code&gt;true&lt;/code&gt; 代表是捕获阶段触发（较少使用）&lt;/li&gt;
&lt;li&gt; 若传入 &lt;code&gt;false&lt;/code&gt; 代表冒泡阶段触发，默认就是 &lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt; 若是用 L0 级事件监听，则只有冒泡阶段，没有捕获&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;!--&lt;/span&gt;&lt;span&gt; HTML标签内直接绑定 &lt;/span&gt;&lt;span&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; onclick&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;alert(&apos;点击了&apos;)&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;按钮&amp;lt;/&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// JS中通过on+事件名绑定&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; btn&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;button&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;btn.&lt;/span&gt;&lt;span&gt;onclick&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;L0级点击事件触发&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个事件捕获的代码案例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    #grandpa {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      margin: 100px auto;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      width: 300px;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      height: 300px;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      background&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;color: cadetblue;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    #father {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      width: 200px;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      height: 200px;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      background&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;color: darkseagreen;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    #son {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      width: 100px;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      height: 100px;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      background&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;color: lightblue;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;!--&lt;/span&gt;&lt;span&gt; 三层嵌套：爷爷 → 爸爸 → 儿子 &lt;/span&gt;&lt;span&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;grandpa&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;爷爷&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;father&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;爸爸&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;son&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;点击我（儿子）&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 给三层都绑定捕获阶段的点击事件（第三个参数为true）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    grandpa.addEventListener(&apos;click&apos;, () =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;爷爷 - 捕获阶段&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, true);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    father.addEventListener(&apos;click&apos;, () =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;爸爸 - 捕获阶段&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, true);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    son.addEventListener(&apos;click&apos;, () =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;儿子 - 捕获阶段&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, true);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;事件冒泡&lt;a href=&quot;#事件冒泡&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;概念&lt;/strong&gt;：事件从触发的的目标节点开始，向上逐层 “扩散” 回到 DOM 树的根节点的过程（由下向上的过程）。这个从下到上扩散回根节点的过程中，沿途如果有节点绑定了与你触发目标节点的触发动作相同的监听事件，就会向上依次触发这些监听函数，知道回到根节点&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;一个比喻理解：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;假设你点击了一片叶子（目标节点，比如一个按钮），事件冒泡就像 “叶子被点击的信号，沿着树枝、树干一路向上传到树根”—— 沿途向上经过的每个节点（比如按钮的父 div、父 body、甚至 html），如果绑定了 “冒泡阶段” 的点击的事件监听，就会依次触发这些监听函数，直到信号传到最顶端的&lt;code&gt;document&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;简单理解&lt;/strong&gt;：当一个元素触发事件后，会依次向上触发所有父级的同名事件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt;&lt;mark&gt;事件冒泡在大多数常用事件（如 click、input、mouseover）里面都是是默认存在的，L1 级、L2 级事件监听第三个参数是 false，或者默认都是冒泡，但是也有少数事件（如 focus、blur、scroll）没有冒泡特性&lt;/mark&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个事件冒泡的代码案例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;     grandpa.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;click&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;爷爷 - 冒泡阶段&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    father.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;click&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;爸爸 - 冒泡阶段&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    son.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;click&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;儿子 - 冒泡阶段&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }); &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;一个小小的问题&lt;a href=&quot;#一个小小的问题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 以上面的案例里面的其中一个事件监听为例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;son.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;click&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;儿子 - 捕获阶段&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;现在上面这个案例里面第三个参数为默认（&lt;code&gt;false&lt;/code&gt;），即现在这个事件监听它监听的是事件冒泡的过程，那么，问题来了，这个事件流里面事件捕获阶段还存在吗？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;答案是存在，只是此时绑定的事件处理函数不会在捕获阶段被触发，只会在目标阶段和冒泡阶段响应触发&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为什么呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;事件流的三个阶段（捕获 → 目标 → 冒泡）是 &lt;strong&gt;DOM 规范规定的固定流程&lt;/strong&gt;，只要事件被触发，这三个阶段就一定会完整执行，与事件绑定方式（是否监听捕获阶段）无关&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;addEventListener&lt;/code&gt; 的第三个参数（&lt;code&gt;useCapture&lt;/code&gt;）的作用是 &lt;strong&gt;决定当前事件处理函数在哪个阶段响应&lt;/strong&gt;：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当 &lt;code&gt;useCapture&lt;/code&gt; 为 &lt;code&gt;true&lt;/code&gt; 时：函数在 &lt;strong&gt;捕获阶段&lt;/strong&gt; 触发（从根到目标的过程中）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当 &lt;code&gt;useCapture&lt;/code&gt; 为 &lt;code&gt;false&lt;/code&gt; 或省略时：函数在 &lt;strong&gt;冒泡阶段&lt;/strong&gt; 触发（到达目标时，或从目标向根传播时）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;目标阶段&lt;/strong&gt; 不论 &lt;code&gt;useCapture&lt;/code&gt; 参数是 &lt;code&gt;true&lt;/code&gt; 还是 &lt;code&gt;false&lt;/code&gt;都会触发&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个关于触发顺序的例子&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;    grandpa.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;click&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;爷爷&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    father.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;click&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;爸爸&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    son.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;click&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;儿子&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;控制事件行为的两种方法&lt;a href=&quot;#控制事件行为的两种方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;理解了捕获和冒泡的原理后，为了避免“意外触发”或实现复杂的事件逻辑，我们将介绍一个&lt;strong&gt;阻止事件传播&lt;/strong&gt;的方法。&lt;/p&gt;
&lt;p&gt;以及另一个&lt;strong&gt;阻止默认行为&lt;/strong&gt;方法，因为经常会与阻止事件传播组合搭配使用，所以我们放在这里一并介绍&lt;/p&gt;
&lt;h5&gt;阻止事件传播：stopPropagation()&lt;a href=&quot;#阻止事件传播stoppropagation&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;event.stopPropagation()&lt;/code&gt;方法可以阻止事件继续向下或向上传播，无论是在捕获阶段还是冒泡阶段调用，都能&lt;strong&gt;中断&lt;/strong&gt; &lt;strong&gt;后续&lt;/strong&gt; &lt;strong&gt;的传播过程&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;两个小问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ev.stopPropagation()&lt;/code&gt;会阻止目标元素事件监听的执行吗？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不会，前面的定义说过，只是会中断捕获和冒泡的后续传播，具体效果看下面例子的效果&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ev.stopPropagation()&lt;/code&gt;会影响该元素其他事件的后续传播吗？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;也不会，每次事件触发都是一个独立的事件对象（&lt;code&gt;ev&lt;/code&gt;），调用 &lt;code&gt;stopPropagation()&lt;/code&gt; 仅作用于当前这个事件实例，不会影响未来触发的其他事件（即使是同一类型）。具体效果看下面例子的效果&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个具体例子：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 思考：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 以上三个事件监听如果都改为默认的冒泡阶段监听时，ev.stopPropagation()这句话在第二个事件监听里面出现和第三个事件监听里面出现，结果有什么不同？&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;grandpa.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;click&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;爷爷&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    father.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;click&apos;&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;ev&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      ev.&lt;/span&gt;&lt;span&gt;stopPropagation&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;爸爸&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    son.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;click&apos;&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;ev&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // ev.stopPropagation();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;儿子&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    grandpa.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;mouseover&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;爷爷（鼠标移入事件出现）&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    father.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;mouseover&apos;&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;ev&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;爸爸（鼠标移入事件出现）&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    son.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;mouseover&apos;&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;ev&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // ev.stopPropagation();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;儿子（鼠标移入事件出现）&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;阻止默认行为：preventDefault()&lt;a href=&quot;#阻止默认行为preventdefault&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;为什么需要？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;很多事件都有浏览器预设的默认行为，比如点击链接会跳转、提交按钮会提交表单。有时候我们不需要浏览器预设的默认行为，我们想要自定义一些事件的默认行为，就需要先阻止浏览器预设的默认行为，再设置我们自己的。所以介绍的这个&lt;code&gt;event.preventDefault()&lt;/code&gt; 方法就可以阻止这些默认行为&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与阻止事件传播方法的区别&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;不会影响事件的传播过程&lt;/strong&gt;（这是与&lt;code&gt;stopPropagation()&lt;/code&gt;的核心区别（作用对象不同））&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个具体例子&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;https://example.com&quot;&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;link&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;点击我&amp;lt;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;form&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;form&quot;&lt;/span&gt;&lt;span&gt; action&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;/submit&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;submit&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;提交&amp;lt;/&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;form&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 阻止链接跳转&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const link = document.getElementById(&apos;link&apos;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    document.querySelector(&apos;div&apos;).addEventListener(&apos;click&apos;, function () {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;父盒子被触发&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    link.addEventListener(&apos;click&apos;, (e) =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // 取消默认跳转行为&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      e.&lt;/span&gt;&lt;span&gt;preventDefault&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;链接被点击，但不跳转&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 阻止表单提交&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const form = document.getElementById(&apos;form&apos;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    form.addEventListener(&apos;submit&apos;, (e) =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // 取消默认提交刷新&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      e.&lt;/span&gt;&lt;span&gt;preventDefault&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;表单提交被拦截，将异步处理&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;&lt;code&gt;stopPropagation()&lt;/code&gt;与&lt;code&gt;preventDefault()&lt;/code&gt;核心区别总结&lt;a href=&quot;#stoppropagation与preventdefault核心区别总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;特性&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;code&gt;stopPropagation()&lt;/code&gt;&lt;/th&gt;&lt;th&gt;&lt;code&gt;preventDefault()&lt;/code&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;作用对象&lt;/td&gt;&lt;td&gt;事件的&lt;strong&gt;传播过程&lt;/strong&gt;（捕获 / 冒泡）&lt;/td&gt;&lt;td&gt;事件的&lt;strong&gt;默认行为&lt;/strong&gt;（浏览器预设）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&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;/td&gt;&lt;td&gt;否（默认行为仍会执行）&lt;/td&gt;&lt;td&gt;是（取消默认行为）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&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;h3&gt;三、事件委托&lt;a href=&quot;#三事件委托&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在说事件委托之前，有个问题，在前面提到捕获和冒泡的比喻里面说的传递信号，大家知道这个传递的信号在事件捕获和冒泡里面指的是什么吗？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;本质是包含了 “触发节点信息” 在内的「&lt;strong&gt;事件对象（event）&lt;/strong&gt;」—— 它&lt;strong&gt;装着整个事件的完整信息&lt;/strong&gt;，是事件传播时的 “信息载体” &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;这个完整信息包括：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;谁是触发者？（&lt;code&gt;event.target&lt;/code&gt;，就是被点的 li，即 “触发节点信息”）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;事件类型是什么？（&lt;code&gt;event.type&lt;/code&gt;，比如是 &lt;code&gt;“click”&lt;/code&gt; 点击事件）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;事件是在哪个阶段传播的？（&lt;code&gt;event.eventPhase&lt;/code&gt;，捕获 / 目标 / 冒泡）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;点击时鼠标在哪个位置？（&lt;code&gt;event.clientX&lt;/code&gt;/&lt;code&gt;event.clientY&lt;/code&gt;）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;甚至能让信号停止传播（&lt;code&gt;event.stopPropagation()&lt;/code&gt;）、阻止默认行为（&lt;code&gt;event.preventDefault()&lt;/code&gt;）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;事件委托（也叫事件代理）是一种&lt;strong&gt;利用事件冒泡特性&lt;/strong&gt;实现的高效事件处理技巧 —— 简单说，就是&lt;strong&gt;不给子节点单独绑定事件，而是把事件绑定在它们的父节点上，由父节点 “代理” 处理所有子节点的事件&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;核心逻辑：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;因为事件会冒泡，子节点触发的事件，最终会传到父节点上。父节点监听到了事件对像携带的事件类型与父节点绑定事件类型一致后，就执行父节点对应的事件处理函数，通过事件对象（&lt;code&gt;event&lt;/code&gt;）的 &lt;code&gt;target&lt;/code&gt; 属性，判断是哪个子节点触发了事件，再针对性处理&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个例子：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    #list {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      margin: 100px auto;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      width: 200px;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      background&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;color: antiquewhite;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    #list li {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      margin&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;bottom: 10px;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      width: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      background&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;color: lightpink;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;!--&lt;/span&gt;&lt;span&gt; 父节点：ul；子节点：多个li &lt;/span&gt;&lt;span&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;ul&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;list&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;li&lt;/span&gt;&lt;span&gt;&amp;gt;列表项1&amp;lt;/&lt;/span&gt;&lt;span&gt;li&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;li&lt;/span&gt;&lt;span&gt;&amp;gt;列表项2&amp;lt;/&lt;/span&gt;&lt;span&gt;li&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;li&lt;/span&gt;&lt;span&gt;&amp;gt;列表项3&amp;lt;/&lt;/span&gt;&lt;span&gt;li&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;ul&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 只给父节点ul绑定一次点击事件（代理所有li的事件）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    document.getElementById(&apos;list&apos;).addEventListener(&apos;click&apos;, function (ev) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // e.target 就是触发事件的子节点（被点击的li）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // 确保点击的是 li 节点&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (ev.target.tagName &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &apos;LI&apos;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`点击了：${&lt;/span&gt;&lt;span&gt;ev&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;textContent&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:分享会</category><category>tag:前端</category><category>tag:分享会</category><category>tag:JavaScript</category></item><item><title>JavaScript解构</title><link>https://wine-congee.vercel.app/post/JavaScript-deconstruction</link><guid isPermaLink="false">JavaScript-deconstruction</guid><description>
JS 中，解构是一种便捷的语法，用于从数组或对象中提取值，并将其赋值给变量。它可以简化代码，让数据提取更直观。解构主要分为 数组解构 和 对象解构。

一、数组解构</description><pubDate>Sat, 18 Oct 2025 00:57:30 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;JS 中，解构是一种便捷的语法，用于从数组或对象中提取值，并将其赋值给变量。它可以简化代码，让数据提取更直观。解构主要分为 &lt;strong&gt;数组解构&lt;/strong&gt; 和 &lt;strong&gt;对象解构&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;一、数组解构&lt;a href=&quot;#一数组解构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;数组解构是一种通过&lt;strong&gt;索引位置&lt;/strong&gt;匹配数组元素，并将其赋值给对应变量的语法。由于数组是有序集合，解构时变量的位置与数组元素的位置严格对应，语法上使用方括号 &lt;code&gt;[]&lt;/code&gt; 包裹变量。&lt;/p&gt;
&lt;h4&gt;1. 基本用法&lt;a href=&quot;#1-基本用法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;数组解构的核心逻辑是“按位置提取”：左侧方括号中的变量按顺序对应右侧数组中的元素，第一个变量匹配数组第一个元素，第二个变量匹配数组第二个元素，以此类推。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 左侧变量 [a, b, c] 按顺序匹配右侧数组 [1, 2, 3] 的元素&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(a); &lt;/span&gt;&lt;span&gt;// 1（变量a匹配数组索引0的元素）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(b); &lt;/span&gt;&lt;span&gt;// 2（变量b匹配数组索引1的元素）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(c); &lt;/span&gt;&lt;span&gt;// 3（变量c匹配数组索引2的元素）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果数组长度大于变量数量，多余的元素会被忽略；如果变量数量多于数组长度，多余的变量会被赋值为 &lt;code&gt;undefined&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;]; &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(x); &lt;/span&gt;&lt;span&gt;// 10（数组有第一个元素）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(y); &lt;/span&gt;&lt;span&gt;// undefined（数组没有第二个元素，变量y无匹配值）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. 跳过元素&lt;a href=&quot;#2-跳过元素&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;当需要提取数组中间或后面的元素，而忽略前面的部分元素时，可以通过&lt;strong&gt;空逗号&lt;/strong&gt;来“跳过”不需要的位置。逗号的数量代表跳过的元素个数，空逗号之间的位置会被忽略。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 数组 [10, 20, 30] 中，第一个逗号跳过索引1的元素（20）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;, , &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(x); &lt;/span&gt;&lt;span&gt;// 10（匹配索引0的元素）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(y); &lt;/span&gt;&lt;span&gt;// 30（跳过索引1，匹配索引2的元素）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如，提取数组的第一个和第四个元素，需跳过中间两个元素：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;first&lt;/span&gt;&lt;span&gt;, , , &lt;/span&gt;&lt;span&gt;fourth&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(first); &lt;/span&gt;&lt;span&gt;// 1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(fourth); &lt;/span&gt;&lt;span&gt;// 4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. 剩余元素（Rest）&lt;a href=&quot;#3-剩余元素rest&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;当需要提取数组的前几个元素，同时将剩余所有元素统一收集到一个新数组中时，可以使用 &lt;code&gt;...变量名&lt;/code&gt; 的语法（称为“剩余操作符”）。剩余变量必须放在所有变量的&lt;strong&gt;最后一位&lt;/strong&gt;，否则会报错。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 提取第一个元素后，将剩余元素收集到 rest 数组中&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;first&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;rest&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(first); &lt;/span&gt;&lt;span&gt;// 1（提取第一个元素）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(rest);  &lt;/span&gt;&lt;span&gt;// [2, 3, 4]（剩余元素组成的新数组）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：剩余操作符只能收集“剩余”的元素，不能单独使用或放在中间：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 错误示例：剩余变量不能放在中间&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;rest&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;]; &lt;/span&gt;&lt;span&gt;// 语法报错&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4. 默认值&lt;a href=&quot;#4-默认值&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;如果数组中某个位置的元素不存在（或为 &lt;code&gt;undefined&lt;/code&gt;），解构时可以为对应的变量设置默认值。默认值仅在“无匹配元素”或“匹配元素为 &lt;code&gt;undefined&lt;/code&gt;”时生效，若元素为 &lt;code&gt;null&lt;/code&gt;、&lt;code&gt;0&lt;/code&gt; 等其他值，会使用元素本身。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 数组 [5] 只有一个元素，变量b无匹配值，使用默认值0&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(a); &lt;/span&gt;&lt;span&gt;// 5（数组有元素，使用原值）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(b); &lt;/span&gt;&lt;span&gt;// 0（无匹配元素，使用默认值）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 若元素为undefined，默认值同样生效&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 10&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(c); &lt;/span&gt;&lt;span&gt;// 10（匹配元素为undefined，使用默认值）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;5. 交换变量&lt;a href=&quot;#5-交换变量&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;传统交换两个变量的值需要借助临时变量，而数组解构可以直接通过“位置互换”实现变量交换，原理是将右侧数组的元素按新顺序赋值给左侧变量。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;, y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 传统交换：需要临时变量temp&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; temp &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; x;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; y;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; temp;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 解构交换：右侧数组[y, x]的元素按顺序赋值给左侧[x, y]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;[x, y] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [y, x];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(x, y); &lt;/span&gt;&lt;span&gt;// 2, 1（变量值成功交换）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式不仅简洁，还能避免临时变量的创建，适用于排序、算法等需要交换值的场景。&lt;/p&gt;
&lt;h3&gt;二、对象解构&lt;a href=&quot;#二对象解构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;对象解构是通过&lt;strong&gt;属性名&lt;/strong&gt;匹配对象属性，并将属性值赋值给对应变量的语法。由于对象是键值对集合，解构时变量名需与对象的属性名一致（或通过重命名指定对应关系），语法上使用花括号 &lt;code&gt;{}&lt;/code&gt; 包裹变量。&lt;/p&gt;
&lt;h4&gt;1. 基本用法&lt;a href=&quot;#1-基本用法-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;对象解构的核心逻辑是“按属性名提取”：左侧花括号中的变量名必须与右侧对象的属性名一致，变量会被赋值为对应属性的值，与变量的顺序无关。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; user&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; { name: &lt;/span&gt;&lt;span&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span&gt;, age: &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 变量name匹配对象的name属性，变量age匹配对象的age属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;age&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; user;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(name); &lt;/span&gt;&lt;span&gt;// &apos;Alice&apos;（属性名匹配成功）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(age);  &lt;/span&gt;&lt;span&gt;// 30（属性名匹配成功）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果变量名在对象中不存在，变量会被赋值为 &lt;code&gt;undefined&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;gender&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; user; &lt;/span&gt;&lt;span&gt;// user对象中没有gender属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(gender); &lt;/span&gt;&lt;span&gt;// undefined&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. 重命名变量&lt;a href=&quot;#2-重命名变量&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;当希望使用与对象属性名不同的变量名时，可以通过 &lt;code&gt;新变量名: 原属性名&lt;/code&gt; 的语法重命名。此时，新变量名用于接收值，原属性名用于匹配对象属性。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; user&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; { name: &lt;/span&gt;&lt;span&gt;&apos;Bob&apos;&lt;/span&gt;&lt;span&gt;, age: &lt;/span&gt;&lt;span&gt;25&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 用userName接收name属性的值，用userAge接收age属性的值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;userName&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;age&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;userAge&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; user;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(userName); &lt;/span&gt;&lt;span&gt;// &apos;Bob&apos;（新变量名生效）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(userAge);  &lt;/span&gt;&lt;span&gt;// 25（新变量名生效）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 原变量名name和age未被定义，使用会报错&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(name); &lt;/span&gt;&lt;span&gt;// ReferenceError: name is not defined&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重命名常用于避免变量名冲突（例如，当对象属性名与当前作用域中的变量名重复时）。&lt;/p&gt;
&lt;h4&gt;3. 默认值&lt;a href=&quot;#3-默认值&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;与数组解构类似，对象解构也可以为变量设置默认值。当对象中不存在对应的属性，或属性值为 &lt;code&gt;undefined&lt;/code&gt; 时，默认值生效；若属性值为 &lt;code&gt;null&lt;/code&gt;、&lt;code&gt;0&lt;/code&gt; 等其他值，会使用属性本身的值。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 对象中只有age属性，city属性不存在，使用默认值&apos;Beijing&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;city&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;Beijing&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;age&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 18&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { age: &lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(city); &lt;/span&gt;&lt;span&gt;// &apos;Beijing&apos;（属性不存在，用默认值）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(age);  &lt;/span&gt;&lt;span&gt;// 20（属性存在，用原值）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 若属性值为undefined，默认值生效&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;score&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 60&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { score: &lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(score); &lt;/span&gt;&lt;span&gt;// 60（属性值为undefined，用默认值）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;默认值也可以结合重命名使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 重命名属性，并设置默认值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;userName&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;Guest&apos;&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {}; &lt;/span&gt;&lt;span&gt;// 对象中无name属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(userName); &lt;/span&gt;&lt;span&gt;// &apos;Guest&apos;（默认值生效）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4. 剩余属性（Rest）&lt;a href=&quot;#4-剩余属性rest&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;当需要提取对象的部分属性，同时将剩余所有属性统一收集到一个新对象中时，可以使用 &lt;code&gt;...变量名&lt;/code&gt; 的语法。剩余变量必须放在所有变量的&lt;strong&gt;最后一位&lt;/strong&gt;，否则会报错。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 提取a和b属性后，将剩余属性收集到rest对象中&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;rest&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { a: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, b: &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, c: &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, d: &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(a);    &lt;/span&gt;&lt;span&gt;// 1（提取a属性）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(b);    &lt;/span&gt;&lt;span&gt;// 2（提取b属性）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(rest); &lt;/span&gt;&lt;span&gt;// { c: 3, d: 4 }（剩余属性组成的新对象）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;剩余属性常用于筛选对象中的部分属性，或复制对象时排除特定属性：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; user&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; { id: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, name: &lt;/span&gt;&lt;span&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span&gt;, password: &lt;/span&gt;&lt;span&gt;&apos;123&apos;&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 提取password，剩余属性作为安全信息（不含密码）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;safeUser&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; user;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(safeUser); &lt;/span&gt;&lt;span&gt;// { id: 1, name: &apos;Alice&apos; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;5. 嵌套对象解构&lt;a href=&quot;#5-嵌套对象解构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;当对象中包含嵌套的子对象时，可以通过“多层解构”直接提取子对象的属性。语法上，在对应位置使用嵌套的花括号，按层级匹配属性。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; obj&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  info: { name: &lt;/span&gt;&lt;span&gt;&apos;Charlie&apos;&lt;/span&gt;&lt;span&gt;, age: &lt;/span&gt;&lt;span&gt;35&lt;/span&gt;&lt;span&gt; }, &lt;/span&gt;&lt;span&gt;// 嵌套的info对象&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  score: &lt;/span&gt;&lt;span&gt;90&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 第一层解构：提取info属性和score属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 第二层解构：从info对象中提取name属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt;: { &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; }, &lt;/span&gt;&lt;span&gt;score&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; obj;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(name); &lt;/span&gt;&lt;span&gt;// &apos;Charlie&apos;（成功提取嵌套属性）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(score); &lt;/span&gt;&lt;span&gt;// 90（提取外层属性）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果需要同时保留外层对象和内层属性，可以单独定义外层变量：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 同时保留info对象和其内部的name属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt;: { &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; } } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; obj;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(info); &lt;/span&gt;&lt;span&gt;// { name: &apos;Charlie&apos;, age: 35 }（外层对象）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(name); &lt;/span&gt;&lt;span&gt;// &apos;Charlie&apos;（内层属性）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;三、其他场景的解构&lt;a href=&quot;#三其他场景的解构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;除了数组和对象的基础解构，解构语法还可以应用于函数参数、字符串等场景，进一步简化代码。&lt;/p&gt;
&lt;h4&gt;1. 函数参数解构&lt;a href=&quot;#1-函数参数解构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;当函数接收一个数组或对象作为参数时，可以直接在参数列表中使用解构语法，快速提取所需的值，避免在函数内部重复编写 &lt;code&gt;参数.属性&lt;/code&gt; 或 &lt;code&gt;参数[索引]&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;对象参数解构&lt;/strong&gt;：适合参数为对象的场景，直接提取所需属性，还可结合默认值处理参数缺失的情况。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 函数参数中直接解构对象，提取name和age属性，并为age设置默认值18&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; printUser&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;age&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 18&lt;/span&gt;&lt;span&gt; }) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`Name: ${&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;}, Age: ${&lt;/span&gt;&lt;span&gt;age&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 调用时只需传入包含name的对象，age会使用默认值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;printUser&lt;/span&gt;&lt;span&gt;({ name: &lt;/span&gt;&lt;span&gt;&apos;Dave&apos;&lt;/span&gt;&lt;span&gt; }); &lt;/span&gt;&lt;span&gt;// Name: Dave, Age: 18&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：若函数可能被无参数调用，需为解构参数设置默认空对象 &lt;code&gt;= {}&lt;/code&gt;，否则会报错：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 错误示例：无参数调用时，解构undefined会报错&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; fn&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; }) {}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fn&lt;/span&gt;&lt;span&gt;(); &lt;/span&gt;&lt;span&gt;// TypeError: Cannot destructure property &apos;a&apos; of &apos;undefined&apos; or &apos;null&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 正确示例：设置默认空对象，避免报错&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; fn&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {}) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(a); &lt;/span&gt;&lt;span&gt;// undefined（安全处理）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fn&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数组参数解构&lt;/strong&gt;：适合参数为数组的场景，按位置提取元素，使函数逻辑更清晰。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 函数参数中解构数组，直接获取a和b&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; sum&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; b;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sum&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;])); &lt;/span&gt;&lt;span&gt;// 5（无需在函数内写arr[0]和arr[1]）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 字符串解构&lt;a href=&quot;#2-字符串解构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;字符串是类数组对象（具有长度和索引），因此可以像数组一样被解构，按索引位置提取字符。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 字符串&apos;hello&apos;按索引0、1、2的位置提取字符&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;c1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;c2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;c3&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;hello&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(c1); &lt;/span&gt;&lt;span&gt;// &apos;h&apos;（索引0的字符）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(c2); &lt;/span&gt;&lt;span&gt;// &apos;e&apos;（索引1的字符）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(c3); &lt;/span&gt;&lt;span&gt;// &apos;l&apos;（索引2的字符）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结合剩余操作符，还可以提取前几个字符和剩余字符：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;first&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;rest&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;hello&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(first); &lt;/span&gt;&lt;span&gt;// &apos;h&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(rest);  &lt;/span&gt;&lt;span&gt;// [&apos;e&apos;, &apos;l&apos;, &apos;l&apos;, &apos;o&apos;]（剩余字符组成的数组）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. 解构与展开（Spread）的区别&lt;a href=&quot;#3-解构与展开spread的区别&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;...&lt;/code&gt; 符号在 JavaScript 中既可以用于解构（剩余操作符），也可以用于展开（Spread 操作符），但两者的作用完全相反：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;解构（剩余操作符）&lt;/strong&gt;：从数组或对象中&lt;strong&gt;提取部分值&lt;/strong&gt;，并将剩余值收集到一个新的数组或对象中（拆包过程）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;展开（Spread 操作符）&lt;/strong&gt;：将数组或对象中的&lt;strong&gt;所有值展开&lt;/strong&gt;到另一个数组、对象或函数参数中（打包过程）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例对比：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 解构（拆包）：从数组中提取first，剩余元素收集到rest&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;first&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;rest&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(first); &lt;/span&gt;&lt;span&gt;// 1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(rest);  &lt;/span&gt;&lt;span&gt;// [2, 3]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 展开（打包）：将rest数组的元素展开到新数组中&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; newArr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;rest, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;]; &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(newArr); &lt;/span&gt;&lt;span&gt;// [2, 3, 4]（rest的元素被展开后添加4）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解构语法在实际开发中应用非常广泛，能极大简化代码逻辑。以下是一些常见的应用场景及示例：&lt;/p&gt;
&lt;h3&gt;四、常见应用场景&lt;a href=&quot;#四常见应用场景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;1. 处理函数参数&lt;a href=&quot;#1-处理函数参数&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;提取对象参数的特定属性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当函数接收一个对象作为参数时，直接解构出需要的属性，避免重复写 &lt;code&gt;obj.xxx&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 传统写法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; getUserInfo&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(user.name, user.age, user.gender);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 解构写法（更简洁）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; getUserInfo&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;age&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;gender&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;未知&apos;&lt;/span&gt;&lt;span&gt; }) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(name, age, gender);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;getUserInfo&lt;/span&gt;&lt;span&gt;({ name: &lt;/span&gt;&lt;span&gt;&apos;张三&apos;&lt;/span&gt;&lt;span&gt;, age: &lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt; }); &lt;/span&gt;&lt;span&gt;// 张三 20 未知&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;处理数组参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;适合需要按顺序提取数组中特定位置的值的场景：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 计算二维坐标距离&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; getDistance&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;x1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;y1&lt;/span&gt;&lt;span&gt;], [&lt;/span&gt;&lt;span&gt;x2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;y2&lt;/span&gt;&lt;span&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;hypot&lt;/span&gt;&lt;span&gt;(x2 &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; x1, y2 &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; y1);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;getDistance&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;], [&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;])); &lt;/span&gt;&lt;span&gt;// 5（3-4-5直角三角形斜边）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. 交换变量值&lt;a href=&quot;#2-交换变量值&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;无需临时变量，一行代码完成变量交换，常用于排序、算法等场景：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 10&lt;/span&gt;&lt;span&gt;, b &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 传统交换（需要临时变量）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; temp &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; a;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;a &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; b;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;b &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; temp;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 解构交换（更简洁）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;[a, b] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [b, a];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(a, b); &lt;/span&gt;&lt;span&gt;// 20 10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. 处理数组返回值&lt;a href=&quot;#3-处理数组返回值&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;函数返回多个值时，通常用数组包裹，解构可直接按位置接收：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 函数返回数组（多值）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; getMinMax&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;arr&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; [Math.&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;arr), Math.&lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;arr)];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; numbers&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; getMinMax&lt;/span&gt;&lt;span&gt;(numbers);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(min, max); &lt;/span&gt;&lt;span&gt;// 1 5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4. 设置函数默认参数&lt;a href=&quot;#4-设置函数默认参数&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;结合默认值，处理函数参数缺失的情况：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 未使用解构时，默认参数写法繁琐&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; timeout&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; options.timeout &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; 5000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; method&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; options.method &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &apos;GET&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 解构+默认值（简洁且直观）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;timeout&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 5000&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;GET&apos;&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {}) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(timeout, method);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;(); &lt;/span&gt;&lt;span&gt;// 5000 GET（参数为空时使用默认值）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;({ method: &lt;/span&gt;&lt;span&gt;&apos;POST&apos;&lt;/span&gt;&lt;span&gt; }); &lt;/span&gt;&lt;span&gt;// 5000 POST&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：&lt;code&gt;= {}&lt;/code&gt; 是为了避免参数为 &lt;code&gt;undefined&lt;/code&gt; 时解构报错（比如直接调用 &lt;code&gt;config()&lt;/code&gt;）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;5. 遍历对象/数组时提取值&lt;a href=&quot;#5-遍历对象数组时提取值&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;在 &lt;code&gt;for...of&lt;/code&gt; 或数组方法（如 &lt;code&gt;map&lt;/code&gt;、&lt;code&gt;forEach&lt;/code&gt;）中，快速提取数据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 遍历数组对象&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; users&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  { id: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, name: &lt;/span&gt;&lt;span&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  { id: &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, name: &lt;/span&gt;&lt;span&gt;&apos;Bob&apos;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;users.&lt;/span&gt;&lt;span&gt;forEach&lt;/span&gt;&lt;span&gt;(({ &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; }) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`ID: ${&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;}, Name: ${&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 遍历Map（Map的entries是[key, value]形式）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; map&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Map&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;map.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;name&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;Charlie&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;map.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;age&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt; map) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`${&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;}: ${&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// name: Charlie; age: 30&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;6. 忽略不需要的数据&lt;a href=&quot;#6-忽略不需要的数据&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;从数组或对象中提取部分值，忽略无关数据，减少内存占用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 数组中只需要第一个和最后一个元素&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;first&lt;/span&gt;&lt;span&gt;, , , &lt;/span&gt;&lt;span&gt;last&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;40&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(first, last); &lt;/span&gt;&lt;span&gt;// 10 40&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 对象中只需要部分属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;userInfo&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { name: &lt;/span&gt;&lt;span&gt;&apos;Dave&apos;&lt;/span&gt;&lt;span&gt;, age: &lt;/span&gt;&lt;span&gt;28&lt;/span&gt;&lt;span&gt;, password: &lt;/span&gt;&lt;span&gt;&apos;123456&apos;&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(userInfo); &lt;/span&gt;&lt;span&gt;// { name: &apos;Dave&apos;, age: 28 }（不含password）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;7. 嵌套结构数据处理&lt;a href=&quot;#7-嵌套结构数据处理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;面对多层嵌套的对象/数组，解构能一次性提取深层数据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  result: {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    items: [&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      { id: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, details: { price: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt; } },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      { id: &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, details: { price: &lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt; } }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 提取第一个item的price&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;: { &lt;/span&gt;&lt;span&gt;items&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;firstItem&lt;/span&gt;&lt;span&gt;] } } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; data;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;details&lt;/span&gt;&lt;span&gt;: { &lt;/span&gt;&lt;span&gt;price&lt;/span&gt;&lt;span&gt; } } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; firstItem;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(price); &lt;/span&gt;&lt;span&gt;// 100&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;解构语法通过“按位置匹配”（数组）和“按属性名匹配”（对象）的方式，简化了从复杂数据结构中提取值的过程，减少重复代码、提升可读性在数据存在缺失值和多余数据的情况下能灵活处理边界情况。其核心优势是&lt;strong&gt;简化数据提取流程&lt;/strong&gt;，尤其在以下场景中表现突出：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;处理函数参数（减少 &lt;code&gt;obj.xxx&lt;/code&gt; 重复调用）。&lt;/li&gt;
&lt;li&gt;变量交换、多值返回处理（减少临时变量）。&lt;/li&gt;
&lt;li&gt;遍历集合时提取关键信息（让循环体更简洁）。&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:前端</category><category>tag:前端</category><category>tag:JavaScript</category></item><item><title>JavaScript 字符串常用属性方法汇总及详解</title><link>https://wine-congee.vercel.app/post/Javascript-stringFn</link><guid isPermaLink="false">Javascript-stringFn</guid><description>方法分类汇总索引

获取字符串信息方法：


length：返回字符串的长度（字符数量）


字符串查找方法：


charAt()：返回指定索引位置的字符
charCodeAt()：返回指定索引位置字符的 Unicode 编码
indexOf()：查找子字符串首次出现的位置</description><pubDate>Sun, 12 Oct 2025 01:15:00 GMT</pubDate><content:encoded>&lt;h2&gt;方法分类汇总索引&lt;a href=&quot;#方法分类汇总索引&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;获取字符串信息方法&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;length&lt;/code&gt;：返回字符串的长度（字符数量）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;字符串查找方法&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;charAt()&lt;/code&gt;：返回指定索引位置的字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;charCodeAt()&lt;/code&gt;：返回指定索引位置字符的 Unicode 编码&lt;/li&gt;
&lt;li&gt;&lt;code&gt;indexOf()&lt;/code&gt;：查找子字符串首次出现的位置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lastIndexOf()&lt;/code&gt;：查找子字符串最后出现的位置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;includes()&lt;/code&gt;：判断是否包含指定子字符串&lt;/li&gt;
&lt;li&gt;&lt;code&gt;startsWith()&lt;/code&gt;：判断是否以指定子字符串开头&lt;/li&gt;
&lt;li&gt;&lt;code&gt;endsWith()&lt;/code&gt;：判断是否以指定子字符串结尾&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;字符串截取/提取方法&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;slice()&lt;/code&gt;：提取字符串的一部分并返回新字符串&lt;/li&gt;
&lt;li&gt;&lt;code&gt;substring()&lt;/code&gt;：提取两个指定索引之间的字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;substr()&lt;/code&gt;：从指定位置提取指定长度的子字符串（不推荐使用）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;字符串转换方法&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;toLowerCase()&lt;/code&gt;：将字符串转换为小写&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toUpperCase()&lt;/code&gt;：将字符串转换为大写&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toString()&lt;/code&gt;：返回字符串本身&lt;/li&gt;
&lt;li&gt;&lt;code&gt;valueOf()&lt;/code&gt;：返回字符串的原始值&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;字符串替换/分割方法&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;replace()&lt;/code&gt;：查找匹配子字符串并替换为新内容&lt;/li&gt;
&lt;li&gt;&lt;code&gt;split()&lt;/code&gt;：将字符串分割成字符串数组&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;字符串修剪方法&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;trim()&lt;/code&gt;：去除字符串两端的空白字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trimStart()/trimLeft()&lt;/code&gt;：去除字符串开头的空白字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trimEnd()/trimRight()&lt;/code&gt;：去除字符串结尾的空白字符&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;字符串重复方法&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;repeat()&lt;/code&gt;：将字符串重复指定的次数&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;字符串连接方法&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;concat()&lt;/code&gt;：连接两个或多个字符串&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;字符串填充方法&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;padStart()&lt;/code&gt;：在字符串开头填充字符至指定长度&lt;/li&gt;
&lt;li&gt;&lt;code&gt;padEnd()&lt;/code&gt;：在字符串结尾填充字符至指定长度&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;其他字符串方法&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;match()&lt;/code&gt;：查找匹配正则表达式的结果&lt;/li&gt;
&lt;li&gt;&lt;code&gt;matchAll()&lt;/code&gt;：返回所有匹配正则表达式的迭代器&lt;/li&gt;
&lt;li&gt;&lt;code&gt;search()&lt;/code&gt;：查找与正则表达式匹配的子字符串位置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;localeCompare()&lt;/code&gt;：考虑区域设置比较两个字符串&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;以下为 JavaScript 中常用的字符串方法详解，这些方法都不会改变原字符串，而是返回一个新的字符串或其他类型的值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;一、获取字符串信息属性&lt;a href=&quot;#一获取字符串信息属性&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. length&lt;a href=&quot;#1-length&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.length&lt;/code&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 获取字符串长度&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; len&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(len); &lt;/span&gt;&lt;span&gt;// 输出: 11&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 注意：length是属性，不是函数，不需要加括号&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;二、字符串查找方法&lt;a href=&quot;#二字符串查找方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. charAt()&lt;a href=&quot;#1-charat&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.charAt(index)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：&lt;code&gt;index&lt;/code&gt; - 必需，表示字符在字符串中的索引（从 0 开始）&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;JavaScript&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 获取索引为4的字符&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; char&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;charAt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(char); &lt;/span&gt;&lt;span&gt;// 输出: &apos;S&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 获取索引超出范围的字符（返回空字符串）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; invalidChar&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;charAt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(invalidChar); &lt;/span&gt;&lt;span&gt;// 输出: &apos;&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. charCodeAt()&lt;a href=&quot;#2-charcodeat&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：返回指定索引位置字符的 Unicode 编码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语法&lt;/strong&gt;：&lt;code&gt;str.charCodeAt(index)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：&lt;code&gt;index&lt;/code&gt; - 必需，字符在字符串中的索引（从 0 开始）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值&lt;/strong&gt;：数字，表示指定索引处字符的 Unicode 编码；如果索引超出范围，则返回 NaN&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;A&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 获取字符 &apos;A&apos; 的 Unicode 编码&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; code&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;charCodeAt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(code); &lt;/span&gt;&lt;span&gt;// 输出: 65&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 获取索引超出范围的字符编码（返回NaN）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; invalidCode&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;charCodeAt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(invalidCode); &lt;/span&gt;&lt;span&gt;// 输出: NaN&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. indexOf()&lt;a href=&quot;#3-indexof&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.indexOf(searchValue[, fromIndex])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;searchValue&lt;/code&gt; - 必需，要查找的子字符串&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fromIndex&lt;/code&gt; - 可选，开始查找的索引位置，默认为 0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值&lt;/strong&gt;：数字，子字符串首次出现的索引；如果没有找到，则返回-1&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello, Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 查找 &quot;Hello&quot; 首次出现的位置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; firstPos&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;indexOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(firstPos); &lt;/span&gt;&lt;span&gt;// 输出: 0&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 从索引5开始查找 &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; posFrom5&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;indexOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(posFrom5); &lt;/span&gt;&lt;span&gt;// 输出: 7&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 查找不存在的子字符串&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; notFound&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;indexOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;JavaScript&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(notFound); &lt;/span&gt;&lt;span&gt;// 输出: -1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. lastIndexOf()&lt;a href=&quot;#4-lastindexof&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.lastIndexOf(searchValue[, fromIndex])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;searchValue&lt;/code&gt; - 必需，要查找的子字符串&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fromIndex&lt;/code&gt; - 可选，开始查找的索引位置，默认为字符串的长度-1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值&lt;/strong&gt;：数字，子字符串最后出现的索引；如果没有找到，则返回-1&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello, Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 查找 &quot;Hello&quot; 最后出现的位置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; lastPos&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;lastIndexOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(lastPos); &lt;/span&gt;&lt;span&gt;// 输出: 7&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 在索引6之前查找 &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; posBefore6&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;lastIndexOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(posBefore6); &lt;/span&gt;&lt;span&gt;// 输出: 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. includes()&lt;a href=&quot;#5-includes&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.includes(searchValue[, fromIndex])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;searchValue&lt;/code&gt; - 必需，要查找的子字符串&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fromIndex&lt;/code&gt; - 可选，开始查找的索引位置，默认为 0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值&lt;/strong&gt;：布尔值，如果包含则返回 true，否则返回 false&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 判断字符串是否包含 &quot;World&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; hasWorld&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;World&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(hasWorld); &lt;/span&gt;&lt;span&gt;// 输出: true&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 从索引6开始查找 &quot;World&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; hasWorldFrom6&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;World&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(hasWorldFrom6); &lt;/span&gt;&lt;span&gt;// 输出: true&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 判断字符串是否包含 &quot;Java&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; hasJava&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Java&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(hasJava); &lt;/span&gt;&lt;span&gt;// 输出: false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. startsWith()&lt;a href=&quot;#6-startswith&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.startsWith(searchValue[, position])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;searchValue&lt;/code&gt; - 必需，要查找的子字符串&lt;/li&gt;
&lt;li&gt;&lt;code&gt;position&lt;/code&gt; - 可选，开始查找的位置，默认为 0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值&lt;/strong&gt;：布尔值，如果以指定子字符串开头则返回 true，否则返回 false&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 判断字符串是否以 &quot;Hello&quot; 开头&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; startsWithHello&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;startsWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(startsWithHello); &lt;/span&gt;&lt;span&gt;// 输出: true&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 判断从索引6开始的子字符串是否以 &quot;W&quot; 开头&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; startsWithW&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;startsWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;W&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(startsWithW); &lt;/span&gt;&lt;span&gt;// 输出: true&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 判断字符串是否以 &quot;World&quot; 开头&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; startsWithWorld&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;startsWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;World&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(startsWithWorld); &lt;/span&gt;&lt;span&gt;// 输出: false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7. endsWith()&lt;a href=&quot;#7-endswith&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.endsWith(searchValue[, length])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;searchValue&lt;/code&gt; - 必需，要查找的子字符串&lt;/li&gt;
&lt;li&gt;&lt;code&gt;length&lt;/code&gt; - 可选，作为字符串长度使用的值，默认为字符串的实际长度&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值&lt;/strong&gt;：布尔值，如果以指定子字符串结尾则返回 true，否则返回 false&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 判断字符串是否以 &quot;World&quot; 结尾&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; endsWithWorld&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;endsWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;World&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(endsWithWorld); &lt;/span&gt;&lt;span&gt;// 输出: true&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 只考虑前5个字符，判断是否以 &quot;Hello&quot; 结尾&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; endsWithHello&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;endsWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(endsWithHello); &lt;/span&gt;&lt;span&gt;// 输出: true&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 判断字符串是否以 &quot;Hello&quot; 结尾&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; endsWithHelloFull&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;endsWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(endsWithHelloFull); &lt;/span&gt;&lt;span&gt;// 输出: false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;三、字符串截取/提取方法&lt;a href=&quot;#三字符串截取提取方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. slice()&lt;a href=&quot;#1-slice&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.slice(startIndex[, endIndex])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;startIndex&lt;/code&gt; - 必需，提取的起始索引（包含）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;endIndex&lt;/code&gt; - 可选，提取的结束索引（不包含），默认为字符串的长度&lt;/li&gt;
&lt;/ul&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 提取从索引6开始到结束的子字符串&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; world&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;slice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(world); &lt;/span&gt;&lt;span&gt;// 输出: &quot;World&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 提取从索引0到5的子字符串（不包含索引5）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; hello&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;slice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(hello); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用负数索引（从字符串末尾开始计算）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; last3&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;slice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(last3); &lt;/span&gt;&lt;span&gt;// 输出: &quot;rld&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. substring()&lt;a href=&quot;#2-substring&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.substring(indexStart[, indexEnd])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;indexStart&lt;/code&gt; - 必需，提取的起始索引（包含）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;indexEnd&lt;/code&gt; - 可选，提取的结束索引（不包含），默认为字符串的长度&lt;/li&gt;
&lt;/ul&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 提取从索引0到5的子字符串&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; hello&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;substring&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(hello); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 如果startIndex大于endIndex，会自动交换它们&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; swapped&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;substring&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(swapped); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 负数索引会被视为0&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; negative&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;substring&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(negative); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. substr()&lt;a href=&quot;#3-substr&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.substr(start[, length])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt; - 必需，提取的起始索引&lt;/li&gt;
&lt;li&gt;&lt;code&gt;length&lt;/code&gt; - 可选，要提取的字符数，默认为到字符串的结尾&lt;/li&gt;
&lt;/ul&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 从索引6开始提取5个字符&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; world&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;substr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(world); &lt;/span&gt;&lt;span&gt;// 输出: &quot;World&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 从索引0开始提取5个字符&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; hello&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;substr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(hello); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用负数作为起始索引（从末尾开始计算）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; last3&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;substr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(last3); &lt;/span&gt;&lt;span&gt;// 输出: &quot;rld&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;四、字符串转换方法&lt;a href=&quot;#四字符串转换方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. toLowerCase()&lt;a href=&quot;#1-tolowercase&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.toLowerCase()&lt;/code&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 将字符串转换为小写&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; lowerStr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;toLowerCase&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(lowerStr); &lt;/span&gt;&lt;span&gt;// 输出: &quot;hello world&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(str); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello World&quot;（原字符串未改变）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. toUpperCase()&lt;a href=&quot;#2-touppercase&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.toUpperCase()&lt;/code&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 将字符串转换为大写&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; upperStr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;toUpperCase&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(upperStr); &lt;/span&gt;&lt;span&gt;// 输出: &quot;HELLO WORLD&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(str); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello World&quot;（原字符串未改变）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. toString()&lt;a href=&quot;#3-tostring&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.toString()&lt;/code&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 返回字符串本身&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; sameStr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(sameStr); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 对于String对象特别有用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; strObj&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; String&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;World&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;typeof&lt;/span&gt;&lt;span&gt; strObj); &lt;/span&gt;&lt;span&gt;// 输出: &quot;object&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; strVal&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; strObj.&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;typeof&lt;/span&gt;&lt;span&gt; strVal); &lt;/span&gt;&lt;span&gt;// 输出: &quot;string&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. valueOf()&lt;a href=&quot;#4-valueof&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.valueOf()&lt;/code&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 对于字符串字面量，与原字符串相同&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(str.&lt;/span&gt;&lt;span&gt;valueOf&lt;/span&gt;&lt;span&gt;()); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 对于String对象，返回其原始值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; strObj&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; String&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;World&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(strObj.&lt;/span&gt;&lt;span&gt;valueOf&lt;/span&gt;&lt;span&gt;()); &lt;/span&gt;&lt;span&gt;// 输出: &quot;World&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;typeof&lt;/span&gt;&lt;span&gt; strObj.&lt;/span&gt;&lt;span&gt;valueOf&lt;/span&gt;&lt;span&gt;()); &lt;/span&gt;&lt;span&gt;// 输出: &quot;string&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;五、字符串替换/分割方法&lt;a href=&quot;#五字符串替换分割方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. replace()&lt;a href=&quot;#1-replace&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.replace(regexp|substr, newSubstr|function)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;第一个参数：可以是字符串或正则表达式，表示要查找的内容&lt;/li&gt;
&lt;li&gt;第二个参数：可以是字符串或函数，表示替换的内容&lt;/li&gt;
&lt;/ul&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World, Hello JavaScript&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 替换第一个匹配的子字符串&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; replacedOnce&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;Hi&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(replacedOnce); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hi World, Hello JavaScript&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用正则表达式替换所有匹配项（g表示全局匹配）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; replacedAll&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;Hello&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;Hi&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(replacedAll); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hi World, Hi JavaScript&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用函数作为替换值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; replacedWithFunc&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;Hello&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; match.&lt;/span&gt;&lt;span&gt;toUpperCase&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(replacedWithFunc); &lt;/span&gt;&lt;span&gt;// 输出: &quot;HELLO World, HELLO JavaScript&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. split()&lt;a href=&quot;#2-split&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.split([separator[, limit]])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;separator&lt;/code&gt; - 可选，字符串或正则表达式，用于指定分割的位置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;limit&lt;/code&gt; - 可选，数字，限制返回的数组长度&lt;/li&gt;
&lt;/ul&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;apple,banana,orange,grape&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用逗号作为分隔符&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fruits&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;split&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;,&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(fruits); &lt;/span&gt;&lt;span&gt;// 输出: [&quot;apple&quot;, &quot;banana&quot;, &quot;orange&quot;, &quot;grape&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 限制返回的数组长度为2&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; limitedFruits&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;split&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;,&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(limitedFruits); &lt;/span&gt;&lt;span&gt;// 输出: [&quot;apple&quot;, &quot;banana&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用空字符串作为分隔符，将每个字符作为数组元素&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; chars&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;hello&quot;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;split&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(chars); &lt;/span&gt;&lt;span&gt;// 输出: [&quot;h&quot;, &quot;e&quot;, &quot;l&quot;, &quot;l&quot;, &quot;o&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;六、字符串修剪方法&lt;a href=&quot;#六字符串修剪方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. trim()&lt;a href=&quot;#1-trim&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.trim()&lt;/code&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;   Hello World   &quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 去除两端空白&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; trimmed&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;trim&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(trimmed); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello World&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(trimmed.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// 输出: 11（原长度为17）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. trimStart() / trimLeft()&lt;a href=&quot;#2-trimstart--trimleft&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.trimStart()&lt;/code&gt; 或 &lt;code&gt;str.trimLeft()&lt;/code&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;   Hello World   &quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 去除左侧空白&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; trimmedStart&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;trimStart&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(trimmedStart); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello World   &quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(trimmedStart.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// 输出: 14（原长度为17）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// trimLeft是trimStart的别名&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; trimmedLeft&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;trimLeft&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(trimmedLeft); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello World   &quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. trimEnd() / trimRight()&lt;a href=&quot;#3-trimend--trimright&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.trimEnd()&lt;/code&gt; 或 &lt;code&gt;str.trimRight()&lt;/code&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;   Hello World   &quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 去除右侧空白&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; trimmedEnd&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;trimEnd&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(trimmedEnd); &lt;/span&gt;&lt;span&gt;// 输出: &quot;   Hello World&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(trimmedEnd.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// 输出: 14（原长度为17）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// trimRight是trimEnd的别名&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; trimmedRight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;trimRight&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(trimmedRight); &lt;/span&gt;&lt;span&gt;// 输出: &quot;   Hello World&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;七、字符串重复方法&lt;a href=&quot;#七字符串重复方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. repeat()&lt;a href=&quot;#1-repeat&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.repeat(count)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：&lt;code&gt;count&lt;/code&gt; - 必需，数字，表示重复的次数（0 到正无穷大之间的整数）&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hi&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 重复3次&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; repeated&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;repeat&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(repeated); &lt;/span&gt;&lt;span&gt;// 输出: &quot;HiHiHi&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 重复0次，返回空字符串&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; empty&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;repeat&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(empty); &lt;/span&gt;&lt;span&gt;// 输出: &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 重复次数为负数会报错&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  str.&lt;/span&gt;&lt;span&gt;repeat&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (e) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(e); &lt;/span&gt;&lt;span&gt;// 输出: RangeError: Invalid count value&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;八、字符串连接方法&lt;a href=&quot;#八字符串连接方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. concat()&lt;a href=&quot;#1-concat&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.concat(str1[, str2[, ...[, strN]]])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：&lt;code&gt;str1, str2, ..., strN&lt;/code&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot; &quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str3&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 连接多个字符串&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str1.&lt;/span&gt;&lt;span&gt;concat&lt;/span&gt;&lt;span&gt;(str2, str3, &lt;/span&gt;&lt;span&gt;&quot;!&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello World!&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 与使用 + 运算符效果相同&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; sameResult&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str1 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; str2 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; str3 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &quot;!&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(sameResult); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hello World!&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;九、字符串填充方法&lt;a href=&quot;#九字符串填充方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. padStart()&lt;a href=&quot;#1-padstart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.padStart(targetLength[, padString])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;targetLength&lt;/code&gt; - 必需，数字，目标字符串的长度&lt;/li&gt;
&lt;li&gt;&lt;code&gt;padString&lt;/code&gt; - 可选，用于填充的字符串，默认为空格&lt;/li&gt;
&lt;/ul&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;5&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 填充到长度为3，使用默认空格填充&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; padded&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;padStart&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(padded); &lt;/span&gt;&lt;span&gt;// 输出: &quot;  5&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 填充到长度为5，使用&quot;0&quot;填充&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; zeroPadded&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;padStart&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;0&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(zeroPadded); &lt;/span&gt;&lt;span&gt;// 输出: &quot;00005&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 如果目标长度小于原字符串长度，则返回原字符串&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; shorter&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;padStart&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(shorter); &lt;/span&gt;&lt;span&gt;// 输出: &quot;5&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. padEnd()&lt;a href=&quot;#2-padend&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.padEnd(targetLength[, padString])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;targetLength&lt;/code&gt; - 必需，数字，目标字符串的长度&lt;/li&gt;
&lt;li&gt;&lt;code&gt;padString&lt;/code&gt; - 可选，用于填充的字符串，默认为空格&lt;/li&gt;
&lt;/ul&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;5&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 填充到长度为3，使用默认空格填充&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; padded&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;padEnd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(padded); &lt;/span&gt;&lt;span&gt;// 输出: &quot;5  &quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 填充到长度为5，使用&quot;0&quot;填充&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; zeroPadded&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;padEnd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;0&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(zeroPadded); &lt;/span&gt;&lt;span&gt;// 输出: &quot;50000&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用多个字符进行填充&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; multiChar&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hi&quot;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;padEnd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;abc&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(multiChar); &lt;/span&gt;&lt;span&gt;// 输出: &quot;Hiabcab&quot;（循环使用填充字符串）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;十、其他字符串方法&lt;a href=&quot;#十其他字符串方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. match()&lt;a href=&quot;#1-match&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.match(regexp)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：&lt;code&gt;regexp&lt;/code&gt; - 必需，正则表达式对象&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值&lt;/strong&gt;：数组，包含匹配结果；如果没有找到匹配，则返回 null&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;The quick brown fox jumps over the lazy dog&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 查找所有以字母&quot;o&quot;开头的单词&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; matches&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;\w&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(matches); &lt;/span&gt;&lt;span&gt;// 输出: [&quot;ox&quot;, &quot;over&quot;, &quot;og&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 查找第一个匹配项的详细信息&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; firstMatch&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;q&lt;/span&gt;&lt;span&gt;\w&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(firstMatch); &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 输出: [&quot;quick&quot;, index: 4, input: &quot;The quick brown fox jumps over the lazy dog&quot;, groups: undefined]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 没有找到匹配项&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; noMatch&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;z&lt;/span&gt;&lt;span&gt;\w&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(noMatch); &lt;/span&gt;&lt;span&gt;// 输出: null&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. matchAll()&lt;a href=&quot;#2-matchall&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.matchAll(regexp)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：&lt;code&gt;regexp&lt;/code&gt; - 必需，正则表达式对象（必须包含全局标志 g）&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello 123, Hello 456&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; regex&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt;Hello (&lt;/span&gt;&lt;span&gt;\d&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 获取所有匹配结果的迭代器&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; matches&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;matchAll&lt;/span&gt;&lt;span&gt;(regex);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 将迭代器转换为数组&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; results&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Array.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(matches);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(results);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 输出: [&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;//   [&quot;Hello 123&quot;, &quot;123&quot;, index: 0, input: &quot;Hello 123, Hello 456&quot;, groups: undefined],&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;//   [&quot;Hello 456&quot;, &quot;456&quot;, index: 11, input: &quot;Hello 123, Hello 456&quot;, groups: undefined]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. search()&lt;a href=&quot;#3-search&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.search(regexp)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：&lt;code&gt;regexp&lt;/code&gt; - 必需，正则表达式对象&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值&lt;/strong&gt;：数字，第一个匹配项的索引；如果没有找到匹配，则返回-1&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Hello World&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 查找第一个大写字母的位置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; upperPos&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;search&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;[A-Z]&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(upperPos); &lt;/span&gt;&lt;span&gt;// 输出: 0&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 查找&quot;World&quot;的位置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; worldPos&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;search&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;World&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(worldPos); &lt;/span&gt;&lt;span&gt;// 输出: 6&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 查找不存在的模式&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; noPos&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; str.&lt;/span&gt;&lt;span&gt;search&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;Java&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(noPos); &lt;/span&gt;&lt;span&gt;// 输出: -1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. localeCompare()&lt;a href=&quot;#4-localecompare&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&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;code&gt;str.localeCompare(compareString[, locales[, options]])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;compareString&lt;/code&gt; - 必需，要比较的字符串&lt;/li&gt;
&lt;li&gt;&lt;code&gt;locales&lt;/code&gt; - 可选，指定区域设置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;options&lt;/code&gt; - 可选，配置比较选项&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值&lt;/strong&gt;：数字，表示比较结果（-1：当前字符串在前；0：相等；1：当前字符串在后）&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;apple&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; str2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;banana&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 比较两个字符串&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(str1.&lt;/span&gt;&lt;span&gt;localeCompare&lt;/span&gt;&lt;span&gt;(str2)); &lt;/span&gt;&lt;span&gt;// 输出: -1（&quot;apple&quot; 在 &quot;banana&quot; 之前）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(str2.&lt;/span&gt;&lt;span&gt;localeCompare&lt;/span&gt;&lt;span&gt;(str1)); &lt;/span&gt;&lt;span&gt;// 输出: 1（&quot;banana&quot; 在 &quot;apple&quot; 之后）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(str1.&lt;/span&gt;&lt;span&gt;localeCompare&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;apple&quot;&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// 输出: 0（相等）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 考虑地区的比较（德语中 &quot;ä&quot; 被视为 &quot;a&quot; 的变音）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;ä&quot;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;localeCompare&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;z&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;de&quot;&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// 输出: -1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;ä&quot;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;localeCompare&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;z&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;sv&quot;&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// 输出: 1（在瑞典语中 &quot;ä&quot; 排在 &quot;z&quot; 之后）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded><category>category:前端</category><category>tag:前端</category><category>tag:JavaScript</category></item><item><title>JavaScript 数组方法详细指南</title><link>https://wine-congee.vercel.app/post/Javascript-ArrayFn</link><guid isPermaLink="false">Javascript-ArrayFn</guid><description>一、方法分类总结
1. 修改原数组的方法（破坏性方法）

添加/删除: push(), pop(), unshift(), shift(), splice()
重排: reverse(), sort()
填充/复制: fill(), copyWithin()

2.</description><pubDate>Mon, 29 Sep 2025 02:54:00 GMT</pubDate><content:encoded>&lt;h2&gt;一、方法分类总结&lt;a href=&quot;#一方法分类总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 修改原数组的方法（破坏性方法）&lt;a href=&quot;#1-修改原数组的方法破坏性方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;添加/删除&lt;/strong&gt;: &lt;code&gt;push()&lt;/code&gt;, &lt;code&gt;pop()&lt;/code&gt;, &lt;code&gt;unshift()&lt;/code&gt;, &lt;code&gt;shift()&lt;/code&gt;, &lt;code&gt;splice()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重排&lt;/strong&gt;: &lt;code&gt;reverse()&lt;/code&gt;, &lt;code&gt;sort()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;填充/复制&lt;/strong&gt;: &lt;code&gt;fill()&lt;/code&gt;, &lt;code&gt;copyWithin()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 不修改原数组的方法（非破坏性方法）&lt;a href=&quot;#2-不修改原数组的方法非破坏性方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;创建新数组&lt;/strong&gt;: &lt;code&gt;concat()&lt;/code&gt;, &lt;code&gt;slice()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;filter()&lt;/code&gt;, &lt;code&gt;flat()&lt;/code&gt;, &lt;code&gt;flatMap()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;搜索查找&lt;/strong&gt;: &lt;code&gt;indexOf()&lt;/code&gt;, &lt;code&gt;lastIndexOf()&lt;/code&gt;, &lt;code&gt;find()&lt;/code&gt;, &lt;code&gt;findIndex()&lt;/code&gt;, &lt;code&gt;findLast()&lt;/code&gt;, &lt;code&gt;findLastIndex()&lt;/code&gt;, &lt;code&gt;includes()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检测判断&lt;/strong&gt;: &lt;code&gt;every()&lt;/code&gt;, &lt;code&gt;some()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;累积计算&lt;/strong&gt;: &lt;code&gt;reduce()&lt;/code&gt;, &lt;code&gt;reduceRight()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;字符串转换&lt;/strong&gt;: &lt;code&gt;join()&lt;/code&gt;, &lt;code&gt;toString()&lt;/code&gt;, &lt;code&gt;toLocaleString()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ES2023 新方法&lt;/strong&gt;: &lt;code&gt;toSorted()&lt;/code&gt;, &lt;code&gt;toReversed()&lt;/code&gt;, &lt;code&gt;toSpliced()&lt;/code&gt;, &lt;code&gt;with()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 迭代器方法&lt;a href=&quot;#3-迭代器方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;遍历&lt;/strong&gt;: &lt;code&gt;entries()&lt;/code&gt;, &lt;code&gt;keys()&lt;/code&gt;, &lt;code&gt;values()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. 静态方法&lt;a href=&quot;#4-静态方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数组创建&lt;/strong&gt;: &lt;code&gt;Array.from()&lt;/code&gt;, &lt;code&gt;Array.of()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;二、使用场景建议&lt;a href=&quot;#二使用场景建议&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;需要修改原数组时&lt;a href=&quot;#需要修改原数组时&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 添加元素&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;arr.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;(newItem);        &lt;/span&gt;&lt;span&gt;// 末尾添加&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;arr.&lt;/span&gt;&lt;span&gt;unshift&lt;/span&gt;&lt;span&gt;(newItem);     &lt;/span&gt;&lt;span&gt;// 开头添加&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 删除元素&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;arr.&lt;/span&gt;&lt;span&gt;pop&lt;/span&gt;&lt;span&gt;();               &lt;/span&gt;&lt;span&gt;// 删除末尾&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;arr.&lt;/span&gt;&lt;span&gt;shift&lt;/span&gt;&lt;span&gt;();             &lt;/span&gt;&lt;span&gt;// 删除开头&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 复杂操作&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;arr.&lt;/span&gt;&lt;span&gt;splice&lt;/span&gt;&lt;span&gt;(index, count, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;newItems); &lt;/span&gt;&lt;span&gt;// 添加/删除/替换&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;需要保持原数组不变时&lt;a href=&quot;#需要保持原数组不变时&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 创建新数组&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; newArr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;);     &lt;/span&gt;&lt;span&gt;// 转换&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; filtered&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 5&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// 过滤&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; combined&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;concat&lt;/span&gt;&lt;span&gt;(otherArr);  &lt;/span&gt;&lt;span&gt;// 合并&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// ES2023 新方法（推荐）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; sorted&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;toSorted&lt;/span&gt;&lt;span&gt;();          &lt;/span&gt;&lt;span&gt;// 排序（不修改原数组）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; reversed&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;toReversed&lt;/span&gt;&lt;span&gt;();      &lt;/span&gt;&lt;span&gt;// 反转（不修改原数组）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;搜索和检测时&lt;a href=&quot;#搜索和检测时&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 查找元素&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;arr.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 10&lt;/span&gt;&lt;span&gt;);          &lt;/span&gt;&lt;span&gt;// 查找第一个满足条件的&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;arr.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(value);            &lt;/span&gt;&lt;span&gt;// 检查是否包含&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 检测条件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;arr.&lt;/span&gt;&lt;span&gt;every&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;);          &lt;/span&gt;&lt;span&gt;// 所有元素都满足&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;arr.&lt;/span&gt;&lt;span&gt;some&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;);           &lt;/span&gt;&lt;span&gt;// 至少一个满足&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;三、修改原数组的方法&lt;a href=&quot;#三修改原数组的方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. push()&lt;a href=&quot;#1-push&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ✅ 是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;...elements&lt;/code&gt; (任意类型): 要添加到数组末尾的元素&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// 4 (新长度)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 2, 3, 4] (原数组被修改)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. pop()&lt;a href=&quot;#2-pop&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;: 移除并返回数组的最后一个元素&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;返回值&lt;/strong&gt;: 被删除的元素，如果数组为空则返回 undefined&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是否修改原数组&lt;/strong&gt;: ✅ 是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;: 无&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;pop&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// 3&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 2] (原数组被修改)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. unshift()&lt;a href=&quot;#3-unshift&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ✅ 是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;...elements&lt;/code&gt; (任意类型): 要添加到数组开头的元素&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;unshift&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// 4 (新长度)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 2, 3, 4] (原数组被修改)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. shift()&lt;a href=&quot;#4-shift&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;: 移除并返回数组的第一个元素&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;返回值&lt;/strong&gt;: 被删除的元素，如果数组为空则返回 undefined&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是否修改原数组&lt;/strong&gt;: ✅ 是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;: 无&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;shift&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// 1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [2, 3] (原数组被修改)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. splice()&lt;a href=&quot;#5-splice&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ✅ 是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt; (number): 开始修改的索引位置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deleteCount&lt;/code&gt; (number): 要删除的元素个数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;...items&lt;/code&gt; (任意类型): 要添加的元素（可选）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 删除元素&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; deleted1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;splice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(deleted1); &lt;/span&gt;&lt;span&gt;// [2, 3]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 4, 5]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 添加元素（不删除）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; deleted2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;splice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;b&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(deleted2); &lt;/span&gt;&lt;span&gt;// [] (没有删除元素)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, &apos;a&apos;, &apos;b&apos;, 4, 5]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 替换元素&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; deleted3&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;splice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;x&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;y&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(deleted3); &lt;/span&gt;&lt;span&gt;// [&apos;b&apos;, 4]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, &apos;a&apos;, &apos;x&apos;, &apos;y&apos;, 5]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. reverse()&lt;a href=&quot;#6-reverse&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ✅ 是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;: 无&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;reverse&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// [4, 3, 2, 1]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [4, 3, 2, 1] (原数组被修改)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7. sort()&lt;a href=&quot;#7-sort&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ✅ 是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;compareFunction&lt;/code&gt; (function, 可选): 定义排序顺序的函数&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;sort&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// [1, 1, 3, 4, 5]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 1, 3, 4, 5] (原数组被修改)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 数字排序&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; numbers&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;40&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;25&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;numbers.&lt;/span&gt;&lt;span&gt;sort&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; b); &lt;/span&gt;&lt;span&gt;// 升序&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(numbers); &lt;/span&gt;&lt;span&gt;// [5, 10, 25, 40]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;8. fill()&lt;a href=&quot;#8-fill&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ✅ 是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt; (任意类型): 填充的值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt; (number, 可选): 开始索引，默认 0&lt;/li&gt;
&lt;li&gt;&lt;code&gt;end&lt;/code&gt; (number, 可选): 结束索引（不包含），默认数组长度&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;fill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// [1, 0, 0, 4, 5]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 0, 0, 4, 5] (原数组被修改)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;9. copyWithin()&lt;a href=&quot;#9-copywithin&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ✅ 是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;target&lt;/code&gt; (number): 复制到的目标索引位置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt; (number, 可选): 开始复制的源索引，默认 0&lt;/li&gt;
&lt;li&gt;&lt;code&gt;end&lt;/code&gt; (number, 可选): 结束复制的源索引（不包含），默认数组长度&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;copyWithin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// [4, 5, 3, 4, 5]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [4, 5, 3, 4, 5] (原数组被修改)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;四、不修改原数组的方法&lt;a href=&quot;#四不修改原数组的方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;10. concat()&lt;a href=&quot;#10-concat&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;...values&lt;/code&gt; (任意类型): 要合并的数组或值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr1.&lt;/span&gt;&lt;span&gt;concat&lt;/span&gt;&lt;span&gt;(arr2, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// [1, 2, 3, 4, 5, 6, 7]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr1); &lt;/span&gt;&lt;span&gt;// [1, 2] (原数组不变)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;11. slice()&lt;a href=&quot;#11-slice&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt; (number, 可选): 开始索引，默认 0&lt;/li&gt;
&lt;li&gt;&lt;code&gt;end&lt;/code&gt; (number, 可选): 结束索引（不包含），默认数组长度&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;slice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result1); &lt;/span&gt;&lt;span&gt;// [2, 3]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 2, 3, 4, 5] (原数组不变)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;12. join()&lt;a href=&quot;#12-join&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;separator&lt;/code&gt; (string, 可选): 分隔符，默认逗号&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result1); &lt;/span&gt;&lt;span&gt;// &quot;1,2,3&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;-&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result2); &lt;/span&gt;&lt;span&gt;// &quot;1-2-3&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;13. toString()&lt;a href=&quot;#13-tostring&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;: 无&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// &quot;1,2,3&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 2, 3] (原数组不变)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;14. toLocaleString()&lt;a href=&quot;#14-tolocalestring&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;locales&lt;/code&gt; (string/array, 可选): 语言代码&lt;/li&gt;
&lt;li&gt;&lt;code&gt;options&lt;/code&gt; (object, 可选): 格式选项&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1234.56&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; Date&lt;/span&gt;&lt;span&gt;()];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;toLocaleString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;en-US&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// &quot;1,234.56,12/19/2012&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;五、遍历和转换方法&lt;a href=&quot;#五遍历和转换方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;15. forEach()&lt;a href=&quot;#15-foreach&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;: 对数组的每个元素执行指定的函数&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;返回值&lt;/strong&gt;: undefined&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是否修改原数组&lt;/strong&gt;: ❌ 否（但回调函数可以修改）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 每个元素执行的函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 回调函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; sum &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;forEach&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    sum &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; element;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`索引 ${&lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;}: 值 ${&lt;/span&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// undefined&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(sum); &lt;/span&gt;&lt;span&gt;// 6&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;16. map()&lt;a href=&quot;#16-map&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 每个元素执行的映射函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 回调函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; element &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; index);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// [2, 5, 8]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 2, 3] (原数组不变)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;17. filter()&lt;a href=&quot;#17-filter&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 测试函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 回调函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; element &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt; ===&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// [2, 4]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 2, 3, 4, 5] (原数组不变)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;18. reduce()&lt;a href=&quot;#18-reduce&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 累积函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initialValue&lt;/code&gt; (任意类型, 可选): 初始累积值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;reduce&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;acc&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;curr&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; acc &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; curr, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// 10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;19. reduceRight()&lt;a href=&quot;#19-reduceright&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 累积函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initialValue&lt;/code&gt; (任意类型, 可选): 初始累积值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;reduceRight&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;acc&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;curr&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; acc &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; curr);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// -2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;六、检测方法&lt;a href=&quot;#六检测方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;20. every()&lt;a href=&quot;#20-every&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 测试函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 回调函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;every&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; element &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt; ===&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;21. some()&lt;a href=&quot;#21-some&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 测试函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 回调函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;some&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; element &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt; ===&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;七、搜索方法&lt;a href=&quot;#七搜索方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;22. indexOf()&lt;a href=&quot;#22-indexof&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;: 查找指定元素在数组中第一次出现的索引&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;返回值&lt;/strong&gt;: 元素的第一个索引，未找到返回 -1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;searchElement&lt;/code&gt; (任意类型): 要查找的元素&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fromIndex&lt;/code&gt; (number, 可选): 开始查找的索引&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr.&lt;/span&gt;&lt;span&gt;indexOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// 1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr.&lt;/span&gt;&lt;span&gt;indexOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// -1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;23. lastIndexOf()&lt;a href=&quot;#23-lastindexof&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;: 查找指定元素在数组中最后一次出现的索引&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;返回值&lt;/strong&gt;: 元素的最后一个索引，未找到返回 -1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;searchElement&lt;/code&gt; (任意类型): 要查找的元素&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fromIndex&lt;/code&gt; (number, 可选): 开始查找的索引&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr.&lt;/span&gt;&lt;span&gt;lastIndexOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;24. find()&lt;a href=&quot;#24-find&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;: 查找数组中第一个满足条件的元素&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;返回值&lt;/strong&gt;: 第一个满足条件的元素，未找到返回 undefined&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 测试函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 回调函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; element &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// 4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;25. findIndex()&lt;a href=&quot;#25-findindex&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;: 查找数组中第一个满足条件的元素的索引&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;返回值&lt;/strong&gt;: 第一个满足条件的元素索引，未找到返回 -1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 测试函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 回调函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;findIndex&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; element &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;26. findLast() (ES2023)&lt;a href=&quot;#26-findlast-es2023&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;: 查找数组中最后一个满足条件的元素&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;返回值&lt;/strong&gt;: 最后一个满足条件的元素，未找到返回 undefined&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 测试函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 回调函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;findLast&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; element &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// 2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;27. findLastIndex() (ES2023)&lt;a href=&quot;#27-findlastindex-es2023&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;: 查找数组中最后一个满足条件的元素的索引&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;返回值&lt;/strong&gt;: 最后一个满足条件的元素索引，未找到返回 -1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 测试函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 回调函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;findLastIndex&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; element &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;28. includes()&lt;a href=&quot;#28-includes&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;searchElement&lt;/code&gt; (任意类型): 要查找的元素&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fromIndex&lt;/code&gt; (number, 可选): 开始查找的索引&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NaN&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// true&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;NaN&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;八、 ES6+ 新增方法&lt;a href=&quot;#八-es6-新增方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;29. flat()&lt;a href=&quot;#29-flat&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;depth&lt;/code&gt; (number, 可选): 扁平化深度，默认 1&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;]]]];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr.&lt;/span&gt;&lt;span&gt;flat&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// [1, 2, 3, [4]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;30. flatMap()&lt;a href=&quot;#30-flatmap&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; (function): 映射函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 回调函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;flatMap&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; [x, x &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(result); &lt;/span&gt;&lt;span&gt;// [1, 2, 2, 4, 3, 6]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;31. Array.from()&lt;a href=&quot;#31-arrayfrom&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 不适用（静态方法）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;arrayLike&lt;/code&gt; (类数组对象): 要转换的对象&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mapFn&lt;/code&gt; (function, 可选): 映射函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thisArg&lt;/code&gt; (任意类型, 可选): 映射函数的 this 值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(Array.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;hello&apos;&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// [&apos;h&apos;, &apos;e&apos;, &apos;l&apos;, &apos;l&apos;, &apos;o&apos;]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(Array.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;], &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// [2, 4, 6]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;32. Array.of()&lt;a href=&quot;#32-arrayof&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 不适用（静态方法）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;...elements&lt;/code&gt; (任意类型): 数组元素&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(Array.&lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// [1, 2, 3]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(Array.&lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;)); &lt;/span&gt;&lt;span&gt;// [3] (与 Array(3) 不同)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;33. toSorted() (ES2023)&lt;a href=&quot;#33-tosorted-es2023&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;compareFunction&lt;/code&gt; (function, 可选): 排序函数&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; sorted&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;toSorted&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; b);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(sorted); &lt;/span&gt;&lt;span&gt;// [1, 1, 3, 4, 5]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [3, 1, 4, 1, 5] (原数组不变)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;34. toReversed() (ES2023)&lt;a href=&quot;#34-toreversed-es2023&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;: 无&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; reversed&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;toReversed&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(reversed); &lt;/span&gt;&lt;span&gt;// [5, 4, 3, 2, 1]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 2, 3, 4, 5] (原数组不变)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;35. toSpliced() (ES2023)&lt;a href=&quot;#35-tospliced-es2023&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt; (number): 开始位置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deleteCount&lt;/code&gt; (number): 删除数量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;...items&lt;/code&gt; (任意类型): 要添加的元素&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; spliced&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;toSpliced&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;b&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(spliced); &lt;/span&gt;&lt;span&gt;// [1, &apos;a&apos;, &apos;b&apos;, 4, 5]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 2, 3, 4, 5] (原数组不变)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;36. with() (ES2023)&lt;a href=&quot;#36-with-es2023&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;index&lt;/code&gt; (number): 要修改的索引&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt; (任意类型): 新值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; newArr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;99&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(newArr); &lt;/span&gt;&lt;span&gt;// [1, 2, 99, 4, 5]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(arr); &lt;/span&gt;&lt;span&gt;// [1, 2, 3, 4, 5] (原数组不变)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;九、迭代器方法&lt;a href=&quot;#九迭代器方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;37. entries()&lt;a href=&quot;#37-entries&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;: 无&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;b&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;c&apos;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(index, value); &lt;/span&gt;&lt;span&gt;// 0 &apos;a&apos;, 1 &apos;b&apos;, 2 &apos;c&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;38. keys()&lt;a href=&quot;#38-keys&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;: 无&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;b&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;c&apos;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;keys&lt;/span&gt;&lt;span&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(key); &lt;/span&gt;&lt;span&gt;// 0, 1, 2&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;39. values()&lt;a href=&quot;#39-values&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&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;是否修改原数组&lt;/strong&gt;: ❌ 否&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;: 无&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;b&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;c&apos;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; arr.&lt;/span&gt;&lt;span&gt;values&lt;/span&gt;&lt;span&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(value); &lt;/span&gt;&lt;span&gt;// &apos;a&apos;, &apos;b&apos;, &apos;c&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded><category>category:前端</category><category>tag:前端</category><category>tag:JavaScript</category></item><item><title>this 的指向问题</title><link>https://wine-congee.vercel.app/post/this-binding-issue</link><guid isPermaLink="false">this-binding-issue</guid><description>关于 this 指向问题的组内分享会文档</description><pubDate>Tue, 23 Sep 2025 01:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;必要知识准备&lt;a href=&quot;#必要知识准备&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;介绍 this 之前，先简单介绍 &lt;strong&gt;四个概念(普通函数、对象方法、构造函数、箭头函数)&lt;/strong&gt;，作为我们的知识储备，为后面我们介绍 this 做铺垫&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;**普通函数：**函数是一段可以被重复调用的代码块，普通函数的声明方法基本结构很简单，我们都知道，就是下面的这种&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; 函数名&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  函数体&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 调用函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;函数名&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;对象方法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是对象？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;概念&lt;/strong&gt;：对象也是 JS 数据类型的一种，和之前学习的数值类型、字符串类型、布尔类型是一样的。对象数据类型可以被理解成是一组 &lt;strong&gt;无序的键值对的&lt;/strong&gt; 集合，是属性的容器
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;键&lt;/strong&gt;： 又称&lt;strong&gt;属性名&lt;/strong&gt;，通常是一个字符串&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;值&lt;/strong&gt;： 可以是任何数据类型，包括：数字、字符串、布尔值、数组、&lt;strong&gt;函数&lt;/strong&gt;，甚至是另一个对象(嵌套)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;属性&lt;/strong&gt;：属性是成对出现的，包括属性名和属性值，它们之间使用英文 &lt;code&gt;:&lt;/code&gt; 分隔，多个属性之间使用英文 &lt;code&gt;,&lt;/code&gt; 分隔&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;怎样创建一个对象呢？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最常用的一种就是使用花括号 &lt;code&gt;&lt;/code&gt; 直接创建&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; 对象名 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  属性名1: 属性值1,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  属性名2: 属性值2,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  属性名3: 属性值3,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  属性名4: 函数,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;什么是方法？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;属性值可以是任何数据类型，这里面有一个数据类型比较特殊，就是&lt;strong&gt;函数&lt;/strong&gt;，如果一个属性的值是一个&lt;strong&gt;函数&lt;/strong&gt;，那么我们称这个属性是这个对象的一个&lt;strong&gt;方法&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于普通函数和方法之间有点像，所以我们举个例子带大家区分一下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 创建一个函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; fn&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;111&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 直接放在script标签里面，他就是一个普通函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; fn&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;111&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 将这个函数放进一个对象里面&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; obj &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  fn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;() {  &lt;/span&gt;&lt;span&gt;// 是这个obj对象的方法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;111&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  } &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;怎样访问对象里面的属性呢？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;创建了一个对象之后，我们怎么访问该怎样访问这个对象里面的属性呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;声明对象并添加了若干属性后，可以使用 &lt;code&gt;.&lt;/code&gt; 或 &lt;code&gt;[]&lt;/code&gt; 获得对象中属性对应的值，&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;基本上写法就是 &lt;strong&gt;对象名.属性名&lt;/strong&gt; 或者 &lt;strong&gt;对象名[‘属性名’]&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果我们需要为这个属性重新赋值或者添加一个属性，也很简单 &lt;strong&gt;对象名.属性名 = 新的属性值&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;我们平常写代码经常写的 &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 获取DOM元素&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; oDiv &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;div&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 给这个元素添加一个字体颜色为红色的样式&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;oDiv.style.color &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;red&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// style 就是 oDiv 的一个属性，这个属性的值其实也是一个对象，而 color 是 style 的一个属性&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的是不是很熟悉，其实当我们把 &lt;code&gt;div&lt;/code&gt; 这个标签获取过来并赋给变量 &lt;code&gt;oDiv&lt;/code&gt; 时，我们也相当于创建一个一个对象名为 &lt;code&gt;oDiv&lt;/code&gt; 的对象，只是这个对象里面已经很多自带的属性和方法了，我们用的时候直接使用 &lt;code&gt;.&lt;/code&gt; 调用我们需要的属性，并给它重新赋值就行了&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;怎样访问对象里面的方法呢？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本上和访问属性的写法是一致的，只有一点不一样，我们都知道普通函数的调用方法，&lt;code&gt;函数名()&lt;/code&gt; ，最后必须要加上一个小括号，这个函数的调用的方法是不论在哪里都不变的，前面讲到方法的属性值是函数，既然是函数，那我们也应该在属性名后面加上 &lt;code&gt;()&lt;/code&gt; ，即 &lt;code&gt;对象名.属性名()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; person &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  name: &lt;/span&gt;&lt;span&gt;&apos;小红&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  age: &lt;/span&gt;&lt;span&gt;18&lt;/span&gt;&lt;span&gt;,    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  singing&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;两只老虎，两只老虎，跑的快，跑的快...&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  run&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;我跑的非常快...&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 调用person对象中 singing 方法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;person.&lt;/span&gt;&lt;span&gt;singing&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 调用person对象中的 run 方法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;person.&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;构造函数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在前面我们学习了对象之后，应该能更好的理解构造函数，因为构造函数其实也是在创建对象&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;什么是构造函数？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;本质上就是一个&lt;strong&gt;普通的函数&lt;/strong&gt;，但是会有两个地方不太一样&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;命名方面上，构造函数的名称首字母要大写，这其实是一种普遍的命名的约定用来区别普通函数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与 &lt;code&gt;new&lt;/code&gt; 操作符一起使用：构造函数通过 &lt;code&gt;new&lt;/code&gt; 操作符来调用，用于&lt;strong&gt;创建并初始化一个新对象&lt;/strong&gt;。你们也可以这样理解，当一个函数使用 &lt;code&gt;new&lt;/code&gt; 操作符调用时，它就成为了“构造函数”，即一个用于构造新对象的函数&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;构造函数的作用：创建对象&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在没有构造函数之前，我们使用对象字面量创建单个对象&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 对象字面量创建单个对象&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; person1 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; name: &lt;/span&gt;&lt;span&gt;&quot;Alice&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; age: &lt;/span&gt;&lt;span&gt;25&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; greet ：&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(Hello, my name is &lt;/span&gt;&lt;span&gt;11&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;person1.&lt;/span&gt;&lt;span&gt;greet&lt;/span&gt;&lt;span&gt;(); &lt;/span&gt;&lt;span&gt;// 输出: Hello, my name is 11&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;但如果要创建多个结构相似（都有 name, age, greet 属性）的对象，重复写对象字面量会很麻烦，这时构造函数就派上用场了&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;构造函数就像一个“工厂模具”，可以批量生产具有相同属性和方法结构的对象&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;怎样使用构造函数呢？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一步：定义构造函数，在其内部使用 &lt;code&gt;this&lt;/code&gt; 来定义未来的实例对象里面的属性和方法&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;   创建一个函数（首字母要大写）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 1. 定义构造函数 (首字母大写)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 这里相当于创建了一个模板&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; Person&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;age&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 2. 使用 this 来添加属性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; name;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.age &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; age;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;第二步：使用 &lt;code&gt;new&lt;/code&gt; 调用构造函数，使用 &lt;code&gt;new&lt;/code&gt; 操作符来调用 &lt;code&gt;Person&lt;/code&gt; 函数，它会按照构造函数的模板创建一个新的对象并返回它&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 使用 new 创建实例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 我们在这里调用这个模板&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; person1 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Person&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;25&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; person2 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Person&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Bob&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(person1.name); &lt;/span&gt;&lt;span&gt;// 输出: Alice&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(person2.age);  &lt;/span&gt;&lt;span&gt;// 输出: 30&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们可以看一个例子：&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/sharedocs/this-binding-issue/1.jpg&quot; alt=&quot;例子1-准备月饼模具阶段&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;例子1-准备月饼模具阶段&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/img/blog/sharedocs/this-binding-issue/2.jpg&quot; alt=&quot;例子2-做月饼阶段&quot; loading=&quot;lazy&quot; /&gt;&lt;figcaption&gt;例子2-做月饼阶段&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;到这里，我想问大家，现在大家知道上面第二个图片里的变量 &lt;code&gt;person1&lt;/code&gt; 和 &lt;code&gt;person2&lt;/code&gt; 的值是什么数据类型吗？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;箭头函数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;箭头函数是 ES6 中引入的一种新的函数语法，它提供了一种更简洁的方式来编写函数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;基本语法：                                                  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我们与传统的函数表达式对比来学&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 完整写法（多行语句或需要显式返回对象时）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 简洁写法（单行表达式，隐含 return）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;大家观察上面的两种写法有什么不同？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仔细观察，赋值等号左边的没有变化，变化在右边，箭头函数删去了 function ，变成了 =&amp;gt; ，并且将 =&amp;gt; 放到了 小括号 和 大括号 的中间&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;好啦，到这里我们的前置只知识准备就完成了，这就开始我们第二部分的介绍吧！&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;this 到底什么？&lt;a href=&quot;#this到底什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在正式开始介绍 this 到底是什么之前，这里有两个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;this 是不是变量？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; 不是，&lt;code&gt;this&lt;/code&gt; 是一个特殊关键字（像 &lt;code&gt;function&lt;/code&gt;, &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;new&lt;/code&gt; 一样），不是可以声明的变量或对象的属性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;this 是对象吗&lt;/strong&gt;？学到现在，大家应该或多或少都应该见过 &lt;code&gt;this.sayName()&lt;/code&gt; 这种写法，那按照我们上面对于对象方法的学习，大家觉得 &lt;strong&gt;this 是对象吗？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;也不是，this 很多变，它本身不是一个对象，只是它的值实际根据是谁在调用它而变的，只是&lt;strong&gt;一般情况&lt;/strong&gt;下 this 的值(它所指向的东西)，总是一个对象&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有一个类比，万能电视遥控器(this)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;万能遥控器(this)本身&lt;/strong&gt;不是电视，但&lt;strong&gt;按下遥控器的按钮（调用 this）&lt;strong&gt;的效果，取决于它&lt;/strong&gt;当前指向并控制的是哪台电视&lt;/strong&gt;，你可以用同一个遥控器（this），通过改变它的指向（不同的调用方式）来控制不同的电视（不同的对象）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;所以 this 到底是什么呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一般来说，this 都是放在一个函数中使用的，调用这个函数也就相当于在调用这个 this ，&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当我们总结上面的问题和类比例子后，其实可以用一句话总结，就是&lt;code&gt;this&lt;/code&gt; &lt;strong&gt;的值不是在我们定义函数时确定的，而是在我们调用这个函数时才被确定的&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个贴近生活的比喻：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;想象你是一个员工（函数），你有一句话（函数体）：“我正在为&lt;code&gt;this&lt;/code&gt;公司工作“&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果你在 &lt;strong&gt;A 公司&lt;/strong&gt; 的办公室里说这句话，&lt;code&gt;this&lt;/code&gt; 就代表 A 公司&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果你在 &lt;strong&gt;B 公司&lt;/strong&gt; 的办公室里说这句话，&lt;code&gt;this&lt;/code&gt; 就代表 B 公司&lt;strong&gt;你（函数）本身没变，但你所在的环境（调用者）变了，&lt;/strong&gt;&lt;code&gt;this&lt;/code&gt; &lt;strong&gt;的含义也就随之改变了&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;说多不如练多，这里有一个小问题，大家可以先试试能不能解答&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; person&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  name: &lt;/span&gt;&lt;span&gt;&apos;小明&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sayHi&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;你好，我是&apos;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt;.name)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;person.&lt;/span&gt;&lt;span&gt;sayHi&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;六个常见环境下的 this 指向问题&lt;a href=&quot;#六个常见环境下的this指向问题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;全局环境中的 this&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;全局环境就是在&lt;code&gt;&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;里（不在任何函数或对象内部），此时的 this 始终指向的是全局对象，在浏览器中就是 window&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;普通函数中的 this&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当一个函数被直接调用时，要考虑两种情况&lt;/p&gt;
&lt;p&gt;this 在非严格模式下指向&lt;strong&gt;全局对象&lt;/strong&gt;（window）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; 	console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 我们实际上是在全局作用域下直接调用函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// fun() 实际上是window.fun(), 所以this -&amp;gt; window&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;在严格模式下指向 &lt;strong&gt;undefined&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;JS 严格模式：JavaScript 在语法和行为上存在一些模糊的特性，可能导致一些不易察觉的错误，为提高代码的质量和可维护性，JS 引入了严格模式，通过启用一些额外的规则，强制执行更严格的语法和行为，帮助提前发现和修复潜在 bug。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 演示严格模式下的情况&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; fu&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;use strict&quot;&lt;/span&gt;&lt;span&gt;  // 在函数体中写一句 &quot;use strict&quot; ，就可以启用函数的严格模式&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fu&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// this 指向 undefined&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;对像方法中的 this&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当函数作为对象的方法被调用时，this 指向该方法所属的对象&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; person &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  name: &lt;/span&gt;&lt;span&gt;&quot;John&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sayName&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.name)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;person.&lt;/span&gt;&lt;span&gt;sayName&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;卡卡&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; cat &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  name:&lt;/span&gt;&lt;span&gt;&apos;有鱼&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  eat1:{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    name:&lt;/span&gt;&lt;span&gt;&apos;年年&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    eat2&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;(){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.name);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;cat.eat1.&lt;/span&gt;&lt;span&gt;eat2&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;构造函数中的 this&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 new 关键字（实例化）调用函数时，该函数被当作构造函数，this 会指向新创建的对象实例&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 构造函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; Person&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;sayHello&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Hello, I&apos;m &quot;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt;.name)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 创建实例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; john &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Person&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;John&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;john.&lt;/span&gt;&lt;span&gt;sayHello&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// 输出 &quot;Hello, I&apos;m John&quot;，这里 this 指向 john 实例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; john &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  name : name,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sayHello&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Hello, I&apos;m &quot;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt;.name)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 构造函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  function&lt;/span&gt;&lt;span&gt; Person&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      this&lt;/span&gt;&lt;span&gt;.name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;sayHello&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`你好，我是 ${&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 创建实例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; person1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Person&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;张三&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;person1.&lt;/span&gt;&lt;span&gt;sayHello&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;事件处理中的 this&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在 DOM 事件处理函数中，this 通常指向触发事件的元素&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;myButton&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;Click me&amp;lt;/&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  var button = document.getElementById(&quot;myButton&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  button.onclick = function () {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;)  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;btu&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;Click&amp;lt;/&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  let oBtu = document.querySelector(&apos;.btu&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  oBtn.addEventListenter(&apos;click&apos;,clickBtu)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    function clickBtu() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;箭头函数中的 this&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;箭头函数没有自己的 this，它的 this 直接“捕获”或“继承”**外层作用域（它父级）**的 this 的值&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;前面介绍过普通函数 的 &lt;code&gt;this&lt;/code&gt; 是&lt;strong&gt;动态的&lt;/strong&gt;，取决于如何被调用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;而箭头函数 的 &lt;code&gt;this&lt;/code&gt; 是&lt;strong&gt;词法的&lt;/strong&gt;，&lt;strong&gt;取决于定义时的上下文&lt;/strong&gt;，且&lt;strong&gt;一旦定义就固定不变&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;词法的 = 写代码时候的位置决定的（this 的出生地）&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 普通函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; outerFunction&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &quot;Outer&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  var&lt;/span&gt;&lt;span&gt; innerFunction&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.name)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  innerFunction&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 箭头函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; outerFunctionWithArrow&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &quot;外层作用域的this&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  var&lt;/span&gt;&lt;span&gt; innerFunction&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.name)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  innerFunction&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 一种情况&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; outerFunction&lt;/span&gt;&lt;span&gt;()             &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; outerFunctionWithArrow&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 另一种调用情况&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;outerFunction&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;outerFunctionWithArrow&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;改变 this 指向的方法&lt;a href=&quot;#改变this指向的方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;由于箭头函数的 this 来自于继承，箭头函数无法使用以下三种方法改变 this 指向&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;call()&lt;/code&gt; 方法&lt;/p&gt;
&lt;p&gt;&lt;code&gt;call()&lt;/code&gt; 方法附加在函数调用后面使用，可以忽略函数本身的 this 指向，然后将这个函数本身的 this 指向绑定到 &lt;code&gt;call()&lt;/code&gt; 方法的第一个参数上面&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;函数.&lt;/span&gt;&lt;span&gt;call&lt;/span&gt;&lt;span&gt;(thisArg,arg1,arg2,&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;,argN)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;参数解析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;thisArg&lt;/code&gt;：就是你想将调用这个方法的函数本身的 this 指向绑定到哪个对象上面&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;arg1-argN&lt;/code&gt;：从参数 &lt;code&gt;arg1&lt;/code&gt; 开始，依次是向函数传递参数&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;注意点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;call()&lt;/code&gt; 方法时，相当于你调用了这个函数，会立刻执行这个函数&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; greet&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.animal, &lt;/span&gt;&lt;span&gt;&quot;的睡眠时间一般在&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.sleepDuration, &lt;/span&gt;&lt;span&gt;&quot;之间&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; obj&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  animal: &lt;/span&gt;&lt;span&gt;&quot;猫&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sleepDuration: &lt;/span&gt;&lt;span&gt;&quot;12 到 16 小时&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;greet.&lt;/span&gt;&lt;span&gt;call&lt;/span&gt;&lt;span&gt;(obj); &lt;/span&gt;&lt;span&gt;// 猫 的睡眠时间一般在 12 到 16 小时 之间&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;apply()&lt;/code&gt; 方法&lt;/p&gt;
&lt;p&gt;和 &lt;code&gt;call()&lt;/code&gt; 方法很相似，几乎一样&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;函数名.&lt;/span&gt;&lt;span&gt;apply&lt;/span&gt;&lt;span&gt;(thisArg,[arg1,arg2,&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;,argN])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;参数解析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;thisArg&lt;/code&gt;：同样为你想将这个函数本身的 this 指向绑定到哪个对象上面&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[arg1,arg2,...,argN]&lt;/code&gt;（主要区别点）：一个 &lt;strong&gt;数组&lt;/strong&gt;，数组里面的每一项依次是向函数传递的参数，这里可以直接写入一个数组，也可以写一个值为数组的变量&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;bind()&lt;/code&gt; 方法&lt;/p&gt;
&lt;p&gt;和上面两个方法不一样，&lt;code&gt;bind()&lt;/code&gt; 方法&lt;strong&gt;创建一个新函数并且还有返回值&lt;/strong&gt;，使用 &lt;code&gt;bind()&lt;/code&gt; 方法后不会立即执行函数，而是返回一个已经改变了 this 指向的函数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;函数名.&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(thisArg, arg1, arg2, ..,argN)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;参数解析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;thisArg&lt;/code&gt;：作用与前两个一致&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;arg1, arg2, ..,argN&lt;/code&gt;： 在调用函数时，插入到传入绑定函数的参数前的参数&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;返回值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个改变了 this 指向以后的 function 函数&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; module&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  x: &lt;/span&gt;&lt;span&gt;42&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  getX&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt;.x;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getX&lt;/span&gt;&lt;span&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; unboundGetX&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; module&lt;/span&gt;&lt;span&gt;.getX;&lt;/span&gt;&lt;span&gt;//undefined 函数未被调用，存储的是一个值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;unboundGetX&lt;/span&gt;&lt;span&gt;()); &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; boundGetX&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; unboundGetX.&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;boundGetX&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结及综合演练&lt;a href=&quot;#总结及综合演练&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;this 指向：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1、一般函数：谁调用函数，this 就指向谁，没有调用者就指向全局对象 Window&lt;/p&gt;
&lt;p&gt;2、箭头函数：箭头函数不会创建 this，它的 this 继承自上层作用域中的 this&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;btu&apos;&lt;/span&gt;&lt;span&gt;&amp;gt;Click&amp;lt;/&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.log(this)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 一个普通函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function fn() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 创建一个对象&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let obj = {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  fn: fn&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 直接调用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fn()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 对象方法调用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;obj.fn()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 事件处理中调用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let oBtu = document.querySelector(&apos;.btu&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;oBtu.addEventLister(&apos;click&apos;,fn)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 构造函数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; Fn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;age&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 111&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.age &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; age,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;currentAge&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.age)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; Fn1 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Fn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Fn1.&lt;/span&gt;&lt;span&gt;currentAge&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// call()方法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; Product&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;price&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; name;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.price &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; price;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; Food&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;price&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  Product.&lt;/span&gt;&lt;span&gt;call&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;, name, price);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  this&lt;/span&gt;&lt;span&gt;.category &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &quot;food&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; Food&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;cheese&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;).name);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;代码解析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;关键点：&lt;code&gt;Product.call(this, name, price)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这行代码的作用是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 Food 的上下文中调用 Product 构造函数&lt;/li&gt;
&lt;li&gt;第一个参数 this 是新创建的 Food 实例&lt;/li&gt;
&lt;li&gt;&lt;code&gt;call()&lt;/code&gt; 方法将 Product 中的 this 绑定到传入的 Food 实例上&lt;/li&gt;
&lt;li&gt;相当于在 Food 实例上设置 name 和 price 属性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;执行过程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;new Food(&quot;cheese&quot;, 5)&lt;/code&gt; 创建 Food 实例&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Food 构造函数中的 this 指向这个新实例&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Product.call(this, &quot;cheese&quot;, 5)&lt;/code&gt; 让 Product 构造函数在这个 Food 实例上工作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最终创建的 Food 对象包含：&lt;code&gt;{name: &quot;cheese&quot;, price: 5, category: &quot;food&quot;}&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; outer&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  name: &lt;/span&gt;&lt;span&gt;&quot;Outer Object&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  innerFunction&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; inner&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      name: &lt;/span&gt;&lt;span&gt;&quot;Inner Object&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      nestedFunction&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.name)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    inner.&lt;/span&gt;&lt;span&gt;nestedFunction&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;outer.&lt;/span&gt;&lt;span&gt;innerFunction&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded><category>category:分享会</category><category>tag:前端</category><category>tag:分享会</category><category>tag:JavaScript</category></item></channel></rss>