<?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/%E7%BC%96%E7%A8%8B%E9%A2%98/</link><description>Recent content in 编程题 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><atom:link href="https://amatsuzero.github.io/LastStand/tags/%E7%BC%96%E7%A8%8B%E9%A2%98/index.xml" rel="self" type="application/rss+xml"/><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></channel></rss>