<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>冰室花园 Blog</title>
        <link>https://blog.mattuy.top/</link>
        <description>冰室花园 Blog</description>
        <lastBuildDate>Mon, 08 Feb 2021 21:26:07 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-Hans</language>
        <item>
            <title><![CDATA[记一次误操作删除800G数据的经历]]></title>
            <link>https://blog.mattuy.top/archives/a-op-that-delete-my-800g-data</link>
            <guid>https://blog.mattuy.top/archives/a-op-that-delete-my-800g-data</guid>
            <pubDate>Mon, 08 Feb 2021 21:26:07 GMT</pubDate>
            <description><![CDATA[前因后果]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="前因后果">前因后果<a href="https://blog.mattuy.top/archives/a-op-that-delete-my-800g-data#%E5%89%8D%E5%9B%A0%E5%90%8E%E6%9E%9C" class="hash-link" aria-label="前因后果的直接链接" title="前因后果的直接链接" translate="no">​</a></h2>
<p>2021年2月5日，我正在尝试运行一份示例代码。该脚本类似这样：</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 这里有检查$REC_ROOT，但本脚本内并未处理，所以只会输出缺少环境变量$REC_ROOT，但继续执行</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./config.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if [ ! -d $WAV_ROOT ]; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  echo "Cannot find wav directory $WAV_ROOT"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  exit 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fi</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">data="$REC_ROOT/data"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 其他代码</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if [ $stage -le 0 ]; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  echo ""</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  echo "Stage 0: Preparing data"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  rm -rf $data/*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  local/chime1_prepare_data.sh || exit 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fi</span><br></div></code></pre></div></div>
<p>由于脚本来自知名开源项目，我并没有仔细审查。另外由于对相关代码并不熟悉，我也没有正确配置相关环境变量，所以脚本中的<code>WAV_ROOT</code>和<code>REC_ROOT</code>理所当然是未定义的。</p>
<p>我就这么冒失地执行了脚本，而它在打印两句警告后并没有停止执行，所以我认为环境变量并不是必须的，于是放任它继续执行。由于该脚本执行的是耗时任务，我将控制台隐藏到后台，去完成其他任务。</p>
<p>过了十几分钟，我收到一个应用程序的崩溃报告，因为相关文件不存在。我疑惑地检查，发现数百GB的数据已经不翼而飞。此时我才想起那个正在执行的脚本，切换过去后发现它还没有停止执行，正在疯狂删除我的文件。我赶忙杀掉了脚本，但包括由于没有root权限而删除失败的，原本800GB+的数据只剩5.6G。</p>
<p>让我们来看看发生了什么。</p>
<p>首先，脚本调用<code>config.sh</code>，检测到<code>REC_ROOT</code>环境变量不存在并打印警告。</p>
<p>然后脚本继续执行，<code>if [ ! -d $WAV_ROOT ]; then</code>这里是在检测<code>WAV_ROOT</code>是否是一个目录，如果不是，就退出脚本。按理说我并没有配置任何环境变量，此处应该退出。但bash脚本神奇地，当<code>WAV_ROOT</code>为空或者不存在时，这个检测会认为这是一个目录，从而通过检测。即：</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">unset NOT_EXIST</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if [ -d $NOT_EXIST ]; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  echo "this is a directory"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fi</span><br></div></code></pre></div></div>
<p>上面的脚本是会输出的。</p>
<p>或许是因为参数为空时bash默认检测当前目录，以至于目录检测总是通过。</p>
<p>再然后，由于<code>REC_ROOT</code>未定义，<code>$data</code>=<code>/data</code>，然后相当于：</p>
<blockquote>
<p><code>rm -rf /data/*</code></p>
</blockquote>
<p>非常不巧和不幸的是，我将一块1TB的数据盘挂载在了<code>/data</code>上，于是迎来了降维打击。该数据盘中有800G+的数据，文件量大于10万，因此非常耐删，过了十几分钟还给我剩了几个G。而大量读写操作将数据恢复的难度推到了地狱级。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="抢救措施">抢救措施<a href="https://blog.mattuy.top/archives/a-op-that-delete-my-800g-data#%E6%8A%A2%E6%95%91%E6%8E%AA%E6%96%BD" class="hash-link" aria-label="抢救措施的直接链接" title="抢救措施的直接链接" translate="no">​</a></h2>
<p>在杀掉脚本之后，我尝试卸载数据盘，但卸载失败，提示正忙。情急之下我忘记了可以通过正在运行的进程恢复它们打开的文件，而是想到先关机避免更多的读写。关机前发现VSCodium还在运行并且有未关闭的文件，于是抢救出几个正在编辑的代码文件。而这成了本次事故中我唯一抢救成功的文件。</p>
<p>之后，通过U盘刻录的系统修改原系统的配置，取消掉自动挂载数据盘，然后系统启动后以只读方式挂载数据盘尝试恢复数据。</p>
<p>正如前面所说，大量的读写操作让我失去了恢复的机会，尝试了不少恢复工具，但都没法扫描出目录结构，唯一可能有效的方法是通过特殊的文件头结构进行特征扫描，但这只能恢复一些特殊格式的文件，而对我最重要的都是纯文本数据，至于一些视频文件，由于尺寸太大数据分散在不同的块，也是基本没戏的。</p>
<p>还好，云端备份让我不至于一无所有，但还是痛失最近一个月的活动数据和大量不可描述之物。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://blog.mattuy.top/archives/a-op-that-delete-my-800g-data#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>数据无价，谨慎操作。备份得当，也别太浪。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[DOM更新与浏览器事件循环]]></title>
            <link>https://blog.mattuy.top/archives/dom-update-and-browser-event-loop</link>
            <guid>https://blog.mattuy.top/archives/dom-update-and-browser-event-loop</guid>
            <pubDate>Sun, 04 Oct 2020 01:05:41 GMT</pubDate>
            <description><![CDATA[通常我们说DOM更新发生在一个宏任务执行完之后，但并不是每次宏任务执行后都会进行DOM更新。浏览器会维护一个相对稳定的帧率，根据硬件条件和页面性能表现。那么事件循环如何判断是否应该更新DOM呢？]]></description>
            <content:encoded><![CDATA[<p>通常我们说DOM更新发生在一个宏任务执行完之后，但并不是每次宏任务执行后都会进行DOM更新。浏览器会维护一个相对稳定的帧率，根据硬件条件和页面性能表现。那么事件循环如何判断是否应该更新DOM呢？</p>
<p>先上一波HTML规范指定的<a href="https://html.spec.whatwg.org/#event-loop-processing-model" target="_blank" rel="noopener noreferrer" class="">事件循环处理章程</a>：</p>
<ol>
<li class="">从事件循环的任务队列中取一个任务队列<em>taskQueue</em>，这里的任务队列指的是宏任务队列。注意，一个事件循环可能并不只有一个宏任务队列。具体有哪些以及这里怎么选由用户代理决定。</li>
<li class=""><em>taskQueue</em>中出队一个（宏）任务<em>oldestTask</em>，并设置事件循环的<em>当前执行的任务</em>为<em>taskQueue</em>。</li>
<li class="">执行<em>taskQueue</em>。</li>
<li class="">设置事件循环的<em>当前执行的任务</em>为null。</li>
<li class="">执行微任务队列中的（task）。</li>
<li class="">处理DOM更新。</li>
</ol>
<p>上面的描述省略了一些步骤，完整版参考<a href="https://html.spec.whatwg.org/#event-loop-processing-model" target="_blank" rel="noopener noreferrer" class="">规范</a>。注意worker环境的事件循环不在本文讨论范畴之内。</p>
<p>可以发现DOM更新确实发生在两个宏任务执行之间，但如果我们深入DOM更新步骤，会发现还有个<em>渲染机会（<a href="https://html.spec.whatwg.org/#rendering-opportunity" target="_blank" rel="noopener noreferrer" class="">rendering opportunity</a>）<em>的概念。DOM更新时会忽略没有</em>渲染机会</em>的文档。</p>
<p>那么什么时候一个DOM文档（准确说是其<a href="https://html.spec.whatwg.org/#concept-document-bc" target="_blank" rel="noopener noreferrer" class="">浏览上下文</a>）拥有<em>渲染机会</em>呢？前面说过，浏览器会维护一个相对稳定的帧率，例如30fps，那么1秒内应该最多拥有30次渲染机会。浏览器根据这些条件和是否有DOM更新（DOM操作，动画等），决定文档是否应该拥有<em>渲染机会</em>。<em>相对稳定</em>的意思是，当硬件条件或者页面性能导致无法维持较高帧率时可能会降帧。虽然这并不是规范规定的，但规范中以此为例，而且主流浏览器应该都是这么实现的。</p>
<p>了解这些有什么用呢？我们可以更精细地把握自己的代码。考虑以下代码：</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//依赖DOM的操作</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>我们可能会用定时器来等待dom更新后执行一些操作，因为定时器创建宏任务，而<del>DOM会在当前宏任务执行结束后更新</del>（错误）。<br>
有趣的是，这往往也不会出大问题。一来一般这时候已经执行了不少代码，可能正好浏览器在当前宏任务执行完后更新了DOM，二来DOM操作往往会导致DOM强制更新（如读取DOM元素几何相关的数值等，但不绝对触发强制更新），也可能会得到想要的结果。<br>
然后结果是，bug若有若无的，全看人品。啊，我测试的时候好好的，演示的时候怎么就...😅</p>
<p>上面的例子不够具体，来个更实际的。假设要实现一个DOM元素从远处飞回来的动画，我们不用css animation，用transform。<br>
首先我们需要给DOM元素一个初始偏移量，否则起点就是终点，就没有动画效果了。然后给它设置transition样式，并把偏移量还原。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 获取DOM元素，这里getElement函数未实现</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> el </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getElement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 初始偏移量</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    el</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">transform</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'translateX(-100px)'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...???</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    el</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">transition</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'transform 100ms linear'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    el</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">transform</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'translateX(0)'</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>为了让动画从初始偏移量开始，我们需要在<code>???</code>前后代码执行之间触发一次DOM更新。</p>
<p>最简单的就是触发DOM强制更新。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 获取DOM元素，这里getElement函数未实现</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> el </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getElement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 初始偏移量</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    el</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">transform</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'translateX(-100px)'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    el</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getBoundingClientRect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    el</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">transition</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'transform 100ms linear'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    el</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">transform</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'translateX(0)'</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>通过<code>getBoundingClientRect()</code>读取元素的几何信息，迫使DOM重新计算元素的属性。但这可能造成额外的运算，带来性能损失。虽然一般场景下问题不大。</p>
<p>如果我们想将<code>???</code>后面的代码延迟到下一帧之后执行呢？靠<code>setTimeout()</code>的话，timeout设置小了就回到bug与人品的故事了，设置大了又会产生卡顿影响体验。这时候我们可以通过一个神奇的API来解决：<code>requestAnimationFrame</code>。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 获取DOM元素，这里getElement函数未实现</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> el </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getElement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 初始偏移量</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">el</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">transform</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'translateX(-100px)'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">requestAnimationFrame</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    el</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">transition</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'transform 100ms linear'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    el</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">transform</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'translateX(0)'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>首先，<code>requestAnimationFrame()</code>的回调会在下一帧绘制<strong>之前</strong>执行。我的理解是，<em>执行requestAnimationFrame的回调函数列表</em>作为一个宏任务被调度，并且此时该DOM文档获得<em>渲染机会</em>，因此回调执行结束后DOM将更新，而当回调函数中设置的定时器任务被执行的时候已经处于新的宏任务中，此时DOM文档已更新。</p>
<p>注意：对于<em>处理一个浏览上下文的requestAnimationFrame回调时的宏任务和下一个宏任务之间，该浏览上下文一定获得会渲染机会</em>是否成立，尚未找到规范证明，仅作参考。</p>
<p>本文链接：<a href="https://blog.mattuy.top/archives/dom-update-and-browser-event-loop" target="_blank" rel="noopener noreferrer" class="">https://blog.mattuy.top/archives/dom-update-and-browser-event-loop</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[LeetCode之旅──696.计数二进制子串]]></title>
            <link>https://blog.mattuy.top/archives/leetcode-count-binary-sub-str</link>
            <guid>https://blog.mattuy.top/archives/leetcode-count-binary-sub-str</guid>
            <pubDate>Mon, 10 Aug 2020 20:43:51 GMT</pubDate>
            <description><![CDATA[题目：给定一个字符串 s，计算具有相同数量0和1的非空(连续)子字符串的数量，并且这些子字符串中的所有0和所有1都是组合在一起的。]]></description>
            <content:encoded><![CDATA[<p>题目：给定一个字符串 s，计算具有相同数量0和1的非空(连续)子字符串的数量，并且这些子字符串中的所有0和所有1都是组合在一起的。<br>
重复出现的子串要计算它们出现的次数。</p>
<p>示例：</p>
<blockquote>
<p>输入: "00110011"
输出: 6
解释: 有6个子串具有相同数量的连续1和0：“0011”，“01”，“1100”，“10”，“0011” 和 “01”。</p>
<p>请注意，一些重复出现的子串要计算它们出现的次数。</p>
<p>另外，“00110011”不是有效的子串，因为所有的0（和1）没有组合在一起。</p>
</blockquote>
<p>最先想用栈来解决，但发现行不通。然后慢慢发现规律了，我们可以用一个指针对准第一个数字的起点（最先是0），然后用另一个指针对准另一个数字的起点（如示例中第一个1的位置），然后两个指针一起跑，只要它们对应位置的值不相等，那答案就加1。值相等后必然是其中一个数字跑完了，可以根据和前一个位置对比得出是跑在前面的指针跑完了还是跑在后面的，如果是前面的先跑完了就让后面的指针直接跑到下一个起点（即前面的指针本次的起点），接着开始下一轮，直到有一个指针到达末尾。</p>
<p>好吧上面一段其实并不用看，我们只需要将相同的数字看作一组，然后遍历每组的数字个数组成的数组，相邻元素取最小值，加起来就得到结果了。比如示例的数组为[2, 2, 2, 2]，相邻取最小再加起来就是6。</p>
<p>其实理论上说两个方法是差不多的，后者像是前者的抽象化。我们刷算法题总是容易下意识的用人类思维思考，然后用计算机去“模拟”，所以经常会遇到将思维转化为代码时不流畅和容易出错。我认为所谓算法思想，就是<strong>一种将人类思维抽象成计算机思维的能力</strong>。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[当绝对定位遇上层叠上下文]]></title>
            <link>https://blog.mattuy.top/archives/css-absolute-position-and-transform</link>
            <guid>https://blog.mattuy.top/archives/css-absolute-position-and-transform</guid>
            <pubDate>Mon, 18 May 2020 20:02:31 GMT</pubDate>
            <description><![CDATA[css中position: absolute可以将元素指定为绝对定位，那么绝对定位元素的几何位置是相对于谁计算呢？]]></description>
            <content:encoded><![CDATA[<p>css中position: absolute可以将元素指定为绝对定位，那么绝对定位元素的几何位置是相对于谁计算呢？</p>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/position#Absolute_positioning" target="_blank" rel="noopener noreferrer" class="">MDN</a>上的描述是：</p>
<blockquote>
<p>绝对定位元素相对于最近的非 static 祖先元素定位。当这样的祖先元素不存在时，则相对于ICB（inital container block, 初始包含块）。</p>
</blockquote>
<p>也即是说，绝对定位元素应该相对其position为非static的最近祖先定位，或者这样的祖先不存在时相对初始包含快（一般为body）定位。而position默认为static。</p>
<p>但似乎有时候也有例外。</p>
<p>今天想在一个scroller组件中使用绝对定位突破到更顶层，但意外的发现，即使从该元素的父元素到body都没有指定<code>position</code>属性，它竟然仍是相对scroller容器定位而不是body或者更上层的具有<code>position: relative</code>属性的元素。</p>
<p>实验了半天发现是因为scroller使用了css的<code>transform</code>属性来变换滚动元素的位置以提升性能。而这直接导致了具有有效<code>transform</code>属性的元素成了绝对定位元素的基准。</p>
<p>考虑如下html：</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag special-attr attr-name" style="color:#00a4db">style</span><span class="token tag special-attr attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag special-attr attr-value value css language-css property" style="color:#36acaa">line-height</span><span class="token tag special-attr attr-value value css language-css punctuation" style="color:#393A34">:</span><span class="token tag special-attr attr-value value css language-css" style="color:#e3116c"> </span><span class="token tag special-attr attr-value value css language-css number" style="color:#36acaa">50</span><span class="token tag special-attr attr-value value css language-css unit" style="color:#e3116c">px</span><span class="token tag special-attr attr-value value css language-css punctuation" style="color:#393A34">;</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">style</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">        </span><span class="token style language-css selector class" style="color:#00009f">.relative-container</span><span class="token style language-css"> </span><span class="token style language-css punctuation" style="color:#393A34">{</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">            </span><span class="token style language-css property" style="color:#36acaa">background</span><span class="token style language-css punctuation" style="color:#393A34">:</span><span class="token style language-css"> </span><span class="token style language-css color">lightcoral</span><span class="token style language-css punctuation" style="color:#393A34">;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">            </span><span class="token style language-css property" style="color:#36acaa">position</span><span class="token style language-css punctuation" style="color:#393A34">:</span><span class="token style language-css"> relative</span><span class="token style language-css punctuation" style="color:#393A34">;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">            </span><span class="token style language-css property" style="color:#36acaa">height</span><span class="token style language-css punctuation" style="color:#393A34">:</span><span class="token style language-css"> </span><span class="token style language-css number" style="color:#36acaa">300</span><span class="token style language-css unit">px</span><span class="token style language-css punctuation" style="color:#393A34">;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">        </span><span class="token style language-css punctuation" style="color:#393A34">}</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">        </span><span class="token style language-css selector class" style="color:#00009f">.midware</span><span class="token style language-css"> </span><span class="token style language-css punctuation" style="color:#393A34">{</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">            </span><span class="token style language-css property" style="color:#36acaa">background</span><span class="token style language-css punctuation" style="color:#393A34">:</span><span class="token style language-css"> </span><span class="token style language-css color">lightcyan</span><span class="token style language-css punctuation" style="color:#393A34">;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">            </span><span class="token style language-css property" style="color:#36acaa">height</span><span class="token style language-css punctuation" style="color:#393A34">:</span><span class="token style language-css"> </span><span class="token style language-css number" style="color:#36acaa">200</span><span class="token style language-css unit">px</span><span class="token style language-css punctuation" style="color:#393A34">;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">        </span><span class="token style language-css punctuation" style="color:#393A34">}</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">        </span><span class="token style language-css selector class" style="color:#00009f">.absolute-block</span><span class="token style language-css"> </span><span class="token style language-css punctuation" style="color:#393A34">{</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">            </span><span class="token style language-css property" style="color:#36acaa">background</span><span class="token style language-css punctuation" style="color:#393A34">:</span><span class="token style language-css"> </span><span class="token style language-css color">black</span><span class="token style language-css punctuation" style="color:#393A34">;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">            </span><span class="token style language-css property" style="color:#36acaa">height</span><span class="token style language-css punctuation" style="color:#393A34">:</span><span class="token style language-css"> </span><span class="token style language-css number" style="color:#36acaa">30</span><span class="token style language-css unit">px</span><span class="token style language-css punctuation" style="color:#393A34">;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">            </span><span class="token style language-css property" style="color:#36acaa">position</span><span class="token style language-css punctuation" style="color:#393A34">:</span><span class="token style language-css"> absolute</span><span class="token style language-css punctuation" style="color:#393A34">;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">            </span><span class="token style language-css property" style="color:#36acaa">top</span><span class="token style language-css punctuation" style="color:#393A34">:</span><span class="token style language-css"> </span><span class="token style language-css number" style="color:#36acaa">0</span><span class="token style language-css punctuation" style="color:#393A34">;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">            </span><span class="token style language-css property" style="color:#36acaa">width</span><span class="token style language-css punctuation" style="color:#393A34">:</span><span class="token style language-css"> </span><span class="token style language-css number" style="color:#36acaa">30</span><span class="token style language-css unit">px</span><span class="token style language-css punctuation" style="color:#393A34">;</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">        </span><span class="token style language-css punctuation" style="color:#393A34">}</span><span class="token style language-css"></span><br></div><div class="token-line" style="color:#393A34"><span class="token style language-css">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">style</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">class</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">relative-container</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ------把下面的div撑下去一点方便观察差异-------</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">class</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">midware</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">class</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">absolute-block</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></div></code></pre></div></div>
<div style="line-height:50px" class="-without-transform">
    <style>.-without-transform .relative-container{background:#f08080;height:300px;position:relative}.-without-transform .midware{background:#e0ffff;height:200px}.-without-transform .absolute-block{background:#000;width:30px;height:30px;position:absolute;top:0}</style>
    <div class="relative-container">
        ------把下面的div撑下去一点-------
        <div class="midware">
            <div class="absolute-block"></div>
        </div>
    </div>
    
</div>
<br>
<p>如上，<code>absolute-block</code>成功突破了<code>midware</code>，<code>top: 0</code>是相对于<code>relative-container</code>而不是其直接父元素<code>midware</code>。但是当我们为<code>midware</code>添加transform属性后：</p>
<div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token selector class" style="color:#00009f">.midware</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">background</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token color">lightcyan</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">height</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token unit">px</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">transform</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">translateZ</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<div style="line-height:50px" class="-with-transform">
    <style>.-with-transform .relative-container{background:#f08080;height:300px;position:relative}.-with-transform .midware{background:#e0ffff;height:200px;transform:translateZ(0)}.-with-transform .absolute-block{background:#000;width:30px;height:30px;position:absolute;top:0}</style>
    <div class="relative-container">
        ------把下面的div撑下去一点-------
        <div class="midware">
            <div class="absolute-block"></div>
        </div>
    </div>
</div>
<br>
<p><code>absolute-block</code>已经相对其父元素<code>midware</code>定位了！但<code>midware</code>的<code>position</code>并没有被显示指定。transform设置为其他有效值效果也一样。</p>
<p>为了测试transform属性是否隐式改变了position属性，我添加了如下代码：</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> el </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">querySelector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.midware'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getComputedStyle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">el</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">position</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// static</span><br></div></code></pre></div></div>
<p>并没有。这个现象应该是由其他机制引起的。</p>
<p>最后查了下资料，有人说是由层叠上下文导致的。但又不是所有的层叠上下文都会造成这样的影响，不同内核的浏览器也有不同的表现。所以应该将这个特性当作bug来对待？</p>
<p>参考：<br>
<a href="https://www.cnblogs.com/coco1s/p/7358830.html" target="_blank" rel="noopener noreferrer" class="">不受控制的 position:fixed</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[JS省略分号导致的灾难]]></title>
            <link>https://blog.mattuy.top/archives/dizaster-from-ignored-js-semi-colon</link>
            <guid>https://blog.mattuy.top/archives/dizaster-from-ignored-js-semi-colon</guid>
            <pubDate>Tue, 05 May 2020 16:25:46 GMT</pubDate>
            <description><![CDATA[挺长一段时间在纠结写JavaScript代码要不要打分号。这是一个个人风格问题，以下观点仅代表个人喜好。]]></description>
            <content:encoded><![CDATA[<p>挺长一段时间在纠结写JavaScript代码要不要打分号。这是一个个人风格问题，以下观点仅代表个人喜好。</p>
<p><strong>不要省略分号！不要省略分号！不要省略分号！</strong></p>
<p>虽然js引擎执行代码时会自动插入分号，但有些时候省略分号可能导致一些隐蔽的问题。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="return语句">return语句<a href="https://blog.mattuy.top/archives/dizaster-from-ignored-js-semi-colon#return%E8%AF%AD%E5%8F%A5" class="hash-link" aria-label="return语句的直接链接" title="return语句的直接链接" translate="no">​</a></h2>
<p>return后面会被自动插入分号，所以下面的代码返回undefined而不是一个字符串。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">foo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"this will return undefined"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>当然，这完全可以避免，我们可以将返回值写在一行或者用括号包起来。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">foo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"this is ok."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>似乎这点也不是不省略分号就能避免的，如果您不清楚这条规则，下面的代码可能会带来疑惑：</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">foo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">       </span><span class="token string" style="color:#e3116c">'a long expresion'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">       </span><span class="token string" style="color:#e3116c">'another long expresion'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">foo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// undefined</span><br></div></code></pre></div></div>
<p>OK，这不是重点，事实上现代编辑器足够聪明，这样的情况应该会将return后面的语句给你标注为灰色，你很容易就可以看到它们没有正确的被执行。这里只是顺带一提。我们来看更隐蔽的坑。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="函数执行">函数执行<a href="https://blog.mattuy.top/archives/dizaster-from-ignored-js-semi-colon#%E5%87%BD%E6%95%B0%E6%89%A7%E8%A1%8C" class="hash-link" aria-label="函数执行的直接链接" title="函数执行的直接链接" translate="no">​</a></h2>
<p>考虑下面的代码：</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> bar </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">foobar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'some condition'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'another condition'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> bar </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> bar</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">foobar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>请问上面的代码输出什么？答案是<code>0 -1</code></p>
<p>我们的本意是在两个条件满足时给<code>foo</code>变量赋值-1，否则给<code>bar</code>变量赋值-1。这里本该输出<code>-1 1</code>，但由于语句以括号开头，js执行引擎误以为上一行的语句还没有结束，正好<code>foobar()</code>返回了一个函数，于是上面的代码相当于（为了更清晰我引入了一个变量）：</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> condition </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">foobar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'some condition'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'another condition'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">condition </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> bar </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p><code>foobar()</code>返回的函数总是返回false，所以被赋值的总是<code>bar</code>变量，这完全改变了我们的初衷！而且编辑器不会有提示：没有语法错误。甚至运行时也不会直接出错，而是在某个case下才命中bug。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="解构赋值">解构赋值<a href="https://blog.mattuy.top/archives/dizaster-from-ignored-js-semi-colon#%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC" class="hash-link" aria-label="解构赋值的直接链接" title="解构赋值的直接链接" translate="no">​</a></h2>
<p>接下来是我今天亲身经历的的场景。</p>
<p>ES2015（ES6）新增了一个解构赋值的特性，用于交换两个变量的值那是非常的方便。例如交换a，b变量的值：<code>[a, b] = [b, a]</code>。当然解构赋值还有很多其他特性，可以参考<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment" target="_blank" rel="noopener noreferrer" class="">MDN</a>。</p>
<p>考虑如下代码：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">var m = n = 0;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">var swap = -1;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">var matrix = [</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [1, 2],</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [3, 4]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">];</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">//do something...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[matrix[m][n], swap] = [swap, matrix[m][n]]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[m, n] = [n, m]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">console.log(matrix) // [[0, 2], [3, 4]]</span><br></div></code></pre></div></div>
<p>OK，我们不用管代码是要做什么，反正就是想交换<code>matrix[m][n]</code>和<code>swap</code>的值，再交换<code>m</code>和<code>n</code>。期望的输出应该是<code>[[-1, 2], [3, 4]]</code>。然鹅...</p>
<p>事实上在写这篇博客之前我是赞成省略分号的。前面两种情况我都习惯性会注意避免，也没出过类似的错误。但终于还是不留神栽在了解构赋值上。</p>
<p>还是解释一下，上面的解构赋值语句等价于：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[matrix[m][n], swap] = [swap, matrix[m][n]][m, n] = [n, m]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">//不太清晰？由于m == n == 0，逗号表达式m,n的值为0，所以再等价于：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[matrix[m][n], swap] = [swap, matrix[m][n]]   [0] = [n, m]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">//即</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[matrix[m][n], swap] = swap = [n, m]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">//即</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[matrix[m][n], swap] = [n, m]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">//即</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">maxtrix[0][0] = 0;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">swap = 0;</span><br></div></code></pre></div></div>
<p>同样，由于没有语法错误，IDE同样不会检测到。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://blog.mattuy.top/archives/dizaster-from-ignored-js-semi-colon#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>暂时没有遇到其他情况，不过有时候是防不胜防。咱一朝被蛇咬，十年怕井绳。添上分号他不香嘛。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[webpack模块加载机制]]></title>
            <link>https://blog.mattuy.top/archives/webpack-module-loading</link>
            <guid>https://blog.mattuy.top/archives/webpack-module-loading</guid>
            <pubDate>Sun, 26 Apr 2020 22:38:06 GMT</pubDate>
            <description><![CDATA[前端项目的规模越来越庞大，模块化开发已经是普遍需求。早期的打包工具将所有模块化的代码打包到一个bundle文件中，在一个简单的html文件中引入脚本。webpack允许输出为多个bundle文件，从而实现按需加载，更好的利用浏览器缓存，提升用户体验。]]></description>
            <content:encoded><![CDATA[<p>前端项目的规模越来越庞大，模块化开发已经是普遍需求。早期的打包工具将所有模块化的代码打包到一个bundle文件中，在一个简单的html文件中引入脚本。webpack允许输出为多个bundle文件，从而实现按需加载，更好的利用浏览器缓存，提升用户体验。</p>
<p>这里不讨论如何配置webpack，只说webpack如何加载模块。考虑一个多页面程序，有page1和page2两个页面，都用到一个工具模块util，page1直接引用util，而page2在页面加载后满足一定条件时动态加载util。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">//util.js</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'util'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">arg</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arg</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">//page1.js</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> log </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./util'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'page1'</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">//page2.js</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//条件满足时动态加载util</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'./util'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">util</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    util</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'page2'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>首先明确webpack中的两个概念：</p>
<ul>
<li class="">module：一般是源代码中的一个文件，打包后被包裹在一个函数中，webpack模拟了模块环境</li>
<li class="">chunk：一个chunk即一个输出bundle文件，不考虑其它分割规则，每个入口将产出一个chunk。一个chunk包含若干module</li>
</ul>
<p>假设我们已经配置好webpack，让它输出三个chunk：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">0.js		//util.js</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">page1.js	//页面1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">page2.js	//页面2</span><br></div></code></pre></div></div>
<p>下面从webpack的打包输出来分析webpack模块加载机制。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="静态依赖">静态依赖<a href="https://blog.mattuy.top/archives/webpack-module-loading#%E9%9D%99%E6%80%81%E4%BE%9D%E8%B5%96" class="hash-link" aria-label="静态依赖的直接链接" title="静态依赖的直接链接" translate="no">​</a></h2>
<p>webpack中，一个js源文件作为一个模块（也可以是其他文件）。webpack将模块代码包裹在一个函数中，返回模块的导出内容。注意，每个模块最多仅被执行一次，第二次请求时会直接从缓存返回。</p>
<p>（打包后的）page1.js：</p>
<div class="language-JavaScript language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">//立即执行函数初始化webpack运行时，然后加载入口模块</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">modules</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//modules是被打包到page1.js这个文件(chunk)中的模块列表，此处有page1和util两个模块</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//已加载的模块的缓存</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> installedModules </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// webpack require函数，用来加载模块</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">__webpack_require__</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">moduleId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//检查模块是否已装载，是则返回缓存的模块</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">installedModules</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">moduleId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> installedModules</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">moduleId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//将模块添加到缓存</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> module </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> installedModules</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">moduleId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token literal-property property" style="color:#36acaa">i</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> moduleId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//模块ID</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token literal-property property" style="color:#36acaa">l</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">       </span><span class="token comment" style="color:#999988;font-style:italic">//模块是否已装载</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token literal-property property" style="color:#36acaa">exports</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">     </span><span class="token comment" style="color:#999988;font-style:italic">//模块的导出内容</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 执行模块初始化</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        modules</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">moduleId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">     </span><span class="token comment" style="color:#999988;font-style:italic">//将模块代码的this指向其自己的exports</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            module</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">             </span><span class="token comment" style="color:#999988;font-style:italic">//相当于commonjs中的module，对模块自身的引用</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">     </span><span class="token comment" style="color:#999988;font-style:italic">//相当于commonjs中的exports，模块的导出内容</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            __webpack_require__ </span><span class="token comment" style="color:#999988;font-style:italic">//相当于commonjs中的require，提供加载同一chunk中其他模块的方法</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 将模块标识为已加载</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">l</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 返回模块的导出内容</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//加载入口模块，即我们的page1.js</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">__webpack_require__</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__webpack_require__</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">s</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./src/page1.js"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//page1模块</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">"./src/page1.js"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">module</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> __webpack_exports__</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> __webpack_require__</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> util </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">__webpack_require__</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'./src/util.js'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            util</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'page1'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//util模块</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">"./src/util.js"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">module</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> __webpack_exports__</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> __webpack_require__</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">log</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">arg</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arg</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//util模块导出log函数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            __webpack_exports__</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'log'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> log</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>代码被我简化了一下，webpack有很多兼容性和安全性方面的考虑，我将那部分修改了让代码看起来清晰。</p>
<p>可以看到，util和page1被函数包围，模拟模块环境，然后作为参数传递给立即执行函数。注意，模块只有被加载时才会执行内部代码。</p>
<p>在立即执行函数中，先进行了webpack初始化，即提供核心的模块加载函数__webpack_require__函数，并在函数上配置一些静态字段记录必要的信息（如__webpack_require__.s为入口模块ID），然后装入入口模块，开始执行我们自己的逻辑代码。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="按需加载">按需加载<a href="https://blog.mattuy.top/archives/webpack-module-loading#%E6%8C%89%E9%9C%80%E5%8A%A0%E8%BD%BD" class="hash-link" aria-label="按需加载的直接链接" title="按需加载的直接链接" translate="no">​</a></h2>
<p>在page2中我们使用了动态import()方法来加载util模块。webpack足够智能，无需配置它也聪明的自动将util独立到单独的文件（chunk），在需要时再进行请求。</p>
<p>webpack通过<a href="https://www.runoob.com/json/json-jsonp.html" target="_blank" rel="noopener noreferrer" class="">jsonp</a>机制加载不同chunk中的模块。</p>
<p>page2.js：</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">modules</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//模块加载函数，同page1。注意，此函数仅用于加载已被</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">__webpack_require__</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">moduleId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//......</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//可用的模块列表，包含本chunk中的模块和已经请求完毕的，来自其他chunk的模块</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    __webpack_require__</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">m</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> modules</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//基路径，用于拼接其他chunk的url</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    __webpack_require__</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">p</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//已装载的模块缓存，注意区分__webpack_require__.m，前者应该是后者的子集</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> installedModules </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//这是相对page1中多出来的东西，用来记录其他chunk的加载情况</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//值可能有3种：</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//    undefined, 即该chunk还没有被请求过</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//    0, 该chunk中的模块已经正确的添加到__webpack_require__.m中，可以通过__webpack_require__加载了</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//    [resolve, reject, promise], chunk正在请求中。promise在chunk请求结束后才被resolve或reject</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> installedChunks </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string-property property" style="color:#36acaa">"page2"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">//page2即页面2的chunk自身，当然已经加载完成</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//jsonp函数，chunk请求成功时由被请求的chunk调用。它的任务为将chunk中的模块加入可用模块列表</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//data参数由被请求的chunk传过来，包含模块信息。这也是jsonp的核心部分</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">webpackJsonpCallback</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> chunkIds </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> moreModules </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> moduleId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> chunkId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> resolves </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> chunkIds</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            chunkId </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> chunkIds</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">hasOwnProperty</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">installedChunks</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> chunkId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> installedChunks</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">chunkId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                resolves</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">installedChunks</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">chunkId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//表示chunk已经加载好啦，下次不用去请求了</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            installedChunks</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">chunkId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">moduleId </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> moreModules</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">hasOwnProperty</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">moreModules</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> moduleId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">//把chunk中的模块们加入可用列表（__webpack_require__.m == modules √）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                modules</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">moduleId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> moreModules</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">moduleId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//原数组的push函数，详见后文</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parentJsonpFunction</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">parentJsonpFunction</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//resolve请求时创建的promise，执行回调</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">while</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">resolves</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            resolves</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">shift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//异步请求chunk</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    __webpack_require__</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">e</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">requireEnsure</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">chunkId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> promises </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> installedChunkData </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> installedChunks</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">chunkId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//检查chunk是否已经加载。0表示已加载</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">installedChunkData </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//正在加载...有点不清楚为啥要重复记录一次promise？</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">installedChunkData</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">//installedChunkData[2]是之前请求的promise</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                promises</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">installedChunkData</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">//没有请求过，开始请求chunk</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">//标识chunkId这个chunk正在请求，并记录promise相关信息</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> promise </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Promise</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">resolve</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> reject</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    installedChunkData </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> installedChunks</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">chunkId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">resolve</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> reject</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                promises</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">installedChunkData</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> promise</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">//现在installedChunks[chunkId] = [resolve, reject, promise]了</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">//用script标签加载chunk</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> script </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createElement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'script'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> onScriptComplete</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                script</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">charset</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'utf-8'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                script</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">timeout</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">120</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                script</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">src</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">jsonpScriptSrc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">chunkId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">//...请求错误处理...省略</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">//...超时处理</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> timeout </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">120000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">appendChild</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">script</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token known-class-name class-name">Promise</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">all</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">promises</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//拼接被请求chunk的url</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">jsonpScriptSrc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">chunkId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> __webpack_require__</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">p</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">chunkId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">||</span><span class="token plain">chunkId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">".js"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//通过window.webpackJsonp数组记录加载成功的chunk数据。其他chunk被加载后会将自己的chunk数据push到这个数组</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> jsonpArray </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"webpackJsonp"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"webpackJsonp"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//注意，webpack覆盖了window.webpackJsonp数组的push函数。将原生的push函数替换成了webpackJsonpCallback</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//在webpackJsonpCallback函数中我们看到有调用parentJsonpFunction，其实那个函数才是原来的数组的push函数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> oldJsonpFunction </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> jsonpArray</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">jsonpArray</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    jsonpArray</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">push</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> webpackJsonpCallback</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//理论上说这时jsonpArray应该是空的。。但如果不是空的就手动调用下webpackJsonpCallback装载chunk</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//window["webpackJsonp"]已经被webpack污染啦，所以它复制了一下？</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    jsonpArray </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> jsonpArray</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">slice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> jsonpArray</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">webpackJsonpCallback</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">jsonpArray</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> parentJsonpFunction </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> oldJsonpFunction</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//加载入口模块</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">__webpack_require__</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__webpack_require__</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">s</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./src/page2.js"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//页面2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">"./src/page2.js"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">module</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> exports</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> __webpack_require__</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//我们的动态import()被webpack转化后大致代码</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//先请求包含util的chunk</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        __webpack_require__</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">e</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//请求成功之后通过__webpack_require__加载util模块</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__webpack_require__</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//执行我们自己的逻辑代码</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">util</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                util</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'page2'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>代码仍然有点长，不过已经删除和修改了很多边缘代码，并且调整了一下顺序，结构比较清晰了。代码中的注释解释了整个模块加载过程。先通过jsonp请求得到chunk数据，然后缓存chunk中的模块到可用列表（未装载），这时同步的模块加载已经可用，直接调用__webpack_require__加载相关模块，步骤就和page1一样了。</p>
<p>被加载的chunk结构就很简单了，只是简单的调用jsonp函数传入模块数据。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">//0.js</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//注意，前面说了，window["webpackJsonp"]数组的push函数被webpack重写了</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//所以实际上这里调用了主模块那边定义的webpackJsonpCallback函数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//一个chunk可能包含多个模块，所以参数为 [moduleIds],moreModules</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"webpackJsonp"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"webpackJsonp"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string-property property" style="color:#36acaa">"./src/util.js"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">module</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> __webpack_exports__</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> __webpack_require__</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token string" style="color:#e3116c">"use strict"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            __webpack_exports__</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'log'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">arg</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arg</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://blog.mattuy.top/archives/webpack-module-loading#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>当项目规模增长到一定程度，模块化已是刚需。在ESModule标准制定之前广泛使用的模块化标准有commonjs，AMD，以及综合两者的UMD等。在ES6中模块化终于得到标准的支持，然而各平台对其的支持有限，暂时还难以替代传统解决方案。万幸，webpack提供了综合各种模块化标准的机制，让我们能够平稳的过渡。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[LeetCode之旅——字母异位词分组（Group Anagrams）]]></title>
            <link>https://blog.mattuy.top/archives/leetcode-group-anagrams</link>
            <guid>https://blog.mattuy.top/archives/leetcode-group-anagrams</guid>
            <pubDate>Wed, 08 Apr 2020 13:57:57 GMT</pubDate>
            <description><![CDATA[题目]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="题目">题目<a href="https://blog.mattuy.top/archives/leetcode-group-anagrams#%E9%A2%98%E7%9B%AE" class="hash-link" aria-label="题目的直接链接" title="题目的直接链接" translate="no">​</a></h2>
<p>给定一个字符串数组，要求将相同字母组成的字符串分组返回。字符串只由小写字母组成。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">示例：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Input: ["eat", "tea", "tan", "ate", "nat", "bat"],</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Output:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ["ate","eat","tea"],</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ["nat","tan"],</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ["bat"]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">]</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="思路一">思路一<a href="https://blog.mattuy.top/archives/leetcode-group-anagrams#%E6%80%9D%E8%B7%AF%E4%B8%80" class="hash-link" aria-label="思路一的直接链接" title="思路一的直接链接" translate="no">​</a></h2>
<p>将输入的每个字符串拆成字符排序，然后利用Map分组。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></div><div class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@param</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">string</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">[</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">]</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment parameter" style="color:#999988;font-style:italic">strs</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"></span><br></div><div class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@return</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">string</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">[</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">]</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">[</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">]</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"></span><br></div><div class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">groupAnagrams</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">strs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> map </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> strs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> key </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> strs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">split</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">has</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">concat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">strs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">strs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token known-class-name class-name">Array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword module" style="color:#00009f">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">values</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="思路二">思路二<a href="https://blog.mattuy.top/archives/leetcode-group-anagrams#%E6%80%9D%E8%B7%AF%E4%BA%8C" class="hash-link" aria-label="思路二的直接链接" title="思路二的直接链接" translate="no">​</a></h2>
<p>由于字符串限定只由小写字母组成，可以构建一个长为26的“桶”，每一格存储对应的字母出现的次数。这样，每个字符串都被转化为一个这样的桶。然后把“桶”重新转为字符串，作为Map的键对原字符串数组进行分组。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></div><div class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@param</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">string</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">[</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">]</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment parameter" style="color:#999988;font-style:italic">strs</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"></span><br></div><div class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> * </span><span class="token doc-comment comment keyword" style="color:#00009f;font-style:italic">@return</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"> </span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">{</span><span class="token doc-comment comment class-name" style="color:#999988;font-style:italic">string</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">[</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">]</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">[</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">]</span><span class="token doc-comment comment class-name punctuation" style="color:#393A34;font-style:italic">}</span><span class="token doc-comment comment" style="color:#999988;font-style:italic"></span><br></div><div class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">groupAnagrams</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">strs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> list </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> str </span><span class="token keyword" style="color:#00009f">of</span><span class="token plain"> strs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//为每个字符串构造一个“桶”</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> layer </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> s </span><span class="token keyword" style="color:#00009f">of</span><span class="token plain"> str</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> s</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">charCodeAt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> layer</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">c </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0x60</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> value </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> value </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            layer</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">c </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0x60</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> value</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        list</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">layer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">' '</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//把桶字符串化后作为key对原数组进行分组</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> res </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> list</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">has</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">list</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">list</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">list</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">concat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">strs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">list</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">strs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token known-class-name class-name">Array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword module" style="color:#00009f">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">values</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://blog.mattuy.top/archives/leetcode-group-anagrams#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>思路一更简洁，但排序可能会消耗更多的时间。思路二利用了桶排序的思想，将排序复杂度降到了线性复杂度。在字符串较长时思路二应该会表现更好。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[彻底搞懂JavaScript怪异函数——bind]]></title>
            <link>https://blog.mattuy.top/archives/javascript-exotic-function-bind</link>
            <guid>https://blog.mattuy.top/archives/javascript-exotic-function-bind</guid>
            <pubDate>Thu, 26 Mar 2020 22:22:31 GMT</pubDate>
            <description><![CDATA[2020.4.30]]></description>
            <content:encoded><![CDATA[<p>2020.4.30
事实上存在<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new.target" target="_blank" rel="noopener noreferrer" class="">new.target</a>这个变量，在函数中会指向构造函数。如果不是以new操作符调用的构造函数，new.target为undefined。因此我们可以通过new.target判断函数是否是new操作符调用。不过各浏览器对bind的支持比对new.target要早，所以在bind函数的polyfill中使用new.target可能不太合适。</p>
<hr>
<p>我们可能遇到过实现bind函数这样的题目，但似乎并不存在完美模拟原生bind函数的可能。ECMAScript 2015中将bind创建的函数称为exotic function object（怪异函数对象），这很适宜，因为它的确存在一些“怪异”之处。</p>
<p>在继续之前我们需要先了解bind函数。这可以参考<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind" target="_blank" rel="noopener noreferrer" class="">MDN</a>的解释：<br>
<code>bind()</code> 方法创建一个新的函数，在 <code>bind()</code> 被调用时，这个新函数的 <code>this</code> 被指定为 <code>bind()</code> 的第一个参数，而其余参数将作为新函数的参数，供调用时使用。</p>
<p>另外还需要了解<code>new</code>操作符的实现，同样参考MDN的解释：</p>
<ol>
<li class="">创建一个空的简单JavaScript对象（即<code>{}</code>）；</li>
<li class="">链接该对象（即设置该对象的构造函数）到另一个对象；</li>
<li class="">将步骤1新创建的对象作为<code>this</code>的上下文 ；</li>
<li class="">如果该函数没有返回对象，则返回<code>this</code>。</li>
</ol>
<p>第2步即为对象绑定隐式原型，将对象的__proto__属性指向构造函数的prototype，而函数默认的prototype拥有constructor属性指向构造函数，从而实现了所谓的“链接构造函数”。</p>
<p>这里约定一下，<code>bind()</code>方法的实现函数叫<strong>bind函数</strong>，创建的新函数叫做<strong>绑定函数</strong>，被封装的原函数叫做<strong>原函数</strong>。</p>
<p>bind函数至少有这些特性：</p>
<ol>
<li class="">除非是被<code>new</code>操作符调用，否则原函数执行环境中的this总是为bind函数被调用时传递的第一个参数；</li>
<li class="">绑定函数的prototype为<code>undefined</code>；</li>
<li class="">通过<code>new</code>操作符调用绑定函数时，原函数执行环境的this仍为<code>new</code>操作符创建的新对象，即bind函数的this绑定被忽略；</li>
<li class="">通过<code>new</code>操作符调用绑定函数返回的对象是原函数的实例。即：
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> fBound </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> func</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">fBound</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">foo </span><span class="token keyword" style="color:#00009f">instanceof</span><span class="token plain"> </span><span class="token class-name">func</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// true</span><br></div></code></pre></div></div>
</li>
</ol>
<p>MDN推荐的bind函数的<a href="https://github.com/Raynos/function-bind/blob/master/implementation.js" target="_blank" rel="noopener noreferrer" class="">Polyfill</a>如下（部分）：</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token class-name">Function</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">bind</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">that</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> target </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">//原函数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> args </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">slice</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arguments</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//绑定参数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> bound</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//绑定函数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//实际上binder才是绑定函数，bound将其再次包装后返回</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">binder</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">instanceof</span><span class="token plain"> </span><span class="token class-name">bound</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//如果是通过new操作符调用的绑定函数，则绑定函数执行环境的this指向new操作符创建的新对象，而这个对象的隐式原型指向构造函数bound的prototype</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//new操作符调用，忽略bind函数绑定的this，以实际执行环境this调用原函数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">apply</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">concat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arguments</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">//如果构造函数返回的是一个对象，返回该对象</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//非new操作符调用，使用绑定的this</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">apply</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                that</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">concat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arguments</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//计算bind函数调用时提供的绑定参数数量</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> boundLength </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">Math</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> args</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> boundArgs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> boundLength</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        boundArgs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'$'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//相当于返回binder。之所以用函数再包一层，应该是为了使函数的length拥有正确的值</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    bound </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'binder'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'return function ('</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> boundArgs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">','</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'){ return binder.apply(this,arguments); }'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">binder</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//调整原型链，使绑定函数的实例仍然是能通过原函数的原型链检测（因为绑定函数实例的隐式原型（__proto__）的隐式原型指向原函数的prototype）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//如果原函数没有prototype，则绑定函数具有默认prototype，且不会被外界访问到（除非通过绑定函数的prototype属性）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//构造一个临时的空函数，防止绑定函数的prototype直接引用原函数的prototype。因为原函数的prototype对外界可见，具有不确定性。如果绑定函数被调用时传递一个隐式原型指向原函数prototype的this参数，直接引用原函数就会造成误判为new操作符调用</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> </span><span class="token function-variable function maybe-class-name" style="color:#d73a49">Empty</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Empty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//绑定函数.prototype-&gt;空函数实例；空函数实例.__proto__-&gt;原函数prototype</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//从而实现了，通过new得到的绑定函数实例的原型链上有原函数的prototype（文章开头的特性4），但隐式原型为原函数prototype的对象不是绑定函数的实例，因为绑定函数的原型是一个内部的对象（Empty实例），不太可能作为外部某对象的隐式原型（除非是绑定函数被当作了构造函数[new操作]），从而在前面的binder函数中，根据判断绑定函数执行环境的this是否是绑定函数的实例，正确的判断出是否为new操作符调用的绑定函数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//当然这里的漏洞是，绑定函数的prototype并不是完全不可访问的，因为绑定函数是公开的，从而绑定函数的prototype也就可访问了。但这一般不会出问题，除非你写一些奇怪的代码（后面有分析到）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Empty</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        bound</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Empty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Empty</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> bound</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>上面的实现已经接近完美了，几乎也没有更好的实现方案了。我们来看看它实现了文章开头列出的哪些特性。</p>
<p>特性2，绑定函数的prototype为undefined。其实这个很容易实现，但为了实现识别new操作符，只好让绑定函数拥有prototype。幸运的是，这对实际使用几乎没有影响。</p>
<p>特性3，通过new操作符调用绑定函数时忽略bind函数绑定的this。OK，通过new调用时一定可以识别到。</p>
<p>特性4，new操作符调用绑定函数返回的对象是原函数的实例。已实现，虽然原型链上多了一个节点，但并不影响原型链判断。
原生bind函数实例的原型链：原函数prototype-&gt;Object.prototype-&gt;undefined
polyfill实现的bind函数实例的原型链：内部临时函数Empty.prototype-&gt;原函数prototype-&gt;Object.prototype-&gt;undefined</p>
<p>特性1就耐人寻味了，显然关键在于对new操作符调用的精确判断。如果是new操作符调用，显然绑定函数执行环境的this即绑定函数的实例，会被当做new操作符调用对待（忽略bind函数绑定的this）。但非new操作符调用的情况，是否一定能够被当作一般情况对待？考虑下面的代码：</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">foo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> obj </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> bar </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> foo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">obj</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> mock </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">bar</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> bar</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">bar</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mock</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Jack'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">obj</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> alice </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">bar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Alice'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">obj</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">alice</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mock</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>理想的输出是：</p>
<blockquote>
<p>Jack
Jack
Alice
[Object: null prototype]</p>
</blockquote>
<p>原生bind函数的输出符合预测，但polyfill实现的版本输出：</p>
<blockquote>
<p>undefined
undefined
Alice
foo { name: 'Jack' }</p>
</blockquote>
<p><code>bar.call(Object.create(bar.prototype), 'Jack')</code>被当作了new操作符调用。因此绑定函数忽略了绑定的this，而使用了传入的this参数调用原函数，因此原函数中<code>this.name = name</code>，<code>this</code>指向<code>mock</code>，所以赋值操作发生在<code>mock</code>上而非<code>obj</code>。</p>
<p>bind函数被成为怪异对象，怪异就怪异在其内部机制无法完全用合法的JavaScript逻辑模拟（至少我没有找到方法）。不过上面的实现已经可用了，最后的不一致行为其实属于“明知故犯”的怪癖代码，实际生产活动中完全可以杜绝。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="参考">参考<a href="https://blog.mattuy.top/archives/javascript-exotic-function-bind#%E5%8F%82%E8%80%83" class="hash-link" aria-label="参考的直接链接" title="参考的直接链接" translate="no">​</a></h2>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind" target="_blank" rel="noopener noreferrer" class="">https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind</a></p>
<p><a href="https://zhuanlan.zhihu.com/p/38968174" target="_blank" rel="noopener noreferrer" class="">https://zhuanlan.zhihu.com/p/38968174</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[JavaScript微任务与宏任务（浏览器）]]></title>
            <link>https://blog.mattuy.top/archives/javascript-micro-task-and-macro-task</link>
            <guid>https://blog.mattuy.top/archives/javascript-micro-task-and-macro-task</guid>
            <pubDate>Sat, 01 Feb 2020 17:05:58 GMT</pubDate>
            <description><![CDATA[问题描述]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题描述">问题描述<a href="https://blog.mattuy.top/archives/javascript-micro-task-and-macro-task#%E9%97%AE%E9%A2%98%E6%8F%8F%E8%BF%B0" class="hash-link" aria-label="问题描述的直接链接" title="问题描述的直接链接" translate="no">​</a></h2>
<p>最近在用Ionic框架（基于Angular），有这么一个需求：<br>
先调用history.go(-delta)返回到某个页面，再调用Angular的Router#navigate()导航到新的页面。</p>
<p>大致代码如下：</p>
<div class="language-TypeScript language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">go</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">delta</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> url</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    history</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">go</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">delta</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">router</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">navigateByUrl</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">url</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> replaceUrl</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>问题出来了，代码执行后只返回到了之前的页面，并没有正确导航到url参数指定的页面。</p>
<p>原因大概是，Angular监听了popstate事件以响应浏览器的回退操作。然而浏览器的事件触发是异步的，即<code>history.go(delta)</code>执行后，要等到下一轮事件循环Angular才能捕捉到回退事件，并渲染对应的组件。然而这时<code>router.navigateByUrl()</code>已经执行完毕，因此看到的是回退后的页面而不是希望导航到的新页面。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="原理分析">原理分析<a href="https://blog.mattuy.top/archives/javascript-micro-task-and-macro-task#%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90" class="hash-link" aria-label="原理分析的直接链接" title="原理分析的直接链接" translate="no">​</a></h2>
<p>JavaScript的事件循环主要是靠两个队列：宏任务（macro task）队列和微任务（micro task）队列。浏览器按下面的顺序执行队列中的任务：</p>
<!-- -->macro task 1  
    micro task 1  
    micro task 2
    micro task 3
    ......
macro task 2
    micro task 1
    micro task 2
    micro task 3
......
<!-- -->
<p>即，在执行完宏任务后必须执行完当前的所有微任务才能执行下一个宏任务。而浏览器环境下，UI事件是宏任务，Promise#then()是微任务。</p>
<p>当go()函数被执行时，<code>history.go(delta)</code>执行后，popstate事件被推入<strong>宏任务</strong>队列，然后执行<code>navigationByUrl()</code>。Angular的路由导航也是异步的，但在没有<a href="https://angular.cn/guide/router#milestone-5-route-guards" target="_blank" rel="noopener noreferrer" class="">路由守卫</a>的情况下，<code>navigateByUrl()</code>函数发起的整个工作流程都只是微任务（可以认为是一连串立即被resolve的Promise），所以在下一个宏任务被读取之前，新页面的导航已经先于回退操作完成。</p>
<p>go函数执行过程如下：</p>
<!-- -->go
    history.go()
        宏任务队列推入popstate事件
    navigateByUrl()
        微任务队列推入NavigationStart
        ...
...
微任务队列弹出NavigationStart
...
微任务队列推入NavigationEnd
...
微任务队列弹出NavigationEnd，新页面导航完成
...
微任务队列空
...
宏任务弹出popstate事件，解析history.go()回退到的url
渲染回退到的页面
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决方法">解决方法<a href="https://blog.mattuy.top/archives/javascript-micro-task-and-macro-task#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95" class="hash-link" aria-label="解决方法的直接链接" title="解决方法的直接链接" translate="no">​</a></h2>
<p>知道了原理就好解决问题了。只需要等到下一次宏任务再执行新页面的导航就好了。</p>
<div class="language-TypeScript language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">go</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">delta</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> url</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    history</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">go</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">delta</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">router</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">navigateByUrl</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">url</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> replaceUrl</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>注意，setTimeout和setInterval函数创建的都是宏任务。另外，这里说的都是浏览器环境下的JavaScript，部分说法对nodejs并不适用。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Javascript的in操作符]]></title>
            <link>https://blog.mattuy.top/archives/javascript-operator-in</link>
            <guid>https://blog.mattuy.top/archives/javascript-operator-in</guid>
            <pubDate>Tue, 13 Aug 2019 10:23:49 GMT</pubDate>
            <description><![CDATA[javascript的in操作符用于判断某个名称的属性是否存在于某个对象的原型链中。]]></description>
            <content:encoded><![CDATA[<p>javascript的in操作符用于判断某个名称的属性是否存在于某个<strong>对象</strong>的原型链中。</p>
<p>语法：</p>
<blockquote>
<p>prop in object</p>
</blockquote>
<p>prop是string类型或Symbol类型，其他类型会被转化为string，返回值是布尔值，如果object.prop存在则返回true，否则返回false。</p>
<p>需要注意的是，object必须是一个<strong>对象</strong>。最容易被误用的场景是对字符串使用in操作符，这将直接抛出一个异常：</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'length'</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'mystring'</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Uncaught TypeError: Cannot use 'in' operator to search for 'length' in mystring</span><br></div></code></pre></div></div>
<p>如果要判断字符串是否包含另一个字符串，请使用<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/includes" target="_blank" rel="noopener noreferrer" class="">includes方法</a>（ES6）。</p>
<p>参考：<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/in" target="_blank" rel="noopener noreferrer" class="">MDN Operator in</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[.NET 匿名函数引用局部变量导致的问题]]></title>
            <link>https://blog.mattuy.top/archives/dotnet-closure-variable-problem</link>
            <guid>https://blog.mattuy.top/archives/dotnet-closure-variable-problem</guid>
            <pubDate>Sun, 09 Jun 2019 13:43:04 GMT</pubDate>
            <description><![CDATA[问题]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题">问题<a href="https://blog.mattuy.top/archives/dotnet-closure-variable-problem#%E9%97%AE%E9%A2%98" class="hash-link" aria-label="问题的直接链接" title="问题的直接链接" translate="no">​</a></h2>
<p>写C#窗口程序，今天遇到的问题。在工作线程（非UI线程）要操作ListView，因此使用了跨线程调用方式。</p>
<div class="language-c# codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c# codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">for (int i = 0; i &lt; videos.Count; ++i)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">{</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    this.BeginInvoke(new Action(() =&gt;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        var item = lvwVideos.FindItemWithText(videos[i]);</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        if (item != null)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            lvwVideos.Items.Remove(item);</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }));</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>代码一跑给我抛出了异常，数组下标越界。原因分析如下。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="分析">分析<a href="https://blog.mattuy.top/archives/dotnet-closure-variable-problem#%E5%88%86%E6%9E%90" class="hash-link" aria-label="分析的直接链接" title="分析的直接链接" translate="no">​</a></h2>
<p>概念理解错误，C#的闭包环境并不会复制用到的局部变量。</p>
<p>.NET对闭包的实现是在编译阶段而不是运行阶段，事实上，匿名函数中的变量 i 和 for 循环中的i就是<strong>同一个变量</strong>，由于函数返回后变量还会被匿名函数使用，它会保存在堆中而不是调用栈——不管这个变量是值类型还是引用类型（如果是引用类型即对象和对象的引用都在堆中）。</p>
<p>因此，循环结束后 i 的值已经超出数组 videos 的下标范围。而BeginInvoke函数是不等待执行完毕的，因此很可能循环结束而匿名函数还没有执行完毕。<strong>这时匿名函数从堆中取到的 i 已经不是定义匿名函数时 i 的值了。</strong></p>
<p>&nbsp;
用下面的代码来说可能更清晰。</p>
<div class="language-c# codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c# codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">static void Main(string[] args)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">{</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    int i = 1;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Action action = new Action(() =&gt;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Console.WriteLine(i);</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    });</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ++i;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    action();    // 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>action执行的时候访问的 i 和Main函数中的 i 是<strong>同一个</strong>，存储在堆中。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决">解决<a href="https://blog.mattuy.top/archives/dotnet-closure-variable-problem#%E8%A7%A3%E5%86%B3" class="hash-link" aria-label="解决的直接链接" title="解决的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="使用invoke">使用Invoke<a href="https://blog.mattuy.top/archives/dotnet-closure-variable-problem#%E4%BD%BF%E7%94%A8invoke" class="hash-link" aria-label="使用Invoke的直接链接" title="使用Invoke的直接链接" translate="no">​</a></h3>
<p>这里最简单的解决方法是将BeginInvoke改为Invoke。Invoke()会等待UI线程执行完毕才会继续执行，能够保证 i 值不会被工作线程改变。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="模仿js">模仿JS<a href="https://blog.mattuy.top/archives/dotnet-closure-variable-problem#%E6%A8%A1%E4%BB%BFjs" class="hash-link" aria-label="模仿JS的直接链接" title="模仿JS的直接链接" translate="no">​</a></h3>
<p>将上面的代码稍作修改：</p>
<div class="language-C# language-c# codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c# codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">static void Main(string[] args)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">{</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    int i = 1;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Action action = null;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    new Action&lt;int&gt;((n) =&gt;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        action = new Action(()=&gt;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            Console.WriteLine(n);</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    })(i);</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ++i;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    action();    // 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>这相当于将 i 复制了一遍。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[基于Go语言的命令行即时聊天工具——StormChat]]></title>
            <link>https://blog.mattuy.top/archives/stormchat</link>
            <guid>https://blog.mattuy.top/archives/stormchat</guid>
            <pubDate>Sun, 30 Dec 2018 21:51:31 GMT</pubDate>
            <description><![CDATA[简介]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="简介">简介<a href="https://blog.mattuy.top/archives/stormchat#%E7%AE%80%E4%BB%8B" class="hash-link" aria-label="简介的直接链接" title="简介的直接链接" translate="no">​</a></h2>
<p>  前段时间心血来潮想学习最近的明星编程语言Golang。于是想做个聊天小程序实践一下。程序基于TCP协议通信，更详细的设计见<a href="https://blog.mattuy.top/archives/stormchat#design" class="">设计思路</a>。</p>
<p>  用Golang实现了服务端程序，同时代码抄抄改改做了个Golang客户端，又由于输出问题，用C++写了个Windows控制台的简陋的<a href="https://github.com/mattuylee/conctrl" target="_blank" rel="noopener noreferrer" class="">输出控制库</a>，于是客户端在Windows上能看了（不过朋友说很丑&gt;_&lt;）。</p>
<p>  在朋友（<a href="https://github.com/KaniuBillows" target="_blank" rel="noopener noreferrer" class="">@Billows</a>）的鼓励下，我们决定用C#写一个客户端程序，正好他在学习WPF编程，于是界面采用了WPF编写。我负责后台数据交互，他负责前台界面逻辑。</p>
<p>  <strong>C#客户端还使用到了JSON格式化库<a href="https://github.com/JamesNK/Newtonsoft.Json" target="_blank" rel="noopener noreferrer" class="">Newtonsoft.Json</a>，特此说明。</strong></p>
<p>github地址：<a href="https://github.com/mattuylee/stormchat" target="_blank" rel="noopener noreferrer" class="">https://github.com/mattuylee/stormchat</a></p>
<p><a id="design" class="anchorTargetStickyNavbar_Vzrq"></a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="设计思路">设计思路<a href="https://blog.mattuy.top/archives/stormchat#%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF" class="hash-link" aria-label="设计思路的直接链接" title="设计思路的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="通信流程">通信流程<a href="https://blog.mattuy.top/archives/stormchat#%E9%80%9A%E4%BF%A1%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="通信流程的直接链接" title="通信流程的直接链接" translate="no">​</a></h3>
<ol>
<li class="">发送方（客户端或者服务器）发送数据包；</li>
<li class="">接收方（服务器或者客户端）处理数据；</li>
<li class="">如果需要反馈，接收方发送反馈数据包；</li>
<li class="">发送方处理反馈数据（如果有）。</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="通信数据包结构">通信数据包结构<a href="https://blog.mattuy.top/archives/stormchat#%E9%80%9A%E4%BF%A1%E6%95%B0%E6%8D%AE%E5%8C%85%E7%BB%93%E6%9E%84" class="hash-link" aria-label="通信数据包结构的直接链接" title="通信数据包结构的直接链接" translate="no">​</a></h3>
<p>数据通信基于TCP协议，每次通信的数据包应包含【包头域+数据域】。包头域总是JSON格式、UTF-8编码的字符串，数据域由包头决定，可以为空。通信数据包结构如图。</p>
<p><img decoding="async" loading="lazy" src="https://io.mattuy.top/public/blog/2018/stormchat/message.png" alt="stormchat通信规则" class="img_ev3q"></p>
<p>HEAD（包头域）至少包含两个参数：</p>
<ul>
<li class="">Toekn</li>
<li class="">Operation</li>
</ul>
<p>Token参数是一次通信的标识文本，由请求方随机生成，处理方返回数据包的Token参数应和请求方的Token参数一致（如果有返回数据）。</p>
<p>Operation参数指定本次通信的请求。它决定了数据包的其他数据。Operation具体行为定义见<a href="https://github.com/mattuylee/stormchat/blob/master/design/operations.svg" target="_blank" rel="noopener noreferrer" class="">这里</a>。</p>
<p>本来做了设计图表，不过第一次用starUML，画了一半才发现完全是鬼画桃符，没有掌握正确的作图方式，也没什么热情重新画了。因此这里不展示完整的设计文件了（本来也不完整），上面的链接是截取的关键部分（才知道starUML可以导出html文档）。</p>
<p>哦，还有服务器端的数据库结构，见文件<a href="https://github.com/mattuylee/stormchat/blob/master/stormchat-server/res/stormchat.sql" target="_blank" rel="noopener noreferrer" class="">stormchat-server/res/stormchat.sql</a>。</p>
<p><a name="env-config" class=""></a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="环境配置">环境配置<a href="https://blog.mattuy.top/archives/stormchat#%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="环境配置的直接链接" title="环境配置的直接链接" translate="no">​</a></h2>
<p><a name="env-config-dev" class=""></a></p>
<ol>
<li class="">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="开发环境">开发环境<a href="https://blog.mattuy.top/archives/stormchat#%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="开发环境的直接链接" title="开发环境的直接链接" translate="no">​</a></h3>
服务器端：Windows/Linux Golang 1.11<br>
客户端-Go：Windows x64，C++，Golang 1.11<br>
客户端-C#：Windows，.NET4.0，WPF，Newtonsoft.Json for .NET4.0</li>
</ol>
<p><a name="env-config-run" class=""></a></p>
<ol start="2">
<li class="">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="运行环境">运行环境<a href="https://blog.mattuy.top/archives/stormchat#%E8%BF%90%E8%A1%8C%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="运行环境的直接链接" title="运行环境的直接链接" translate="no">​</a></h3>
服务器端：Linux/Windows, MySQL5.5+/MariaDB10.0+<br>
客户端：Windows10 x64（其他平台没测试过）</li>
</ol>
<p><a name="soft-config" class=""></a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="程序配置">程序配置<a href="https://blog.mattuy.top/archives/stormchat#%E7%A8%8B%E5%BA%8F%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="程序配置的直接链接" title="程序配置的直接链接" translate="no">​</a></h2>
<p>由于懒癌发作，一些参数设置只能在编译时指定好，没有运行中指定参数的功能。</p>
<p>Go语言的部分（服务器程序和golang客户端程序）这块都在control.go文件中，C#客户端这边也没什么可配置的，也就是连接服务器的地址和端口。下面列出部分配置参数：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="服务器端">服务器端<a href="https://blog.mattuy.top/archives/stormchat#%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF" class="hash-link" aria-label="服务器端的直接链接" title="服务器端的直接链接" translate="no">​</a></h3>
<ul>
<li class="">
<p><strong>serveMode</strong><br>
服务（后台）模式。如果此参数为true，日志输出到str_log_file参数指定的文件中，且Debug()函数将不输出内容。如果为false，日志输出和Debug()函数都将直接向控制台或终端输出。</p>
</li>
<li class="">
<p>max_head_length<br>
最大包头长度，单位字节，如果包头长度超过此参数将被抛弃。</p>
</li>
<li class="">
<p>max_message_length<br>
最大消息长度，单位字节，如果消息长度超过此参数将被抛弃。</p>
</li>
<li class="">
<p>max_photo_size<br>
最大头像大小，单位字节，如果头像数据长度超过此参数将被抛弃。</p>
</li>
<li class="">
<p>timeout_message<br>
客户端连接最大数据等待时间，单位秒。如果超过此时间客户端没有数据到达则断开连接（此参数当前未启用）。</p>
</li>
<li class="">
<p>str_log_file<br>
日志文件。仅在serveMode为true时有效。注意，程序并不会自动清理此文件。</p>
</li>
<li class="">
<p><strong>str_db_conn_str</strong><br>
MySQL数据库连接字符串。</p>
</li>
</ul>
<p><a name="soft-config-client-go" class=""></a></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="客户端go">客户端（Go）<a href="https://blog.mattuy.top/archives/stormchat#%E5%AE%A2%E6%88%B7%E7%AB%AFgo" class="hash-link" aria-label="客户端（Go）的直接链接" title="客户端（Go）的直接链接" translate="no">​</a></h3>
<ul>
<li class="">server_addr<br>
服务器地址和端口。</li>
</ul>
<p><a name="soft-config-client-cs" class=""></a></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="客户端c">客户端（C#）<a href="https://blog.mattuy.top/archives/stormchat#%E5%AE%A2%E6%88%B7%E7%AB%AFc" class="hash-link" aria-label="客户端（C#）的直接链接" title="客户端（C#）的直接链接" translate="no">​</a></h3>
<p>资源定义在StormChat解决方案，Interact项目的属性-&gt;资源中。</p>
<ul>
<li class="">
<p>RemoteServerAddr<br>
服务器地址。</p>
</li>
<li class="">
<p>RemoteServerPort<br>
服务器端口。</p>
</li>
</ul>
<p><a name="build" class=""></a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="如何编译">如何编译<a href="https://blog.mattuy.top/archives/stormchat#%E5%A6%82%E4%BD%95%E7%BC%96%E8%AF%91" class="hash-link" aria-label="如何编译的直接链接" title="如何编译的直接链接" translate="no">​</a></h2>
<p>首先安装git和golang，这一步请自行解决；</p>
<p>克隆项目到本地：</p>
<blockquote>
<p><code>git clone -b master https://github.com/mattuylee/stormchat.git</code></p>
</blockquote>
<p>假设项目已克隆到本地<em>DIR</em>目录，命令行切换到stormchat目录:</p>
<blockquote>
<p><code>cd DIR/stormchat</code></p>
</blockquote>
<p><a name="build-server" class=""></a></p>
<ol>
<li class="">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="服务器端-1">服务器端<a href="https://blog.mattuy.top/archives/stormchat#%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF-1" class="hash-link" aria-label="服务器端的直接链接" title="服务器端的直接链接" translate="no">​</a></h3>
</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="切换到服务器端工程目录">切换到服务器端工程目录：<a href="https://blog.mattuy.top/archives/stormchat#%E5%88%87%E6%8D%A2%E5%88%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E5%B7%A5%E7%A8%8B%E7%9B%AE%E5%BD%95" class="hash-link" aria-label="切换到服务器端工程目录：的直接链接" title="切换到服务器端工程目录：的直接链接" translate="no">​</a></h4>
<blockquote>
<p><code>cd stormchat-server</code></p>
</blockquote>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="克隆mysql操作库">克隆mysql操作库<a href="https://blog.mattuy.top/archives/stormchat#%E5%85%8B%E9%9A%86mysql%E6%93%8D%E4%BD%9C%E5%BA%93" class="hash-link" aria-label="克隆mysql操作库的直接链接" title="克隆mysql操作库的直接链接" translate="no">​</a></h4>
<p>Go标准库里是没有数据库操作的库的，因此先添加mysql操作库到项目中。创建目录<em>sotormchat-server/src/github.com/go-sql-driver/</em>，然后克隆MySQL操作库：</p>
<blockquote>
<p><code>cd src/github.com/go-sql-driver</code><br>
<code>git clone https://github.com/go-sql-driver/mysql.git</code></p>
</blockquote>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置环境变量gopath">配置环境变量GOPATH<a href="https://blog.mattuy.top/archives/stormchat#%E9%85%8D%E7%BD%AE%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8Fgopath" class="hash-link" aria-label="配置环境变量GOPATH的直接链接" title="配置环境变量GOPATH的直接链接" translate="no">​</a></h4>
<p>Windows下：<br>
如果环境变量GOPATH存在，则在GOPATH后添加 ";DIR/stormchat/stormchat-server"(不含引号，注意分号)，如果不存在添加GOPATH环境变量并将其设置为<em>DIR/stormchat/stormchat-server</em>即可，注意把DIR换成git仓库所在目录。<br>
Linux下:<br>
先查看GOPATH环境变量的值，再添加项目目录到GOPATH：</p>
<blockquote>
<p><code>echo $GOPATH</code><br>
如果值为空：<br>
<code>export GOPATH=DIR/stormchat/stormchat-server</code><br>
如果值不为空：<br>
<code>export GOPATH=$GOPATH:DIR/stormchat/stormchat-server</code></p>
</blockquote>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="编译程序">编译程序<a href="https://blog.mattuy.top/archives/stormchat#%E7%BC%96%E8%AF%91%E7%A8%8B%E5%BA%8F" class="hash-link" aria-label="编译程序的直接链接" title="编译程序的直接链接" translate="no">​</a></h4>
<p>切换到stormchat-server/src/stormchat/目录，然后编译：</p>
<blockquote>
<p><code>cd DIR/stormchat/stormchat-server/src/stormchat</code><br>
<code>go build</code></p>
</blockquote>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置mysql">配置MySQL<a href="https://blog.mattuy.top/archives/stormchat#%E9%85%8D%E7%BD%AEmysql" class="hash-link" aria-label="配置MySQL的直接链接" title="配置MySQL的直接链接" translate="no">​</a></h4>
<p>登录mysql：</p>
<blockquote>
<p><code>mysql -uroot -p</code></p>
</blockquote>
<p>为stormchat创建数据库：</p>
<blockquote>
<p><code>CREATE DATABASE stormchat CHARSET=UTF8;</code></p>
</blockquote>
<p>导入数据库结构:</p>
<blockquote>
<p><code>SOURCE DIR/stormchat/stormchat-server/res/stormchat.sql;</code></p>
</blockquote>
<p>创建用户并授权：</p>
<blockquote>
<p><code>CREATE USER 'stormchat'@'localhost' IDENTIFIED BY 'stormchat';</code><br>
<code>GRANT ALL ON stormchat.* TO 'stormchat'@'localhost';</code><br>
<code>FLUSH PRIVILEGES;</code></p>
</blockquote>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="启动服务器程序">启动服务器程序<a href="https://blog.mattuy.top/archives/stormchat#%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%A8%8B%E5%BA%8F" class="hash-link" aria-label="启动服务器程序的直接链接" title="启动服务器程序的直接链接" translate="no">​</a></h4>
<p>Linux下执行下列命令以守护进程运行：</p>
<blockquote>
<p><code>nohup ./stormchat &amp;</code></p>
</blockquote>
<p>Windows请自行探索。</p>
<ol start="2">
<li class="">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="客户端-go">客户端-Go<a href="https://blog.mattuy.top/archives/stormchat#%E5%AE%A2%E6%88%B7%E7%AB%AF-go" class="hash-link" aria-label="客户端-Go的直接链接" title="客户端-Go的直接链接" translate="no">​</a></h3>
</li>
</ol>
<blockquote>
<p><code>cd DIR/stormchat/stormchat-client-golang/src</code><br>
<code>go build</code></p>
</blockquote>
<p>注意，<strong>客户端运行时需要conctrl_x64.dll在运行目录</strong>下，此文件在stormchat-client-golang/res/目录下。</p>
<ol start="3">
<li class="">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="客户端-c">客户端-C#<a href="https://blog.mattuy.top/archives/stormchat#%E5%AE%A2%E6%88%B7%E7%AB%AF-c" class="hash-link" aria-label="客户端-C#的直接链接" title="客户端-C#的直接链接" translate="no">​</a></h3>
</li>
</ol>
<p>Visual Studio 2015以上版本打开项目，直接编译即可。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="注意事项">注意事项<a href="https://blog.mattuy.top/archives/stormchat#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9" class="hash-link" aria-label="注意事项的直接链接" title="注意事项的直接链接" translate="no">​</a></h2>
<ul>
<li class="">没有设计注册账户的API，只能在强插数据库。emmmm，这个坑懒得填了。</li>
<li class="">服务器端的日志文件不会自动清除（反正也没什么日志要写）。</li>
<li class="">其他的，想到再补充。</li>
</ul>
<p><a name="dir-struct" class=""></a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="目录结构主要部分">目录结构（主要部分）<a href="https://blog.mattuy.top/archives/stormchat#%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84%E4%B8%BB%E8%A6%81%E9%83%A8%E5%88%86" class="hash-link" aria-label="目录结构（主要部分）的直接链接" title="目录结构（主要部分）的直接链接" translate="no">​</a></h2>
<!-- -->stormchat
│  .gitattributes
│  .gitignore
│  LICENSE          //许可证
│  README.md       //此帮助文件
│  
├─design            //设计文件
│    message.png
│    operations.svg
│    stormchat.zip       //starUML设计文件
│      
│
├─stormchat-server  //服务器端工程目录
│  ├─res
│  │     stormchat.sql  //数据库结构
│  │      
│  └─src                //代码文件
│      └─stormchat
│            control.go
│            err.go
│            main.go
│            message.go
│            session-deprecated.go  //已不推荐使用的接口
│            session.go
│            storm-server.go
│            user.go
│─stormchat-client-golang  //Go客户端工程目录
│  ├─res
│  │     conctrl_x64.dll            //Winodws控制台输出库
│  │     icon.ico                   //客户端图标
│  │      
│  └─src
│        control.go                 //参数控制
│        main.go
│        session.go
│        stormchat-client.syso      //资源文件（图标资源）
│        user.go
│        win-console.go             //输出控制，调用conctrl库
│               
└─stormchat-client-csharp   //C#客户端工程目录
   ├─Interact                   //数据交互模块
   │  │  Interact.csproj            //Visual Studio项目文件
   │  │  Newtonsoft.Json.dll        //JSON格式化库
   │  │  AttrNames.cs               //一些字符串常量
   │  │  Client.cs                  //提供给数据表现模块的静态类
   │  │  Client-Fields.cs           //部分类，定义内部字段
   │  │  Client-Handle.cs           //部分类，处理服务器数据的方法
   │  │  Client-Read.cs             //部分类，接收服务器数据的方法
   │  │  Client-Send.cs             //部分类，向服务器发送数据的方法
   │  │  Exception.cs
   │  │  jsonObject.cs              //定义一些内部使用的结构，用于JSON格式化
   │  │  Message.cs                 //定义一些数据结构，用于数据交换
   │  │  User.cs                    //定义用户
   │  │  
   │  └─Properties                  //项目属性和资源
   │          AssemblyInfo.cs
   │          Resources.Designer.cs
   │          Resources.resx
   │          
   └─StormChatWPF               //数据表现和用户交互模块*
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="使用截图">使用截图<a href="https://blog.mattuy.top/archives/stormchat#%E4%BD%BF%E7%94%A8%E6%88%AA%E5%9B%BE" class="hash-link" aria-label="使用截图的直接链接" title="使用截图的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="golang客户端">Golang客户端<a href="https://blog.mattuy.top/archives/stormchat#golang%E5%AE%A2%E6%88%B7%E7%AB%AF" class="hash-link" aria-label="Golang客户端的直接链接" title="Golang客户端的直接链接" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" src="https://io.mattuy.top/public/blog/2018/stormchat/client-login.png" alt="stormchat使用截图" class="img_ev3q">
<img decoding="async" loading="lazy" src="https://io.mattuy.top/public/blog/2018/stormchat/client-chat.png" alt="stormchat使用截图" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="源代码">源代码<a href="https://blog.mattuy.top/archives/stormchat#%E6%BA%90%E4%BB%A3%E7%A0%81" class="hash-link" aria-label="源代码的直接链接" title="源代码的直接链接" translate="no">​</a></h2>
<p>github地址：<a href="https://github.com/mattuylee/stormchat" target="_blank" rel="noopener noreferrer" class="">https://github.com/mattuylee/stormchat</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[AVL树的C语言实现]]></title>
            <link>https://blog.mattuy.top/archives/avl-tree-c-implement</link>
            <guid>https://blog.mattuy.top/archives/avl-tree-c-implement</guid>
            <pubDate>Tue, 11 Dec 2018 17:08:04 GMT</pubDate>
            <content:encoded><![CDATA[<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 2018-12-08</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// By Mattuy</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// AVL树的C语言实现</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 实现对AVL树节点的增删改查</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;stdio.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;stdlib.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;stdbool.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">typedef</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> DataType</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//树的数据域</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//定义AVL树</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">typedef</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token class-name">SearchTree</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> height</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//树的深度，空树（NULL）的深度为-1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    DataType value</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token class-name">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> left</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token class-name">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> right</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> TreeNode</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> SearchTree</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithLeft</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> grandpa</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//左左单旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> grandpa</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//右右单旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">DoubleRotateWithLeft</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> grandpa</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//左右双旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">DoubleRotateWithRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> grandpa</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//右左双旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//删除节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Assign</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> dest</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> DataType</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//将一个节点的值赋给另外一个节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Find</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> DataType value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//查找节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//获取树高度</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//删除同时有左右孩子的节点时寻找子合适的子节点来顶替被删除节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">findExtreamNode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//中序遍历输出AVL树</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">output</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//左左单旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithLeft</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> grandpa</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//将祖父变为父亲的右儿子，父亲原来的右儿子变为祖父的左儿子（祖父原来的左儿子就是父亲，关系已断开）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> parent </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> parent</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    parent</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> grandpa</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//新的关系是，原来的孙子和祖父变成父亲的左右儿子（孙子位置没动）。</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//原祖父(现父亲右儿子)的深度取决于原父亲的右儿子和原祖父的右儿子</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//父亲的深度取决于孙子和祖父（现右儿子），因此须先计算祖父（右儿子）的深度</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    parent</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parent</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//返回新的根节点（原来是祖父，现在是父亲）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> parent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//右右单旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> grandpa</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> parent </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> parent</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    parent</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> grandpa</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    parent</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parent</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> parent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//左右双旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">DoubleRotateWithLeft</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> grandpa</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithLeft</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">grandpa</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//右左双旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">DoubleRotateWithRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> grandpa</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithLeft</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">grandpa</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">grandpa</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//插入节点，返回插入后的根节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Insert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> DataType value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> temp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">)</span><span class="token function" style="color:#d73a49">malloc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">sizeof</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">temp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//申请内存失败</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        temp</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> temp</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        temp</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        temp</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> temp</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//插入新节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Insert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//当平衡被破坏时调整</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//插入的节点在哪边就旋转哪边</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithLeft</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">DoubleRotateWithLeft</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Insert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">DoubleRotateWithRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//不允许插入值相同的节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//删除节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">tree </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">node </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//找到一个合适的子节点来替换被删除的节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> leaf </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">findExtreamNode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//记录是在左子树找的子节点还是右子树</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            bool doesLeft </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">leaf</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                doesLeft </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//用子节点的值替代要删除节点的值</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">Assign</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> leaf</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//删除子节点。因为现在tree节点的值和子节点一样，所以不能直接传tree节点作为参数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">doesLeft</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> leaf</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> leaf</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//被删除的节点有两个儿子</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">free</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//被删除的是叶子节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> temp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">free</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> temp</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//被删除的节点只有一个儿子</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//当前节点为待删除节点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">node</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//如果删除节点后破坏平衡，调整以重新平衡</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//从右子树删除节点后进行左旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//如果左孩子有左孩子则进行单旋转，否则进行双旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">abs</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithLeft</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">DoubleRotateWithLeft</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//待删除节点在右子树</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//从左子树删除节点后进行右旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//如果右孩子有右孩子则进行单旋转，否则进行双旋转</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">abs</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SingleRotateWithRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">DoubleRotateWithRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//待删除节点在左子树</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//为节点赋值</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Assign</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> dest</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> DataType</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    dest</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//查找</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Find</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> DataType value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> cur </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cur </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cur</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cur </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> value </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> cur</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> cur</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> cur</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//获取树高度</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> tree </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/**</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 当被删除节点有左右孩子时找出左子树的最右节点或右子树的最左节点。务必保证传入的参数为被搜索的节点，</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> *     函数将根据其左右子树的深度来决定返回左孩子的最右子树还是右孩子的最左子树。</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 此函数仅应被Remove函数调用</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">findExtreamNode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">node</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> node</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> cur </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cur</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cur </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cur</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        TreeNode</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> cur </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cur</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cur </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cur</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//中序遍历输出</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">output</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">output</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">printf</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"value = %d, height = %d\n"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">height</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">output</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//测试</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SearchTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">8</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Insert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Find</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">6</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">output</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"pause"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[LeetCode之旅——Two Sum，哈希表的应用]]></title>
            <link>https://blog.mattuy.top/archives/leetcode-two-sum-hash-table</link>
            <guid>https://blog.mattuy.top/archives/leetcode-two-sum-hash-table</guid>
            <pubDate>Thu, 22 Nov 2018 20:29:29 GMT</pubDate>
            <description><![CDATA[今天做的题叫Two Sum，简单题，给定一个整形数组和一个整数target，存在唯一的两个成员相加等于target，要求返回这两个成员的位置。]]></description>
            <content:encoded><![CDATA[<p>今天做的题叫<strong>Two Sum</strong>，简单题，给定一个整形数组和一个整数target，存在唯一的两个成员相加等于target，要求返回这两个成员的位置。</p>
<p>示例：</p>
<blockquote>
<p>Given nums = [2, 7, 11, 15], target = 9,</p>
<p>Because nums[0] + nums[1] = 2 + 7 = 9,<br>
return [0, 1].</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决方案">解决方案<a href="https://blog.mattuy.top/archives/leetcode-two-sum-hash-table#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="解决方案的直接链接" title="解决方案的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-暴力算法">1. 暴力算法<a href="https://blog.mattuy.top/archives/leetcode-two-sum-hash-table#1-%E6%9A%B4%E5%8A%9B%E7%AE%97%E6%B3%95" class="hash-link" aria-label="1. 暴力算法的直接链接" title="1. 暴力算法的直接链接" translate="no">​</a></h3>
<p>最简单的当然是暴力算法，一个嵌套的for循环搞定。标准答案如下：</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">public int[] twoSum(int[] nums, int target) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    for (int i = 0; i &lt; nums.length; i++) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        for (int j = i + 1; j &lt; nums.length; j++) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            if (nums[j] == target - nums[i]) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                return new int[] { i, j };</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-哈希表">2. 哈希表<a href="https://blog.mattuy.top/archives/leetcode-two-sum-hash-table#2-%E5%93%88%E5%B8%8C%E8%A1%A8" class="hash-link" aria-label="2. 哈希表的直接链接" title="2. 哈希表的直接链接" translate="no">​</a></h3>
<p>第一种方法的时间复杂度是O(n<sup>2</sup>)，空间复杂度O(1)。另一个更快的解决方案是利用哈希表。遍历数组并将成员其插入哈希表，再查询[target - 成员]是否在表中（不能等于自身），如果在则结果已产生。至于是一次遍历实现还是两次遍历个人认为区别不大。
标准答案如下：</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">public int[] twoSum(int[] nums, int target) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Map&lt;Integer, Integer&gt; map = new HashMap&lt;&gt;();</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    for (int i = 0; i &lt; nums.length; i++) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        map.put(nums[i], i);</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    for (int i = 0; i &lt; nums.length; i++) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        int complement = target - nums[i];</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        if (map.containsKey(complement) &amp;&amp; map.get(complement) != i) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            return new int[] { i, map.get(complement) };</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://blog.mattuy.top/archives/leetcode-two-sum-hash-table#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>哈希表最大的优势在于查询。理想的哈希表可以以O(1)的时间复杂度处理查询。此题的微妙之处在于，需要将数组索引作为表的值而数组成员作为键。而思维惯性可能让人一时转不过弯。</p>
<p>哈希表虽然高效，但却不是任何时候都适用。它的空间复杂度是O(n)，但其常数因子并不小，可能花费甚至浪费很大的空间。另外冲突处理也会一定程度降低哈希表的性能。</p>
<p>因此哈希表并不总是比暴力解法好。如果你的空间足够，数据量大，查询频度高，我认为使用哈希表是合理的选择。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[C++实现贪吃蛇]]></title>
            <link>https://blog.mattuy.top/archives/gluttonous-snake-cpp-implement</link>
            <guid>https://blog.mattuy.top/archives/gluttonous-snake-cpp-implement</guid>
            <pubDate>Sat, 20 Oct 2018 16:41:42 GMT</pubDate>
            <description><![CDATA[注意，编译前源文件字符编码必须为GB2312/GBK。否则填充字符█会出现异常。]]></description>
            <content:encoded><![CDATA[<p>注意，编译前源文件字符编码必须为GB2312/GBK。否则填充字符<code>█</code>会出现异常。</p>
<p>编译时需要指定按C++11标准编译，为了支持结构体字面量的语法。
<code>g++ -std=c++11 -o gluttonous-snake.exe ./source.cpp</code></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="代码">代码<a href="https://blog.mattuy.top/archives/gluttonous-snake-cpp-implement#%E4%BB%A3%E7%A0%81" class="hash-link" aria-label="代码的直接链接" title="代码的直接链接" translate="no">​</a></h3>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;cstdlib&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;conio.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;deque&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;iostream&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;time.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;windows.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//定义一次步进</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">typedef</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//是否纵向移动</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">bool</span><span class="token plain"> virticle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//移动步长</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> offset </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">Step</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//定义'成长礼包'类型</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">enum</span><span class="token plain"> </span><span class="token class-name">GiftType</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//礼物，增加长度</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    GIFT_GIFT </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> FOREGROUND_GREEN</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//陷阱，减少长度</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    GIFT_TRAP </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> FOREGROUND_GREEN </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> FOREGROUND_BLUE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//利剑，直接死亡</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    GIFT_SWORD </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> FOREGROUND_RED</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//定义移动区域。窗口宽度应为width的两倍，因为ansi字符宽度仅高度的1/2。</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">define</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property macro-name" style="color:#36acaa">FACTORY_WIDTH</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property expression number" style="color:#36acaa">64</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">define</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property macro-name" style="color:#36acaa">FACTORY_HEIGHT</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property expression number" style="color:#36acaa">36</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//定义蛇身颜色</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">define</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property macro-name" style="color:#36acaa">SNAKE_BODY_COLOR</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property expression punctuation" style="color:#393A34">(</span><span class="token macro property expression" style="color:#36acaa">FOREGROUND_RED </span><span class="token macro property expression operator" style="color:#393A34">|</span><span class="token macro property expression" style="color:#36acaa"> FOREGROUND_GREEN </span><span class="token macro property expression operator" style="color:#393A34">|</span><span class="token macro property expression" style="color:#36acaa"> FOREGROUND_BLUE</span><span class="token macro property expression punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">namespace</span><span class="token plain"> std</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//控制台输出句柄</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">HANDLE hOutput </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">GetStdHandle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">STD_OUTPUT_HANDLE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//蛇身数据容器。</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">deque</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">COORD</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> snakeBody</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//死亡标记</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">bool</span><span class="token plain"> dead </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//'成长礼包'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">COORD gift</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> trap</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sword</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//判定点是否在蛇身上</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">inSnake</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">COORD point</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    deque</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">COORD</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">iterator iter </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">begin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">iter </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">end</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//生成'成长礼包'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">COORD </span><span class="token function" style="color:#d73a49">createGift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">GiftType color</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//统计递归调用次数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> count </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">count</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    COORD point</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">srand</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">rand</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">rand</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">%</span><span class="token plain"> FACTORY_WIDTH </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">srand</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">rand</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">rand</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">%</span><span class="token plain"> FACTORY_HEIGHT</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">inSnake</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createGift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">color</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">SetConsoleCursorPosition</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">SetConsoleTextAttribute</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> color</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cout </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"█"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">SetConsoleTextAttribute</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> SNAKE_BODY_COLOR</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        dead </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> count </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">12</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        count </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token comment" style="color:#999988;font-style:italic">//连礼包都没地方放了，死了算了</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//初始化</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"cls"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">clear</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">srand</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">time</span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_front</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_front</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_front</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    deque</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">COORD</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">iterator iter </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">begin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">iter </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">end</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">SetConsoleCursorPosition</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cout </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"█"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    sword </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createGift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">GIFT_SWORD</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    trap </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createGift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">GIFT_TRAP</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    gift </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createGift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">GIFT_GIFT</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//步进</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">stepOnece</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Step step</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    COORD head </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">front</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">virticle </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//死亡</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">inSnake</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> sword</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> sword</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> FACTORY_WIDTH </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> FACTORY_HEIGHT</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        dead </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_front</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">SetConsoleCursorPosition</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> head</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    cout </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"█"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> count</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> trap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> trap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        count </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        trap </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createGift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">GIFT_TRAP</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token comment" style="color:#999988;font-style:italic">//陷阱，变短</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> gift</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> gift</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        count </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        gift </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createGift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">GIFT_GIFT</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token comment" style="color:#999988;font-style:italic">//礼物，增长</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        count </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> count</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        COORD back </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">back</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">SetConsoleCursorPosition</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> back</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">printf</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"  "</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pop_back</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">snakeBody</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            dead </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//控制循环</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">gameLoop</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Step curStep </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Step step </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> curStep</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">dead</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">Sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token function" style="color:#d73a49">_kbhit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">continue</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">char</span><span class="token plain"> cmd</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">bool</span><span class="token plain"> breakdown </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cmd </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">_getch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cmd</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token char">'w'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">virticle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token char">'s'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">virticle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token char">'a'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">virticle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token char">'d'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">virticle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">default</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                breakdown </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//禁止当前方向反方向步进</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">virticle </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> curStep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">virticle </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> step</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> curStep</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">continue</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                curStep </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> step</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">breakdown</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">stepOnece</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">curStep</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//设置缓冲区大小</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SMALL_RECT rect </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">SetConsoleWindowInfo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">rect</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">SetConsoleScreenBufferSize</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> FACTORY_WIDTH </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> FACTORY_HEIGHT </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//设置窗口大小</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rect </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> FACTORY_WIDTH </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> FACTORY_HEIGHT </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">SetConsoleWindowInfo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">rect</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//设置窗口样式</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">SetConsoleTextAttribute</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> SNAKE_BODY_COLOR</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    CONSOLE_CURSOR_INFO cursorInfo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">SetConsoleCursorInfo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">cursorInfo</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//规则介绍</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    cout </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"使用W、S、A、D控制方向，吃到绿色礼包长度增加，吃到黄色礼包时长度减短，"</span><span class="token plain">\</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"吃到红色礼包直接死亡。您也可以按CTRL + C退出游戏。按任意键开始游戏。"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> endl</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"pause"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//开始游戏</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">gameLoop</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"cls"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">SetConsoleCursorPosition</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hOutput</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">printf</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"You has dead! Retry? (y/n)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">char</span><span class="token plain"> cmd</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cin </span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"> cmd</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cmd </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token char">'y'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            dead </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[逆波兰法-算术表达式语法分析C++]]></title>
            <link>https://blog.mattuy.top/archives/reverse-polish-notation</link>
            <guid>https://blog.mattuy.top/archives/reverse-polish-notation</guid>
            <pubDate>Thu, 20 Sep 2018 22:55:26 GMT</pubDate>
            <description><![CDATA[逆波兰表达式的C++实现。算术表达式求值，支持加减乘除和幂运算，支持圆括号改变优先级。]]></description>
            <content:encoded><![CDATA[<p>逆波兰表达式的C++实现。算术表达式求值，支持加减乘除和幂运算，支持圆括号改变优先级。</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">//后缀表达式练习</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//2018-09-20</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;stack&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;iostream&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;cstdlib&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;string&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;math.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">namespace</span><span class="token plain"> std</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//定义优先级</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">enum</span><span class="token plain"> </span><span class="token class-name">Priority</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRI_IGNORE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token comment" style="color:#999988;font-style:italic">//无效字符，忽略</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRI_NUMBER</span><span class="token punctuation" style="color:#393A34">,</span><span class="token comment" style="color:#999988;font-style:italic">//操作数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRI_PLUS</span><span class="token punctuation" style="color:#393A34">,</span><span class="token comment" style="color:#999988;font-style:italic">//加减</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRI_DIVIDE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token comment" style="color:#999988;font-style:italic">//乘除</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRI_POWER</span><span class="token punctuation" style="color:#393A34">,</span><span class="token comment" style="color:#999988;font-style:italic">//幂</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRI_LEFT_PAR</span><span class="token punctuation" style="color:#393A34">,</span><span class="token comment" style="color:#999988;font-style:italic">//左圆括号</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRI_RIGTHT_PAR</span><span class="token punctuation" style="color:#393A34">,</span><span class="token comment" style="color:#999988;font-style:italic">//右圆括号</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//取操作符优先级</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Priority </span><span class="token function" style="color:#d73a49">getPriority</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">char</span><span class="token plain"> symbol</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">symbol </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token char">'0'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> symbol </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> </span><span class="token char">'9'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> symbol </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">'.'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> PRI_NUMBER</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">symbol </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">'+'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> symbol </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">'-'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> PRI_PLUS</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">symbol </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">'*'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> symbol </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">'/'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> PRI_DIVIDE</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">symbol </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">'^'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> PRI_POWER</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">symbol </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">'('</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> PRI_LEFT_PAR</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">symbol </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">')'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> PRI_RIGTHT_PAR</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> PRI_IGNORE</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//中缀表达式转后缀表达式</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">string </span><span class="token function" style="color:#d73a49">toSufixExpression</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">string express</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    stack</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">char</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> operendStack</span><span class="token punctuation" style="color:#393A34">;</span><span class="token comment" style="color:#999988;font-style:italic">//操作符暂存栈</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    string output</span><span class="token punctuation" style="color:#393A34">;</span><span class="token comment" style="color:#999988;font-style:italic">//输出后缀表达式</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//上一操作符的优先级，如果当前处理的操作符优先级低于它则前操作符出栈</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Priority lastPriority </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> PRI_NUMBER</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    string</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">iterator iter </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> express</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">begin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> iter </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> express</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">end</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Priority priority </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getPriority</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">priority</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> PRI_IGNORE</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">default</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">continue</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> PRI_NUMBER</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            output</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_back</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> PRI_PLUS</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> PRI_DIVIDE</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> PRI_POWER</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> PRI_LEFT_PAR</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">//遇到符号向前追加间隔符</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            output</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_back</span><span class="token punctuation" style="color:#393A34">(</span><span class="token char">' '</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">getPriority</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">top</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> priority </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">top</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">'('</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                output</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_back</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">top</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pop</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            lastPriority </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> priority</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> PRI_RIGTHT_PAR</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">top</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token char">'('</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    output</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_back</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">top</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pop</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pop</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//处理完毕，剩余操作符出栈</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        output</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_back</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">top</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        operendStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pop</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> output</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//计算后缀表达式</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">double</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">caculate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">string express</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    stack</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">double</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> calcStack</span><span class="token punctuation" style="color:#393A34">;</span><span class="token comment" style="color:#999988;font-style:italic">//计算存储栈</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    string</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">iterator iter </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> express</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">begin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">iter </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> express</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">end</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//字符串转整形，并压入栈</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token char">'0'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> </span><span class="token char">'9'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            string number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">do</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                number</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_back</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token char">'0'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> </span><span class="token char">'9'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">'.'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">atoi</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">number</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">c_str</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">continue</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//间隔符</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token char">' '</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">iter</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">continue</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">//操作符，执行运算</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">double</span><span class="token plain"> operandOne </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">top</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pop</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">double</span><span class="token plain"> operandTwo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">top</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pop</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">iter</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token char">'+'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operandTwo </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> operandOne</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token char">'-'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operandTwo </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> operandOne</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token char">'*'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operandTwo </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> operandOne</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token char">'/'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operandTwo </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> operandOne</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token char">'^'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">pow</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operandTwo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> operandOne</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">default</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operandTwo</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">operandOne</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> calcStack</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">top</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    cout </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Please enter an expression:"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> endl</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    string express</span><span class="token punctuation" style="color:#393A34">;</span><span class="token comment" style="color:#999988;font-style:italic">//表达式</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">getline</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cin</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> express</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">express</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">empty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cout </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"empty express.\n"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    string output </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">toSufixExpression</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">express</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    cout </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">caculate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">output</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> endl</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"pause"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[PHP学习-LoadXML与网页格式错乱]]></title>
            <link>https://blog.mattuy.top/archives/php-xml-html-mix-fuss</link>
            <guid>https://blog.mattuy.top/archives/php-xml-html-mix-fuss</guid>
            <pubDate>Tue, 14 Aug 2018 22:25:06 GMT</pubDate>
            <description><![CDATA[用php写后端动态生成网页内容的时候，用到了DOMDocument类的操作。为了减少创建元素和文本节点的代码(与效率无关)，使用了loadXML()方法载入静态的HTML文本(通过heredoc)。]]></description>
            <content:encoded><![CDATA[<p>用php写后端动态生成网页内容的时候，用到了DOMDocument类的操作。为了减少创建元素和文本节点的代码(与效率无关)，使用了loadXML()方法载入静态的HTML文本(通过heredoc)。</p>
<!-- -->$xml = new DOMDocument();
$xml-&gt;loadXML(&lt;&lt;&lt;_HTML
&lt;div class="-article"&gt;
  &lt;div class="-article-title" onselectstart="return false;"&gt;&lt;/div&gt;
  &lt;hr/&gt;
  &lt;div class="-article-body"&gt;&lt;/div&gt;
  &lt;hr/&gt;
  &lt;div class="-article-extra"&gt;&lt;/div&gt;
  &lt;div class="-aborted"&gt;&lt;/div&gt;
  &lt;div class="-article-picture"&gt;&lt;/div&gt;
&lt;/div&gt;
_HTML
);
......
echo xml-&gt;saveXML();
<!-- -->
<p>没错，就是用loadXML()载入HTML，这样做是因为saveHTML()的时候会输出完整的HTML文档(包含html和body元素)而不是我想要的文章部分，而saveXML()则只需要去除首行的文档声明即可。</p>
<p>这里不谈这样的做法好与不好，只说说我遇到的问题。</p>
<p>遇到的问题是，网页版面乱了。出现了块级元素的堆叠，就是生成的元素后面的同级元素变成了它的子元素。感觉是标签没有闭合导致的，用浏览器看了生成的网页代码，终于找到了问题所在。</p>
<p>耗子屎在这一行：</p>
<p><strong>&lt;div class="-aborted"&gt;&lt;/div&gt;</strong></p>
<p>由于一些原因，生成元素中这块被废弃了，后面的代码又很多地方使用了getElementsByTagName方法获取指定元素，需要靠子元素的位置定位，所以不好直接删除(可见装载静态的html文档结构并不是个好点子)，于是把这个&lt;div&gt;的类名设置为-aborted，然后统一处理。因为是废弃元素，所以自然也不会为它生成内容了，最后saveXML输出的文本中，<strong>将这个空元素&lt;div class="-aborted"&gt;&lt;/div&gt;转化成了&lt;div class="-aborted"/&gt;</strong>。在html5中自闭合标签是有严格控制的，只有特定的标签才允许，因此&lt;div/&gt;并没有被浏览器认为是一个闭合的标签，然后和后面的div块混乱了，才导致的这个问题。</p>
<p>解决办法是，给heredoc中的废弃元素的内容加个空格，xml封装器就不会将它当作空元素了。不过最好还是全都动态生成元素，少生幺蛾子。或者使用其他更好的办法。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[PHP-防止静态资源被直接访问]]></title>
            <link>https://blog.mattuy.top/archives/php-avoid-illegal-access-to-resource</link>
            <guid>https://blog.mattuy.top/archives/php-avoid-illegal-access-to-resource</guid>
            <pubDate>Tue, 14 Aug 2018 17:03:52 GMT</pubDate>
            <description><![CDATA[用PHP写后端，想要达到用户登录后才可以访问一些图片和视频资源的效果，因此要阻止用户直接输入资源地址访问资源。]]></description>
            <content:encoded><![CDATA[<p>用PHP写后端，想要达到用户登录后才可以访问一些图片和视频资源的效果，因此要阻止用户直接输入资源地址访问资源。</p>
<p>找了一些资料，自己总结了几种方法。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1根据referer头防盗链">1.根据Referer头——防盗链<a href="https://blog.mattuy.top/archives/php-avoid-illegal-access-to-resource#1%E6%A0%B9%E6%8D%AEreferer%E5%A4%B4%E9%98%B2%E7%9B%97%E9%93%BE" class="hash-link" aria-label="1.根据Referer头——防盗链的直接链接" title="1.根据Referer头——防盗链的直接链接" translate="no">​</a></h2>
<p>浏览器在发起HTTP请求时一般都会一同发送Referer头。Referer头是用户跳转前的页面，也就是通过哪个页面发起的请求。通过禁止非法Referer头的资源请求可以一定程度防止资源被非法访问。一般这个都是在web服务器软件上设置而不是后端处理。由于这个方法并不是很靠谱所以没试过（毕竟请求头是由请求方控制的），不过应付一般用户足够了，特别适合用来防止其他网站挂自己服务器的资源链接以转移服务器负载，不过一般小网站用不到就是了。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2通过复杂文件名">2.通过复杂文件名<a href="https://blog.mattuy.top/archives/php-avoid-illegal-access-to-resource#2%E9%80%9A%E8%BF%87%E5%A4%8D%E6%9D%82%E6%96%87%E4%BB%B6%E5%90%8D" class="hash-link" aria-label="2.通过复杂文件名的直接链接" title="2.通过复杂文件名的直接链接" translate="no">​</a></h2>
<p>给资源文件赋以随机的文件名，用数据库记录，然后定期或不定期更新文件名，用户访问页面时后端php动态的查询资源文件名。</p>
<p>这个方法还算可以，缺点是频繁的数据库连接将会增大服务器负载。如果服务器支持可以试试数据库持久连接，不过需要注意持久连接的一些坑，不然可能造成连接锁死之类的问题。</p>
<h2><strong>3.隐藏资源——将资源文件放在用户无法访问的目录。</strong></h2>
这样做有两种方案可以选择，一是在用户需要访问时将资源文件复制到相应位置(可通过创建硬链接避免时间和空间浪费)，二是将所有对资源的访问重定位到一个文件，后端统一验证身份后输出文件内容。
<p>第一种其实意义不大，因为总是要让用户访问的，那只要有授权用户在需要资源文件，你就得把资源放在那里，然后就谁都可以访问了，再然后发现问题回到方法2了——还是得改文件名。</p>
<p>第二种方法是比较靠谱的方法。比如我将资源访问重定向到resource.php这个文件，然后验证身份后根据GET请求参数去找用户请求的文件，然后用readfile函数读取并输出文件就OK。用户的看到的网页源代码将类似这样：</p>
<p>&lt;img src="<a href="http://127.0.0.1/resource.php?path=filename%22/" target="_blank" rel="noopener noreferrer" class="">http://127.0.0.1/resource.php?path=filename"/</a>&gt;</p>
<p>filename可以是真正的资源相对路径，因为用户反正是无法直接访问的，暴露文件路径反而可以省去查数据库的消耗。需要注意的是，如果需要传递的文件路径中包含特殊字符如“/”等需要转义。可在后端统一由某个接口封装，生成安全的资源链接，类似这样：</p>
<!-- -->&lt;?php
function getURL($path) {
    return 'http://127.0.0.1/resource.php?path=' . urlencode($path);
}
?&gt;

&lt;body&gt;
  &lt;img src="&lt;?php echo getURL('picture/dog.jpg')?&gt;"&gt;
&lt;/body&gt;
<!-- -->
<p>然后resource.php中验证用户是否已授权，如果是且资源访问合法，readfile('/resource_path/' . $_GET['path'])，结束。</p>
<p>这应该是目前最靠谱的办法，不过它也有缺陷。如果请求的资源是视频这种比较大的文件，浏览器会一直等待资源接收完毕才显示后面的内容，而不是页面加载完再以流媒体的方式加载视频资源，因此这个方法无法用于大文件资源。同时，测试发现，css中的url()资源不支持这样的方式，因此背景图片之类的资源也无法使用这种方法。</p>
<h2><strong>4.大杂侩——结合两种方法</strong></h2>
非常不幸，我要做的东西正好需要请求大量视频资源，因此采用方法3中的第二类发现浏览器一直转加载视频，后面的评论等板块得等视频下载完成才加载，完全不能忍。于是想了半天，采取了折中的办法：对于小图片、少量图片、文本资源采用方法3第二方案，也就是资源访问重定向到resource.php统一处理；对于大图片、视频资源、大量图片和css中的资源，则通过临时硬链接的方式。
<p>上面3中已经说了readfile()输出的方法，下面说说硬链接的具体做法。</p>
<p>我们知道，php中有个session的概念，它为一个会话生成一个id，并在客户端以cookie的形式保存，在服务器端创建一个唯一的session文件，用于保存与相关会话相关的数据，每次用户请求中包含的cookie便告诉服务器当前会话的相关数据，比如是否已经登录等。</p>
<p>这里正利用了php的session机制。</p>
<p>我在网站目录中创建了一个temp目录，它包含一个空文件index.html以防止用户直接访问目录看到目录下的文件列表(也可在服务器端配置禁止对目录的访问)，因此用户可以访问该目录下的文件而无法得知它包含哪些子目录或文件，这是前提。</p>
<p>当用户页面需要请求一个需要授权访问的资源时，如果用户是授权的(通过session机制判断)，后端生成相应资源一个<strong>非随机的硬链接</strong>。它是这样的一个硬链接：</p>
<ol>
<li class="">它的父目录是<code>temp/当前会话session ID/</code></li>
<li class="">它的文件名由它的相对路径通过哈希算法生成，再加上文件后缀</li>
</ol>
<p>例如，如果我的资源目录(禁止用户访问)是<code>/resource_path</code>，存在资源<code>/resource_path/video/dog.mp4</code>。网站目录是<code>/</code>（对于用户），包含<code>temp</code>子目录。那么我的页面应该这样写：</p>
<!-- -->&lt;video src="&lt;?php echo '/temp/' . session_id() . '/' . md5('video/dog.mp4') . '.mp4'?&gt;"&gt;&lt;/video&gt;
<!-- -->
<p>之前的getURL函数变成这样：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">function getURL($path, $flow = false) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    //非法资源</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if(!file_exists('/resource_path/' . $path)) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        return '';</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    //小文件资源，采用资源重定向方案</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if(!$flow) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        return '/resource.php?path=' . urlencode($path);</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    //获取后缀</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    preg_match('/\.[^\.\/]*$/', $path, $sufix);</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    $filename = '/temp/'. session_id() . '/' . md5($path) . $sufix[0];</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    //判断资源链接是否已创建，WWW_ROOT为网站根目录实际路径</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if(file_exists(WWW_ROOT . $filename)) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        return $filename;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    //创建temp/sessionID目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    else if(!file_exists(dirname(WWW_ROOT . $filename))) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        mkdir(dirname(WWW_ROOT . $filename));</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    //创建硬链接。注意Windows不支持PHP的link函数，看你服务器平台</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if(stripos(PHP_OS, 'WIN') === false) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        link(HEVER_ROOT . $path, HEVER_ROOT . $filename);</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    else {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        system('mklink /H "' . HEVER_ROOT . $filename . '" "' . HEVER_ROOT . $path . '"');</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return HEVER_HOME . $filename;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>当然，md5()的参数也可以另外的算，不一定是相对路径。</p>
<p>这样做的好处是，当用户再次请求相同的资源时，只需确保相应的硬链接存在即可直接不管了，因此需要这个硬链接的文件名是非随机的避免查询数据库。而且这样多了一层session id阻隔，即使非法用户知道了生成资源链接文件名的规则也无法访问到资源，因为资源链接是在当前会话的session id目录下的，除非他能猜到某个会话的session id再模拟发送cookie——还不如让他猜用户名和密码呢。</p>
<p>当然这个方法也不是完美的，由于可能会生成大量的硬链接和session文件并且废弃后不会消失，需要定期执行清理脚本来清除过期的链接和文件。我的解决方案是，当用户登录或登出时触发一个脚本，它会清除超过1天未访问过的session文件和对应的temp目录中的同名名录(其实不是同名，session文件还有sess_前缀)。这个灵感来自于wordpress的伪cron机制。</p>
<p>需要注意的是，Windows系统不支持php的link函数，因此得用windows的shell。还有一点，清理php session文件时，如果php.ini中未配置<code>session.save_path</code>，在php中用<code>session_save_path()</code>可能获取不到php默认的session文件存放目录，因此建议在文件首主动配置session目录，使用<code>session_save_path(string $path)</code>函数。</p>
<p>注：以上方案均未经过严密的测试，请谨慎参考。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[转载]windows下进程间通信的（13种方法）]]></title>
            <link>https://blog.mattuy.top/archives/windows-inter-process-communication</link>
            <guid>https://blog.mattuy.top/archives/windows-inter-process-communication</guid>
            <pubDate>Fri, 27 Jul 2018 23:02:53 GMT</pubDate>
            <description><![CDATA[查看原文]]></description>
            <content:encoded><![CDATA[<p><a href="https://www.cnblogs.com/findumars/p/6329593.html" target="_blank" rel="noopener noreferrer" class="">查看原文</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[转载]内网与外网间通信——NAT穿透]]></title>
            <link>https://blog.mattuy.top/archives/conmunication-of-lan-and-wan-with-nat-hole</link>
            <guid>https://blog.mattuy.top/archives/conmunication-of-lan-and-wan-with-nat-hole</guid>
            <pubDate>Wed, 25 Jul 2018 22:36:26 GMT</pubDate>
            <description><![CDATA[查看原文]]></description>
            <content:encoded><![CDATA[<p><strong><a href="https://blog.csdn.net/zhuzhihai1988/article/details/8568116" target="_blank" rel="noopener noreferrer" class="">查看原文</a></strong></p>]]></content:encoded>
        </item>
    </channel>
</rss>