<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Sokiy</title>
  
  <subtitle>香蕉大则香蕉皮也大</subtitle>
  <link href="http://sokiy.github.io/atom.xml" rel="self"/>
  
  <link href="http://sokiy.github.io/"/>
  <updated>2024-04-11T03:40:55.360Z</updated>
  <id>http://sokiy.github.io/</id>
  
  <author>
    <name>Sokiy</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>自动区分工作仓库和个人仓库的 Git 提交</title>
    <link href="http://sokiy.github.io/2024/git-config-auto-distribute/"/>
    <id>http://sokiy.github.io/2024/git-config-auto-distribute/</id>
    <published>2024-04-10T07:47:36.000Z</published>
    <updated>2024-04-11T03:40:55.360Z</updated>
    
    <content type="html"><![CDATA[<h3 id="自动区分工作仓库和个人仓库的-Git-提交"><a href="#自动区分工作仓库和个人仓库的-Git-提交" class="headerlink" title="自动区分工作仓库和个人仓库的 Git 提交"></a>自动区分工作仓库和个人仓库的 Git 提交</h3><p>通常，公司会自建 <code>GitHub</code> 或 <code>GitLab</code> 服务，而个人可能在 GitHub 官网上有自己的个人项目。然而，公司内部项目和个人项目的邮箱配置可能不同。当项目数量较多时，使用 <code>git config --local</code> 或 <code>--global</code> 进行设置就会变得相当麻烦。在这里，我将记录下我个人的解决方案，以便后续参考。</p><h3 id="区分不同的-SSH-Key"><a href="#区分不同的-SSH-Key" class="headerlink" title="区分不同的 SSH Key"></a>区分不同的 SSH Key</h3><h4 id="生成-SSH-Key-文件"><a href="#生成-SSH-Key-文件" class="headerlink" title="生成 SSH Key 文件"></a>生成 SSH Key 文件</h4><p>在 <code>~/.ssh/</code> 目录下生成 SSH Key 文件：</p><ul><li>对于公司内部使用的邮箱，生成一个 SSH Key 文件命名为 <code>ssh-company</code></li><li>对于个人 GitHub 使用的邮箱，生成一个 SSH Key 文件命名为 <code>ssh-github</code></li></ul><h4 id="添加-config-文件"><a href="#添加-config-文件" class="headerlink" title="添加 config 文件"></a>添加 config 文件</h4><p>在 <code>~/.ssh/</code> 目录下创建一个 <code>config</code> 文件，并添加以下内容：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">Host github.com</span><br><span class="line">  HostName github.com</span><br><span class="line">  User git</span><br><span class="line">  PreferredAuthentications publickey</span><br><span class="line">  IdentityFile ~/.ssh/ssh-github</span><br><span class="line"></span><br><span class="line">Host gitlab.com</span><br><span class="line">  HostName gitlab.com</span><br><span class="line">  User git</span><br><span class="line">  PreferredAuthentications publickey</span><br><span class="line">  IdentityFile ~/.ssh/ssh-company</span><br></pre></td></tr></table></figure><p>这样设置后，使用 <code>git</code> 命令和远程 Git 仓库进行交互时，将根据 Git 远程地址前缀使用不同的 SSH Key。</p><h3 id="使用不同的姓名和邮箱"><a href="#使用不同的姓名和邮箱" class="headerlink" title="使用不同的姓名和邮箱"></a>使用不同的姓名和邮箱</h3><p>在进行 Git 提交时，可以区分个人项目和公司项目，使用不同的姓名和邮箱。</p><h4 id="添加-gitconfig-文件"><a href="#添加-gitconfig-文件" class="headerlink" title="添加 .gitconfig 文件"></a>添加 .gitconfig 文件</h4><p>生成 <code>~/.gitconfig</code> 文件，相当于使用 <code>git config --global</code> 进行全局配置。在该文件中，可以设置个人的 Git 相关配置，例如：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[alias]</span><br><span class="line">  st = status</span><br><span class="line">  co = checkout</span><br><span class="line">[includeIf &quot;hasconfig:remote.*.url:git@gitlab.com:*/**&quot;]</span><br><span class="line">  path = ~/.gitconfig-company</span><br><span class="line">[includeIf &quot;hasconfig:remote.*.url:git@github.com:*/**&quot;]</span><br><span class="line">  path = ~/.gitconfig-github</span><br></pre></td></tr></table></figure><p><code>includeIf</code> 是 Git 的条件引入配置语法，它允许根据特定条件从其他文件中读取并合并配置。通过使用 <code>includeIf</code>，可以根据当前仓库的位置或其他条件有选择地包含额外的配置文件，从而实现为不同的仓库或目录设置不同配置而无需手动切换。</p><h4 id="生成-gitconfig-xxx-文件"><a href="#生成-gitconfig-xxx-文件" class="headerlink" title="生成 .gitconfig-xxx 文件"></a>生成 .gitconfig-xxx 文件</h4><p>为了区分姓名和邮箱，可以创建 <code>.gitconfig-xxx</code> 文件，并根据个人喜好添加配置。如果只想区分姓名和邮箱，可以按照以下方式设置：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="comment">## .gitconfig-company</span></span></span><br><span class="line">[user]</span><br><span class="line">    name = 公司姓名</span><br><span class="line">  email = 公司邮箱</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment">## .gitconfig-github</span></span></span><br><span class="line">[user]</span><br><span class="line">    name = 个人姓名</span><br><span class="line">  email = 个人邮箱</span><br></pre></td></tr></table></figure><p>这样，当进行提交时，根据远程主机地址前缀判断使用哪个姓名和邮箱。</p><h3 id="处理-Hexo-部署异常问题"><a href="#处理-Hexo-部署异常问题" class="headerlink" title="处理 Hexo 部署异常问题"></a>处理 Hexo 部署异常问题</h3><p>在使用 <code>.gitconfig</code> 文件自动区分提交后，执行 <code>hexo d</code> 命令时可能会出现以下提示：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Initialized empty Git repository <span class="keyword">in</span> F:/Blog/.deploy_git/.g</span><br><span class="line">Author identity unknown                                   </span><br><span class="line">                                                          </span><br><span class="line">*** Please tell me who you are.                           </span><br><span class="line">                                                          </span><br><span class="line">Run                                                       </span><br><span class="line">                                                          </span><br><span class="line">  git config --global user.email <span class="string">&quot;you@example.com&quot;</span>        </span><br><span class="line">  git config --global user.name <span class="string">&quot;Your Name&quot;</span>               </span><br><span class="line">                                                          </span><br><span class="line">to <span class="built_in">set</span> your account<span class="string">&#x27;s default identity.                   </span></span><br><span class="line"><span class="string">Omit --global to set the identity only in this repository.</span></span><br></pre></td></tr></table></figure><p>这是因为在执行 <code>hexo d</code> 命令时，默认使用了全局的 Git <code>user.name</code> 和 <code>user.email</code>。</p><h4 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h4><p>在 Hexo 的 <code>_config.yml</code> 配置文件中进行设置：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># You can use this:</span></span><br><span class="line">deploy:</span><br><span class="line">  <span class="built_in">type</span>: git</span><br><span class="line">  repo: &lt;repository url&gt;</span><br><span class="line">  branch: [branch]</span><br><span class="line">  message: [message]</span><br><span class="line">  name: [git user]</span><br><span class="line">  email: [git email]</span><br><span class="line">  extend_dirs: [extend directory]</span><br></pre></td></tr></table></figure><p>然而，即使使用了上述解决方案，再次执行 <code>hexo d</code> 命令时，仍然会使用全局的 Git 用户信息，导致报错。</p><h4 id="解决方案的解决方案"><a href="#解决方案的解决方案" class="headerlink" title="解决方案的解决方案"></a>解决方案的解决方案</h4><p>如果 <code>.deploy_git</code> 目录已经生成并存在，会导致错误发生。此时，需要删除整个 <code>.deploy_git</code> 目录，然后再次执行 <code>hexo d</code> 命令。</p><p>希望这些解决方案能解决你的问题！如果还有其他疑问，请随时提问。</p><p>Done！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;自动区分工作仓库和个人仓库的-Git-提交&quot;&gt;&lt;a href=&quot;#自动区分工作仓库和个人仓库的-Git-提交&quot; class=&quot;headerlink&quot; title=&quot;自动区分工作仓库和个人仓库的 Git 提交&quot;&gt;&lt;/a&gt;自动区分工作仓库和个人仓库的 Git 提交&lt;/</summary>
      
    
    
    
    
    <category term="git" scheme="http://sokiy.github.io/tags/git/"/>
    
  </entry>
  
  <entry>
    <title>git stash clear 恢复</title>
    <link href="http://sokiy.github.io/2024/git-stash-clear-recover/"/>
    <id>http://sokiy.github.io/2024/git-stash-clear-recover/</id>
    <published>2024-03-14T02:38:28.000Z</published>
    <updated>2024-03-14T02:58:20.515Z</updated>
    
    <content type="html"><![CDATA[<p>** <code>git stash clear </code>之后恢复解决方案**</p><p>首先执行 <code>git fsck --lost-found</code></p><p>会出现</p><img src="./git-fsck.png"><p>只用关注 <strong>dangling commit</strong> 后面跟着的 id</p><p>然后 <code>git show </code> 对应的 id，查看是不是自己需要恢复的文件内容，尽量从下往上找。</p><img src="./git-show.png"><p>找到对应的 id 之后执行  <code>git merge &lt;id&gt;</code>，然后就还原了。</p><p>不过还原之后是作为一次 commit 提交到本地的，并非暂存状态</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;** &lt;code&gt;git stash clear &lt;/code&gt;之后恢复解决方案**&lt;/p&gt;
&lt;p&gt;首先执行 &lt;code&gt;git fsck --lost-found&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;会出现&lt;/p&gt;
&lt;img src=&quot;./git-fsck.png&quot;&gt;

&lt;p&gt;只</summary>
      
    
    
    
    
    <category term="git" scheme="http://sokiy.github.io/tags/git/"/>
    
  </entry>
  
  <entry>
    <title>张乃霞和李建军的爱恨情仇（1）</title>
    <link href="http://sokiy.github.io/2024/flomo-sync/"/>
    <id>http://sokiy.github.io/2024/flomo-sync/</id>
    <published>2024-01-12T13:30:22.000Z</published>
    <updated>2024-01-12T13:44:06.445Z</updated>
    
    <content type="html"><![CDATA[<p>模仿银教授的段子，图一乐。</p><img src="/2024/flomo-sync/love.png" class="" title="由文心一言绘制"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">张乃霞面无表情的看着眼前跪在地上声泪俱下哭诉的李建军，拿起刀缓缓地抵向了李建军的胸口。</span><br><span class="line"></span><br><span class="line">&quot;这是你第 17 次欺骗我的感情了，我已经原谅了你 16 次了，我这次绝对不会原谅你了&quot;</span><br><span class="line"></span><br><span class="line">李建军回忆起了前 16 次似曾相识的场景，不由得心中一喜，便开口道：你听我解...</span><br><span class="line"></span><br><span class="line">释字还没出口，顿觉心口一热，裆部也是一热。</span><br><span class="line"></span><br><span class="line">早知道刚才不喝这么多水了，李建军心想。</span><br><span class="line"></span><br><span class="line">张乃霞擦了擦眼泪和脸上的血，又握住了刀把，说道：渣男就是没有感情的感情机器，你给我去死吧。</span><br><span class="line"></span><br><span class="line">说罢一脚踹向了李建军的胸口。李建军倒飞出 2.14 米远，路上落满了血迹和水渍。</span><br><span class="line"></span><br><span class="line">李建军悟了，想到自己的感情经历，他在弥留之际终于悟了。</span><br><span class="line"></span><br><span class="line">用手指蘸着地上的混合的液体留下了：This shit is Life.  --Sokiy.</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;模仿银教授的段子，图一乐。&lt;/p&gt;
&lt;img src=&quot;/2024/flomo-sync/love.png&quot; class=&quot;&quot; title=&quot;由文心一言绘制&quot;&gt;

&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td clas</summary>
      
    
    
    
    
    <category term="段子" scheme="http://sokiy.github.io/tags/%E6%AE%B5%E5%AD%90/"/>
    
  </entry>
  
  <entry>
    <title>多产品集成跳转方案优化</title>
    <link href="http://sokiy.github.io/2024/go-http-redict/"/>
    <id>http://sokiy.github.io/2024/go-http-redict/</id>
    <published>2024-01-09T11:10:33.000Z</published>
    <updated>2024-01-09T12:18:28.804Z</updated>
    
    <content type="html"><![CDATA[<h3 id="需求来源"><a href="#需求来源" class="headerlink" title="需求来源"></a>需求来源</h3><p>我们目前需要整合多个不同的产品平台,让他们能够通过一个统一的入口来访问。但是这些被集成的产品都没有实施单点登录机制,而是使用  <code>session-cookie</code> 来做权限验证。因此,我们需要在用户点击进入不同产品时,先进行权限判断和跳转。大多数产品都是直接访问登录界面,然后系统会自动填充账号和密码后跳转到产品的默认首页。这种方案改造成本较低,但是会有一个短暂的白屏过程。我们可以尝试对此流程进行优化,实现无感知的平滑跳转。</p><h3 id="优化思路"><a href="#优化思路" class="headerlink" title="优化思路"></a>优化思路</h3><p>一个核心点：不用访问登录界面，自己模拟一个权限验证接口，如果已登录就直接跳转产品首页，如果未登录就接口层直接模拟登录流程生成 session，接口通过 302 和 set-cookie 完成上述需求。</p><!-- <img src="./flow.png" width="500px"/> --><img src="/2024/go-http-redict/flow.png" class="" title="FlowChart"><p>使用 <code>golang</code> 模拟一个 <code>http server</code> 完成这个需求，代码如下</p><img src="/2024/go-http-redict/code.png" class="" title="code"><h3 id="效果展示"><a href="#效果展示" class="headerlink" title="效果展示"></a>效果展示</h3><p>当访问 login 接口时，判断用户权限，根据用户权限判断是否需要 Set-cookie, 这样就针对于这个项目而言，改造成本就没有那么大，而且访问也是无感知的，不会出现白屏这种现象。</p><img src="/2024/go-http-redict/flow.gif" class="" title="flow"><p>Done!</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;需求来源&quot;&gt;&lt;a href=&quot;#需求来源&quot; class=&quot;headerlink&quot; title=&quot;需求来源&quot;&gt;&lt;/a&gt;需求来源&lt;/h3&gt;&lt;p&gt;我们目前需要整合多个不同的产品平台,让他们能够通过一个统一的入口来访问。但是这些被集成的产品都没有实施单点登录机制,而是使用</summary>
      
    
    
    
    
    <category term="tech" scheme="http://sokiy.github.io/tags/tech/"/>
    
  </entry>
  
  <entry>
    <title>下载安装激活 Office（和 Visio 共存）</title>
    <link href="http://sokiy.github.io/2023/active-office/"/>
    <id>http://sokiy.github.io/2023/active-office/</id>
    <published>2023-02-22T08:24:25.000Z</published>
    <updated>2023-02-22T09:05:09.013Z</updated>
    
    <content type="html"><![CDATA[<p>微软在 Office 2016 之后的版本均不提供 ISO 镜像下载（指正版商业镜像），VL （批量授权）版本的 Office 需要管理员手动使用 ODT （Office Deployment Tools）工具进行部署。</p><p>简单记录一下安装步骤</p><p>总体分四步</p><ol><li>下载官方部署工具</li><li>生成配置文件</li><li>根据配置文件下载安装</li><li>激活</li></ol><p><strong>使用 Terminal 操作时使用管理员权限</strong></p><h4 id="下载官方部署工具"><a href="#下载官方部署工具" class="headerlink" title="下载官方部署工具"></a>下载官方部署工具</h4><p>在 <a href="https://www.microsoft.com/en-us/download/details.aspx?id=49117">https://www.microsoft.com/en-us/download/details.aspx?id=49117</a> 下载 ODT 官方工具包</p><p><strong>尽量使用 Edge 浏览器打开，我曾经使用 Chrome 会出现一道白条完全无法进行下一步，遇到下载不了可以尝试换一个浏览器</strong></p><p>安装执行 ODT 工具会得到一个 <code>setup.exe</code> 文件和四个 XML 文件</p><h4 id="生成配置文件"><a href="#生成配置文件" class="headerlink" title="生成配置文件"></a>生成配置文件</h4><p>在 <a href="https://www.microsoft.com/en-us/download/details.aspx?id=49117">https://www.microsoft.com/en-us/download/details.aspx?id=49117</a> 根据界面选配自己需要的软件</p><blockquote><p>选择带<em>批量许可证</em>描述的版本，不要选择带 SPLA 字样的版本<br>授权和激活：选 KMS 选项。</p></blockquote><p>不止三件套 Word、Excel、PowerPoint，也可以跟 Visio、Project 一起下载安装<br>选配完成之后点击导出会生成一个 XML 文件，比如命名成 <code>Sokiy.xml</code>，跟之前 ODT 安装生成的 setup.exe 放到一个目录下</p><h4 id="根据配置文件下载安装"><a href="#根据配置文件下载安装" class="headerlink" title="根据配置文件下载安装"></a>根据配置文件下载安装</h4><p>使用 cmd 或者其他 terminal 在放置 setup.exe 的文件夹下执行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.\setup.exe /download Sokiy.xml</span><br></pre></td></tr></table></figure><p>然后会在当前目录下生成一个 Office 文件夹，所有需要的数据都会下载到这个目录里面。<br>根据选配的参数和网络情况下载时间有长有短，等到 terminal 显示下载完成时候执行下一步操作</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.\setup.exe /configure Sokiy.xml</span><br></pre></td></tr></table></figure><p>开始执行安装操作，这时候等待安装完成即可。</p><h4 id="激活"><a href="#激活" class="headerlink" title="激活"></a>激活</h4><p>64 位版本进入到 <code>C:\Program Files\Microsoft Office\</code>,<br>其他版本在 <code>C:\Program Files(x86)\Microsoft Office\Office16</code></p><p>里面可能有 Office16、Office15、Office14 字样，选大的。</p><p>进去之后有一个 <code>OSPP.VBS</code>, 然后执行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cscript ospp.vbs /sethst:kms.03k.org</span><br></pre></td></tr></table></figure><p>kms.03k.org 是 KMS 服务器地址，有很多在线的服务器</p><blockquote><p><a href="http://kms.03k.org/">http://kms.03k.org</a><br><a href="http://kms.chinancce.com/">http://kms.chinancce.com</a><br><a href="http://kms.luody.info/">http://kms.luody.info</a><br><a href="http://kms.lotro.cc/">http://kms.lotro.cc</a><br><a href="http://kms.luochenzhimu.com/">http://kms.luochenzhimu.com</a><br><a href="http://kms8.msguides.com/">http://kms8.MSGuides.com</a><br><a href="http://kms9.msguides.com/">http://kms9.MSGuides.com</a>  </p></blockquote><p>填写 KMS 服务器的时候<strong>不需要</strong>前面的 http://</p><p>然后执行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cscript ospp.vbs /act</span><br></pre></td></tr></table></figure><p>出现 Successful 字样就算成功了</p><p>参考</p><ul><li><a href="https://blog.03k.org/post/dowload-vloffice.html">安装最新VL版office快捷指南</a></li><li><a href="https://zhuanlan.zhihu.com/p/81561582">KMS服务,一句命令激活windows/office!</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;微软在 Office 2016 之后的版本均不提供 ISO 镜像下载（指正版商业镜像），VL （批量授权）版本的 Office 需要管理员手动使用 ODT （Office Deployment Tools）工具进行部署。&lt;/p&gt;
&lt;p&gt;简单记录一下安装步骤&lt;/p&gt;
&lt;p&gt;总</summary>
      
    
    
    
    
    <category term="tools" scheme="http://sokiy.github.io/tags/tools/"/>
    
  </entry>
  
  <entry>
    <title>命令式、函数式、响应式编程</title>
    <link href="http://sokiy.github.io/2023/Imperative-Function-Reactive-Programming/"/>
    <id>http://sokiy.github.io/2023/Imperative-Function-Reactive-Programming/</id>
    <published>2023-02-20T04:00:01.000Z</published>
    <updated>2023-02-20T06:44:51.498Z</updated>
    
    <content type="html"><![CDATA[<p>一点点的个人理解</p><h4 id="命令式编程"><a href="#命令式编程" class="headerlink" title="命令式编程"></a>命令式编程</h4><p>所见即所得，代码看起来就是一串命令的组合，看代码就能看出来具体要干啥。<br>例如：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// double array items</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">doubleItem</span> (<span class="params">arr</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">const</span> ret = []</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">let</span> i =<span class="number">0</span>;i &lt; arr.length;i++&gt;)&#123;</span><br><span class="line">        ret.push(arr[i] * <span class="number">2</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ret</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//add one array items</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">doubleItem</span> (<span class="params">arr</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">const</span> ret = []</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">let</span> i =<span class="number">0</span>;i &lt; arr.length;i++&gt;)&#123;</span><br><span class="line">        ret.push(arr[i] + <span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ret</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>代码的实现细节都是可以看到的，但是可扩展性不强且有一些重复代码。<br>代码量一上去很容易就能体会到，平常实现的某些需求从一些程度来讲模式都是相似的，这时候可以把共性的代码提取出来，把差异化作为参数传入，这个时候就能减少很多的重复代码。<br>这时候函数式编程的好处就体现出来了，我们就可以写出更简洁、更有表现力的代码。</p><h4 id="函数式编程"><a href="#函数式编程" class="headerlink" title="函数式编程"></a>函数式编程</h4><blockquote><p>函数式编程就是非常强调使用函数来解决问题的一种编程方式。</p></blockquote><p>还是上面的列子，就可以写成</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// double array items</span></span><br><span class="line"><span class="keyword">const</span> doubleItem = <span class="function">(<span class="params">arr</span>) =&gt;</span> arr.map(<span class="function">(<span class="params">item</span>) =&gt;</span> item * <span class="number">2</span>);</span><br><span class="line"><span class="keyword">const</span> addOne = <span class="function">(<span class="params">arr</span>) =&gt;</span> arr.map(<span class="function">(<span class="params">item</span>) =&gt;</span> item + <span class="number">1</span>);</span><br></pre></td></tr></table></figure><p>比命令式编程更加的简洁，无需关心内部的实现，只需要知道这个函数能达到需要的效果。  </p><p>函数式编程对函数有如下的特殊要求</p><ul><li>声明式（Declarative）</li><li>纯函数（Pure Function）</li><li>数据不可变性（Immutability）</li></ul><h5 id="声明式"><a href="#声明式" class="headerlink" title="声明式"></a>声明式</h5><p>声明式有点像是用描述的字符定义了一些行为的映射，比如 doubleItem 代表的就是把传入的数字数组中每个 item 都乘以 2，并且返回新的数组，doubleItem 和数组每个子项乘以 2 的映射，<br>doubleItem 就是这个功能的声明。</p><h5 id="纯函数"><a href="#纯函数" class="headerlink" title="纯函数"></a>纯函数</h5><p>纯函数需要符合两个条件</p><ul><li>函数的执行过程完全由输入参数决定，不会受除参数之外的任何数据影响。</li><li>函数不会修改任何外部状态。</li></ul><h5 id="数据不可变性"><a href="#数据不可变性" class="headerlink" title="数据不可变性"></a>数据不可变性</h5><p>在原数据不变的情况下，产生新的数据来表现这种变化，而不是修改原数据。<br>毕竟原数据不一定是一个程序在用，多进程操作数据会有很多意想不到的结果，还不如数据不可变，用新数据表现数据的变化，让数据的变化有迹可循。</p><p>//Todo</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;一点点的个人理解&lt;/p&gt;
&lt;h4 id=&quot;命令式编程&quot;&gt;&lt;a href=&quot;#命令式编程&quot; class=&quot;headerlink&quot; title=&quot;命令式编程&quot;&gt;&lt;/a&gt;命令式编程&lt;/h4&gt;&lt;p&gt;所见即所得，代码看起来就是一串命令的组合，看代码就能看出来具体要干啥。&lt;br&gt;例如：</summary>
      
    
    
    
    
    <category term="随便想想" scheme="http://sokiy.github.io/tags/%E9%9A%8F%E4%BE%BF%E6%83%B3%E6%83%B3/"/>
    
  </entry>
  
  <entry>
    <title>手写 call 函数</title>
    <link href="http://sokiy.github.io/2022/call-apply/"/>
    <id>http://sokiy.github.io/2022/call-apply/</id>
    <published>2022-10-27T06:14:14.000Z</published>
    <updated>2024-01-09T12:20:23.632Z</updated>
    
    <content type="html"><![CDATA[<h4 id="手写-call-函数"><a href="#手写-call-函数" class="headerlink" title="手写 call 函数"></a>手写 call 函数</h4><blockquote><p>call 函数就是改变当前函数 this 的指向<br>思路就是在自己手写的函数内部，在传入的对象中增加同样的函数，然后执行返回，最后删除即可。</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Obj1 = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&quot;Sokiy&quot;</span>,</span><br><span class="line">    <span class="attr">say</span>: <span class="function"><span class="keyword">function</span> (<span class="params">prefix, age</span>) </span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(</span><br><span class="line">            <span class="string">`<span class="subst">$&#123;prefix&#125;</span>, My name is <span class="subst">$&#123;<span class="built_in">this</span>.name&#125;</span>, i&#x27;m <span class="subst">$&#123;age&#125;</span> years old.`</span></span><br><span class="line">        );</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">Obj1.say(<span class="string">&quot;Hello&quot;</span>, <span class="number">20</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> Obj2 = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&quot;Tong&quot;</span>,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">Obj1.say.call(Obj2, <span class="string">&quot;Hello&quot;</span>, <span class="number">18</span>);</span><br></pre></td></tr></table></figure><p>output:</p><blockquote><p> Hello, My name is Sokiy, i’m 20 years old.<br>   Hello, My name is Tong, i’m 18 years old.</p></blockquote><h5 id="手写的-call-函数"><a href="#手写的-call-函数" class="headerlink" title="手写的 call 函数"></a>手写的 call 函数</h5><p>不用箭头是因为箭头函数没有自己的<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this"><code>this</code></a>，<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments"><code>arguments</code></a>，<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/super"><code>super</code></a>或<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new.target"><code>new.target</code></a><br>我们需要用到这个东西</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.tinycall = <span class="function"><span class="keyword">function</span> (<span class="params">target, ...args</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> key = <span class="built_in">Symbol</span>();  <span class="comment">//给定一个独一无二的 key，有可能会和原 target 中key 产生冲突</span></span><br><span class="line">  target[key] = <span class="built_in">this</span>; <span class="comment">// this 就是需要执行的函数，所谓的重新指向就是复制了一份</span></span><br><span class="line">  <span class="keyword">const</span> res = target[key](...args);</span><br><span class="line">  <span class="keyword">delete</span> target[key];</span><br><span class="line">  <span class="keyword">return</span> res;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h4 id="手写-apply-函数"><a href="#手写-apply-函数" class="headerlink" title="手写 apply 函数"></a>手写 apply 函数</h4><p>同 call 函数，无非是 args 参数是否是数组的区别</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h4 id=&quot;手写-call-函数&quot;&gt;&lt;a href=&quot;#手写-call-函数&quot; class=&quot;headerlink&quot; title=&quot;手写 call 函数&quot;&gt;&lt;/a&gt;手写 call 函数&lt;/h4&gt;&lt;blockquote&gt;
&lt;p&gt;call 函数就是改变当前函数 this 的指向&lt;</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>HTTP 30X 跳转问题记录</title>
    <link href="http://sokiy.github.io/2022/http-status-30x/"/>
    <id>http://sokiy.github.io/2022/http-status-30x/</id>
    <published>2022-08-29T07:00:27.000Z</published>
    <updated>2022-08-29T07:39:28.573Z</updated>
    
    <content type="html"><![CDATA[<h4 id="现象"><a href="#现象" class="headerlink" title="现象"></a>现象</h4><p>在做一个项目的时候遇到了需要做 30x 跳转的问题，记录一下。</p><blockquote><p>做单点登录的时候需要访问某一个接口后跳转到 CAS 服务器的登录界面，这时候采取了返回 30X 状态码让浏览器做重定向到其他界面。<br>然后发现并不能跳转，如果 IP 不一样的话直接会报跨域错误。</p></blockquote><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status">HTTP 响应状态码</a></p><h4 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h4><h5 id="跨域原因"><a href="#跨域原因" class="headerlink" title="跨域原因"></a>跨域原因</h5><p>当我在 <strong><a href="http://www.a.com/">www.a.com</a></strong> 做 <code>Ajax XHR</code> 请求，想在请求中重定向到其他的界面，这时候接口返回 302 状态码，location 为 <strong><a href="http://www.b.com/">www.b.com</a></strong>。  </p><p>浏览器收到 302 的请求之后，会自己在当前界面请求 request header 中的 location 地址，比如说 location 为 <strong><a href="http://www.b.com/">www.b.com</a></strong>，但是这个时候就是在 <strong><a href="http://www.a.com/">www.a.com</a></strong> 的界面请求 <strong><a href="http://www.b.com/">www.b.com</a></strong> 的接口数据，这时候会有 cors 跨域问题。</p><p>这时候查看控制台，会发现请求的 <strong><a href="http://www.b.com/">www.b.com</a></strong> 的请求并非是 <code>document</code> 资源请求类型，而是 <code>xhr</code> 的类型。</p><p>但是如果 <strong><a href="http://www.a.com/">www.a.com</a></strong> 是一个 <code>document</code> 的请求，302 后就相当于在 <strong><a href="http://www.a.com/">www.a.com</a></strong> 打开 <strong><a href="http://www.b.com/">www.b.com</a></strong> 的超链接，会跳转到 <strong><a href="http://www.b.com/">www.b.com</a></strong>。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h4 id=&quot;现象&quot;&gt;&lt;a href=&quot;#现象&quot; class=&quot;headerlink&quot; title=&quot;现象&quot;&gt;&lt;/a&gt;现象&lt;/h4&gt;&lt;p&gt;在做一个项目的时候遇到了需要做 30x 跳转的问题，记录一下。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;做单点登录的时候需要访问某一个接口后</summary>
      
    
    
    
    
    <category term="HTTP" scheme="http://sokiy.github.io/tags/HTTP/"/>
    
  </entry>
  
  <entry>
    <title>异或 XOR 及其应用</title>
    <link href="http://sokiy.github.io/2022/what-is-exclusive-or/"/>
    <id>http://sokiy.github.io/2022/what-is-exclusive-or/</id>
    <published>2022-08-12T08:23:19.000Z</published>
    <updated>2022-08-12T10:31:38.335Z</updated>
    
    <content type="html"><![CDATA[<h4 id="含义"><a href="#含义" class="headerlink" title="含义"></a>含义</h4><p>XOR 是 exclusive OR 的缩写，更单纯的 OR 运算。</p><p>OR 运算的运算子有两种情况，计算结果为 true。</p><ul><li>  一个为 true，另一个为 false</li><li>  两个都为 true</li></ul><p>XOR 排除了第二种情况，只针对两个运算子值不一样的情况，更符合理想中的 OR 运算。</p><p>XOR 可以用来判断两个值是否相等。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0</span> ^ <span class="number">0</span> = <span class="number">0</span></span><br><span class="line"><span class="number">1</span> ^ <span class="number">1</span> = <span class="number">0</span></span><br><span class="line"><span class="number">0</span> ^ <span class="number">1</span> = <span class="number">1</span></span><br><span class="line"><span class="number">1</span> ^ <span class="number">0</span> = <span class="number">1</span></span><br></pre></td></tr></table></figure><p>一个通俗的解释</p><blockquote><p>只有男性和女性能生出孩子，否则就不行。</p></blockquote><h4 id="明确含义"><a href="#明确含义" class="headerlink" title="明确含义"></a>明确含义</h4><p>XOR 是数学运算，既然是数学运算，首先需要明确一个点</p><p><strong>异或运算仅仅适用于数字间的运算</strong><br><strong>异或运算仅仅适用于数字间的运算</strong><br><strong>异或运算仅仅适用于数字间的运算</strong></p><h5 id="数字间的异或"><a href="#数字间的异或" class="headerlink" title="数字间的异或"></a>数字间的异或</h5><p>以 javascript 语言举例</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span> ^ <span class="number">2</span> = <span class="number">3</span></span><br><span class="line"><span class="number">3</span> ^ <span class="number">4</span> = <span class="number">7</span></span><br><span class="line"><span class="number">3</span> ^ <span class="number">5</span> = <span class="number">6</span></span><br></pre></td></tr></table></figure><p>数字间的异或就是按位进行异或操作</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">3</span> ^ <span class="number">4</span>  =  <span class="number">0110</span> ^ <span class="number">1000</span> = <span class="number">1110</span> = <span class="number">7</span></span><br></pre></td></tr></table></figure><h5 id="非数字的异或"><a href="#非数字的异或" class="headerlink" title="非数字的异或"></a>非数字的异或</h5><p>然后测试一下字符串异或</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;a&#x27;</span> ^ <span class="string">&#x27;b&#x27;</span> = <span class="number">0</span></span><br><span class="line"><span class="string">&#x27;aaaaaaa&#x27;</span> ^ <span class="string">&#x27;dadasdasdasdas&#x27;</span> = <span class="number">0</span></span><br><span class="line"><span class="literal">true</span> ^ <span class="literal">false</span> = <span class="number">1</span></span><br><span class="line"><span class="literal">true</span> ^ <span class="string">&#x27;a&#x27;</span> = <span class="number">1</span></span><br></pre></td></tr></table></figure><p>为什么两个字符串间异或会是 0 ?<br>为什么 true 跟 false 异或会是 1 ?<br>为什么布尔值跟字符串异或会是 1 ?</p><h5 id="非数字异或操作原理分析"><a href="#非数字异或操作原理分析" class="headerlink" title="非数字异或操作原理分析"></a>非数字异或操作原理分析</h5><p>异或运算仅仅适用于数字间的运算，所以在进行异或操作前，会对两边的操作数做类型转换操作，</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Number</span>(<span class="string">&#x27;String&#x27;</span>) = <span class="literal">NaN</span></span><br><span class="line"><span class="built_in">Number</span>(<span class="number">1</span>) = <span class="number">1</span></span><br><span class="line"><span class="built_in">Number</span>(<span class="literal">true</span>) = <span class="number">1</span></span><br><span class="line"><span class="built_in">Number</span>(<span class="literal">false</span>) = <span class="number">0</span></span><br></pre></td></tr></table></figure><p>所以</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;a&#x27;</span> ^ <span class="string">&#x27;b&#x27;</span> = <span class="literal">NaN</span> ^ <span class="literal">NaN</span> = <span class="number">0</span></span><br><span class="line"><span class="literal">true</span> ^ <span class="literal">false</span> = <span class="number">1</span> ^ <span class="number">0</span> = <span class="number">1</span></span><br><span class="line"><span class="literal">true</span> ^ <span class="string">&#x27;a&#x27;</span> = <span class="number">1</span> ^ <span class="literal">NaN</span> = <span class="number">1</span></span><br></pre></td></tr></table></figure><p>这个在 Python 语言中同样适用</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span> ^ <span class="number">2</span> = <span class="number">3</span></span><br><span class="line"><span class="string">&#x27;1&#x27;</span> ^ <span class="string">&#x27;1&#x27;</span> = TypeError: unsupported operand <span class="built_in">type</span>(s) <span class="keyword">for</span> ^: <span class="string">&#x27;str&#x27;</span> <span class="keyword">and</span> <span class="string">&#x27;str&#x27;</span></span><br><span class="line"><span class="literal">True</span> ^ <span class="literal">False</span> = <span class="number">1</span></span><br><span class="line"><span class="built_in">int</span>(<span class="literal">True</span>) = <span class="number">1</span></span><br></pre></td></tr></table></figure><h4 id="运算定律"><a href="#运算定律" class="headerlink" title="运算定律"></a>运算定律</h4><p>XOR 满足如下定律，</p><ol><li>因为 0 ^ 0 === 1 ^ 1, 所以</li></ol><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">x ^ x = <span class="number">0</span></span><br></pre></td></tr></table></figure><ol start="2"><li>因为 0 ^ 1 === 1 ^ 0, 所以</li></ol><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(a ^ b) === (b ^ a);</span><br></pre></td></tr></table></figure><ol start="3"><li>因为 0 ^ ( 1 ^ 1 ) === (0 ^ 1) ^ 1, 所以</li></ol><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">a ^ b ^ (c === a) ^ (b ^ c);</span><br></pre></td></tr></table></figure><h4 id="应用"><a href="#应用" class="headerlink" title="应用"></a>应用</h4><h5 id="简化运算"><a href="#简化运算" class="headerlink" title="简化运算"></a>简化运算</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">a ^ b ^ c ^ b ^c =  b ^ b ^ c ^ c ^ a = <span class="number">0</span> ^ <span class="number">0</span> ^ a = a</span><br></pre></td></tr></table></figure><h5 id="加密"><a href="#加密" class="headerlink" title="加密"></a>加密</h5><p>根据 a ^ b ^ b = a, 我们可以这么推断 text ^ key ^ key = text,<br>因为 text 如果是字符串的话，是无法参与 XOR 运算的，所以我们首先要把字符串转成可以用数字代替的形式。</p><p>以 ASCll 中的字符举例，可以使用 ASCll 对照表还原</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> key = <span class="string">&quot;Sokiy&quot;</span></span><br><span class="line">  .split(<span class="string">&quot;&quot;</span>)</span><br><span class="line">  .map(<span class="function">(<span class="params">item</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> item.charCodeAt();</span><br><span class="line">  &#125;)</span><br><span class="line">  .join(<span class="string">&quot;&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//加密 &amp; 解密</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">encrypt</span>(<span class="params">str</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> str !== <span class="string">&quot;string&quot;</span>) &#123;</span><br><span class="line">    <span class="keyword">throw</span> <span class="string">&quot;Parameter is not a string!&quot;</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">let</span> result = [];</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; str.length; i++) &#123;</span><br><span class="line">    result.push(<span class="built_in">String</span>.fromCharCode(str[i].charCodeAt() ^ key));</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> result.join(<span class="string">&quot;&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(encrypt(<span class="string">&quot;Sokiy&quot;</span>)); <span class="comment">//ᄲᄎᄊᄈᄘ</span></span><br><span class="line"><span class="built_in">console</span>.log(encrypt(encrypt(<span class="string">&quot;Sokiy&quot;</span>))); <span class="comment">//Sokiy</span></span><br></pre></td></tr></table></figure><h4 id="一道面试题"><a href="#一道面试题" class="headerlink" title="一道面试题"></a>一道面试题</h4><p>Single Number<br>Given an array of integers, every element appears twice except for one. Find that single one.</p><p>给定一个整数数组，其中只有一个整数出现了一次，其余的整数都出现了两次，求出这个出现了一次的整数的值</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> arr = [<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">3</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> single = arr[<span class="number">0</span>];</span><br><span class="line">arr.forEach(<span class="function">(<span class="params">element</span>) =&gt;</span> &#123;</span><br><span class="line">  single = single ^ element;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h4 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h4><ul><li><a href="https://www.ruanyifeng.com/blog/2021/01/_xor.html">阮一峰：异或运算 XOR 教程</a></li><li><a href="https://juejin.cn/post/6844903840450363399">JS迷你书 Number类型二进制表示法</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h4 id=&quot;含义&quot;&gt;&lt;a href=&quot;#含义&quot; class=&quot;headerlink&quot; title=&quot;含义&quot;&gt;&lt;/a&gt;含义&lt;/h4&gt;&lt;p&gt;XOR 是 exclusive OR 的缩写，更单纯的 OR 运算。&lt;/p&gt;
&lt;p&gt;OR 运算的运算子有两种情况，计算结果为 true。&lt;/</summary>
      
    
    
    
    
    <category term="Math" scheme="http://sokiy.github.io/tags/Math/"/>
    
  </entry>
  
  <entry>
    <title>threeJS 键盘控制物块移动动画优化</title>
    <link href="http://sokiy.github.io/2022/threejs-move-control/"/>
    <id>http://sokiy.github.io/2022/threejs-move-control/</id>
    <published>2022-08-04T09:59:28.000Z</published>
    <updated>2022-08-04T11:32:17.485Z</updated>
    
    <content type="html"><![CDATA[<h3 id="机制分析"><a href="#机制分析" class="headerlink" title="机制分析"></a>机制分析</h3><h4 id="控制物块移动核心思想"><a href="#控制物块移动核心思想" class="headerlink" title="控制物块移动核心思想"></a>控制物块移动核心思想</h4><ul><li>  监听键盘事件</li><li>  在键盘触发的 callback 函数中更改物块 <code>position</code> 属性的 <code>x,y,z</code> 值</li></ul><h4 id="一个小问题"><a href="#一个小问题" class="headerlink" title="一个小问题"></a>一个小问题</h4><p>监听键盘的 callback 函数可以触发对应的物块移动，假如一直按下绑定的移动按键，物块移动看起来就生硬，一卡一卡的，有顿挫感。</p><h4 id="原因分析"><a href="#原因分析" class="headerlink" title="原因分析"></a>原因分析</h4><p>webGL 动画更新时采用 <a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a> 来告诉下一帧需要执行什么操作，以屏幕刷新率为 <code>60HZ</code> 举例，相当于 <code>1s</code> 内会执行 60 次 <code>requestAnimationFrame</code> 调用的函数。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">render</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&quot;Hello world!&quot;</span>);</span><br><span class="line">  requestAnimationFrame(render);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>一秒内会输出 60 次 Hello world!</p><p>但是 <code>document.addEventListener</code> 监听的 <code>keydown 、keyup 、keypress</code> 的触发时间并没有跟屏幕刷新帧率保持一致，而且 <code>keydown</code> 事件的第一次触发到按下持续触发中间还有延迟，这就造成了在键盘监听事件中进行物块的移动会导致动画看起来一卡一卡的。</p><h3 id="优化调整"><a href="#优化调整" class="headerlink" title="优化调整"></a>优化调整</h3><p>思路就是把物块移动的操作放到 <code>requestAnimationFrame</code> 的调用函数中执行。</p><p>问题就来了，在 <code>requestAnimationFrame</code> 是要怎么感知到当前按下了哪个键的，总不能在  <code>requestAnimationFrame</code>  中每执行一次就监听一次 <code>keydown、keyup</code> 事件吧？</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="built_in">global</span> = &#123;&#125;;</span><br><span class="line"><span class="comment">//创建一个 cube</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createCube</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> cubeGeometry = <span class="keyword">new</span> THREE.BoxGeometry(<span class="number">10</span>, <span class="number">10</span>, <span class="number">10</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line">  <span class="keyword">const</span> cubeMaterial = <span class="keyword">new</span> THREE.MeshBasicMaterial(&#123;</span><br><span class="line">    <span class="attr">color</span>: <span class="number">0xfff000</span>,</span><br><span class="line">    <span class="attr">wireframe</span>: <span class="literal">true</span>,</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="built_in">global</span>.cube = <span class="keyword">new</span> THREE.Mesh(cubeGeometry, cubeMaterial);</span><br><span class="line">  <span class="built_in">global</span>.cube.position.set(<span class="number">0</span>, <span class="number">5</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">global</span>.scene.add(<span class="built_in">global</span>.cube);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Todo</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;机制分析&quot;&gt;&lt;a href=&quot;#机制分析&quot; class=&quot;headerlink&quot; title=&quot;机制分析&quot;&gt;&lt;/a&gt;机制分析&lt;/h3&gt;&lt;h4 id=&quot;控制物块移动核心思想&quot;&gt;&lt;a href=&quot;#控制物块移动核心思想&quot; class=&quot;headerlink&quot; titl</summary>
      
    
    
    
    
    <category term="optimize" scheme="http://sokiy.github.io/tags/optimize/"/>
    
    <category term="threeJS" scheme="http://sokiy.github.io/tags/threeJS/"/>
    
  </entry>
  
  <entry>
    <title>浏览器环境 js 加载 json 文件</title>
    <link href="http://sokiy.github.io/2022/js-load-json-file/"/>
    <id>http://sokiy.github.io/2022/js-load-json-file/</id>
    <published>2022-07-28T03:11:18.000Z</published>
    <updated>2022-08-08T03:56:36.206Z</updated>
    
    <content type="html"><![CDATA[<h2 id="加载-json-文件方式"><a href="#加载-json-文件方式" class="headerlink" title="加载 json 文件方式"></a>加载 json 文件方式</h2><p>在浏览器环境加载 json 文件，不同于 Node 环境可以采用 commonJS 模块化加载方式，直接</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const data = require(&quot;./demo.json&quot;)</span><br></pre></td></tr></table></figure><p>就行，浏览器环境不支持这种加载模式</p><p>记录一下怎么在浏览器环境加载 json 文件</p><h3 id="js-文件引入"><a href="#js-文件引入" class="headerlink" title=".js 文件引入"></a><code>.js</code> 文件引入</h3><p>使用 <code>script</code> 的机制，对 json 文件做适量改造，例如</p><p>// demo.json</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">&quot;id&quot;</span>: <span class="number">8848</span>,</span><br><span class="line">  <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;Sokiy&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>改造后<br>// demo.json.js</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> demo = &#123;</span><br><span class="line">  <span class="attr">id</span>: <span class="number">8848</span>,</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&quot;Sokiy&quot;</span>,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>直接 <code>script</code> 引入就行</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;script src=<span class="string">&#x27;./demo.json.js&#x27;</span>&gt;&lt;/script&gt;</span><br></pre></td></tr></table></figure><h4 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h4><ul><li>  只需要少量改造就可以加载对应的 json 文件</li><li>  json 对象会保存在全局对象中，随用随取</li></ul><h4 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h4><ul><li>  需要改造</li><li>  容易造成全局变量污染</li></ul><h3 id="XHR-加载"><a href="#XHR-加载" class="headerlink" title="XHR 加载"></a>XHR 加载</h3><p>使用原生 XHR (XMLHttpRequest) 或者 jQuery 加载 json 文件</p><p>使用 jQuery 加载 json 文件</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$(selector).getJSON(url, data, success(data, status, xhr));</span><br><span class="line"></span><br><span class="line">$.getJSON(<span class="string">&quot;demo.json&quot;</span>, <span class="function"><span class="keyword">function</span> (<span class="params">data, status, xhr</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// code</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h4 id="优点-1"><a href="#优点-1" class="headerlink" title="优点"></a>优点</h4><ul><li>  语法简单</li><li>  不用对 json 文件做改动</li></ul><h4 id="缺点-1"><a href="#缺点-1" class="headerlink" title="缺点"></a>缺点</h4><ul><li>  需要加载 jQuery 文件</li></ul><h3 id="Fetch-加载"><a href="#Fetch-加载" class="headerlink" title="Fetch 加载"></a>Fetch 加载</h3><p>目前浏览器大都支持 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">fetch Api</a></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">fetch(<span class="string">&quot;./demo,json&quot;</span>).then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> res.json();</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>如果需要加载多个 json 文件</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> file_list = [<span class="string">&quot;./demo.json&quot;</span>, <span class="string">&quot;./data.json&quot;</span>];</span><br><span class="line"><span class="built_in">Promise</span>.all(</span><br><span class="line">  file_list.map(<span class="function">(<span class="params">file</span>) =&gt;</span></span><br><span class="line">    fetch(file).then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> res.json();</span><br><span class="line">    &#125;)</span><br><span class="line">  )</span><br><span class="line">).then(<span class="function">(<span class="params">ret</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// ret = [&#123;demo.json.data&#125;,&#123;data.json.data&#125;]</span></span><br><span class="line">  <span class="comment">//code After load some json files</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h4 id="优点-2"><a href="#优点-2" class="headerlink" title="优点"></a>优点</h4><ul><li>  fetch 目前支持度比较广且语法简单</li><li>  不用额外引入其他第三方库资源</li></ul><h4 id="缺点-2"><a href="#缺点-2" class="headerlink" title="缺点"></a>缺点</h4><ul><li>  基于 Promise 的，但是对 http status 的状态 reject 会跟一般流程存在差异</li><li>  加载的 status 状态没有像 XHR 那么直观</li></ul><p>Done.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;加载-json-文件方式&quot;&gt;&lt;a href=&quot;#加载-json-文件方式&quot; class=&quot;headerlink&quot; title=&quot;加载 json 文件方式&quot;&gt;&lt;/a&gt;加载 json 文件方式&lt;/h2&gt;&lt;p&gt;在浏览器环境加载 json 文件，不同于 Node 环境可以</summary>
      
    
    
    
    
    <category term="javascript" scheme="http://sokiy.github.io/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>JS 递归速度优化 &amp; 堆栈异常优化</title>
    <link href="http://sokiy.github.io/2022/js-optimize-trampoline/"/>
    <id>http://sokiy.github.io/2022/js-optimize-trampoline/</id>
    <published>2022-07-25T08:44:20.000Z</published>
    <updated>2022-07-28T03:46:30.375Z</updated>
    
    <content type="html"><![CDATA[<h3 id="为什么会发生堆栈异常"><a href="#为什么会发生堆栈异常" class="headerlink" title="为什么会发生堆栈异常"></a>为什么会发生堆栈异常</h3><p>JS 执行时遇到新的执行函数的时候就会把需要执行的函数压入堆栈，函数执行完成之后会退栈释放对应的内存空间。<br>如果压入的函数数量过多，就会造成：</p><img src="/2022/js-optimize-trampoline/stack.png" class="" title="Maximum call stack size exceeded"><h3 id="复现异常"><a href="#复现异常" class="headerlink" title="复现异常"></a>复现异常</h3><p>先简单复现一下怎么造成堆栈异常</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">stack</span>(<span class="params">n</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (n === <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> stack(n - <span class="number">1</span>);</span><br><span class="line">&#125;</span><br><span class="line">stack(<span class="number">100000</span>);</span><br></pre></td></tr></table></figure><p>打断点看一下堆栈调用情况</p><img src="/2022/js-optimize-trampoline/stack-1.jpg" class="" title="堆栈溢出"><p>随着递归次数的增多，stack 函数一直在压入堆栈，然后超过浏览器堆栈数量上限（貌似不同平台不同版本会有些差异），直接 GG。</p><h3 id="实例研究"><a href="#实例研究" class="headerlink" title="实例研究"></a>实例研究</h3><p>我们就以经典的 Fibonacci 求值举例，做一次优化</p><h4 id="递归实现-Fibonacci-数列求值"><a href="#递归实现-Fibonacci-数列求值" class="headerlink" title="递归实现 Fibonacci 数列求值"></a>递归实现 Fibonacci 数列求值</h4><p>用递归实现计算一下第 100 位的 Fibonacci 的值，顺带计算一下执行时间。</p><p>代码如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params">n</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (n === <span class="number">0</span> || n === <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> fibonacci(n - <span class="number">1</span>) + fibonacci(n - <span class="number">2</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.time(<span class="string">&quot;fibonacci&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(fibonacci(<span class="number">100</span>));</span><br><span class="line"><span class="built_in">console</span>.timeEnd(<span class="string">&quot;fibonacci&quot;</span>);</span><br></pre></td></tr></table></figure><p>WTF，我的机器配置 <code>Intel i7-10700 2.90GHz</code> + <code>16GB</code> 跑了能有 2 分钟还没出来，<br>CPU 一直在 10% 左右。</p><p>降低一下标准，计算一下第 45 位的 Fibonacci 的值，顺带计算一下执行时间。<br>（降到 50 都算的时间很长，45 终于是有结果输出了）</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params">n</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (n === <span class="number">0</span> || n === <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> fibonacci(n - <span class="number">1</span>) + fibonacci(n - <span class="number">2</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.time(<span class="string">&quot;fibonacci&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(fibonacci(<span class="number">45</span>));</span><br><span class="line"><span class="built_in">console</span>.timeEnd(<span class="string">&quot;fibonacci&quot;</span>);</span><br></pre></td></tr></table></figure><img src="/2022/js-optimize-trampoline/fibonacci-1.png" class="" title="斐波那契数列输出"><p>差不多 10S 输出结果，Emm，属实有点拉跨。</p><h4 id="优化的点分析"><a href="#优化的点分析" class="headerlink" title="优化的点分析"></a>优化的点分析</h4><p>上面的递归 Fibonacci 存在一个严重的问题 <strong>重复计算太多了</strong>，<br>计算 fibonacci(5) 就需要计算 fibonacci(4)、fibonacci(3)、fibonacci(2)、fibonacci(1)，然后这一轮里计算 fibonacci(4) 就又要计算 fibonacci(3)、fibonacci(2)、fibonacci(1)，然后依此类推，CPU 占比那么高不是没有理由的。</p><p>可以做一下统计，稍微改动一下代码</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> count = <span class="number">0</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params">n</span>) </span>&#123;</span><br><span class="line">  count++;</span><br><span class="line">  <span class="keyword">if</span> (n === <span class="number">0</span> || n === <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> fibonacci(n - <span class="number">1</span>) + fibonacci(n - <span class="number">2</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.time(<span class="string">&quot;fibonacci&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(fibonacci(<span class="number">45</span>));</span><br><span class="line"><span class="built_in">console</span>.timeEnd(<span class="string">&quot;fibonacci&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">`the number of exec count is <span class="subst">$&#123;count&#125;</span>`</span>);</span><br></pre></td></tr></table></figure><p>看一下结果输出</p><img src="/2022/js-optimize-trampoline/fibonacci-count-45.png" class="" title="斐波那契数列输出"><p>fibonacci(45) 已经 10 亿级别的计算量了。</p><p>有一个优化的点就是我们可以把重复计算部分去掉</p><h5 id="优化一-去除重复计算"><a href="#优化一-去除重复计算" class="headerlink" title="优化一: 去除重复计算"></a>优化一: 去除重复计算</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fibonacci(3) = fibonacci(2) + fibonacci(1)</span><br></pre></td></tr></table></figure><p>我们计算 fibonacci(4) 的时候，可以把 fibonacci(3) 跟 fibonacci(2) 的值带上，这样就不用重复计算了。</p><p>然后代码如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> count = <span class="number">0</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params">n</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (n === <span class="number">0</span> || n === <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param </span>n2  当前计算数的前面第二个值</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param </span>n1   当前计算数的前一个值</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param </span>flag  当前计算到第几位</span></span><br><span class="line"><span class="comment">   * **/</span></span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">fibonacci_inner</span>(<span class="params">n2, n1, flag</span>) </span>&#123;</span><br><span class="line">    count++;</span><br><span class="line">    <span class="keyword">if</span> (flag === n) &#123;</span><br><span class="line">      <span class="keyword">return</span> n1 + n2;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> fibonacci_inner(n1, n1 + n2, flag + <span class="number">1</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//从第二位开始计算</span></span><br><span class="line">  <span class="keyword">return</span> fibonacci_inner(<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.time(<span class="string">&quot;fibonacci&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(fibonacci(<span class="number">45</span>));</span><br><span class="line"><span class="built_in">console</span>.timeEnd(<span class="string">&quot;fibonacci&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">`the number of exec count is <span class="subst">$&#123;count&#125;</span>`</span>);</span><br></pre></td></tr></table></figure><p>每次递归都会带上前两次值的结果，最终只需要输出前两次结果的和就行。<br>看一下结果输出：</p><img src="/2022/js-optimize-trampoline/fibonacci-count-45-optimize.png" class="" title="斐波那契优化一"><p>快的不是一点半点，从 <code>29019ms</code> 到 <code>0.083ms</code> 的提升。 而且也只计算了每个数各自的结果，没有重复计算。</p><p>然后我们多计算几组值</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">fibonacci(<span class="number">100</span>)</span><br><span class="line">the result is <span class="number">573147844013817200000</span></span><br><span class="line">fibonacci: <span class="number">0.078857421875</span> ms</span><br><span class="line">the number of exec count is <span class="number">99</span></span><br><span class="line"></span><br><span class="line">fibonacci(<span class="number">1000</span>)</span><br><span class="line">the result is <span class="number">7.0330367711422765e+208</span></span><br><span class="line">fibonacci: <span class="number">0.1318359375</span> ms</span><br><span class="line">the number of exec count is <span class="number">999</span></span><br><span class="line"></span><br><span class="line">fibonacci(<span class="number">5000</span>)</span><br><span class="line">the result is Infinity</span><br><span class="line">fibonacci: <span class="number">0.325927734375</span> ms</span><br><span class="line">the number of exec count is <span class="number">4999</span></span><br></pre></td></tr></table></figure><p>到 fibonacci(5000) 时，结果已经超过 js Number 类型能表示的数量的最大上限 <code>2^53 -1</code>，<br>我们再改动一下代码, 使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt">Bigint</a></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> count = <span class="number">0</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params">n</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (n === <span class="number">0</span> || n === <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param </span>n2  当前计算数的前面第二个值</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param </span>n1   当前计算数的前一个值</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param </span>flag  当前计算到第几位</span></span><br><span class="line"><span class="comment">   * **/</span></span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">fibonacci_inner</span>(<span class="params">n2, n1, flag</span>) </span>&#123;</span><br><span class="line">    count++;</span><br><span class="line">    <span class="keyword">if</span> (flag === n) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">BigInt</span>(n1 + n2);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> fibonacci_inner(<span class="built_in">BigInt</span>(n1), <span class="built_in">BigInt</span>(n1 + n2), flag + <span class="number">1</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//从第二位开始计算</span></span><br><span class="line">  <span class="keyword">return</span> fibonacci_inner(<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.time(<span class="string">&quot;fibonacci&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">`the result is <span class="subst">$&#123;<span class="built_in">BigInt</span>(fibonacci(<span class="number">5000</span>))&#125;</span>`</span>);</span><br><span class="line"><span class="built_in">console</span>.timeEnd(<span class="string">&quot;fibonacci&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">`the number of exec count is <span class="subst">$&#123;count&#125;</span>`</span>);</span><br></pre></td></tr></table></figure><p>结果为</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">the result is <span class="number">6276302800488957086035253108349684055478528702736457439025824448927937256811663264475883711527806250329984690249846819800648580083040107584710332687596562185073640422286799239932615797105974710857095487342820351307477141875012176874307156016229965832589137779724973854362777629878229505500260477136108363709090010421536915488632339240756987974122598603591920306874926755600361865354330444681915154695741851960071089944015319300128574107662757054790648152751366475529121877212785489665101733755898580317984402963873738187000120737824193162011399200547424034440836239726275765901190914513013217132050988064832024783370583789324109052449717186857327239783000020791777804503930439875068662687670678802914269784817022567088069496231111407908953313902398529655056082228598715882365779469902465675715699187225655878240668599547496218159297881601061923195562143932693324644219266564617042934227893371179832389642895285401263875342640468017378925921483580111278055044254198382265567395946431803304304326865077742925818757370691726168228648841319231470626</span></span><br><span class="line">fibonacci: <span class="number">3.984130859375</span> ms</span><br><span class="line">the number of exec count is <span class="number">4999</span></span><br></pre></td></tr></table></figure><p>那我们计算 fibonacci(10000) 怎样？<br>然后是</p><blockquote><p>Maximum call stack size exceeded</p></blockquote><p>又超过堆栈上限了，所以我们需要在做一次优化</p><h5 id="优化二-防止递归超过堆栈上限"><a href="#优化二-防止递归超过堆栈上限" class="headerlink" title="优化二: 防止递归超过堆栈上限"></a>优化二: 防止递归超过堆栈上限</h5><p>这个时候需要用到一个思路，就是把递归时递归的函数暴露出来，交给外面去执行，把递归变成循环同步执行。<br>所以我们会用到一个 js 函数 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">bind</a></p><blockquote><p>The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.</p></blockquote><p>bind 会创建一个新的函数，bind 的第一个参数会作为创建函数的 <code>this</code> 值，其余参数会作为参数传递给新函数。<br>然后我们还会用到 <code>trampoline 函数</code> 蹦床函数这个说法，蹦床函数其实很简单，就是参数是函数就执行函数，参数是其他类型就返回。</p><p>再改动一下代码</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 蹦床函数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">trampoline</span>(<span class="params">f</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">while</span> (f &amp;&amp; f <span class="keyword">instanceof</span> <span class="built_in">Function</span>) &#123;</span><br><span class="line">    f = f();</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> f;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> count = <span class="number">0</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params">n</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (n === <span class="number">0</span> || n === <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param </span>n2  当前计算数的前面第二个值</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param </span>n1   当前计算数的前一个值</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param </span>flag  当前计算到第几位</span></span><br><span class="line"><span class="comment">   * **/</span></span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">fibonacci_inner</span>(<span class="params">n2, n1, flag</span>) </span>&#123;</span><br><span class="line">    count++;</span><br><span class="line">    <span class="keyword">if</span> (flag === n) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">BigInt</span>(n1 + n2);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//返回的不是 fibonacci_inner 的执行结果，而是 fibonacci_inner 本身</span></span><br><span class="line">    <span class="keyword">return</span> fibonacci_inner.bind(<span class="literal">null</span>, <span class="built_in">BigInt</span>(n1), <span class="built_in">BigInt</span>(n1 + n2), flag + <span class="number">1</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//从第二位开始计算</span></span><br><span class="line">  <span class="keyword">return</span> fibonacci_inner(<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.time(<span class="string">&quot;fibonacci&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">`the result is <span class="subst">$&#123;<span class="built_in">BigInt</span>(trampoline(fibonacci(<span class="number">10000</span>)))&#125;</span>`</span>);</span><br><span class="line"><span class="built_in">console</span>.timeEnd(<span class="string">&quot;fibonacci&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">`the number of exec count is <span class="subst">$&#123;count&#125;</span>`</span>);</span><br></pre></td></tr></table></figure><p>看一下输出值：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">the result is <span class="number">54438373113565281338734260993750380135389184554695967026247715841208582865622349017083051547938960541173822675978026317384359584751116241439174702642959169925586334117906063048089793531476108466259072759367899150677960088306597966641965824937721800381441158841042480997984696487375337180028163763317781927941101369262750979509800713596718023814710669912644214775254478587674568963808002962265133111359929762726679441400101575800043510777465935805362502461707918059226414679005690752321895868142367849593880756423483754386342639635970733756260098962462668746112041739819404875062443709868654315626847186195620146126642232711815040367018825205314845875817193533529827837800351902529239517836689467661917953884712441028463935449484614450778762529520961887597272889220768537396475869543159172434537193611263743926337313005896167248051737986306368115003088396749587102619524631352447499505204198305187168321623283859794627245919771454628218399695789223798912199431775469705216131081096559950638297261253848242007897109054754028438149611930465061866170122983288964352733750792786069444761853525144421077928045979904561298129423809156055033032338919609162236698759922782923191896688017718575555520994653320128446502371153715141749290913104897203455577507196645425232862022019506091483585223882711016708433051169942115775151255510251655931888164048344129557038825477521111577395780115868397072602565614824956460538700280331311861485399805397031555727529693399586079850381581446276433858828529535803424850845426446471681531001533180479567436396815653326152509571127480411928196022148849148284389124178520174507305538928717857923509417743383331506898239354421988805429332440371194867215543576548565499134519271098919802665184564927827827212957649240235507595558205647569365394873317659000206373126570643509709482649710038733517477713403319028105575667931789470024118803094604034362953471997461392274791549730356412633074230824051999996101549784667340458326852960388301120765629245998136251652347093963049734046445106365304163630823669242257761468288461791843224793434406079917883360676846711185597501</span></span><br><span class="line">fibonacci: <span class="number">4.223876953125</span> ms</span><br><span class="line">the number of exec count is <span class="number">9999</span></span><br></pre></td></tr></table></figure><p>然后 fibonacci(100000) 的值</p><img src="/2022/js-optimize-trampoline/fibonacci-count-100000.png" class="" title="斐波那契 100000 输出"><p>有点像尾递归优化，之前 node 短暂的支持尾递归优化，就是递归的函数会替换掉调用函数的执行栈，后续貌似不支持了。。。</p><p>OK，现在递归应该没有啥问题了，实际已经不能称之为递归了，看起来是递归的写法，但是底层执行逻辑是循环，直接写循环也挺好的。</p><p>Done。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;为什么会发生堆栈异常&quot;&gt;&lt;a href=&quot;#为什么会发生堆栈异常&quot; class=&quot;headerlink&quot; title=&quot;为什么会发生堆栈异常&quot;&gt;&lt;/a&gt;为什么会发生堆栈异常&lt;/h3&gt;&lt;p&gt;JS 执行时遇到新的执行函数的时候就会把需要执行的函数压入堆栈，函数执行完成</summary>
      
    
    
    
    
    <category term="optimize" scheme="http://sokiy.github.io/tags/optimize/"/>
    
  </entry>
  
  <entry>
    <title>Array &amp; Map 读取数据 Benchmark 测试</title>
    <link href="http://sokiy.github.io/2022/array-and-map-read-data-benchmark/"/>
    <id>http://sokiy.github.io/2022/array-and-map-read-data-benchmark/</id>
    <published>2022-03-23T03:38:00.000Z</published>
    <updated>2022-08-08T04:00:20.630Z</updated>
    
    <content type="html"><![CDATA[<p>针对 JavaScript Array 和 Map 类型读取数据做一次性能测试，测试一下读取数据的性能。</p><span id="more"></span><h4 id="测试方案"><a href="#测试方案" class="headerlink" title="测试方案"></a>测试方案</h4><ul><li>  创建长度为 len 的 Array 和 Map 结构，内容都相同</li><li>  创建一个乱序的长度为 len 且内容都是 true false 各半的数组</li><li>  循环乱序数组，如果为 true 则分别取 Array 和 Map 的值做拼接，测试最终的代码运行时间</li></ul><h5 id="Rander-Array-amp-Map"><a href="#Rander-Array-amp-Map" class="headerlink" title="Rander Array &amp; Map"></a>Rander Array &amp; Map</h5><p>首先创建好我们的 Array 和 Map 结构</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> BSAECHAR =</span><br><span class="line">  <span class="string">&quot;0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;</span>;</span><br><span class="line"><span class="keyword">let</span> Ret = &#123;&#125;; <span class="comment">//Array 和 Map 的输出集合</span></span><br><span class="line"><span class="keyword">let</span> len = <span class="number">1000</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//在给定的集合中返回对应长度的 Array 和  Map</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">randomString</span>(<span class="params">length, chars</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> retArr = [];</span><br><span class="line">  <span class="keyword">let</span> retMap = <span class="keyword">new</span> <span class="built_in">Map</span>();</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">    <span class="keyword">let</span> char = chars[<span class="built_in">Math</span>.floor(<span class="built_in">Math</span>.random() * chars.length)];</span><br><span class="line">    retArr[i] = char;</span><br><span class="line">    retMap.set(i, char);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> &#123; <span class="attr">arr</span>: retArr, <span class="attr">map</span>: retMap &#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.time(<span class="string">&quot;render Ret&quot;</span>);</span><br><span class="line">Ret = randomString(len, BSAECHAR);</span><br><span class="line"><span class="built_in">console</span>.timeEnd(<span class="string">&quot;render Ret&quot;</span>);</span><br></pre></td></tr></table></figure><h5 id="Random-Array"><a href="#Random-Array" class="headerlink" title="Random Array"></a>Random Array</h5><p>然后定义我们的乱序数组，乱序函数使用 <code>Fisher–Yates shuffle</code> 洗牌算法</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> RandomArr = [];</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Fisher–Yates shuffle</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">shuffle</span>(<span class="params">arr</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> len = arr.length;</span><br><span class="line">  <span class="keyword">while</span> (len &gt; <span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> index = <span class="built_in">Math</span>.floor(<span class="built_in">Math</span>.random() * len--);</span><br><span class="line">    [arr[len], arr[index]] = [arr[index], arr[len]];</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> arr;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//创建一个乱序的长度为 len 且内容都是 true false 各半的数组</span></span><br><span class="line"><span class="built_in">console</span>.time(<span class="string">&quot;render RandomArr&quot;</span>);</span><br><span class="line">RandomArr = shuffle(</span><br><span class="line">  <span class="built_in">Array</span>(len / <span class="number">2</span>)</span><br><span class="line">    .fill(<span class="literal">true</span>)</span><br><span class="line">    .concat(<span class="built_in">Array</span>(len / <span class="number">2</span>).fill(<span class="literal">false</span>))</span><br><span class="line">);</span><br><span class="line"><span class="built_in">console</span>.timeEnd(<span class="string">&quot;render RandomArr&quot;</span>);</span><br></pre></td></tr></table></figure><h5 id="Array-benchmark"><a href="#Array-benchmark" class="headerlink" title="Array benchmark"></a>Array benchmark</h5><p>首先测试从 Array 中取值的时长</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 从 Array 中取值</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">renderResultInArray</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> ret = <span class="string">&quot;&quot;</span>;</span><br><span class="line">  RandomArr.forEach(<span class="function">(<span class="params">item, index</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (item) &#123;</span><br><span class="line">      ret += Ret.arr[index];</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.time(<span class="string">&quot;array&quot;</span>);</span><br><span class="line"><span class="keyword">let</span> retArr = renderResultInArray();</span><br><span class="line"><span class="built_in">console</span>.timeEnd(<span class="string">&quot;array&quot;</span>);</span><br></pre></td></tr></table></figure><h5 id="Map-benchmark"><a href="#Map-benchmark" class="headerlink" title="Map benchmark"></a>Map benchmark</h5><p>然后测试从 Map 中取值的时长</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 从 Map 中取值</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">renderResultInMap</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> ret = <span class="string">&quot;&quot;</span>;</span><br><span class="line">  RandomArr.forEach(<span class="function">(<span class="params">item, index</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (item) &#123;</span><br><span class="line">      ret += Ret.map[index];</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.time(<span class="string">&quot;map&quot;</span>);</span><br><span class="line"><span class="keyword">let</span> retMap = renderResultInMap();</span><br><span class="line"><span class="built_in">console</span>.timeEnd(<span class="string">&quot;map&quot;</span>);</span><br></pre></td></tr></table></figure><h4 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h4><p>然后执行程序进行输出：</p><img src="/2022/array-and-map-read-data-benchmark/benchmark.png" class="" title="benchmark"><p>貌似 Map 结构并没有说比 Array 取值快, WTF。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;针对 JavaScript Array 和 Map 类型读取数据做一次性能测试，测试一下读取数据的性能。&lt;/p&gt;</summary>
    
    
    
    
    <category term="javascript" scheme="http://sokiy.github.io/tags/javascript/"/>
    
    <category term="optimize" scheme="http://sokiy.github.io/tags/optimize/"/>
    
  </entry>
  
  <entry>
    <title>在 npm 私有仓库中发布一个 package</title>
    <link href="http://sokiy.github.io/2021/publish-a-package-in-npm-private-repository/"/>
    <id>http://sokiy.github.io/2021/publish-a-package-in-npm-private-repository/</id>
    <published>2021-09-29T06:22:34.000Z</published>
    <updated>2022-03-25T07:10:12.984Z</updated>
    
    <content type="html"><![CDATA[<p>Verdaccio + pm2 搭建一个 npm 私有仓库，网上很多 <a href="https://verdaccio.org/">教程</a>，主要记录一下发布过程中遇到的问题。</p><img src="/2021/publish-a-package-in-npm-private-repository/verdaccio.png" class="" title="Verdaccio"><span id="more"></span><h3 id="包名规范"><a href="#包名规范" class="headerlink" title="包名规范"></a>包名规范</h3><p>即使是自己练手的项目，如果对包名不加限制的话，也很难管理和维护，所以可以通过增加和命名空间类似的  <code>Scope</code> 做限制。</p><p>egg:</p><ul><li><p>@sokiy-tools/switch-dns</p></li><li><p>@sokiy-tools/ip-proxy</p></li><li><p>@common-tools/test</p></li></ul><h3 id="登录私有源"><a href="#登录私有源" class="headerlink" title="登录私有源"></a>登录私有源</h3><ol><li><p>Method 1：</p><p>可以通过 <code>nrm</code>  添加私有源路径然后切换到对应私有源</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nrm add XXX YYY &amp; nrm use XXX</span><br></pre></td></tr></table></figure><p>然后添加用户或者进行登录</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">//添加             //登录</span><br><span class="line">npm adduser  or   npm login</span><br></pre></td></tr></table></figure><p>然后输入账号名密码邮箱，添加账号密码自定义，登录时输入添加时对应账号的密码。</p></li><li><p>Method 2：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm adduser --registry  http://xxxxxxxx </span><br></pre></td></tr></table></figure></li></ol><p>todo</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;Verdaccio + pm2 搭建一个 npm 私有仓库，网上很多 &lt;a href=&quot;https://verdaccio.org/&quot;&gt;教程&lt;/a&gt;，主要记录一下发布过程中遇到的问题。&lt;/p&gt;
&lt;img src=&quot;/2021/publish-a-package-in-npm-private-repository/verdaccio.png&quot; class=&quot;&quot; title=&quot;Verdaccio&quot;&gt;</summary>
    
    
    
    
    <category term="npm" scheme="http://sokiy.github.io/tags/npm/"/>
    
  </entry>
  
  <entry>
    <title>合并 &amp; 修改本地 commit 提交</title>
    <link href="http://sokiy.github.io/2020/modify-local-commit/"/>
    <id>http://sokiy.github.io/2020/modify-local-commit/</id>
    <published>2020-05-27T09:38:27.000Z</published>
    <updated>2022-08-08T03:12:52.283Z</updated>
    
    <content type="html"><![CDATA[<p>针对 <code>commit</code> 提交中的问题 &amp; 解决方案做一些记录。</p><ul><li>想要合并本地的多次 <code>commit</code> 提交。</li><li>有几次的 <code>commit message</code> 写的有问题，想要进行修改。</li></ul><span id="more"></span><h3 id="修改-commit-message"><a href="#修改-commit-message" class="headerlink" title="修改 commit message"></a>修改 <code>commit message</code></h3><h4 id="修改本地最新一次提交的-commit-message"><a href="#修改本地最新一次提交的-commit-message" class="headerlink" title="修改本地最新一次提交的 commit message"></a>修改本地最新一次提交的 <code>commit message</code></h4><p>可以使用</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit --amend</span><br></pre></td></tr></table></figure><p>来针对最新一次本地的 <code>commit message</code> 做修改。</p><p>默认会打开编辑器界面，有可能是 <code>nano</code>，可以使用：   </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global core.editor vim</span><br></pre></td></tr></table></figure><p>设置默认的编辑器为 <code>vim</code>。</p><h4 id="修改本地其中某一次的-commit-message"><a href="#修改本地其中某一次的-commit-message" class="headerlink" title="修改本地其中某一次的 commit message"></a>修改本地其中某一次的 <code>commit message</code></h4><p>假如我们本地的提交记录是</p><img src="/2020/modify-local-commit/git-log.png" class="" title="git-log"><p>可以看到 <code>local</code> 相对于 <code>origin</code> 有三个提交没有 <code>push</code>。</p><p>可以使用</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git rebase -i 2967706</span><br></pre></td></tr></table></figure><p><code>2967706</code> 这个 <code>commit id</code> 是本地分支记录里远程分支的最新一次提交的 <code>commit id</code> ，这是一个合并 <code>commit</code> 的操作，会把我们本地还未 <code>push</code> 的 <code>commit</code> 都包含进来，可以用这个操作修改其中某次的 <code>commit message</code>。</p><p>执行 <code>git rebase -i 2967706</code> 命令后，我们可以针对未提交的 <code>commit meaasge</code> 做修改。</p><p><img src="/2020/modify-local-commit/git-rebase.png" alt="git-rebase"></p><p>然后把 <code>9ec87bb</code> 前面的 <code>pick</code> 改成 <code>reword</code> 或者 <code>r</code></p><blockquote><p> r, reword <commit> = use commit, but edit the commit message</p></blockquote><p><img src="/2020/modify-local-commit/git-reword-step-1.png" alt="git-reword-step-1"></p><p><strong>列出的 <code>commit</code> 记录是最新的在最下面</strong>。然后会弹出 <code>vim</code> 编辑界面，改完之后保存并退出。</p><p><img src="/2020/modify-local-commit/git-reword-step-2.png" alt="git-reword-step-2"></p><p>然后就会变成</p><p><img src="/2020/modify-local-commit/git-reword-step-3.png" alt="git-reword-step-3"></p><p>发现我们修改的那次提交的 <code>commit id</code> 和它之后提交的记录的 <code>commit id</code> 都变了。</p><h3 id="合并-commit-提交记录"><a href="#合并-commit-提交记录" class="headerlink" title="合并 commit 提交记录"></a>合并 commit 提交记录</h3><p>拿上面修改的 <code>commit</code> 做一次合并提交，把本地的三次提交合并到一次提交。</p><p>使用</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git rebase -i 2967706</span><br></pre></td></tr></table></figure><p>弹出编辑界面，保存并退出。</p><p><img src="/2020/modify-local-commit/git-rebase-1.png" alt="git-rebase-1"></p><p>回车之后又出现编辑界面，因为我改了最新的一次提交由 <code>pick</code> 改成了 <code>record</code> 。</p><p><img src="/2020/modify-local-commit/git-rebase-2.png" alt="git-rebase-2"></p><p>终端输出</p><p><img src="/2020/modify-local-commit/git-rebase-3.png" alt="git-rebase-3"></p><p>然后提交修改</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin master</span><br></pre></td></tr></table></figure><p><strong>It’s Done</strong></p><blockquote><p>已经 <code>push</code> 到远程的 <code>commit</code> 记录，还是不建议改了。强行改其他协同的人要哭了。</p></blockquote>]]></content>
    
    
    <summary type="html">&lt;p&gt;针对 &lt;code&gt;commit&lt;/code&gt; 提交中的问题 &amp;amp; 解决方案做一些记录。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;想要合并本地的多次 &lt;code&gt;commit&lt;/code&gt; 提交。&lt;/li&gt;
&lt;li&gt;有几次的 &lt;code&gt;commit message&lt;/code&gt; 写的有问题，想要进行修改。&lt;/li&gt;
&lt;/ul&gt;</summary>
    
    
    
    
    <category term="git" scheme="http://sokiy.github.io/tags/git/"/>
    
  </entry>
  
  <entry>
    <title>csrf 原理和防护措施</title>
    <link href="http://sokiy.github.io/2019/csrf/"/>
    <id>http://sokiy.github.io/2019/csrf/</id>
    <published>2019-10-17T06:33:48.000Z</published>
    <updated>2022-07-28T03:47:53.647Z</updated>
    
    <content type="html"><![CDATA[<h3 id="CSRF-介绍"><a href="#CSRF-介绍" class="headerlink" title="CSRF 介绍"></a>CSRF 介绍</h3><p>CSRF（Cross-site request forgery），中文名称：跨站请求伪造。<br>可以在 B 网站利用 A 网站的 cookie 去做一些针对 A 网站的操作,但这用户是没法感知的</p><h4 id="攻击方式"><a href="#攻击方式" class="headerlink" title="攻击方式"></a>攻击方式</h4><p>举个栗子  </p><p>小明在 A 网站登录买了一个 8848 钛合金手机,准备在朋友面前装个逼, 美滋滋的下了单,填好收货信息付了款之后没有关闭 A 网站的页签(有时候关了页签 cookie 也还是会存留一段时间的),然后在 B 网站开始溜达, 但是恰好 B 网站就是针对 A 网站做的一个钓鱼网站, 里面有一个按钮链接是修改已经登录了 A 网站用户的收货信息的, 这个链接对小明是迷惑的,比如就是一个链接到 NSFW 网站的地址,小明点了进去然后发送了一条请求(相同的路径和参数)给 A 网站, 因为 A 网站没有做 CSRF 防护, 导致这条请求会携带 A 网站的 cookie, 那么 A 网站会认为这个请求就是该用户发起的, 所以地址修改成功, 到时候小明就是人财两空</p><h4 id="核心原理"><a href="#核心原理" class="headerlink" title="核心原理"></a>核心原理</h4><p>就是在 B 网站点击一个带有 A 网站请求的链接时, 这条链接会带上 A 网站的 cookie,就相当于你访问了 A 网站的那条链接, 这个时候 cookie 会自动带上的</p><h4 id="防护措施"><a href="#防护措施" class="headerlink" title="防护措施"></a>防护措施</h4><p>服务端生成一个随机的 csrftoken, 这个只要是随机的都成,<br>然后用户在登录的时候,把这个值放在响应头的 set-cookie 中,然后客户端在请求接口的时候从 cookie 中拿出这个值,放在请求头的 header 中(不是 cookie 里面,是 header 里面,放到 cookie 里面一点用都没),   </p><p><strong>B 网站是只能用 A 网站的 cookie,<br>用的意思是 B 网站只知道在 B 网站访问 A 网站的链接,是可以带上 A 网站的 cookie 的,但是这个 cookie 的内容, B 网站是没法感知的,当然也是不能操作的</strong></p><p>所以当把 csrftoken 放到请求 header 中的时候, B 网站中点击 A 网站的链接是没法去传递这个值的, 然后后端再去校验 csrftoken 的值是否正确就行。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;CSRF-介绍&quot;&gt;&lt;a href=&quot;#CSRF-介绍&quot; class=&quot;headerlink&quot; title=&quot;CSRF 介绍&quot;&gt;&lt;/a&gt;CSRF 介绍&lt;/h3&gt;&lt;p&gt;CSRF（Cross-site request forgery），中文名称：跨站请求伪造。&lt;br&gt;可</summary>
      
    
    
    
    
    <category term="csrf" scheme="http://sokiy.github.io/tags/csrf/"/>
    
  </entry>
  
  <entry>
    <title>为什么要有 package-lock</title>
    <link href="http://sokiy.github.io/2019/package-lock/"/>
    <id>http://sokiy.github.io/2019/package-lock/</id>
    <published>2019-05-29T07:08:22.000Z</published>
    <updated>2022-08-08T03:50:34.145Z</updated>
    
    <content type="html"><![CDATA[<h3 id="设计美学"><a href="#设计美学" class="headerlink" title="设计美学"></a>设计美学</h3><p>所有的设计最终一定是符合大众对事物的认知的，一定是满足大部分人的使用习惯的。<br>「平平淡淡才是真」</p><img src="/2019/package-lock/1.jpg" class="" title="平平淡淡才是真"><h4 id="为什么需要-package-lock-json"><a href="#为什么需要-package-lock-json" class="headerlink" title="为什么需要 package-lock.json"></a>为什么需要 package-lock.json</h4><p>在 <code>npm 5.0</code> 版本之前，如果在 package.json 中某个依赖库版本加上 <code>^</code> 或者 <code>~</code> 的前缀，那么下次安装的时候，如果该依赖库有升级，那么默认就会安装符合前缀要求的最新的版本，这样就可能导致同一个 package.json，在不同时间安装的依赖库版本号可能不一致。所以 npm 对版本号的命名做了一些规范，小版本号之间的升级只是做一些小改动，不要影响之前版本的运行  </p><p><strong>但是</strong></p><p>「理想往往会被现实打脸」<br>因为只是规范，没有强约束（也没法强约束），架不住有的依赖库作者不按这个来。<br>所以就必须锁住版本，就直接在项目中不要用 <code>^~</code> 等前缀，写死版本号，这样就没啥问题了。</p><p><strong>但是</strong></p><p>npm 不能这么干啊，npm 要这么干那都得乱套，所以就新增一个版本锁文件吧（我猜的）<br>那不就是 package-lock.json</p><h4 id="善变的规则"><a href="#善变的规则" class="headerlink" title="善变的规则"></a>善变的规则</h4><p><code>npm 5.0 - 5.6</code> 中间，群魔乱舞，package-lock.json 的处理逻辑一直在改。</p><ul><li>要么是升级了 package.json 的版本号，然后再次安装的时候，还是之前的版本（因为 package-lock 就是之前的版本）。  </li><li>要么是 package-lock 文件就是个摆设，npm install 的时候无论 package-lock 文件是怎么样的，默认都会安装最新版本</li></ul><p>5.6 之后的规则终于符合大众的认知了， 当 package.json 没有更新的时候，默认安装 package-lock 中指定的版本，如果 package.json 有更新，则安装 package.json 中的版本，然后同步到 package-lock 中。</p><p>起码从我的认知来讲，这样是最合适的，又能锁版本，又能更新版本。</p><p><img src="/2019/package-lock/2.jpg" alt="岂不美哉"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;设计美学&quot;&gt;&lt;a href=&quot;#设计美学&quot; class=&quot;headerlink&quot; title=&quot;设计美学&quot;&gt;&lt;/a&gt;设计美学&lt;/h3&gt;&lt;p&gt;所有的设计最终一定是符合大众对事物的认知的，一定是满足大部分人的使用习惯的。&lt;br&gt;「平平淡淡才是真」&lt;/p&gt;
&lt;img s</summary>
      
    
    
    
    
    <category term="技术瞎扯淡" scheme="http://sokiy.github.io/tags/%E6%8A%80%E6%9C%AF%E7%9E%8E%E6%89%AF%E6%B7%A1/"/>
    
  </entry>
  
  <entry>
    <title>正则匹配 IP 思路</title>
    <link href="http://sokiy.github.io/2019/regExp/"/>
    <id>http://sokiy.github.io/2019/regExp/</id>
    <published>2019-03-07T02:40:38.000Z</published>
    <updated>2022-08-08T03:50:29.195Z</updated>
    
    <content type="html"><![CDATA[<h3 id="正则匹配思路"><a href="#正则匹配思路" class="headerlink" title="正则匹配思路"></a>正则匹配思路</h3><p>个人理解: 用一种描述性的语言定义一个规则,去匹配需要匹配到的字符串的子串<br>匹配ip地址的思路</p><img src="/2019/regExp/1.jpg" class="" title="你配不上"><h4 id="维度切分"><a href="#维度切分" class="headerlink" title="维度切分"></a>维度切分</h4><p>要匹配 0.0.0.0-255.255.255.255,可以先匹配 0-255,这一个区间,然后向ip去扩展.  </p><p>要匹配 0-255,不能直接去匹配255,正则本来就是一个规则,255这个数字不是很规则,因为数字是从0-9,直接去匹配符合小于255的数字显然是不太切合实际的,可以再做维度切分.<br>可以把255切分成几层。</p><h4 id="举例"><a href="#举例" class="headerlink" title="举例"></a>举例</h4><p><strong>举个例子,不一定要按这个来</strong><br>255拆分成<br>0-9<br>10-99<br>100-199<br>200-249<br>250-255<br>然后对应的正则就是</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[0-9]         //对应0-9</span><br><span class="line">[1-9][0-9]    //对应10-99</span><br><span class="line">1[0-9]&#123;2&#125;     //对应100-199</span><br><span class="line">2[0-4][0-9]   //对应200-249</span><br><span class="line">25[0-5]       //对应250-255</span><br></pre></td></tr></table></figure><p>然后拼接这个正则表达式  </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">(25[0-5]|2[0-4][0-9]|1[0-9]&#123;2&#125;|[1-9][0-9]|[0-9])  </span><br><span class="line">([0-9]|[1-9][0-9]|1[0-9]&#123;2&#125;|2[0-4][0-9]|25[0-5])  //这两种都行,只不过不加^$开始结束符号的时候,匹配到的子串不同</span><br></pre></td></tr></table></figure><p>匹配0-255加.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(([0-9]|[1-9][0-9]|1[0-9]&#123;2&#125;|2[0-4][0-9]|25[0-5])\.)</span><br></pre></td></tr></table></figure><p>然后组装IP匹配的正则  </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/^((([0-9]|[1-9][0-9]|1[0-9]&#123;2&#125;|2[0-4][0-9]|25[0-5])\.)&#123;3&#125;([0-9]|[1-9][0-9]|1[0-9]&#123;2&#125;|2[0-4][0-9]|25[0-5]))$/im</span><br></pre></td></tr></table></figure><p>齐活</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;正则匹配思路&quot;&gt;&lt;a href=&quot;#正则匹配思路&quot; class=&quot;headerlink&quot; title=&quot;正则匹配思路&quot;&gt;&lt;/a&gt;正则匹配思路&lt;/h3&gt;&lt;p&gt;个人理解: 用一种描述性的语言定义一个规则,去匹配需要匹配到的字符串的子串&lt;br&gt;匹配ip地址的思路&lt;/p&gt;</summary>
      
    
    
    
    
    <category term="regExp" scheme="http://sokiy.github.io/tags/regExp/"/>
    
  </entry>
  
</feed>
