<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Joy</title>
  
  <subtitle>JOY的个人博客</subtitle>
  <link href="https://joyer-lee.github.io/blog/atom.xml" rel="self"/>
  
  <link href="https://joyer-lee.github.io/blog/"/>
  <updated>2026-10-18T10:36:38.013Z</updated>
  <id>https://joyer-lee.github.io/blog/</id>
  
  <author>
    <name>Joy Lee</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>前端手写题整理（二）：数组与字符串</title>
    <link href="https://joyer-lee.github.io/blog/2026/10/18/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/%E5%89%8D%E7%AB%AF%E6%89%8B%E5%86%99%E9%A2%98%E6%95%B4%E7%90%86%E4%BA%8C-%E6%95%B0%E7%BB%84%E4%B8%8E%E5%AD%97%E7%AC%A6%E4%B8%B2/"/>
    <id>https://joyer-lee.github.io/blog/2026/10/18/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/%E5%89%8D%E7%AB%AF%E6%89%8B%E5%86%99%E9%A2%98%E6%95%B4%E7%90%86%E4%BA%8C-%E6%95%B0%E7%BB%84%E4%B8%8E%E5%AD%97%E7%AC%A6%E4%B8%B2/</id>
    <published>2026-10-18T11:10:00.000Z</published>
    <updated>2026-10-18T10:36:38.013Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>手写题系列第二篇：字符串反转、数组扁平化、数组去重，以及一道结合缓存的工具类设计题。整理时顺手修正了原笔记里的两处笔误（递归函数名写错、漏写 return）。</p><h2 id="字符串反转"><a href="#字符串反转" class="headerlink" title="字符串反转"></a>字符串反转</h2><p>三种写法，从 API 组合到递归：</p><figure class="highlight js"><table><tbody><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="comment">// Array.reverse()</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">reverseString</span>(<span class="params">str</span>) {</span><br><span class="line">  <span class="keyword">return</span> str.<span class="title function_">split</span>(<span class="string">''</span>).<span class="title function_">reverse</span>().<span class="title function_">join</span>(<span class="string">''</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// for 循环倒序拼接</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">reverseString</span>(<span class="params">str</span>) {</span><br><span class="line">  <span class="keyword">let</span> reversedStr = <span class="string">''</span>;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = str.<span class="property">length</span> - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i--) {</span><br><span class="line">    reversedStr += str[i];</span><br><span class="line">  }</span><br><span class="line">  <span class="keyword">return</span> reversedStr;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 递归：每次取第一个字符放到末尾</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">reverseString</span>(<span class="params">str</span>) {</span><br><span class="line">  <span class="keyword">if</span> (str === <span class="string">''</span>) {</span><br><span class="line">    <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line">  } <span class="keyword">else</span> {</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">reverseString</span>(str.<span class="title function_">substr</span>(<span class="number">1</span>)) + str.<span class="title function_">charAt</span>(<span class="number">0</span>);</span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h2 id="数组扁平化"><a href="#数组扁平化" class="headerlink" title="数组扁平化"></a>数组扁平化</h2><p>四种实现，面试常要求手写后三种：</p><figure class="highlight js"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1. 原生 flat</span></span><br><span class="line">arr.<span class="title function_">flat</span>(<span class="title class_">Infinity</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2. 扩展运算符：只要还有嵌套就拍一层</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">flatten1</span>(<span class="params">arr</span>) {</span><br><span class="line">  <span class="keyword">while</span> (arr.<span class="title function_">some</span>(<span class="function">(<span class="params">item</span>) =&gt;</span> <span class="title class_">Array</span>.<span class="title function_">isArray</span>(item))) {</span><br><span class="line">    arr = [].<span class="title function_">concat</span>(...arr);</span><br><span class="line">  }</span><br><span class="line">  <span class="keyword">return</span> arr;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3. reduce 递归</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">flatten2</span>(<span class="params">arr</span>) {</span><br><span class="line">  <span class="keyword">return</span> arr.<span class="title function_">reduce</span>(<span class="function">(<span class="params">prev, cur</span>) =&gt;</span> {</span><br><span class="line">    <span class="keyword">if</span> (<span class="title class_">Array</span>.<span class="title function_">isArray</span>(cur)) {</span><br><span class="line">      <span class="keyword">return</span> prev.<span class="title function_">concat</span>(<span class="title function_">flatten2</span>(cur));</span><br><span class="line">    } <span class="keyword">else</span> {</span><br><span class="line">      <span class="keyword">return</span> prev.<span class="title function_">concat</span>(cur);</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 class="comment">// 4. 基础递归</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">flatten3</span>(<span class="params">arr</span>) {</span><br><span class="line">  <span class="keyword">let</span> res = [];</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; i++) {</span><br><span class="line">    <span class="keyword">if</span> (<span class="title class_">Array</span>.<span class="title function_">isArray</span>(arr[i])) {</span><br><span class="line">      res = res.<span class="title function_">concat</span>(<span class="title function_">flatten3</span>(arr[i]));</span><br><span class="line">    } <span class="keyword">else</span> {</span><br><span class="line">      res.<span class="title function_">push</span>(arr[i]);</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line">  <span class="keyword">return</span> res;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h2 id="数组去重"><a href="#数组去重" class="headerlink" title="数组去重"></a>数组去重</h2><p>四种方式，追问点通常是各自的适用场景（NaN、对象引用、性能）：</p><figure class="highlight js"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// Set：最简洁，NaN 也能正确去重</span></span><br><span class="line"><span class="keyword">const</span> newArr = [...<span class="keyword">new</span> <span class="title class_">Set</span>(arr)];</span><br><span class="line"></span><br><span class="line"><span class="comment">// for + indexOf： indexOf 找到的是第一个位置，等于当前 index 说明首次出现</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">unique</span>(<span class="params">arr</span>) {</span><br><span class="line">  <span class="keyword">const</span> newArr = [];</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; i++) {</span><br><span class="line">    <span class="keyword">if</span> (arr.<span class="title function_">indexOf</span>(arr[i]) === i) {</span><br><span class="line">      newArr.<span class="title function_">push</span>(arr[i]);</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line">  <span class="keyword">return</span> newArr;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// for + includes：结果顺序稳定</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">unique</span>(<span class="params">arr</span>) {</span><br><span class="line">  <span class="keyword">const</span> newArr = [];</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; i++) {</span><br><span class="line">    <span class="keyword">if</span> (!newArr.<span class="title function_">includes</span>(arr[i])) {</span><br><span class="line">      newArr.<span class="title function_">push</span>(arr[i]);</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line">  <span class="keyword">return</span> newArr;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// filter 写法</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">unique</span>(<span class="params">arr</span>) {</span><br><span class="line">  <span class="keyword">return</span> arr.<span class="title function_">filter</span>(<span class="function">(<span class="params">item, index</span>) =&gt;</span> arr.<span class="title function_">indexOf</span>(item) === index);</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>注意 <code>indexOf</code> 内部用严格相等（<code>===</code>），所以 <code>NaN</code> 永远查不到自身（<code>[NaN].indexOf(NaN) === -1</code>），只有 Set 方案能对 NaN 去重。</p><h2 id="设计题：按-id-批量取数，优先走缓存"><a href="#设计题：按-id-批量取数，优先走缓存" class="headerlink" title="设计题：按 id 批量取数，优先走缓存"></a>设计题：按 id 批量取数，优先走缓存</h2><blockquote><p>写一个通用工具类，通过 id 集合获取数据集合；先查缓存，未命中再调服务查询并写入缓存，最后返回数据集合。</p></blockquote><p>考察点：缓存数据结构选型（Map）、批量流程编排、边界处理：</p><figure class="highlight js"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> api = {</span><br><span class="line">  <span class="attr">getDataById</span>: <span class="function">(<span class="params">id</span>) =&gt;</span> {</span><br><span class="line">    <span class="keyword">return</span> <span class="string">'dataFromService'</span>;</span><br><span class="line">  },</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">DataFetch</span> {</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) {</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">cache</span> = <span class="keyword">new</span> <span class="title class_">Map</span>();</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="title function_">getDataList</span>(<span class="params">idList</span>) {</span><br><span class="line">    <span class="keyword">const</span> dataList = [];</span><br><span class="line">    idList.<span class="title function_">forEach</span>(<span class="function">(<span class="params">id</span>) =&gt;</span> {</span><br><span class="line">      <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">has</span>(id)) {</span><br><span class="line">        dataList.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">get</span>(id));</span><br><span class="line">      } <span class="keyword">else</span> {</span><br><span class="line">        <span class="keyword">const</span> data = api.<span class="title function_">getDataById</span>(id);</span><br><span class="line">        <span class="keyword">if</span> (data) {</span><br><span class="line">          <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">set</span>(id, data);</span><br><span class="line">          dataList.<span class="title function_">push</span>(data);</span><br><span class="line">        }</span><br><span class="line">      }</span><br><span class="line">    });</span><br><span class="line">    <span class="keyword">return</span> dataList; <span class="comment">// 原笔记漏了这行 return</span></span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>可以延伸的方向：把同步的 <code>api.getDataById</code> 换成异步接口（<code>Promise.all</code> 并行请求未命中的 id）、加缓存容量上限（LRU）。</p><hr><p>两篇整理完，原始代码归档在 <a class="link" href="https://github.com/joyer-lee/code-question-bank">code-question-bank<i class="fas fa-external-link-alt"></i></a>。</p></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;手写题系列第二篇：字符串反转、数组扁平化、数组去重，以及一道结合缓存的工具类设计题。整理时顺手修正了原笔记里的两处笔误（递归函数名写错、漏写 return）。&lt;/p&gt;
&lt;h2 id=&quot;字符串反转&quot;&gt;&lt;a href=&quot;#字符串</summary>
      
    
    
    
    <category term="大前端技术圈" scheme="https://joyer-lee.github.io/blog/categories/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/"/>
    
    
    <category term="JavaScript" scheme="https://joyer-lee.github.io/blog/tags/JavaScript/"/>
    
    <category term="手写题" scheme="https://joyer-lee.github.io/blog/tags/%E6%89%8B%E5%86%99%E9%A2%98/"/>
    
  </entry>
  
  <entry>
    <title>前端手写题整理（一）：函数与设计模式</title>
    <link href="https://joyer-lee.github.io/blog/2026/10/18/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/%E5%89%8D%E7%AB%AF%E6%89%8B%E5%86%99%E9%A2%98%E6%95%B4%E7%90%86%E4%B8%80-%E5%87%BD%E6%95%B0%E4%B8%8E%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    <id>https://joyer-lee.github.io/blog/2026/10/18/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/%E5%89%8D%E7%AB%AF%E6%89%8B%E5%86%99%E9%A2%98%E6%95%B4%E7%90%86%E4%B8%80-%E5%87%BD%E6%95%B0%E4%B8%8E%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/</id>
    <published>2026-10-18T11:00:00.000Z</published>
    <updated>2026-10-18T10:36:38.013Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>把早期积攒在手写题仓库里的题目整理成系列发出来，这一篇覆盖函数工具与设计模式：防抖节流、深拷贝、发布订阅、观察者模式。每道题保留当时的实现思路，适合面试前快速过一遍。</p><h2 id="防抖与节流"><a href="#防抖与节流" class="headerlink" title="防抖与节流"></a>防抖与节流</h2><p>两者都是为了减少函数的调用频率：</p><ul><li><strong>防抖（debounce）</strong>：短时间内多次触发同一事件，只执行最后一次——把频繁触发的函数延迟处理</li><li><strong>节流（throttle）</strong>：一定时间窗口内只触发一次</li></ul><figure class="highlight js"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">debounce</span>(<span class="params">fn, delay</span>) {</span><br><span class="line">  <span class="keyword">let</span> timer = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">...args</span>) {</span><br><span class="line">    <span class="keyword">if</span> (timer) {</span><br><span class="line">      <span class="built_in">clearTimeout</span>(timer);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    timer = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> {</span><br><span class="line">      fn.<span class="title function_">apply</span>(<span class="variable language_">this</span>, args);</span><br><span class="line">    }, delay);</span><br><span class="line">  };</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">throttle</span>(<span class="params">fn, delay</span>) {</span><br><span class="line">  <span class="keyword">let</span> timer = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">...args</span>) {</span><br><span class="line">    <span class="keyword">if</span> (timer) {</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    timer = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> {</span><br><span class="line">      fn.<span class="title function_">apply</span>(<span class="variable language_">this</span>, args);</span><br><span class="line">      timer = <span class="literal">null</span>;</span><br><span class="line">    }, delay);</span><br><span class="line">  };</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>典型应用：防抖用于搜索框输入、窗口 resize；节流用于滚动监听、按钮防连点。</p><h2 id="深拷贝"><a href="#深拷贝" class="headerlink" title="深拷贝"></a>深拷贝</h2><p>难点在循环引用和特殊对象（Date、RegExp、不可枚举属性）。用 <code>WeakMap</code> 记录已拷贝对象解决循环引用，用 <code>Object.getOwnPropertyDescriptors</code> 保留属性描述符：</p><figure class="highlight js"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">isComplexDataType</span> = (<span class="params">obj</span>) =&gt;</span><br><span class="line">  (<span class="keyword">typeof</span> obj === <span class="string">'object'</span> || <span class="keyword">typeof</span> obj === <span class="string">'function'</span>) &amp;&amp; obj !== <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> deepClone = <span class="keyword">function</span> (<span class="params">obj, hash = <span class="keyword">new</span> <span class="built_in">WeakMap</span>()</span>) {</span><br><span class="line">  <span class="keyword">if</span> (obj.<span class="property">constructor</span> === <span class="title class_">Date</span>) <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Date</span>(obj);</span><br><span class="line">  <span class="keyword">if</span> (obj.<span class="property">constructor</span> === <span class="title class_">RegExp</span>) <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RegExp</span>(obj);</span><br><span class="line">  <span class="keyword">if</span> (hash.<span class="title function_">has</span>(obj)) <span class="keyword">return</span> hash.<span class="title function_">get</span>(obj); <span class="comment">// 循环引用直接返回缓存</span></span><br><span class="line">  <span class="keyword">let</span> allDesc = <span class="title class_">Object</span>.<span class="title function_">getOwnPropertyDescriptors</span>(obj);</span><br><span class="line">  <span class="keyword">let</span> cloneObj = <span class="title class_">Object</span>.<span class="title function_">create</span>(<span class="title class_">Object</span>.<span class="title function_">getPrototypeOf</span>(obj), allDesc); <span class="comment">// 继承原型链</span></span><br><span class="line">  hash.<span class="title function_">set</span>(obj, cloneObj);</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> key <span class="keyword">of</span> <span class="title class_">Reflect</span>.<span class="title function_">ownKeys</span>(obj)) {</span><br><span class="line">    cloneObj[key] =</span><br><span class="line">      <span class="title function_">isComplexDataType</span>(obj[key]) &amp;&amp; <span class="keyword">typeof</span> obj[key] !== <span class="string">'function'</span></span><br><span class="line">        ? <span class="title function_">deepClone</span>(obj[key], hash)</span><br><span class="line">        : obj[key];</span><br><span class="line">  }</span><br><span class="line">  <span class="keyword">return</span> cloneObj;</span><br><span class="line">};</span><br></pre></td></tr></tbody></table></figure><p>验证时可以构造一个含循环引用的对象：<code>obj.loop = obj</code>，拷贝后修改 <code>cloneObj.arr</code> 不会影响原对象即通过。</p><h2 id="发布订阅模式"><a href="#发布订阅模式" class="headerlink" title="发布订阅模式"></a>发布订阅模式</h2><p>与观察者的区别：发布订阅有一个<strong>事件中心</strong>（调度中心）解耦发布者和订阅者，双方互不感知；观察者模式中主题直接持有观察者引用。</p><figure class="highlight js"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> pubsub = {</span><br><span class="line">  <span class="attr">subscribers</span>: {},</span><br><span class="line"></span><br><span class="line">  <span class="attr">subscribe</span>: <span class="keyword">function</span> (<span class="params">eventName, callback</span>) {</span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">subscribers</span>[eventName]) {</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">subscribers</span>[eventName] = [];</span><br><span class="line">    }</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">subscribers</span>[eventName].<span class="title function_">push</span>(callback);</span><br><span class="line">  },</span><br><span class="line"></span><br><span class="line">  <span class="attr">unsubscribe</span>: <span class="keyword">function</span> (<span class="params">eventName, callback</span>) {</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">subscribers</span>[eventName]) {</span><br><span class="line">      <span class="keyword">const</span> index = <span class="variable language_">this</span>.<span class="property">subscribers</span>[eventName].<span class="title function_">indexOf</span>(callback);</span><br><span class="line">      <span class="keyword">if</span> (index !== -<span class="number">1</span>) {</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">subscribers</span>[eventName].<span class="title function_">splice</span>(index, <span class="number">1</span>);</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 class="attr">publish</span>: <span class="keyword">function</span> (<span class="params">eventName, data</span>) {</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">subscribers</span>[eventName]) {</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">subscribers</span>[eventName].<span class="title function_">forEach</span>(<span class="function">(<span class="params">callback</span>) =&gt;</span> {</span><br><span class="line">        <span class="title function_">callback</span>(data);</span><br><span class="line">      });</span><br><span class="line">    }</span><br><span class="line">  },</span><br><span class="line">};</span><br></pre></td></tr></tbody></table></figure><p>前端里的典型落地：EventBus、Vue 早期的事件总线、消息通知中心。</p><h2 id="观察者模式"><a href="#观察者模式" class="headerlink" title="观察者模式"></a>观察者模式</h2><p>主题（Subject）维护观察者列表，状态变化时统一通知：</p><figure class="highlight js"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Subject</span> {</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) {</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">observers</span> = [];</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="title function_">addObserver</span>(<span class="params">observer</span>) {</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">observers</span>.<span class="title function_">push</span>(observer);</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="title function_">removeObserver</span>(<span class="params">observer</span>) {</span><br><span class="line">    <span class="keyword">const</span> index = <span class="variable language_">this</span>.<span class="property">observers</span>.<span class="title function_">indexOf</span>(observer);</span><br><span class="line">    <span class="keyword">if</span> (index &gt; -<span class="number">1</span>) {</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">observers</span>.<span class="title function_">splice</span>(index, <span class="number">1</span>);</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="title function_">notifyAll</span>(<span class="params"></span>) {</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">observers</span>.<span class="title function_">forEach</span>(<span class="function">(<span class="params">observer</span>) =&gt;</span> {</span><br><span class="line">      observer.<span class="title function_">update</span>();</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 class="keyword">class</span> <span class="title class_">Observer</span> {</span><br><span class="line">  <span class="title function_">update</span>(<span class="params"></span>) {</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Observer updated'</span>);</span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>系列下一篇整理数组与字符串类手写题。</p></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;把早期积攒在手写题仓库里的题目整理成系列发出来，这一篇覆盖函数工具与设计模式：防抖节流、深拷贝、发布订阅、观察者模式。每道题保留当时的实现思路，适合面试前快速过一遍。&lt;/p&gt;
&lt;h2 id=&quot;防抖与节流&quot;&gt;&lt;a href=&quot;</summary>
      
    
    
    
    <category term="大前端技术圈" scheme="https://joyer-lee.github.io/blog/categories/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/"/>
    
    
    <category term="JavaScript" scheme="https://joyer-lee.github.io/blog/tags/JavaScript/"/>
    
    <category term="手写题" scheme="https://joyer-lee.github.io/blog/tags/%E6%89%8B%E5%86%99%E9%A2%98/"/>
    
  </entry>
  
  <entry>
    <title>机器人基础编程</title>
    <link href="https://joyer-lee.github.io/blog/2023/06/08/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%9F%BA%E7%A1%80%E7%BC%96%E7%A8%8B/"/>
    <id>https://joyer-lee.github.io/blog/2023/06/08/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%9F%BA%E7%A1%80%E7%BC%96%E7%A8%8B/</id>
    <published>2023-06-08T02:38:00.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h2 id="机器人基本知识"><a href="#机器人基本知识" class="headerlink" title="机器人基本知识"></a>机器人基本知识</h2><h4 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h4><p>国际标准化组织1987年对工业机器人的定义：</p><blockquote><p>工业机器人是一种具有自动控制操作和移动功能的，能够完成各种作业的可编程操作机器。</p></blockquote><p>国家标准GB/T 12643-2013将工业机器人定义为：</p><blockquote><p>自动控制的、可重复编程、多用途的操作机，可对三个或三个以上轴进行编程。可以是固定式或移动式、在工业自动化中使用。</p></blockquote><h4 id="系统组成"><a href="#系统组成" class="headerlink" title="系统组成"></a>系统组成</h4><p>主要参数</p><p>如何进行人机交互</p><p>相关概念</p><p>机器人奇点</p><p>机器人零点 </p><h2 id="机器人几种坐标系的介绍与标定"><a href="#机器人几种坐标系的介绍与标定" class="headerlink" title="机器人几种坐标系的介绍与标定"></a>机器人几种坐标系的介绍与标定</h2><h3 id="机器人坐标系"><a href="#机器人坐标系" class="headerlink" title="机器人坐标系"></a>机器人坐标系</h3><h3 id="法兰坐标系"><a href="#法兰坐标系" class="headerlink" title="法兰坐标系"></a>法兰坐标系</h3><h3 id="工具坐标系"><a href="#工具坐标系" class="headerlink" title="工具坐标系"></a>工具坐标系</h3><h3 id="用户坐标系"><a href="#用户坐标系" class="headerlink" title="用户坐标系"></a>用户坐标系</h3><h2 id="机器人编程"><a href="#机器人编程" class="headerlink" title="机器人编程"></a>机器人编程</h2><p>运动编程：</p><p>代表指令：</p><p>关节运动</p><p>直线运动</p><p>圆弧运动</p><p>圆周运动</p><p>逻辑编程</p><p>赋值语句</p><h3 id="贝塞尔曲线"><a href="#贝塞尔曲线" class="headerlink" title="贝塞尔曲线"></a>贝塞尔曲线</h3></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 id=&quot;机器人基本知识&quot;&gt;&lt;a href=&quot;#机器人基本知识&quot; class=&quot;headerlink&quot; title=&quot;机器人基本知识&quot;&gt;&lt;/a&gt;机器人基本知识&lt;/h2&gt;&lt;h4 id=&quot;定义&quot;&gt;&lt;a href=&quot;#定义&quot; cl</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>微前端架构</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/21/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84/%E5%BE%AE%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/21/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84/%E5%BE%AE%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84/</id>
    <published>2023-04-21T06:04:14.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    
    
    
    <category term="大前端技术圈" scheme="https://joyer-lee.github.io/blog/categories/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/"/>
    
    <category term="微前端架构" scheme="https://joyer-lee.github.io/blog/categories/%E5%BE%AE%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84/"/>
    
    
  </entry>
  
  <entry>
    <title>如何做好 Code Review</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/20/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%A6%82%E4%BD%95%E5%81%9A%E5%A5%BDCode%20Review/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/20/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%A6%82%E4%BD%95%E5%81%9A%E5%A5%BDCode%20Review/</id>
    <published>2023-04-20T08:04:14.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h4 id="职责"><a href="#职责" class="headerlink" title="职责"></a>职责</h4><p>Code review 不应该承担发现代码错误的职责。Code Review主要是审核代码的质量，如可读性，可维护性，以及程序的逻辑和对需求和设计的实现。</p><h3 id="如何审查代码"><a href="#如何审查代码" class="headerlink" title="如何审查代码"></a>如何审查代码</h3><p>1.关注代码风格规范： 包括但不限于：命名规范、代码缩进、注释和文档等等<br>2.关注代码调用是否破坏了当前代码架构<br>3.代码逻辑中的异常处理、资源处理、线程、安全<br>4.关注业务实现逻辑<br>5.是否有优化空间： 重复代码、过长函数等等</p><h4 id="Code-Review时该关注的"><a href="#Code-Review时该关注的" class="headerlink" title="Code Review时该关注的"></a>Code Review时该关注的</h4><p>1.体系结构和代码设计</p><ul><li>代码复用: 根据“三振法”, 如果代码被复制一次，虽然不喜欢这种方式，但通常没什么问题。但如果再一次被复制，就应该通过提取公共的部分来重构它。</li><li>用更好的代码: 如果在一块混乱的代码做修改，添加几行代码也许更容易，但建议更进一步，用比原来更好的代码。</li><li>潜在的bugs: 是否会引起的其他错误？循环是否以我们期望的方式终止？</li><li>错误处理: 错误确定被优雅的修改？会导致其他错误？如果这样，修改是否有用？</li><li>效率: 如果代码中包含算法，这种算法是否是高效？ 例如，在字典中使用迭代，遍历一个期望的值，这是一种低效的方式。</li><li>新代码与全局的架构是否保持一致？</li><li>基础代码是否有结合使用了一些标准或设计样式，新的代码是否遵循当前的规范？代码是否正确迁移，或参照了因不规范而淘汰的旧代码？</li><li>代码的位置是否正确？比如涉及订单的新代码是否在订单服务相关的位置？</li><li>新代码是否重用了现存的代码？新代码是否可以被现有代码重用？新代码是否有重复代码？如果是的话，是否应该重构成一个更可被重用的模式，还是当前还可以接受？</li><li>新代码是否被过度设计了？是否引入现在还不需要的重用设计？</li><li></li></ul><p>2、可读性和可维护性</p><ul><li>字段、变量、参数、方法、类的命名是否真实反映它们所代表的事物, 是否能够望文生义?</li><li>是否可以通过读代码理解它做了什么？</li><li>是否理解测试用例测了什么？</li><li>测试是否很好地覆盖了用例的各种情况？它们是否覆盖了正常和异常用例？是否有忽略的情况？</li><li>错误信息是否可被理解？ log打的是否正确和足够?</li><li>不清晰的代码是否被文档、注释或容易理解的测试用例所覆盖？具体可以根据团队自身的喜好决定使用哪种方式。</li></ul><p>3.功能</p><ul><li>代码是否真的达到了预期的目标？如果有自动化测试来确保代码的正确性，测试的代码是否真的可以验证代码达到了协定的需求？</li><li>代码看上去是否包含不明显的bug，比如使用错误的变量进行检查，或误把and写成or？</li><li>作者是否需要创建公共文档或修改现存的帮助文档？</li><li>是否检查了面向用户的信息的正确性？</li><li>是否有会在生产环境中导致应用停止运行的明显错误？代码是否会错误地指向测试数据库，是否存在应在真实服务中移除的硬编码的stub代码？</li><li>你对性能的需求是什么，你是否考虑了安全问题？</li><li>这个新增或修复的功能是否会反向影响到现存的性能测试结果</li><li>外部调用很昂贵(a. 数据库调用. b. 不必要的远程调用. c. 移动或穿戴设备过频繁地调用后端程序)</li></ul><p>4.其他方面</p><ul><li>是否合理地释放了资源</li><li>是否存在内存泄漏?</li><li>是否存在内存无限增长? 例如, 如果审查者看到不断有变量被追加到list或map中, 那么就要考虑下这个list或map什么时候失效, 或清除无用数据</li><li>代码是否及时关闭了连接或数据流?</li><li>资源池配置是否是否正确? 有没有过大或者过小?</li><li>异常情况是否能够正确处理?</li><li>超时是否能够正确处理?</li><li>调用接口出错的时候, 是否有出错处理逻辑, 并且处理正确?</li><li>进程意外重启后, 是否能够恢复到崩溃前的环境?</li></ul><h4 id="如何提高-Code-Review-的效率"><a href="#如何提高-Code-Review-的效率" class="headerlink" title="如何提高 Code Review 的效率"></a>如何提高 Code Review 的效率</h4><p>1.合并信息规范：[序号]. [类型]: [内容] [禅道号]<br>2.每次只 review 少量代码，即发起的 MR 代码量要少，也就是说要小步提交<br>问题：怎么设计分支管理与开发阶段的合并请求?</p><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p><a class="link" href="https://blog.csdn.net/zhang_yin_liang/article/details/113876208">https://blog.csdn.net/zhang_yin_liang/article/details/113876208<i class="fas fa-external-link-alt"></i></a></p></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&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;Code review 不应该承担发现代码错误的职责。Code Review主要是审核代码</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>前端基础架构之工作流设计</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/19/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84/%E5%B7%A5%E4%BD%9C%E6%B5%81%E8%AE%BE%E8%AE%A1/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/19/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84/%E5%B7%A5%E4%BD%9C%E6%B5%81%E8%AE%BE%E8%AE%A1/</id>
    <published>2023-04-19T06:04:14.000Z</published>
    <updated>2026-10-18T10:36:38.013Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><blockquote><p>关键词：工作流程、规范、文档、自动化、工具、效率、生产力、规范硬编码、强制执行</p></blockquote><h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><h3 id="前端工作流设计是什么"><a href="#前端工作流设计是什么" class="headerlink" title="前端工作流设计是什么"></a>前端工作流设计是什么</h3><p> 前端工作流设计是指设计和优化前端开发的流程和工具，旨在提高团队的效率和质量，使得开发过程更加规范化和可靠化。</p><h3 id="常见的工作流设计有哪些："><a href="#常见的工作流设计有哪些：" class="headerlink" title="常见的工作流设计有哪些："></a>常见的工作流设计有哪些：</h3><ul><li>代码管理：使用版本控制工具（如Git）来管理代码，使得代码可以被跟踪和回溯，并且多人协作开发时能够更加顺畅。</li><li>构建工具：使用构建工具（如Webpack、Rollup等）来打包和压缩代码，使得前端项目可以在生产环境中更快地加载，同时还能够处理一些依赖关系、模块化、ES6转义等问题。</li><li>自动化测试：使用自动化测试工具（如Jest、Mocha等）来测试代码，确保代码的质量和稳定性，并且可以提前发现和修复潜在的问题。</li><li>部署工 具：使用部署工具（如Jenkins、Travis CI等）来自动化部署代码到服务器或云平台，避免手动操作带来的错误和不可靠性。</li><li>文档管理：使用文档管理工具（如JSDoc、Swagger等）来自动生成API文档和代码注释，使得代码更加易于理解和维护。</li></ul><h2 id="如何使前端开发流程更加规范"><a href="#如何使前端开发流程更加规范" class="headerlink" title="如何使前端开发流程更加规范"></a>如何使前端开发流程更加规范</h2><blockquote><p>通过对前端工作流的设计和优化，可以使得前端开发人员能够更加专注于业务逻辑的开发和优化，同时也能够提高开发效率和代码质量，从而提高整个项目的价值和竞争力。</p></blockquote><h3 id="基础规范的制定"><a href="#基础规范的制定" class="headerlink" title="基础规范的制定"></a>基础规范的制定</h3><p>要保证代码的可读性，可从以下几个方面进行约束。</p><ul><li>规范代码组织结构：代码组织决定了应用架构，我们应该按照与架构相似的方式来编写代码。</li><li>代码检查与统一代码风格： 可使用 prettier 代码风格工具结合 Lint 工具来统一代码风格。</li><li>组件、函数命名规范:<br>常见命名方式有：驼峰式命名、下划线命名法；<br>css可遵照bem命名法；</li><li>开发工具规范<br>  统一编辑器配置；<br>  统一lint插件等；<br>  统一格式化工具；</li></ul><h3 id="创建-README-搭建指南"><a href="#创建-README-搭建指南" class="headerlink" title="创建 README 搭建指南"></a>创建 README 搭建指南</h3><p>包含的内容应该有：<br>1.支持运行的环境<br>2.必要的依赖准备，如何搭建<br>3.项目的安装指南<br>4.线上的示例<br>5.相关的文档链接<br>6.相关人员的联系方式，讨论群</p><h3 id="其他文档"><a href="#其他文档" class="headerlink" title="其他文档"></a>其他文档</h3><p>1.绘制架构图：架构图一般展示的是各个子系统之前如何通信，如果是简单系统，可以是项目的技术栈组成。<br>2.可编辑文档库-提升协作性<br>3.轻量级架构决策记录<br>4.可视化文档<br>5.看板工具-统一管理业务知识：可追溯历史需求与变更</p><h3 id="提交信息：每次代码提交文档化"><a href="#提交信息：每次代码提交文档化" class="headerlink" title="提交信息：每次代码提交文档化"></a>提交信息：每次代码提交文档化</h3><p>项目方式：结合项目特点定制提交信息规范，使得提交有意义，能真正作为变更记录的重要参考；建议小步提交，可防止修改维护困难<br>开源项目方式：开源库需要有对应的 CHANGELOG.md 文件，可通过git提交记录自动化生成CHANGELOG文件。</p><h3 id="通过流程化提高代码质量"><a href="#通过流程化提高代码质量" class="headerlink" title="通过流程化提高代码质量"></a>通过流程化提高代码质量</h3><p>1.设置提交拦截/远程提交拦截：结合pre-commit 钩子 和 lint-staged 实现<br>2.代码review 团队review/pull Request</p><h3 id="测试策略"><a href="#测试策略" class="headerlink" title="测试策略"></a>测试策略</h3><ul><li>引入单元测试：<br>工作中常见的测试范围为：<br>1.通用、公用的Utils函数<br>2.复杂交互操作逻辑<br>对于隐藏在模板中的逻辑，单元测试很难覆盖，因此在编写业务逻辑的时候，尽可能把代码写在js或ts中；<br>可以在项目中采用驱动测试开发，以测试来驱动业务逻辑。</li></ul><h3 id="设计自己的工作流"><a href="#设计自己的工作流" class="headerlink" title="设计自己的工作流"></a>设计自己的工作流</h3><p>实验项目：inktank-core<br>目标：</p><ol><li>代码要符合项目规范</li><li>CR 后的代码都是能准确执行的<br>目标1： 通过Code Review<br>目标2：需要测试功能</li></ol></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;blockquote&gt;
&lt;p&gt;关键词：工作流程、规范、文档、自动化、工具、效率、生产力、规范硬编码、强制执行&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;介绍&quot;&gt;&lt;a href=&quot;#介绍&quot; class=&quot;headerli</summary>
      
    
    
    
    <category term="大前端技术圈" scheme="https://joyer-lee.github.io/blog/categories/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/"/>
    
    <category term="前端架构" scheme="https://joyer-lee.github.io/blog/categories/%E5%89%8D%E7%AB%AF%E6%9E%B6%E6%9E%84/"/>
    
    
  </entry>
  
  <entry>
    <title>技术单词</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/18/%E8%8B%B1%E6%96%87%E5%B0%8F%E8%8F%9C/%E5%8D%95%E8%AF%8D/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/18/%E8%8B%B1%E6%96%87%E5%B0%8F%E8%8F%9C/%E5%8D%95%E8%AF%8D/</id>
    <published>2023-04-18T06:30:00.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h3 id="illustrate-v-举例；-用例子-图解等-说明；举例证明；加上插图-图解"><a href="#illustrate-v-举例；-用例子-图解等-说明；举例证明；加上插图-图解" class="headerlink" title="illustrate v.举例；(用例子,图解等)说明；举例证明；加上插图[图解]"></a>illustrate v.举例；(用例子,图解等)说明；举例证明；加上插图[图解]</h3><p>美: [ˈɪləˌstreɪt] 英: [ˈɪləstreɪt] </p><h3 id="palette-n-调色板；（画家使用的）主要色彩"><a href="#palette-n-调色板；（画家使用的）主要色彩" class="headerlink" title="palette n.    调色板；（画家使用的）主要色彩"></a>palette n.    调色板；（画家使用的）主要色彩</h3><p>美: [ˈpælət]<br>英: [‘pælət]<br>网络    调色盘；画板；面板<br>eg.Command Palette</p><h3 id="iteration-n-迭代；（计算机）新版软件"><a href="#iteration-n-迭代；（计算机）新版软件" class="headerlink" title="iteration n.    迭代；（计算机）新版软件"></a>iteration n.    迭代；（计算机）新版软件</h3><p>美: [ˌɪtəˈreɪʃ(ə)n]<br>英: [.ɪtə’reɪʃ(ə)n]<br>网络    反复；叠代；反覆</p></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h3 id=&quot;illustrate-v-举例；-用例子-图解等-说明；举例证明；加上插图-图解&quot;&gt;&lt;a href=&quot;#illustrate-v-举例；-用例子-图解等-说明；举例证明；加上插图-图解&quot; class=&quot;header</summary>
      
    
    
    
    <category term="英文小菜" scheme="https://joyer-lee.github.io/blog/categories/%E8%8B%B1%E6%96%87%E5%B0%8F%E8%8F%9C/"/>
    
    
  </entry>
  
  <entry>
    <title>vscode项目国际化</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/14/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/vscode%E9%A1%B9%E7%9B%AE%E5%9B%BD%E9%99%85%E5%8C%96/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/14/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/vscode%E9%A1%B9%E7%9B%AE%E5%9B%BD%E9%99%85%E5%8C%96/</id>
    <published>2023-04-14T09:30:00.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h2 id="为什么要进行国际化"><a href="#为什么要进行国际化" class="headerlink" title="为什么要进行国际化"></a>为什么要进行国际化</h2><p>国际化（i18n）是指将应用程序设计为可以轻松地适应不同语言、地区和文化的能力，更好的在海外推广国内产品。</p><h2 id="国际化功能要点"><a href="#国际化功能要点" class="headerlink" title="国际化功能要点"></a>国际化功能要点</h2><p>1.多语言支持：包括界面和文档翻译、本地化应用等<br>2.多语言环境切换：切换后，读取相应的语言包内容</p><h2 id="如何实现国际化（步骤）"><a href="#如何实现国际化（步骤）" class="headerlink" title="如何实现国际化（步骤）"></a>如何实现国际化（步骤）</h2><p>1.将所有需要翻译的字符串放在单独的消息文件中。如 json 格式文件，每个文件对应一个语言。<br>2.使用国际化框架或库如<code>vue-i18n</code>，这些框架可帮助管理不同语言的消息文件。<br>3.根据用户的语言环境动态加载适当的消息文件。</p><h2 id="结合自身项目特点实现国际化"><a href="#结合自身项目特点实现国际化" class="headerlink" title="结合自身项目特点实现国际化"></a>结合自身项目特点实现国际化</h2><p>我们的产品为多项目架构，主项目基于 vscode 源码实现，包含 vscode 扩展项目、webview 界面，包含三种情况：</p><h3 id="vscode-原生项目国际化"><a href="#vscode-原生项目国际化" class="headerlink" title="vscode 原生项目国际化"></a>vscode 原生项目国际化</h3><p>安装时可选环境</p><ul><li><p>设置默认语言环境<br>初始安装时：默认语言环境为本机语言环境、若没有相应的语言包，默认为 en </p></li><li><p>扩展中文包消息字段<br>语言包目录：<code>extensions\ms-ceintl.vscode-language-pack-zh-hans-1.55.1\translations\main.i18n.json</code></p><figure class="highlight json"><table><tbody><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="attr">"vs/workbench/browser/parts/headerbar/modelLibraryView"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"><span class="attr">"loadModel"</span><span class="punctuation">:</span> <span class="string">"载入模型"</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></tbody></table></figure></li><li><p>本地化应用</p></li></ul><figure class="highlight typescript"><table><tbody><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">import</span> * <span class="keyword">as</span> nls <span class="keyword">from</span> <span class="string">'vs/nls'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="attr">test1</span>: <span class="title class_">IAction</span> = {</span><br><span class="line">  <span class="attr">id</span>: <span class="string">'1'</span>,</span><br><span class="line">  <span class="attr">label</span>: nls.<span class="title function_">localize</span>(<span class="string">'loadModel'</span>, <span class="string">'load model'</span>), <span class="comment">// 本地化</span></span><br><span class="line">  <span class="attr">run</span>: <span class="title function_">async</span> () =&gt; {</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'载入模型 run'</span>);</span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">loadModelToScene</span>(item);</span><br><span class="line">    rename;</span><br><span class="line">  },</span><br><span class="line">  <span class="title function_">dispose</span>(<span class="params"></span>) {},</span><br><span class="line">};</span><br></pre></td></tr></tbody></table></figure><ul><li>语言环境切换方法<br>可以通过使用Configure Display Language命令显式设置 VS Code 显示语言来覆盖默认 UI 语言，按Ctrl+Shift+P调出命令面板 &gt; 键入“display” &gt; 显示Configure Display Language命令</li></ul><p>底层实现：</p><figure class="highlight typescript"><table><tbody><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"><span class="comment">// src\vs\workbench\contrib\localizations\browser\localizationsActions.ts</span></span><br><span class="line"><span class="keyword">if</span> (selectedLanguage) {</span><br><span class="line"><span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">jsonEditingService</span>.<span class="title function_">write</span>(<span class="variable language_">this</span>.<span class="property">environmentService</span>.<span class="property">argvResource</span>, [{ <span class="attr">path</span>: [<span class="string">'locale'</span>], <span class="attr">value</span>: selectedLanguage.<span class="property">label</span> }], <span class="literal">true</span>); <span class="comment">// 写入运行时配置文件中 路径：C:\Users\userName\.modouide-oss</span></span><br><span class="line"><span class="keyword">const</span> restart = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">dialogService</span>.<span class="title function_">confirm</span>({</span><br><span class="line"><span class="attr">type</span>: <span class="string">'info'</span>,</span><br><span class="line"><span class="attr">message</span>: <span class="title function_">localize</span>(<span class="string">'relaunchDisplayLanguageMessage'</span>, <span class="string">"A restart is required for the change in display language to take effect."</span>),</span><br><span class="line"><span class="attr">detail</span>: <span class="title function_">localize</span>(<span class="string">'relaunchDisplayLanguageDetail'</span>, <span class="string">"Press the restart button to restart {0} and change the display language."</span>, <span class="variable language_">this</span>.<span class="property">productService</span>.<span class="property">nameLong</span>),</span><br><span class="line"><span class="attr">primaryButton</span>: <span class="title function_">localize</span>(<span class="string">'restart'</span>, <span class="string">"&amp;&amp;Restart"</span>)</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (restart.<span class="property">confirmed</span>) {</span><br><span class="line"><span class="variable language_">this</span>.<span class="property">hostService</span>.<span class="title function_">restart</span>();</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h3 id="基于vscode的子项目国际化"><a href="#基于vscode的子项目国际化" class="headerlink" title="基于vscode的子项目国际化"></a>基于vscode的子项目国际化</h3><blockquote><p>语言切换需要重启项目才可生效<br>  browerview项目可通过界面查询字符获取locale值<br>  扩展项目可通过通信访问配置文件中的locale值</p></blockquote><h2 id="vue-项目国际化"><a href="#vue-项目国际化" class="headerlink" title="vue 项目国际化"></a>vue 项目国际化</h2><p>1.使用 vue-i18n 插件实现<br>2.切换语言环境:可以使用 $i18n.locale 属性来切换语言</p><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><h3 id="后端返回的数据仅中文，如何兼容？"><a href="#后端返回的数据仅中文，如何兼容？" class="headerlink" title="后端返回的数据仅中文，如何兼容？"></a>后端返回的数据仅中文，如何兼容？</h3></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 id=&quot;为什么要进行国际化&quot;&gt;&lt;a href=&quot;#为什么要进行国际化&quot; class=&quot;headerlink&quot; title=&quot;为什么要进行国际化&quot;&gt;&lt;/a&gt;为什么要进行国际化&lt;/h2&gt;&lt;p&gt;国际化（i18n）是指将应用程序设</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>前瞻技术</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/14/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/%E5%89%8D%E7%9E%BB%E6%8A%80%E6%9C%AF/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/14/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/%E5%89%8D%E7%9E%BB%E6%8A%80%E6%9C%AF/</id>
    <published>2023-04-14T06:04:14.000Z</published>
    <updated>2026-10-18T10:36:38.013Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h2 id="前瞻技术"><a href="#前瞻技术" class="headerlink" title="前瞻技术"></a>前瞻技术</h2><blockquote><p>此处临时存放一些工作中没怎么用到，但比较感兴趣的前端概念，供我扫除知识盲点</p></blockquote><ul><li>service workers 离线缓存</li><li>微前端架构</li><li>低代码平台</li><li>SSR</li><li>微服务</li><li>计算机图形学</li><li>计算机运动学</li><li>webGL</li><li>线性代数</li><li>算法</li><li>数据结构</li><li>可视化大屏适配</li></ul></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 id=&quot;前瞻技术&quot;&gt;&lt;a href=&quot;#前瞻技术&quot; class=&quot;headerlink&quot; title=&quot;前瞻技术&quot;&gt;&lt;/a&gt;前瞻技术&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;此处临时存放一些工作中没怎么用到，但比较感兴趣的</summary>
      
    
    
    
    <category term="大前端技术圈" scheme="https://joyer-lee.github.io/blog/categories/%E5%A4%A7%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E5%9C%88/"/>
    
    
  </entry>
  
  <entry>
    <title>mockjs在前端项目中的应用</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/14/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/mockjs%E5%9C%A8%E5%89%8D%E7%AB%AF%E9%A1%B9%E7%9B%AE%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/14/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/mockjs%E5%9C%A8%E5%89%8D%E7%AB%AF%E9%A1%B9%E7%9B%AE%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/</id>
    <published>2023-04-14T02:38:00.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h3 id="使用mockjs模拟请求数据"><a href="#使用mockjs模拟请求数据" class="headerlink" title="使用mockjs模拟请求数据"></a>使用mockjs模拟请求数据</h3><blockquote><p>Mock.js 是一个前端数据模拟库，它可以拦截前端代码中的 XMLHttpRequest 请求，并返回模拟的数据；在前端开发中，使用 Mock 数据可以帮助我们模拟后端接口数据，提高开发效率，同时也可以减少对后端接口的依赖。</p></blockquote><p>示例：</p><figure class="highlight javascript"><table><tbody><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">// 引入 Mock.js</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Mock</span> <span class="keyword">from</span> <span class="string">'mockjs'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用 Mock.js 模拟数据</span></span><br><span class="line"><span class="title class_">Mock</span>.<span class="title function_">mock</span>(<span class="string">'/api/users'</span>, <span class="string">'get'</span>, {</span><br><span class="line">  <span class="attr">code</span>: <span class="number">200</span>,</span><br><span class="line">  <span class="attr">message</span>: <span class="string">'请求成功'</span>,</span><br><span class="line">  <span class="string">'data|10-20'</span>: [{</span><br><span class="line">    <span class="string">'id|+1'</span>: <span class="number">1</span>,</span><br><span class="line">    <span class="attr">name</span>: <span class="string">'@cname'</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="string">'@integer(20, 50)'</span>,</span><br><span class="line">    <span class="string">'gender|1'</span>: [<span class="string">'男'</span>, <span class="string">'女'</span>],</span><br><span class="line">    <span class="attr">address</span>: <span class="string">'@county(true)'</span>,</span><br><span class="line">    <span class="attr">avatar</span>: <span class="string">'@image("100x100")'</span></span><br><span class="line">  }]</span><br><span class="line">})</span><br></pre></td></tr></tbody></table></figure><h4 id="使用-webpack-dev-server-的-proxy-功能将ajax请求转发到后端服务中"><a href="#使用-webpack-dev-server-的-proxy-功能将ajax请求转发到后端服务中" class="headerlink" title="使用 webpack-dev-server 的 proxy 功能将ajax请求转发到后端服务中"></a>使用 webpack-dev-server 的 proxy 功能将ajax请求转发到后端服务中</h4><blockquote><p>Mock.js 和 devServer 代理的作用方式不同，所以它们的拦截顺序也不同。在默认情况下，Mock.js 会比 devServer 代理先执行，即 Mock.js 可以拦截前端请求并返回模拟数据，而不会将请求转发到后端服务器。如果想让 devServer 代理先执行，可以通过配置 before 选项将其放到 Mock.js 之前执行。</p></blockquote><ul><li>流程图<br><img src="/blog/_posts/images/uploads/sites/2/2023/4/image-20220323005542649.png" alt="image-20230414005542649"></li><li>实现<figure class="highlight javascript"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// main.js</span></span><br><span class="line">process.<span class="property">env</span>.<span class="property">VUE_APP_MOCK</span> === <span class="string">'true'</span> &amp;&amp; <span class="built_in">require</span>(<span class="string">'@/mock/index'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// .env.mock</span></span><br><span class="line"># just a flag</span><br><span class="line"><span class="variable constant_">ENV</span> = <span class="string">'mock'</span></span><br><span class="line"></span><br><span class="line"># base api</span><br><span class="line"><span class="variable constant_">VUE_APP_MOCK</span> = <span class="literal">true</span></span><br><span class="line"><span class="variable constant_">VUE_APP_BASE_API</span> = <span class="string">'/api'</span></span><br><span class="line"><span class="variable constant_">VUE_APP_PROXY_API</span>=<span class="string">'http://your.service.com'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// vue.config.js</span></span><br><span class="line"><span class="attr">devServer</span>: {</span><br><span class="line">  <span class="attr">proxy</span>: {</span><br><span class="line">    <span class="string">'/api'</span>: {</span><br><span class="line">      <span class="attr">target</span>: process.<span class="property">env</span>.<span class="property">VUE_APP_PROXY_API</span>,</span><br><span class="line">      <span class="attr">pathRewrite</span>: {</span><br><span class="line">        <span class="string">'^/api'</span>: <span class="string">''</span></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></pre></td></tr></tbody></table></figure></li></ul></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h3 id=&quot;使用mockjs模拟请求数据&quot;&gt;&lt;a href=&quot;#使用mockjs模拟请求数据&quot; class=&quot;headerlink&quot; title=&quot;使用mockjs模拟请求数据&quot;&gt;&lt;/a&gt;使用mockjs模拟请求数据&lt;/h3&gt;</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>二次封装axios</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/13/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E4%BA%8C%E6%AC%A1%E5%B0%81%E8%A3%85axios/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/13/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E4%BA%8C%E6%AC%A1%E5%B0%81%E8%A3%85axios/</id>
    <published>2023-04-13T02:38:00.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h3 id="封装axios请求"><a href="#封装axios请求" class="headerlink" title="封装axios请求"></a>封装axios请求</h3><blockquote><p>axios是一个基于promise的http请求库，可以用于浏览器和node环境。</p></blockquote><h4 id="为什仫要对axios进行二次封装"><a href="#为什仫要对axios进行二次封装" class="headerlink" title="为什仫要对axios进行二次封装"></a>为什仫要对axios进行二次封装</h4><p>1.封装通用功能：二次封装可以封装通用的功能，比如请求头添加token、统一处理错误信息等，这样可以减少重复的代码，提高开发效率。<br>2.方便维护：通过二次封装可以将请求和处理逻辑分离，使得代码结构更加清晰，方便维护。<br>3.接口升级：在接口升级的情况下，如果没有二次封装，那么所有调用该接口的地方都需要进行修改，如果使用了二次封装，那么只需要修改封装的代码即可。<br>4.更好的可扩展性：通过二次封装，我们可以根据业务需求进行定制化的处理，比如统一添加loading效果、处理特殊的请求参数等。<br>5.更好的适应性：二次封装可以根据不同的业务场景进行定制，比如不同的请求方式、不同的请求地址等，使得代码更加灵活、适应性更强。</p><h4 id="如何实现axios二次封装"><a href="#如何实现axios二次封装" class="headerlink" title="如何实现axios二次封装"></a>如何实现axios二次封装</h4><p>我们可以创建一个<code>request.ts</code>文件，在该文件中实现axios的二次封装。</p><ul><li>1.封装 Axios 的基本配置：这包括设置请求的默认 URL、HTTP 方法、请求头、响应数据格式等等。</li></ul><figure class="highlight javascript"><table><tbody><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">import</span> axios <span class="keyword">from</span> <span class="string">'axios'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> instance = axios.<span class="title function_">create</span>({</span><br><span class="line">  <span class="attr">baseURL</span>: <span class="string">'http://your-api-base-url.com'</span>,</span><br><span class="line">  <span class="attr">timeout</span>: <span class="number">1000</span>,</span><br><span class="line">  <span class="attr">headers</span>: {</span><br><span class="line">    <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span></span><br><span class="line">  }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> instance; <span class="comment">// 导出axios实例</span></span><br></pre></td></tr></tbody></table></figure><ul><li><p>2.处理请求参数和响应数据：对于一些通用的数据处理操作，比如请求参数的转换或响应数据的处理，避免在每个请求中都写相同的代码。</p><figure class="highlight javascript"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 我们可以使用 instance.interceptors.request.use() 方法来添加请求拦截器</span></span><br><span class="line">instance.<span class="property">interceptors</span>.<span class="property">request</span>.<span class="title function_">use</span>(</span><br><span class="line"><span class="function"><span class="params">config</span> =&gt;</span> {</span><br><span class="line">    <span class="comment">// 处理请求参数</span></span><br><span class="line">    config.<span class="property">params</span> = {</span><br><span class="line">    ...config.<span class="property">params</span>,</span><br><span class="line">    <span class="attr">api_key</span>: <span class="string">'xxxxxxxxxxxxxx'</span>,</span><br><span class="line">    };</span><br><span class="line">    <span class="keyword">return</span> config;</span><br><span class="line">},</span><br><span class="line"><span class="function"><span class="params">error</span> =&gt;</span> {</span><br><span class="line">    <span class="comment">// 处理请求错误</span></span><br><span class="line">    <span class="keyword">throw</span> error;</span><br><span class="line">});</span><br><span class="line"><span class="comment">// 类似地，我们也可以使用 instance.interceptors.response.use() 方法来添加响应拦截器</span></span><br><span class="line">instance.<span class="property">interceptors</span>.<span class="property">response</span>.<span class="title function_">use</span>(</span><br><span class="line"><span class="function"><span class="params">response</span> =&gt;</span> {</span><br><span class="line">    <span class="comment">// 处理响应数据</span></span><br><span class="line">    <span class="keyword">return</span> response.<span class="property">data</span>;</span><br><span class="line">},</span><br><span class="line"><span class="function"><span class="params">error</span> =&gt;</span> {</span><br><span class="line">    <span class="comment">// 处理响应错误</span></span><br><span class="line">    <span class="keyword">throw</span> error;</span><br><span class="line">}</span><br><span class="line">);</span><br></pre></td></tr></tbody></table></figure></li><li><p>3.处理请求错误：在请求过程中可能会发生错误，比如请求超时或网络错误。针对这些错误，需要进行适当的处理，比如进行重试或提示用户错误信息,可通过拦截器第二个参数配置，可参照第二个例子。</p></li><li><p>4.统一处理请求返回数据格式：如果项目要求返回数据格式一致，可以在封装中统一处理，而不是在每个请求中处理。</p>  <figure class="highlight javascript"><table><tbody><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="comment">// 假设与后端约定返回的字段为</span></span><br><span class="line"><span class="comment">// {</span></span><br><span class="line"><span class="comment">//   "code": 200,</span></span><br><span class="line"><span class="comment">//   "message": "",</span></span><br><span class="line"><span class="comment">//   "data": {}</span></span><br><span class="line"><span class="comment">// }</span></span><br><span class="line"><span class="comment">// 我们可以在响应拦截中判断响应数据的 code 字段是否为 200，如果是，就返回 data 字段，否则就抛出一个异常</span></span><br><span class="line">    instance.<span class="property">interceptors</span>.<span class="property">response</span>.<span class="title function_">use</span>(</span><br><span class="line">    <span class="function"><span class="params">response</span> =&gt;</span> {</span><br><span class="line">        <span class="keyword">const</span> { data } = response;</span><br><span class="line">        <span class="keyword">if</span> (data.<span class="property">code</span> === <span class="number">200</span>) {</span><br><span class="line">        <span class="keyword">return</span> data.<span class="property">data</span>;</span><br><span class="line">        } <span class="keyword">else</span> {</span><br><span class="line">        <span class="comment">// 处理异常情况</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(data.<span class="property">message</span> || <span class="string">'未知错误'</span>);</span><br><span class="line">        }</span><br><span class="line">    },</span><br><span class="line">    <span class="function"><span class="params">error</span> =&gt;</span> {</span><br><span class="line">        <span class="comment">// 处理请求错误</span></span><br><span class="line">        <span class="keyword">throw</span> error;</span><br><span class="line">    }</span><br><span class="line">    );</span><br></pre></td></tr></tbody></table></figure></li><li><p>5.处理接口鉴权：如果项目需要接口鉴权，可以在二次封装中进行处理，统一添加鉴权信息。</p><figure class="highlight javascript"><table><tbody><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">  instance.<span class="property">interceptors</span>.<span class="property">request</span>.<span class="title function_">use</span>(</span><br><span class="line">  <span class="function"><span class="params">config</span> =&gt;</span> {</span><br><span class="line">    <span class="keyword">const</span> token = <span class="variable language_">localStorage</span>.<span class="title function_">getItem</span>(<span class="string">'token'</span>); <span class="comment">// 获取存储在本地的 token</span></span><br><span class="line">    <span class="keyword">if</span> (token) {</span><br><span class="line">      config.<span class="property">headers</span>.<span class="property">Authorization</span> = <span class="string">`Bearer <span class="subst">${token}</span>`</span>; <span class="comment">// 在请求头中添加鉴权信息</span></span><br><span class="line">    }</span><br><span class="line">    <span class="keyword">return</span> config;</span><br><span class="line">  },</span><br><span class="line">  <span class="function"><span class="params">error</span> =&gt;</span> {</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">reject</span>(error);</span><br><span class="line">  }</span><br><span class="line">);</span><br></pre></td></tr></tbody></table></figure></li><li><p>6.处理请求取消：在一些场景下，用户可能需要取消正在进行的请求，比如在搜索框中输入关键字时，用户很可能会多次发送请求，此时需要取消前一次的请求，只保留最后一次请求的结果。</p></li></ul><figure class="highlight javascript"><table><tbody><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><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">'axios'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> { <span class="title class_">CancelToken</span> } = axios;</span><br><span class="line"><span class="keyword">const</span> source = <span class="title class_">CancelToken</span>.<span class="title function_">source</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> request = axios.<span class="title function_">create</span>({</span><br><span class="line"><span class="attr">baseURL</span>: process.<span class="property">env</span>.<span class="property">VUE_APP_BASE_API</span>,</span><br><span class="line"><span class="attr">timeout</span>: <span class="number">5000</span>,</span><br><span class="line"><span class="attr">cancelToken</span>: source.<span class="property">token</span> <span class="comment">//将source.token属性作为cancelToken参数传递给axios</span></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">source.<span class="title function_">cancel</span>(<span class="string">'请求已被取消！'</span>); <span class="comment">// 取消请求</span></span><br></pre></td></tr></tbody></table></figure><ul><li><p>7.处理并发请求：在一些场景下，需要同时发送多个请求并等待所有请求都完成后再进行下一步操作，可以使用 Axios 提供的并发请求功能来处理，以便更好地控制网络流量。</p>  <figure class="highlight javascript"><table><tbody><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"><span class="keyword">const</span> instance = axios.<span class="title function_">create</span>({</span><br><span class="line"><span class="attr">baseURL</span>: <span class="string">'https://api.example.com'</span>,</span><br><span class="line"><span class="attr">timeout</span>: <span class="number">5000</span>,</span><br><span class="line"><span class="attr">maxContention</span>: <span class="number">3</span>, <span class="comment">// 限制并发请求数量</span></span><br><span class="line">});</span><br></pre></td></tr></tbody></table></figure></li></ul><h3 id="封装api方法"><a href="#封装api方法" class="headerlink" title="封装api方法"></a>封装api方法</h3><ul><li>创建一个<code>api.js</code>文件，并在其中封装api方法</li></ul><figure class="highlight javascript"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> request <span class="keyword">from</span> <span class="string">'./request.js'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">getUserList</span> = (<span class="params">params</span>) =&gt; {</span><br><span class="line">  <span class="keyword">return</span> request.<span class="title function_">get</span>(<span class="string">'/api/users'</span>, {</span><br><span class="line">    params,</span><br><span class="line">  });</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">getUserInfo</span> = (<span class="params">id</span>) =&gt; {</span><br><span class="line">  <span class="keyword">return</span> request.<span class="title function_">get</span>(<span class="string">`/api/users/<span class="subst">${id}</span>`</span>);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">addUser</span> = (<span class="params">data</span>) =&gt; {</span><br><span class="line">  <span class="keyword">return</span> request.<span class="title function_">post</span>(<span class="string">'/api/users'</span>, data);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">updateUser</span> = (<span class="params">id, data</span>) =&gt; {</span><br><span class="line">  <span class="keyword">return</span> request.<span class="title function_">put</span>(<span class="string">`/api/users/<span class="subst">${id}</span>`</span>, data);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">deleteUser</span> = (<span class="params">id</span>) =&gt; {</span><br><span class="line">  <span class="keyword">return</span> request.<span class="title function_">delete</span>(<span class="string">`/api/users/<span class="subst">${id}</span>`</span>);</span><br><span class="line">};</span><br></pre></td></tr></tbody></table></figure><ul><li>使用api方法<figure class="highlight javascript"><table><tbody><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><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { getUserList, addUser, updateUser, deleteUser } <span class="keyword">from</span> <span class="string">'./api'</span>;</span><br><span class="line"><span class="title function_">getUserList</span>({</span><br><span class="line">  <span class="attr">page</span>: <span class="number">1</span>,</span><br><span class="line">  <span class="attr">size</span>: <span class="number">10</span>,</span><br><span class="line">})</span><br><span class="line">  .<span class="title function_">then</span>(<span class="function"><span class="params">data</span> =&gt;</span> {</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(data);</span><br><span class="line">  })</span><br><span class="line">  .<span class="title function_">catch</span>(<span class="function"><span class="params">error</span> =&gt;</span> {</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(error);</span><br><span class="line">  });</span><br><span class="line"></span><br><span class="line">  <span class="title function_">addUser</span>({</span><br><span class="line">    <span class="attr">name</span>: <span class="string">'Tom'</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">18</span>,</span><br><span class="line">  })</span><br><span class="line">    .<span class="title function_">then</span>(<span class="function"><span class="params">data</span> =&gt;</span> {</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(data);</span><br><span class="line">    })</span><br><span class="line">    .<span class="title function_">catch</span>(<span class="function"><span class="params">error</span> =&gt;</span> {</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(error);</span><br><span class="line">    });</span><br><span class="line"></span><br><span class="line">  <span class="title function_">updateUser</span>(<span class="number">1</span>, {</span><br><span class="line">    <span class="attr">name</span>: <span class="string">'Jerry'</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">20</span>,</span><br><span class="line">  })</span><br><span class="line">    .<span class="title function_">then</span>(<span class="function"><span class="params">data</span> =&gt;</span> {</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(data);</span><br><span class="line">    })</span><br><span class="line">    .<span class="title function_">catch</span>(<span class="function"><span class="params">error</span> =&gt;</span> {</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(error);</span><br><span class="line">    });</span><br><span class="line"></span><br><span class="line">  <span class="title function_">deleteUser</span>(<span class="number">1</span>)</span><br><span class="line">    .<span class="title function_">then</span>(<span class="function"><span class="params">data</span> =&gt;</span> {</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(data);</span><br><span class="line">    })</span><br><span class="line">    .<span class="title function_">catch</span>(<span class="function"><span class="params">error</span> =&gt;</span> {</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(error);</span><br><span class="line">    });</span><br></pre></td></tr></tbody></table></figure></li></ul></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h3 id=&quot;封装axios请求&quot;&gt;&lt;a href=&quot;#封装axios请求&quot; class=&quot;headerlink&quot; title=&quot;封装axios请求&quot;&gt;&lt;/a&gt;封装axios请求&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;axio</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>《如何阅读一本书》</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/12/%E8%AF%BB%E6%9C%AC%E5%A5%BD%E4%B9%A6/%E5%A6%82%E4%BD%95%E9%98%85%E8%AF%BB%E4%B8%80%E6%9C%AC%E4%B9%A6/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/12/%E8%AF%BB%E6%9C%AC%E5%A5%BD%E4%B9%A6/%E5%A6%82%E4%BD%95%E9%98%85%E8%AF%BB%E4%B8%80%E6%9C%AC%E4%B9%A6/</id>
    <published>2023-04-12T14:04:14.000Z</published>
    <updated>2026-10-18T10:36:38.015Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><blockquote><p>《如何阅读一本书》在我的书架上放了有两年多的时间，一直想要好好的阅读，之前几次翻开都由于没有集中精力的原因，最后不了了之。现在我又翻开了它…</p></blockquote><h2 id="部分摘抄"><a href="#部分摘抄" class="headerlink" title="部分摘抄"></a>部分摘抄</h2><ul><li>阅读是个复杂的的活动，要达到良好的阅读效果，就要更主动的阅读，在阅读的每一种活动中参与更多的阅读技巧。</li><li>阅读的艺术包括了所有非辅助型自我发现学习的技巧，敏锐的观察，灵敏可靠的记忆，想象的空间，再者，当然就是训练有素的分析，省思能力。</li><li>我们的成人教育要完全依赖书籍本身的时候，我们就不能再有老师的帮助了，如果我们打算继续学习与发现我们就要懂得如何让书本来教导我们。</li></ul><h2 id="阅读的四个层次"><a href="#阅读的四个层次" class="headerlink" title="阅读的四个层次"></a>阅读的四个层次</h2><p>阅读的四个层次分别是基础阅读、检视阅读、分析阅读、主题阅读。</p><h3 id="基础阅读"><a href="#基础阅读" class="headerlink" title="基础阅读"></a>基础阅读</h3><p>基础阅读的四个阶段</p><ul><li>第一阶段：阅读准备阶段（七岁之前）：身体、智力、语言、个人都要发育到一定程度;</li><li>第二阶段：学习读一些简单的读物：着重练习发音，理解文字含义，可通过看图识字学习；</li><li>第三阶段：快速建立词汇,根据上下文含义可联想不熟悉字眼；</li><li>第四阶段：精炼与增进前三个阶段,消化阅读经验，能够举一反三；</li></ul><h3 id="检视阅读"><a href="#检视阅读" class="headerlink" title="检视阅读"></a>检视阅读</h3><h4 id="第一个子层次：由系统的略读或粗读"><a href="#第一个子层次：由系统的略读或粗读" class="headerlink" title="第一个子层次：由系统的略读或粗读"></a>第一个子层次：由系统的略读或粗读</h4><blockquote><p>目的：有限的时间内快速的了解书的基本信息（是怎样的书，重点是什么），确定是否有阅读价值。<br>如何略读或粗读一本书？</p></blockquote><ul><li>1.看书名，看序言。注意副标题与主旨，为书归类。</li><li>2.看目录，了解书店基本结构。</li><li>3.看索引，评估书涵盖的议题范围，关注重点词汇与重点词汇相关的内文。</li><li>4.看书衣，读介绍，读宣传文案。</li><li>5.挑选与主题相关的篇章阅读，优先读摘要部分。</li><li>6.来回翻一翻全书，读一两段或连续读几页，随时寻找主要论点，留意主题脉动。</li></ul><h4 id="第二个子层次粗浅的阅读"><a href="#第二个子层次粗浅的阅读" class="headerlink" title="第二个子层次粗浅的阅读"></a>第二个子层次粗浅的阅读</h4><p>对一些难读的书通读一遍，遇到难懂的地方也不要停下，只关注能理解的地方。</p><h4 id="关于阅读速度"><a href="#关于阅读速度" class="headerlink" title="关于阅读速度"></a>关于阅读速度</h4><p>理想的阅读速度不只要能读得快，还要能用不同的速度来阅读。</p><h4 id="提升阅读速度的建议"><a href="#提升阅读速度的建议" class="headerlink" title="提升阅读速度的建议"></a>提升阅读速度的建议</h4><p>用手指着讲要阅读的文字，顺着一行一行的字移动，速度比眼睛感觉的还要快点，强迫眼睛跟着首部的动作移动。</p><h4 id="如何做一个自我要求的读者？"><a href="#如何做一个自我要求的读者？" class="headerlink" title="如何做一个自我要求的读者？"></a>如何做一个自我要求的读者？</h4><ul><li>主动阅读的基础：一个阅读者要提出四个基本问题–1.这本书讲的什么？2.作者细说了什么，怎么说的？？3.你觉得作者的观点对吗？部分对还是全部对？4.这本书跟我有什么关系？</li><li>主动阅读的核心就是在阅读时提出问题来，在阅读的过程中，自己去回答问题</li></ul><h4 id="阅读的好习惯"><a href="#阅读的好习惯" class="headerlink" title="阅读的好习惯"></a>阅读的好习惯</h4><p>在阅读时，手中有一支笔会更好的记录问题和回答问题，也是提醒我们记录问题的讯号。</p><ul><li><p>做笔记的方法：<br>1.画底线<br>2.画底线处的栏外再加画一道线，做重点描述<br>3.在空白处做星号或其他符号<br>4.在空白处编号<br>5.在空白处记下其他的页码<br>6.将关键字或句子圈出来<br>7.在树叶的空白处做笔记</p></li><li><p>做笔记的三种方式：<br>1.结构笔记-检视阅读<br>2.概念笔记-分析阅读<br>3.概念/辩证笔记-主题阅读</p></li><li><p>要养成习惯，除了不断地运作练习之外别无他法。</p><ul><li>照着规则联系，就可以培养出一种技巧或技能的习惯。</li><li>由许多规则中养成一个习惯</li><li>对每一个步骤或规则都熟练后，才能将所有不同的步骤连结起来，变成一个复杂却和谐的动作，然后养成习惯</li></ul></li></ul></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;blockquote&gt;
&lt;p&gt;《如何阅读一本书》在我的书架上放了有两年多的时间，一直想要好好的阅读，之前几次翻开都由于没有集中精力的原因，最后不了了之。现在我又翻开了它…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;部分</summary>
      
    
    
    
    <category term="读本好书" scheme="https://joyer-lee.github.io/blog/categories/%E8%AF%BB%E6%9C%AC%E5%A5%BD%E4%B9%A6/"/>
    
    
  </entry>
  
  <entry>
    <title>ajax与fetch请求的区别</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/12/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/ajax%E4%B8%8Efetch%E8%AF%B7%E6%B1%82%E7%9A%84%E5%8C%BA%E5%88%AB/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/12/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/ajax%E4%B8%8Efetch%E8%AF%B7%E6%B1%82%E7%9A%84%E5%8C%BA%E5%88%AB/</id>
    <published>2023-04-12T13:31:00.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h2 id="ajax与fetch请求的区别"><a href="#ajax与fetch请求的区别" class="headerlink" title="ajax与fetch请求的区别"></a>ajax与fetch请求的区别</h2><h3 id="关于前端样式主题化"><a href="#关于前端样式主题化" class="headerlink" title="关于前端样式主题化"></a>关于前端样式主题化</h3><h3 id="基于websocket的消息通信"><a href="#基于websocket的消息通信" class="headerlink" title="基于websocket的消息通信"></a>基于websocket的消息通信</h3><h3 id="参考elementPlus源码实现自己的svg图标库"><a href="#参考elementPlus源码实现自己的svg图标库" class="headerlink" title="参考elementPlus源码实现自己的svg图标库"></a>参考elementPlus源码实现自己的svg图标库</h3><h3 id="参考elementPlus源码实现全局组件方法"><a href="#参考elementPlus源码实现全局组件方法" class="headerlink" title="参考elementPlus源码实现全局组件方法"></a>参考elementPlus源码实现全局组件方法</h3><h3 id="如何把js项目迁移为typescript项目"><a href="#如何把js项目迁移为typescript项目" class="headerlink" title="如何把js项目迁移为typescript项目"></a>如何把js项目迁移为typescript项目</h3><h3 id="使用prettier、eslint、husky、lintstage定制开发规范"><a href="#使用prettier、eslint、husky、lintstage定制开发规范" class="headerlink" title="使用prettier、eslint、husky、lintstage定制开发规范"></a>使用prettier、eslint、husky、lintstage定制开发规范</h3><h3 id="关于前端样式主题化-1"><a href="#关于前端样式主题化-1" class="headerlink" title="关于前端样式主题化"></a>关于前端样式主题化</h3><h3 id="关于静态文档网站那些事儿"><a href="#关于静态文档网站那些事儿" class="headerlink" title="关于静态文档网站那些事儿"></a>关于静态文档网站那些事儿</h3><h3 id="关于如何提升打包效率"><a href="#关于如何提升打包效率" class="headerlink" title="关于如何提升打包效率"></a>关于如何提升打包效率</h3><h3 id="electron-嵌入项目嵌入web界面的几种方式"><a href="#electron-嵌入项目嵌入web界面的几种方式" class="headerlink" title="electron 嵌入项目嵌入web界面的几种方式"></a>electron 嵌入项目嵌入web界面的几种方式</h3><h3 id="桌面应用的几种数据存储方式"><a href="#桌面应用的几种数据存储方式" class="headerlink" title="桌面应用的几种数据存储方式"></a>桌面应用的几种数据存储方式</h3><h3 id="登录功能的实现"><a href="#登录功能的实现" class="headerlink" title="登录功能的实现"></a>登录功能的实现</h3></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 id=&quot;ajax与fetch请求的区别&quot;&gt;&lt;a href=&quot;#ajax与fetch请求的区别&quot; class=&quot;headerlink&quot; title=&quot;ajax与fetch请求的区别&quot;&gt;&lt;/a&gt;ajax与fetch请求的区别&lt;</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>关于码垛流程仿真</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/10/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%85%B3%E4%BA%8E%E7%A0%81%E5%9E%9B%E6%B5%81%E7%A8%8B%E4%BB%BF%E7%9C%9F/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/10/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%85%B3%E4%BA%8E%E7%A0%81%E5%9E%9B%E6%B5%81%E7%A8%8B%E4%BB%BF%E7%9C%9F/</id>
    <published>2023-04-10T07:47:00.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h2 id="关于码垛流程仿真"><a href="#关于码垛流程仿真" class="headerlink" title="关于码垛流程仿真"></a>关于码垛流程仿真</h2><h3 id="码垛有哪些流程"><a href="#码垛有哪些流程" class="headerlink" title="码垛有哪些流程"></a>码垛有哪些流程</h3><p><code>一般码垛流程</code><br>1.物料准备：码垛前需要准备好要码垛的物料，通常是已经包装好的成品或半成品，要保证物料的尺寸和重量符合要求。<br>2.码垛规划：根据物料的尺寸、重量和码垛的要求，制定码垛方案，包括堆垛层数、堆垛方式等。<br>3.堆垛机械运作：使用自动化的堆垛机械将物料按照码垛方案堆垛起来。常用的堆垛机械包括自动堆垛机、机械手等。<br>4.码垛质检：在码垛完成后，需要对堆垛的物料进行质检，确保码垛的质量符合要求。<br>5.包装：对已经完成码垛的物料进行包装，保护物料，以便运输和储存。<br>6.输送：将已经完成包装的物料输送到指定的地点，例如仓库或运输车辆。<br><code>码垛流程仿真</code><br>我们这里只对码垛流程中的前三个阶段进行仿真应用，且使用的自动化堆垛机械为机械手，主要功能包括：工件的输送、工件的搬运、垛型设置、机器人路径及逻辑指令设置。以下为仿真过程。<br>1.仿真项目默认存在一个空白3D场景<br>2.向3D场景中添加码垛应用使用到的机械设备，机械设备包含机器人、传送带、工件、托盘、传感器、夹爪/吸盘<br>3设置工件运输流程：通过设置传送带运动速度、运动方向、绑定工件、上料点位置、上料频率等属性参数，获取3D运动参数，在传送带末端设置传感器，当工件运动至与传送带末端时会与传感器物体碰撞，此时传送带停止运输工件，等待机器人搬运。<br>4.设置托盘垛型：载入托盘后，可自主设置托盘垛层，设置垛层绑定的工件，依次在托盘上码放绑定工件，也可自定义码放的工件顺序与层数<br>5：工件搬运流程：3D场景载入机器人并为机器人设置合适位置，设置机器人的运动路径即夹爪的起始位置、抓取工件位置、工件码放位置等，若传送带停止运输工件，则触发机器人按照规定路径运动，若工件被机器人抓走后，传送带可重新启动运输下一个工件</p><h3 id="threejs-在码垛场景中的应用"><a href="#threejs-在码垛场景中的应用" class="headerlink" title="threejs 在码垛场景中的应用"></a>threejs 在码垛场景中的应用</h3><p>1.初始化场景: 创建基本的3D场景，场景中包含基本的光照、相机等元素，绑定控制器并使用webgl渲染器渲染到指定dom上<br>2.对于添加到场景中的物体，采用的是threejs 提供的模型加载器，也可结合threejs提供的创建几何体的方式添加<br>3.3D物体的运动效果可以结合threejs中的矩阵变换函数和3D缓动库tweenjs来实现（平移、旋转、缩放等效果），对于更复杂的运动需要结合相关运动学算法来实现<br>4.关于模型的压缩，可以使用draco算法以及LOD（levels of detail 多细节层次）技术或者酌情减少模型顶点进行优化</p></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 id=&quot;关于码垛流程仿真&quot;&gt;&lt;a href=&quot;#关于码垛流程仿真&quot; class=&quot;headerlink&quot; title=&quot;关于码垛流程仿真&quot;&gt;&lt;/a&gt;关于码垛流程仿真&lt;/h2&gt;&lt;h3 id=&quot;码垛有哪些流程&quot;&gt;&lt;a href</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>关于工业3D仿真</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/07/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%85%B3%E4%BA%8E%E5%B7%A5%E4%B8%9A3D%E4%BB%BF%E7%9C%9F/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/07/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%85%B3%E4%BA%8E%E5%B7%A5%E4%B8%9A3D%E4%BB%BF%E7%9C%9F/</id>
    <published>2023-04-07T07:47:00.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h2 id="关于工业3D仿真"><a href="#关于工业3D仿真" class="headerlink" title="关于工业3D仿真"></a>关于工业3D仿真</h2><p>其实接触工业3D仿真业务已经有近一年的时间了，因为不是3D业务主要负责人，平时的业务侧重点并不在3D那一块，但它确实是我们的核心业务，加上我对web 3D很有渊源，来上海后的第一份工作也是对web 3D的研发，我想我很有必要对这个领域的知识进行梳理和分析。</p><h3 id="背景：为什么而来，解决什么问题"><a href="#背景：为什么而来，解决什么问题" class="headerlink" title="背景：为什么而来，解决什么问题"></a>背景：为什么而来，解决什么问题</h3><p>工业仿真是一个比较宽泛的概念，有数据3D模型搭建、过程仿真等环节。在我们的业务场景中3D仿真指的是工业流程仿真。仿真技术的加持能有效提高企业开发效率，加强数据采集、分析、处理能力，减少决策失误并降低企业风险。我们公司主要的产品是工业机器人，提供产线系统集成服务。在系统集成作业中存在大量的人工作业，完全依赖人工调节，产品线遇到问题维护成本很高，且相关技术人员紧缺、培养成本高；基于此，公司想要做出一套能够模拟产线上机器人系统集成的可视化交互工具，甚至可结合机器人编程实现拓展为<code>一个跨平台工业仿真+工业机器人离线编程系统平台</code>，可为作为整个工业机器人行业的一套解决方案。</p><h3 id="目标：要做成什么样的东西"><a href="#目标：要做成什么样的东西" class="headerlink" title="目标：要做成什么样的东西"></a>目标：要做成什么样的东西</h3><p>我们要做一套<code>集工业业务仿真与离线编程与一体的集成开发平台</code></p><h3 id="实现思路："><a href="#实现思路：" class="headerlink" title="实现思路："></a>实现思路：</h3><p>开源的代码编辑器-vscode + threejs + vue</p><h3 id="技术生态："><a href="#技术生态：" class="headerlink" title="技术生态："></a>技术生态：</h3><p>1.魔改vscode实现自己的登录功能、模型库、tab切换、头部工具栏<br>2.实现vscode业务功能扩展项目：3D仿真，rpl语言解析<br>3.实现基于vscode的内嵌界面：账户与资源管理项目、3D编辑器项目<br>4.实现3D组件库、树状菜单组件库<br>5.实现组件库文档项目搭建与自动化部署</p><h3 id="技术栈："><a href="#技术栈：" class="headerlink" title="技术栈："></a>技术栈：</h3><p>1.vue3<br>2.threejs<br>3.electron<br>4.nodejs<br>5.typescript<br>6.elementPlus<br>7.webpack、vite、rollup<br>8.prettier、eslint<br>9.vitepress、vuepress<br>10.jest、vue-test</p></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 id=&quot;关于工业3D仿真&quot;&gt;&lt;a href=&quot;#关于工业3D仿真&quot; class=&quot;headerlink&quot; title=&quot;关于工业3D仿真&quot;&gt;&lt;/a&gt;关于工业3D仿真&lt;/h2&gt;&lt;p&gt;其实接触工业3D仿真业务已经有近一年的时间</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>简单的行业liao&#39;jie</title>
    <link href="https://joyer-lee.github.io/blog/2023/04/05/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%972023_4_5/"/>
    <id>https://joyer-lee.github.io/blog/2023/04/05/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%972023_4_5/</id>
    <published>2023-04-05T05:47:00.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>今天是清明节，对我这打工族来说也就是居家休息的一天，距离上一篇工作日志已经过去了一个周末和两个工作日，虽然偷懒没有记录工作上的内容，但也没有完全偷懒到没有任何作为，周末两天是舒缓的两天，我观看了公司内部发布的两篇关于《回归价值本质-我们在做一个怎样的产品》与《企业战略规划洞察》的课程，这让一直埋头实现技术工作的我对公司与行业发展多了一些思考。两个工作日也没有投入特别好的状态，因为邻近项目发版，做的一些代码检查与功能联调的工作，不过对于项目中涉及的web CSP（content safe protocol）内容安全协议很感兴趣，做了一些了解。</p><p>关于《回归价值的本质-我们在做一个怎样的产品》</p><p>确切的说这是关于介绍产品特性、如何度量我们的产品价值、如何促进产品交易以及如何提升产品价值的宏观讨论。下面是课程主要讲述的内容：</p><p>（1）什么情况下会促进商品交易？</p><p>&nbsp;&nbsp;&nbsp;&nbsp;商品价格高于卖方的成本价格，低于买方的预期的价格</p><p>（2）我们的商品是什么？特性是什么？</p><p>&nbsp;&nbsp;&nbsp;&nbsp;我们的商品是机器人，本质是一种生产工具，所产生的价值是显性可度量的。根据这样的特点引申出我们的所面对的挑战-比拼硬实力。</p><p>（3）我们产品的终端用户是？</p><p>&nbsp;&nbsp;&nbsp;&nbsp;以盈利为目的的制造型企业，关心的点在于引入机器人生产工具所带来的经济回报。</p><p>（4）促进交易的简单公式</p><p>如果产品的投资回报年限小于企业预期的投资回报年限，即商品价格小于买方的预期价格，则我们的终端用户是很乐意购买我们的产品的。</p><p>商品投资回报年限 = （系统集成一次性投入+机器人产品购置价格）/  价值增量</p><p>机器人产品价值增量 = 机器人产品直接创造的价值 - 机器人使用带来的额外成本-机器人购置带来的成本</p><p>（5）关于国内高端制造装备企业如何与国外同行竞争市场？</p><p><strong>提升产品力</strong>：产品力提高至可与国外同等产品竞争，中国市场会选择国产品牌，销量增加后成本会有一定降低，价格也会下降从而产生交易的良性循环。</p><p>为了提升生产力，企业可内部聚焦局部优势，外部借助融资以及政府支持。</p><p>总结：这篇课程简单说明了只有聚焦做好一个产品，才能为企业以及国内市场带来价值，这也是我们企业的最终目标。作为一个小小的技术人员，也许目前没有那样的技术力，但依然期望在未来的个人发展中能出这样的一份力。以上关于《回归价值的本质-我们在做一个怎样的产品》课程的学习记录也只是简单的对行业和机器人产品的一个基础了解，还没有涉及到更深入的思考，希望通过这段文字能带给我更多关于行业的思考。</p><p>关于《企业战略规划洞察》</p><p>这一课程分享的是在企业战略规划时用到的BLM模型–（Business leadership model，业务领先模型）中的市场洞察。BLM模型并不是课程要分享的重点，只需要知道它是一个给企业制定战略规划的思考框架，是以市场为导向，从市场结果中分析业绩差距和机会差距，进而指导企业的战略设计和执行。该课程重点在于市场洞察，分别从宏观/趋势洞察、市场/行业洞察、客户洞察、竞争/对手洞察、洞察自身等方面进行了分析。</p><p>（1）宏观趋势</p><p>&nbsp;&nbsp;&nbsp;&nbsp;我们的机器人行业属于中国制造业重要的产业，是政策性非常强的行业，制造业是立国之本，机器人是通用核心装备。在2021年下半年国家陆续出台多个与机器人行业直接或间接相关的产业规划。其中’十四五机器人产业发展规划‘明确指出到2025年我国要成为全球机器人技术创新策源地、高端制造集聚地、集成应用新高地，并提出对国产机器人高品质发展的定位：’两标准，一评测‘，与此同时根据对中国机器人装机总量预测，在未来的几年，中国市场对机器人的需求量将成倍数上升。</p><p>根据中国机器人市场整体销售规模变化曲线来看，从2012年<strong>27200台</strong>销售量到2022年<strong>280000台</strong>的增长曲线看到未来对机器人需求的涨势。</p><p>根据对机器人装备成本与人力成本关系图可知，人力成本在逐步上升，机器人装备成本在逐步下降，当人力成本大于机器人装备成本时，机器人市场将进一步打开，根据目前估算机器人的市场拐点将会提前。</p><p>所以从市场与政策上来讲，机器人行业有很好的前景。</p><p>（2）市场行业</p><p>行业目前处于起步期：存量市场有限，但持续扩展、缺乏系统性的行业标准、机器人行业巨头为国外企业，国内企业过于弱小、行业人才基础薄弱，但资本和人才逐步进入、国家政策扶持</p><p>根据行业的现状，可以说发展较为困难，但机遇并存，其中可以切入的点是扩展机器人增量市场、扎住行业标准作为壁垒和控制点、发挥中国市场的特点吃透中国市场、抓住政策红利，抢得先机。</p><p>（3）客户</p><p>客户可以分为存量市场客户与增量市场客户。</p><p>存量市场客户如：汽车、汽车零部件、3C、半导体等。</p><p>增量市场客户如：光伏、锂电、钢结构、轨道交通，集装箱、物流、家具家居、五金陶瓷建材等。</p><p>客户的基本诉求即为对机器人的可靠性和性能，对于部分增量市场还具有功能诉求，国产品牌想要提升竞争力可以从价格和服务来实现国产替换策略。</p><p>（4）竞争</p><p>了解第一类全谱系行业四巨头（ABB、发那科、安川、库卡）的技术积累与业务范围。</p><p>了解其他应用类或技术类行业代表企业。</p><p>我们要做什么样类型的机器人公司？</p><p>以平台化机器人公司进行架构，强调平台和技术点的复用性，形成战略纵深；</p><p>补强核心能力（产品和技术点）时按特定战略行业和应用进行牵引有序拓展，在一定时间段形成在某些核心能力上的聚焦。</p><p>（5）自己</p><p>进行SWOT分析。</p><p>S（strengths）：更贴近中国这个终端市场、相对进口品牌，历史包袱少，具有后发优势、相对大多数国产品牌，有一定技术积累</p><p>W（weaknesses）：相对进口品牌技术团队弱小、起步晚、积累少、成本控制能力弱、缺乏清晰的产品战略以及产品型组织保证</p><p>O（opportunities）：增量市场显现、政策支持、互联网和人工智能技术兴起、有一定知名度</p><p>T（threats）：竞争大、行业噪音对国产机器人品牌有伤害</p><p>SO（用优势去抓住机会）：利用政策、成本、服务去抓住增量市场，利用新技术形成功能差异化，利用规模效应降低成本、夯实产品力、提升品牌影响力</p><p>WO（通过机会消除弱点）：利用政策聚焦细分市场，通过高速增长的增量市场拉动销量并带动核心技术平台和部件的孵化</p><p>ST（用优势抵抗威胁）：聚焦产品优势、强调专业性、快速形成客户关系、技术、标准壁垒，利用影响力形成行业标杆、与低端国产品牌拉开差距。</p><p>WT（最小化弱点和风险）：利用市场化薪资与激励政策保留核心人才，明确产品和技术路标，坚定产品型思维和产品力的底线思维，评出低价低劣带来的低毛利低投入的恶性循环。</p><p>总结：以上的信息纯属于行业科普，并没有过多的行业思考，对于一个底层的开发人员来说，了解这些行业信息与动向貌似对我们的日常开发没有太大关系，实则不尽然也，这是对我们要做一个什么样的产品的基本了解，这也是为我们在开发的过程中能有一定的产品思维的，而不是成为一个麻木的开发工具人。</p><p>今天的记录先到这里吧，休息一下，更好的迎接明天。</p></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;今天是清明节，对我这打工族来说也就是居家休息的一天，距离上一篇工作日志已经过去了一个周末和两个工作日，虽然偷懒没有记录工作上的内容，但也没有完全偷懒到没有任何作为，周末两天是舒缓的两天，我观看了公司内部发布的两篇关于《回归价</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>工作日志 2023/3/30</title>
    <link href="https://joyer-lee.github.io/blog/2023/03/30/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%972023_3_30/"/>
    <id>https://joyer-lee.github.io/blog/2023/03/30/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%972023_3_30/</id>
    <published>2023-03-30T14:20:14.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>今天依然处理了一整天的vitepress项目构建问题。</p><p>从昨天负责编写公共库的同事反馈文档项目无法构建起，我已经排查并解决了一系列的问题，其中主要是：</p><p>（1）构建所依赖的外部包版本问题；</p><p>（2）vitepress 服务端渲染（SSR）兼容问题</p><p>（3）多工作区项目之间的引用问题</p><p>对于问题（1）构建所依赖的外部包版本问题</p><p>最终的解决方案是比对了ElementPlus文档项目（我们的文档项目，是基于elementPlus文档项目的实现）中使用的<strong>包版本</strong>，跟其保持一致。问题出在我们的文档项目所使用的vite依赖包高于elementPlus</p><p>对于问题（2）</p><p>原因是文档项目所引入的内部人员开发的公共依赖库存在对SSR不友好操作，比如在文档导入时即操作了dom，在不好修改所依赖的对SSR不友好三方库的情况下，vitepress官方提供了一些<strong>ssr兼容</strong>方案，其中一些方案需要升级vitepress版本，由于改动较大，临时使用<strong>动态导入三依赖包</strong>的方案。</p><p>对于问题（3）</p><p>虽然目前我们的文档项目和另外的几个公共库项目放在同一级目录下，但并未采用多工作区的源码管理策略(吐槽：模块引用混乱，构建繁琐，建议架构人员学习下element的源码管理，好好设计下源码结构)；</p><p>文档项目所参与的文档及Demo编写人员起初是通过设置相对路径别名引用了公共组件库源文件，这种引用方案导致构建文档时会连带组件库源文件的构建，难以实现自动化部署，所以需要全部替换为引入外部依赖包的方式；</p><p>（3.1）由于vitepress在构建期间使用vue的服务端渲染功能在node.js中预渲染应用程序，我们的web公共组件库至少需要构建为es、cjs两种格式的包文件，此处又了解了组件库构建配置、包文件路径映射等内容</p><p>到此，三个问题解决完毕后，我的文档项目已成功构建并配合运维人员实现了自动化部署工作。</p><p><strong>后续问题</strong></p><p>在顺手配置了公共组件库以构建出SSR兼容的包文件后，出现了两个问题：</p><p>（1）负责编写公共组件库的同事反馈在文档启动开发服务运行项目后，动态导入的内容为undefined，</p><p>（2）在业务项目中使用公共组件库的同事反馈构建的包抛出很多错误</p><p>对于问题（1）</p><p>我启动文档本地服务后，确实发现了此问题，我联想到是包文件映射的问题，因为动态导入时es语法，只有基于es语法的包文件才能正确导入，若导入的是其他包文件，大概率会产生这个错误，检查公共组件库的package.json文件后，exports.import映射的路径非es module包文件，修正后，打包，手动copy到docs项目中的node_modules目录下后，重新运行项目，发现错误仍然存在，在又尝试了一次后我陷入了迷惑；后来我再构建好的文件中埋点，运行测试发现并未执行我的新增代码，我终于了解到是包缓存问题，我又了解到了vite的依赖预构建机制，在手动删除vite缓存后，再次执行，结果是成功导入了正确的es包文件，问题解决了。</p><p>对于问题（2）</p><p>我运行了业务项目，看到了抛出的问题，经过分析很快就发现是依赖包版本不一致导致的问题。原因如下：</p><p>我们的公共组件库引用的three包的版本是0.125.1，而业务项目中也引入了three包，版本是0.150，当业务项目中用yarn去安装依赖的时候，由于依赖包版本不一致，公共组件库和业务项目在各自目录下装了不同版本的three依赖包，引发了兼容问题，导致了一些ts类型报错。</p><p>目前的解决方案是：在公共组件库中的package.json文件中删除three依赖项，这样在业务项目中引入公共组件库时只会安装一份three，就暂时不会产生兼容问题。</p><p>我终于明白为什么我运行公共组件库时项目明明引入了three，package.json中却没有相关依赖项。我对此种方案无法接受（但是由于我不是主要负责人，而且很晚了，暂时没有过多去查找其他解决方案），因为我想到在其他情况下会产生的问题，比如：</p><p>1.如果我们有了新的业务项目，当前业务项目无需引入three包，但需要引入当前的公共组件库，由于没有在package.json中生命依赖包，到导致三方公共库报错。</p><p>2.如果我们的新业务项目中引用了three包，但是比公共组件库高或低很多个版本，那势必会与组件库中的three依赖产生兼容性问题。</p><p>今天的问题虽然处理完了，但是也留下了一些疑问，此时夜已经很深了，就留给明天去探索吧！</p></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;今天依然处理了一整天的vitepress项目构建问题。&lt;/p&gt;
&lt;p&gt;从昨天负责编写公共库的同事反馈文档项目无法构建起，我已经排查并解决了一系列的问题，其中主要是：&lt;/p&gt;
&lt;p&gt;（1）构建所依赖的外部包版本问题；&lt;/p&gt;
</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>工作日志 2023/3/31</title>
    <link href="https://joyer-lee.github.io/blog/2023/03/30/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%972023_3_31/"/>
    <id>https://joyer-lee.github.io/blog/2023/03/30/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%972023_3_31/</id>
    <published>2023-03-30T12:26:00.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>今天的工作很零碎，也没有技术上太值得讨论的问题，今天的任务主要是检查在即将发布的项目迭代中我负责的功能模块的代码，把遗留的一点小问题处理掉并合并代码。</p><p>上午处理了的问题是：</p><p>（1）业务项目中，依赖的公共组件包存在类型问题</p><p>（2）昨天配合运维同事实现的自动构建失败问题</p><p>对于问题（1）</p><p>原因是负责开发公共组件的同事没有为对外抛出的方法提供正确的参数类型，导致我的项目编译报错，至于之前为什么没错误，那是因为没有在vue 项目中启用ts（同事写法，提醒后才加-<em>-||），回到参数类型报错的问题，我确定在早几天已经与公共组件开发同事约定过函数的传参及返回值，无类型检查时运行完全没有问题，经协作同事检查后回复逻辑代码中确实使用了之前约定的参数，由于同事没时间处理我的问题，先在我的业务代码中显示修改为any类型（项目紧急，问题多多，显得代码规范都不算什么问题了 -</em>-||），我设想了内部用的ts编写的代码的话，不应该逻辑与类型不一致的情况，如果出现这样的问题，那应该是js实现的代码，然后手写了一份与js匹配的声明文件，拉了同事分支阅读源码后，确实如此，考虑到职责及还有其他工作要做的问题，最终并未帮同事解决这个小问题，而是暂时用any保证项目的正常运行。</p><p>思考了下由于公共组件库项目，由于历史原因，部分源码基于js实现，为了兼容ts，为这些js添加了类型声明文件，一旦改变代码逻辑，就要手动维护声明文件，还是有些维护成本的。至于为什么不能替换为ts文件，我猜测也是因为同事们对typescript的了解不够深入吧，或者对开发过程中的问题有不一样的容忍度吧。篇幅所限，有机会再好好去体会typescript的强大之处吧。</p><p>对于问题（2）</p><p>这个问题的原因实在是因为主观上对自己的行为有点自信，理由很简单，我认为我发布了包，但实际上未发布，所以获取的包是有问题的。但在一开始遇到这个问题时，我首先排除了发布包的问题，分别排除了vite缓存的问题，以及安装包时使用的npm镜像地址问题，才意识的是自己的盲目自信。</p><p>下午处理了一些样式问题后，发起了提交请求，但注意到之前在vscode源码的渲染进程中请求了dev环境的接口，当时发现vscode配置了CSP(内容安全协议)，不允许请求http协议接口，当时简单的开放了此安全配置，此操作降低了安全等级，不是合适的处理方案，了解csp相关知识后，经人提醒，可以在csp配置参数中指定我们的域名，例如connect-src: <a class="link" href="http://example.com.cn,这样对安全等级上影响不大,目前我认为此方案更合适./">http://example.com.cn，这样对安全等级上影响不大，目前我认为此方案更合适。<i class="fas fa-external-link-alt"></i></a></p><p>一周过得好快啊，已经周五了，打算过个轻松充实的周末，也不能忘记要努力提升自己的技术力！</p></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;今天的工作很零碎，也没有技术上太值得讨论的问题，今天的任务主要是检查在即将发布的项目迭代中我负责的功能模块的代码，把遗留的一点小问题处理掉并合并代码。&lt;/p&gt;
&lt;p&gt;上午处理了的问题是：&lt;/p&gt;
&lt;p&gt;（1）业务项目中，依赖</summary>
      
    
    
    
    <category term="工作日志" scheme="https://joyer-lee.github.io/blog/categories/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"/>
    
    
  </entry>
  
  <entry>
    <title>语法高亮指南</title>
    <link href="https://joyer-lee.github.io/blog/2022/12/06/%E8%8B%B1%E6%96%87%E5%B0%8F%E8%8F%9C/%E6%96%87%E6%A1%A3%E7%BF%BB%E8%AF%91/%E8%AF%AD%E6%B3%95%E9%AB%98%E4%BA%AE%E6%8C%87%E5%8D%97/"/>
    <id>https://joyer-lee.github.io/blog/2022/12/06/%E8%8B%B1%E6%96%87%E5%B0%8F%E8%8F%9C/%E6%96%87%E6%A1%A3%E7%BF%BB%E8%AF%91/%E8%AF%AD%E6%B3%95%E9%AB%98%E4%BA%AE%E6%8C%87%E5%8D%97/</id>
    <published>2022-12-06T07:43:00.000Z</published>
    <updated>2026-10-18T10:36:38.015Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h1 id="语法高亮指南"><a href="#语法高亮指南" class="headerlink" title="语法高亮指南"></a>语法高亮指南</h1><p>语法高亮决定了在Visual Studio 代码编辑器中显示的源代码的颜色和风格。 它负责为 <code>if</code> 或 <code>for</code> 着色以区别于字符串、注释和变量名等其他JavaScript关键字。</p><p>语法高亮由两部分组成：</p><ul><li><a href="#tokenization">令牌化</a>: 将文本分解为令牌列表</li><li><a href="#theming">主题化</a>: 使用主题或用户设置将令牌映射到特定颜色和样式</li></ul><p>在深入了解细节之前， 一个良好的开端是使用 <a href="#scope-inspector">范围检查器</a> 工具来探索源文件中存在什么样的令牌以及它们匹配的主题规则。 要看到语义和语法令牌，请在TypeScript 文件上使用一个内置的主题 (例如，Dark+)。</p><h2 id="令牌化"><a href="#令牌化" class="headerlink" title="令牌化"></a>令牌化</h2><p>文本的令牌化就是将文本分解为段，并用标记类型对每个段进行分类。</p><p>VS Code的令牌华引擎由<a class="link" href="https://macromates.com/manual/en/language_grammars">TextMate 语法<i class="fas fa-external-link-alt"></i></a>驱动。 TextMate 语法是一个结构化的正则表达式集，作为插件(XML) 或JSON文件写成的。 VS Code扩展可通过 <code>语法</code> 贡献点贡献语法。</p><p>TextMate令牌化引擎与渲染器运行在相同的进程中，令牌随着用户类型的变化而更新。 令牌用于语法高亮，但也用于将源代码划分为注释、字符串、正则表达式区域。</p><p>从版本1.43开始，VS 代码也允许扩展通过 <a href="/api/references/vscode-api#DocumentSemanticTokensProvider">语义令牌提供商</a> 提供令牌化。 语义提供者通常由语言服务器实现，这些语言服务器对源文件有更深的了解，并且可以在项目中解析符号。 例如，一个常量变量名可以在整个项目中使用常量高亮来呈现，而不仅仅是在其声明的地方。</p><p>基于语义令牌的高亮被视为基于 TextMate 的语法高亮的补充。 语义高亮显示在语法高亮上。 由于语言服务器可能需要一段时间来加载和分析一个项目，语义标记高亮显示可能会在短时间延迟后出现。</p><p>这篇文章着重于基于 TextMate 的令牌化。 语义令牌化和主题化在 <a href="semantic-highlight-guide">语义高亮指南</a> 中进行了解释。</p><h3 id="TextMate-语法"><a href="#TextMate-语法" class="headerlink" title="TextMate 语法"></a>TextMate 语法</h3><p>VS Code使用 <a class="link" href="https://macromates.com/manual/en/language_grammars">TextMate 语法<i class="fas fa-external-link-alt"></i></a> 作为语法令牌化引擎。 TextMate 编辑器创造以来， 由于大量的语言包被被开源社区创建和维护，许多其他的编辑器和IDE都采用了这些准则。</p><p>TextMate 语法依靠 <a class="link" href="https://macromates.com/manual/en/regular_expressions">Oniguruma 正则表达式<i class="fas fa-external-link-alt"></i></a> 并且通常都是作为插件或 JSON 编写的。 您可以在<a class="link" href="https://www.apeth.com/nonblog/stories/textmatebundle.html">这里<i class="fas fa-external-link-alt"></i></a>找到 TextMate 语法 很好的简介， 并且你可以看看现有的 TextMate 语法来更多地了解它们是如何工作的。</p><h3 id="TextMate-令牌和范围"><a href="#TextMate-令牌和范围" class="headerlink" title="TextMate 令牌和范围"></a>TextMate 令牌和范围</h3><p>令牌是一个或多个字符，是同一个程序元素的一部分。 示例令牌包括操作符，如 <code>+</code> 和<code>*</code>, 变量名如 <code>myVar</code>, 或字符串如 <code>"my string"</code>。</p><p>每个令牌都与定义令牌上下文的范围相关联。 作用域是一个点分隔的标识符列表，用于指定当前标记的上下文。 例如，JavaScript中的 <code>+</code> 操作符作用域为 <code>keyword.operator.arithmetic.js</code>。</p><p>主题将作用域映射到颜色和样式以提供语法高亮。 TextMate为许多主题目标提供了<a class="link" href="https://macromates.com/manual/en/language_grammars">常用作用域列表<i class="fas fa-external-link-alt"></i></a> 。 为了使您的语法得到尽可能广泛的支持，请尝试在现有范围基础上进一步发展，而不是确定新的范围。</p><p>作用域嵌套，以便每个令牌也与父作用域列表相关联。 下面的示例使用<a href="#scope-inspector">范围检查器</a>在一个简单的JavaScript函数中显示 <code>+</code>操作符的范围层次结构。 最具体的范围列在顶部，较一般的父范围列于下面：</p><p><img src="/blog/_posts/英文小菜/文档翻译/blog/images/syntax-highlighting/scopes.png" alt="syntax highlighting scopes"></p><p>父范围信息也用于主题化。 当主题以一个作用域为目标时，所有带有该父作用域的令牌都将被着色，除非主题还为它们各自的作用域提供更具体的着色。</p><h3 id="贡献基本语法"><a href="#贡献基本语法" class="headerlink" title="贡献基本语法"></a>贡献基本语法</h3><p>VS Code支持 json TextMate 语法。 这些都是通过 <code>语法</code> <a href="/api/references/contribution-points">贡献点</a> 贡献的。</p><p>每个语法贡献具体指：语法所适用语言的标识符。 语法标记的顶级范围名称和语法文件的相对路径。 下面的例子展示了一个虚构的<code>abc</code>语言的语法贡献</p><figure class="highlight json"><table><tbody><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="punctuation">{</span></span><br><span class="line">  <span class="attr">"contributes"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"languages"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">{</span></span><br><span class="line">        <span class="attr">"id"</span><span class="punctuation">:</span> <span class="string">"abc"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"extensions"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">".abc"</span><span class="punctuation">]</span></span><br><span class="line">      <span class="punctuation">}</span></span><br><span class="line">    <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">"grammars"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">{</span></span><br><span class="line">        <span class="attr">"language"</span><span class="punctuation">:</span> <span class="string">"abc"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"scopeName"</span><span class="punctuation">:</span> <span class="string">"source.abc"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"path"</span><span class="punctuation">:</span> <span class="string">"./syntaxes/abc.tmGrammar.json"</span></span><br><span class="line">      <span class="punctuation">}</span></span><br><span class="line">    <span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></tbody></table></figure><p>语法文件本身由顶层规则组成。 这通常分为列出程序顶层元素的 <code>patterns</code> 部分和定义每个元素的 <code>repository</code>。 语法中的其他规则可以通过 <code>repository</code> 使用 <code>{ "include": "#id" }</code>来引用元素。</p><p>示例 <code>abc</code> 语法标记字母 <code>a</code>, <code>b</code>, 和 <code>c</code> 作为关键词和括号内嵌套表达式。</p><figure class="highlight json"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line">  <span class="attr">"scopeName"</span><span class="punctuation">:</span> <span class="string">"source.abc"</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"patterns"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">{</span> <span class="attr">"include"</span><span class="punctuation">:</span> <span class="string">"#expression"</span> <span class="punctuation">}</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"repository"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"expression"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">      <span class="attr">"patterns"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">{</span> <span class="attr">"include"</span><span class="punctuation">:</span> <span class="string">"#letter"</span> <span class="punctuation">}</span><span class="punctuation">,</span> <span class="punctuation">{</span> <span class="attr">"include"</span><span class="punctuation">:</span> <span class="string">"#paren-expression"</span> <span class="punctuation">}</span><span class="punctuation">]</span></span><br><span class="line">    <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">"letter"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">      <span class="attr">"match"</span><span class="punctuation">:</span> <span class="string">"a|b|c"</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"keyword.letter"</span></span><br><span class="line">    <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">"paren-expression"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">      <span class="attr">"begin"</span><span class="punctuation">:</span> <span class="string">"\\("</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">"end"</span><span class="punctuation">:</span> <span class="string">"\\)"</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">"beginCaptures"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">        <span class="attr">"0"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"punctuation.paren.open"</span> <span class="punctuation">}</span></span><br><span class="line">      <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">"endCaptures"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">        <span class="attr">"0"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"punctuation.paren.close"</span> <span class="punctuation">}</span></span><br><span class="line">      <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"expression.group"</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">"patterns"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">{</span> <span class="attr">"include"</span><span class="punctuation">:</span> <span class="string">"#expression"</span> <span class="punctuation">}</span><span class="punctuation">]</span></span><br><span class="line">    <span class="punctuation">}</span></span><br><span class="line">  <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></tbody></table></figure><p>语法引擎将尝试对文档中的所有文本依次应用 <code>表达式</code>规则。 对于一个简单的程序，例如：</p><figure class="highlight plaintext"><table><tbody><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">a</span><br><span class="line">(</span><br><span class="line">    b</span><br><span class="line">)</span><br><span class="line">x</span><br><span class="line">(</span><br><span class="line">    (</span><br><span class="line">        c</span><br><span class="line">        xyz</span><br><span class="line">    )</span><br><span class="line">)</span><br><span class="line">(</span><br><span class="line">a</span><br></pre></td></tr></tbody></table></figure><p>示例语法生成以下作用域(从左到右从最特定的作用域到最不特定的作用域列出)</p><figure class="highlight plaintext"><table><tbody><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">a               keyword.letter, source.abc</span><br><span class="line">(               punctuation.paren.open, expression.group, source.abc</span><br><span class="line">    b           keyword.letter, expression.group, source.abc</span><br><span class="line">)               punctuation.paren.close, expression.group, source.abc</span><br><span class="line">x               source.abc</span><br><span class="line">(               punctuation.paren.open, expression.group, source.abc</span><br><span class="line">    (           punctuation.paren.open, expression.group, expression.group, source.abc</span><br><span class="line">        c       keyword.letter, expression.group, expression.group, source.abc</span><br><span class="line">        xyz     expression.group, expression.group, source.abc</span><br><span class="line">    )           punctuation.paren.close, expression.group, expression.group, source.abc</span><br><span class="line">)               punctuation.paren.close, expression.group, source.abc</span><br><span class="line">(               punctuation.paren.open, expression.group, source.abc</span><br><span class="line">a               keyword.letter, expression.group, source.abc</span><br></pre></td></tr></tbody></table></figure><p>注意，当前作用域中包含了不被任何规则匹配的文本，例如字符串<code>xyz</code>。 文件末尾的最后一个括号是<code>expression.group</code>的一部分，即使结束规则不匹配，因为在结束规则之前找到了文档结束。</p><h3 id="嵌入式语言（Embedded-languages）"><a href="#嵌入式语言（Embedded-languages）" class="headerlink" title="嵌入式语言（Embedded languages）"></a>嵌入式语言（Embedded languages）</h3><p>如果您的语法在父语言中包含嵌入式语言，例如HTML中的CSS样式块，你可以使用<code>embeddedLanguages</code>贡献点告诉VS Code将嵌入式语言与父语言区别对待。 这确保括号匹配、注释和其他基本语言特性在嵌入式语言中按预期工作。</p><p><code>embeddedLanguages</code>贡献点将嵌入式语言中的作用域映射到顶级语言作用域。 在下面的例子中，<code>meta.embedded.block.javascript</code>作用域中的任何令牌都将被视为JavaScript内容：</p><figure class="highlight json"><table><tbody><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="punctuation">{</span></span><br><span class="line">  <span class="attr">"contributes"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"grammars"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">{</span></span><br><span class="line">        <span class="attr">"path"</span><span class="punctuation">:</span> <span class="string">"./syntaxes/abc.tmLanguage.json"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"scopeName"</span><span class="punctuation">:</span> <span class="string">"source.abc"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"embeddedLanguages"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">          <span class="attr">"meta.embedded.block.javascript"</span><span class="punctuation">:</span> <span class="string">"javascript"</span></span><br><span class="line">        <span class="punctuation">}</span></span><br><span class="line">      <span class="punctuation">}</span></span><br><span class="line">    <span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></tbody></table></figure><p>现在，如果你试图评论代码或触发代码片段在标记为 <code>meta.embeded.block.javascript</code>的令牌集合中, 他们将得到正确的 <code>//</code> JavaScript 风格的评论和正确的 JavaScript 代码片段。</p><h3 id="开发新的语法扩展"><a href="#开发新的语法扩展" class="headerlink" title="开发新的语法扩展"></a>开发新的语法扩展</h3><p>快速创建一个新的语法扩展， 使用 <a href="/api/get-started/your-first-extension">VS Code’s Yeoman templates</a> 来运行 <code>yo code</code> 并选择 <code>New Language</code> 选项：</p><p><img src="/blog/_posts/英文小菜/文档翻译/blog/images/syntax-highlighting/yo-new-language.png" alt="Selecting the 'new language' template in 'yo code'"></p><p>Yeoman将通过一些基本问题带你去搭建新的扩展。 创建新语法的重要问题是：</p><ul><li><code>Language id</code> - 您的语言的唯一标识符。</li><li><code>Language name</code> - 为您的语言提供一个人类可读的名称。</li><li><code>Scope names</code> - 语法的根TextMate作用域名称.</li></ul><p><img src="/blog/_posts/英文小菜/文档翻译/blog/images/syntax-highlighting/yo-new-language-questions.png" alt="Filling in the 'new language' questions"></p><p>生成器假设您想要为该语言定义一种新语言和一种新语法。 如果您正在为现有语言创建语法，只需用目标语言的信息填充这些语法，并确保删除生成的<code>package.json</code>中的<code>languages</code>贡献点。</p><p>在回答所有问题后，Yeoman将创建一个结构性的新扩展：</p><p><img src="/blog/_posts/英文小菜/文档翻译/blog/images/syntax-highlighting/generated-new-language-extension.png" alt="A new language extension"></p><p>记住，如果你要为VS Code已经知道的语言贡献语法，一定要删除生成的<code>package.json</code>中的<code>languages</code>贡献点。</p><h4 id="转换现有的-TextMate-语法"><a href="#转换现有的-TextMate-语法" class="headerlink" title="转换现有的 TextMate 语法"></a>转换现有的 TextMate 语法</h4><p><code>yo code</code> 也可以帮助将现有的 TextMate 语法转换为 VS 代码扩展。 同样，首先运行<code>yo code</code>并选择<code>语言扩展</code>。 当被问到一个现有的语法文件时，给它一个<code>.tmLanguage</code>或<code>.json TextMate</code>语法文件的完整路径：</p><p><img src="/blog/_posts/英文小菜/文档翻译/blog/images/syntax-highlighting/yo-convert.png" alt="Converting an existing TextMate grammar"></p><h4 id="使用-YAML-书写语法"><a href="#使用-YAML-书写语法" class="headerlink" title="使用 YAML 书写语法"></a>使用 YAML 书写语法</h4><p>随着语法变得越来越复杂，将其作为json来理解和维护可能会变得困难。 如果您发现自己正在编写复杂的正则表达式，或者需要添加注释来解释语法的各个方面，那么可以考虑使用yaml来定义语法。</p><p>Yaml语法具有与基于json的语法完全相同的结构，但允许您使用Yaml更简洁的语法，以及多行字符串和注释等特性。</p><p><img src="/blog/_posts/英文小菜/文档翻译/blog/images/syntax-highlighting/yaml-grammar.png" alt="A yaml grammar using multiline strings and comments"></p><p>VS Code只能加载json语法，所以基于yaml的语法必须转换成json。 <code>js-yaml</code>包和命令行工具使这变得很容易。</p><figure class="highlight bash"><table><tbody><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"><span class="comment"># 将js-yaml安装为扩展中的开发依赖项</span></span><br><span class="line">$ npm install js-yaml --save-dev</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用命令行工具将yaml语法转换为json</span></span><br><span class="line">$ npx js-yaml syntaxes/abc.tmLanguage.yaml &gt; syntaxes/abc.tmLanguage.json</span><br></pre></td></tr></tbody></table></figure><h3 id="注入语法（Injection-grammars）"><a href="#注入语法（Injection-grammars）" class="headerlink" title="注入语法（Injection grammars）"></a>注入语法（Injection grammars）</h3><p>注入语法允许您扩展现有的语法。 注入语法是一种常规的TextMate语法，它被注入到现有语法中的特定范围中。 注入语法的实例应用：</p><ul><li>在评论中突出TODO等关键字。</li><li>在现有语法中添加更具体的范围信息。</li><li>为Markdown围栏代码块添加新语言的高亮显示。</li></ul><h4 id="创建一个基本的注入语法"><a href="#创建一个基本的注入语法" class="headerlink" title="创建一个基本的注入语法"></a>创建一个基本的注入语法</h4><p>就像常规语法一样，注入语法通过 <code>package.json</code> 所提供。 然而，注入语法不指定语言，而是使用<code>injectTo</code>来指定要将语法注入到其中的目标语言作用域列表。</p><p>对于本例，我们将创建一个简单的注入语法，将<code>TODO</code>突出显示为JavaScript注释中的关键字。 为了在JavaScript文件中应用我们的注入语法，我们在<code>injectTo</code>中使用<code>source.js</code>目标语言作用域：</p><figure class="highlight json"><table><tbody><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="punctuation">{</span></span><br><span class="line">  <span class="attr">"contributes"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"grammars"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">{</span></span><br><span class="line">        <span class="attr">"path"</span><span class="punctuation">:</span> <span class="string">"./syntaxes/injection.json"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"scopeName"</span><span class="punctuation">:</span> <span class="string">"todo-comment.injection"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"injectTo"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">"source.js"</span><span class="punctuation">]</span></span><br><span class="line">      <span class="punctuation">}</span></span><br><span class="line">    <span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></tbody></table></figure><p>除了最顶层的<code>injectionSelector</code>条目外，语法本身是标准的TextMate语法。 <code>injectionSelector</code>是一个范围选择器，它指定应该在哪个范围中应用注入的语法。 在我们的例子中，我们想要在所有的<code>//</code>注释凸显单词<code>TODO</code>。 使用<code>scope inspector</code>，我们发现JavaScript的双斜杠注释具有<code>comment.line.double-slash</code>范围，所以我们的注入选择器是<code>L:comment.line.double-slash</code>：</p><figure class="highlight json"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line">  <span class="attr">"scopeName"</span><span class="punctuation">:</span> <span class="string">"todo-comment.injection"</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"injectionSelector"</span><span class="punctuation">:</span> <span class="string">"L:comment.line.double-slash"</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"patterns"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">{</span></span><br><span class="line">      <span class="attr">"include"</span><span class="punctuation">:</span> <span class="string">"#todo-keyword"</span></span><br><span class="line">    <span class="punctuation">}</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"repository"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"todo-keyword"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">      <span class="attr">"match"</span><span class="punctuation">:</span> <span class="string">"TODO"</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"keyword.todo"</span></span><br><span class="line">    <span class="punctuation">}</span></span><br><span class="line">  <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></tbody></table></figure><p>注入选择器中的 <code>L：</code> 意味着注入被添加到现有语法规则的左边。 这基本上意味着我们注入的语法规则将在任何现有语法规则之前应用。</p><h4 id="嵌入式语言（Embedded-languages）-1"><a href="#嵌入式语言（Embedded-languages）-1" class="headerlink" title="嵌入式语言（Embedded languages）"></a>嵌入式语言（Embedded languages）</h4><p>注入语法也可以为父级语法提供嵌入语言。 就像普通语法一样，注入语法可以使用<code>embeddedLanguages</code>将范围从嵌入式语言映射到顶级语言范围。</p><p>例如，在JavaScript字符串中突出显示SQL查询的扩展可以使用<code>embeddedLanguages</code>来确保标记为<code>meta.embedded.inline.sql</code>的字符串中的所有令牌都被视为SQL，以实现基本的语言功能，如括号匹配和代码片段选择。</p><figure class="highlight json"><table><tbody><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"><span class="punctuation">{</span></span><br><span class="line">  <span class="attr">"contributes"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"grammars"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">{</span></span><br><span class="line">        <span class="attr">"path"</span><span class="punctuation">:</span> <span class="string">"./syntaxes/injection.json"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"scopeName"</span><span class="punctuation">:</span> <span class="string">"sql-string.injection"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"injectTo"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">"source.js"</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"embeddedLanguages"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">          <span class="attr">"meta.embedded.inline.sql"</span><span class="punctuation">:</span> <span class="string">"sql"</span></span><br><span class="line">        <span class="punctuation">}</span></span><br><span class="line">      <span class="punctuation">}</span></span><br><span class="line">    <span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></tbody></table></figure><h4 id="令牌类型和嵌入语言"><a href="#令牌类型和嵌入语言" class="headerlink" title="令牌类型和嵌入语言"></a>令牌类型和嵌入语言</h4><p>对于注入语言嵌入式语言还有一个额外的复杂性: 默认情况下，VS Code将字符串中的所有标记视为字符串内容，将带有注释的所有标记视为标记内容。 由于括号匹配和自动关闭对等功能在字符串和注释中被禁用，如果嵌入式语言出现在字符串或注释中，这些嵌入式语言中的功能也将被禁用。</p><p>要覆盖此行为，可以使用<code>meta.embedded.*</code>范围重置VS Code标记为字符串或注释内容。 将嵌入式语言封装在<code>meta.embedded.*</code>范围中是个好主意，以确保VS Code正确的处理嵌入式语言。</p><p>如果您不能添加 <code>meta.embeded.</code> 范围到您的语法中， 您也可以在语法的贡献点中使用 <code>tokenTypes</code> 将特定范围映射到内容模式。 下面的 <code>tokenTypes</code> 部分确保了 <code>my.sql.template.string</code> 范围中的任何内容被当作源代码处理：</p><figure class="highlight json"><table><tbody><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="punctuation">{</span></span><br><span class="line">  <span class="attr">"contributes"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"grammars"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">{</span></span><br><span class="line">        <span class="attr">"path"</span><span class="punctuation">:</span> <span class="string">"./syntaxes/injection.json"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"scopeName"</span><span class="punctuation">:</span> <span class="string">"sql-string.injection"</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"injectTo"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">"source.js"</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"embeddedLanguages"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">          <span class="attr">"my.sql.template.string"</span><span class="punctuation">:</span> <span class="string">"sql"</span></span><br><span class="line">        <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">"tokenTypes"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">          <span class="attr">"my.sql.template.string"</span><span class="punctuation">:</span> <span class="string">"other"</span></span><br><span class="line">        <span class="punctuation">}</span></span><br><span class="line">      <span class="punctuation">}</span></span><br><span class="line">    <span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></tbody></table></figure><h2 id="主题"><a href="#主题" class="headerlink" title="主题"></a>主题</h2><p>主题化是为令牌分配颜色和样式 主题规则在颜色主题中指定，但用户可以在用户设置中自定义主题规则。</p><p>TextMate 主题规则在 <code>tokenColors</code> 中定义，并且与普通的 TextMate 主题具有相同的语法。 每个规则都定义一个 TextMate 范围选择器和由此产生的颜色和风格。</p><p>在评估令牌的颜色和样式时，将根据规则的选择器匹配当前令牌的作用域，为每个样式属性(前景色、粗体、斜体、下划线) 找到最具体的规则。</p><p><a href="/api/extension-guides/color-theme#syntax-colors">颜色主题指南</a> 描述了如何创建一个颜色主题。 语义令牌的主题在 <a href="semantic-highlight-guide#theming">语义高亮指南</a> 中作了解释。</p><h2 id="范围检查器（Scope-inspector）"><a href="#范围检查器（Scope-inspector）" class="headerlink" title="范围检查器（Scope inspector）"></a>范围检查器（Scope inspector）</h2><p>VS Code的内置范围检查工具有助于调试语法和语义标记。 它在文件中当前位置显示令牌和语义语义令牌的范围，以及关于应用于该令牌的主题规则的元数据。</p><p>在命令面板使用<code>Developer: Inspect Editor Tokens and Scopes</code>或<code>create a keybinding</code>命令可触发范围检查器：</p><figure class="highlight json"><table><tbody><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="punctuation">{</span></span><br><span class="line">  <span class="attr">"key"</span><span class="punctuation">:</span> <span class="string">"cmd+alt+shift+i"</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"command"</span><span class="punctuation">:</span> <span class="string">"editor.action.inspectTMScopes"</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></tbody></table></figure><p><img src="/blog/_posts/英文小菜/文档翻译/blog/images/syntax-highlighting/scope-inspector.png" alt="scope inspector"></p><p>范围检查器显示以下信息：</p><ol><li>当前令牌。</li><li>关于令牌的元数据和关于其计算外观的信息。 如果您使用的是嵌入式语言，那么这里的重要条目是<code>language</code>和<code>token type</code>。</li><li>当语义令牌提供程序可用于当前语言且当前主题支持语义高亮显示时，将显示语义令牌部分。 它显示了当前的语义标记令牌和修饰符，以及与语义令牌类型和修饰符匹配的主题规则。</li><li>TextMate部分显示了当前TextMate令牌的作用域列表，最具体的作用域位于顶部。 它还显示与范围相匹配的最具体主题规则。 这只显示负责令牌当前样式的主题规则，不显示被覆盖的规则。 如果存在语义令牌，则仅当主题规则与匹配语义令牌的规则不同时才显示主题规则。</li></ol></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h1 id=&quot;语法高亮指南&quot;&gt;&lt;a href=&quot;#语法高亮指南&quot; class=&quot;headerlink&quot; title=&quot;语法高亮指南&quot;&gt;&lt;/a&gt;语法高亮指南&lt;/h1&gt;&lt;p&gt;语法高亮决定了在Visual Studio 代码编辑器中显</summary>
      
    
    
    
    <category term="--vscode docs" scheme="https://joyer-lee.github.io/blog/categories/vscode-docs/"/>
    
    
  </entry>
  
  <entry>
    <title>记录一次rebase操作</title>
    <link href="https://joyer-lee.github.io/blog/2021/04/28/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E8%AE%B0%E5%BD%95%E4%B8%80%E6%AC%A1rebase%E6%93%8D%E4%BD%9C/"/>
    <id>https://joyer-lee.github.io/blog/2021/04/28/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/%E8%AE%B0%E5%BD%95%E4%B8%80%E6%AC%A1rebase%E6%93%8D%E4%BD%9C/</id>
    <published>2021-04-28T02:20:14.000Z</published>
    <updated>2026-10-18T10:36:38.014Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><h2 id="git-合并方法介绍"><a href="#git-合并方法介绍" class="headerlink" title="git 合并方法介绍"></a>git 合并方法介绍</h2><h3 id="方法一：git-merge"><a href="#方法一：git-merge" class="headerlink" title="方法一：git merge"></a>方法一：git merge</h3><p>把两个父节点及其提交记录包含起来生成一个新的节点</p><h3 id="方法二：git-rebase"><a href="#方法二：git-rebase" class="headerlink" title="方法二：git rebase"></a>方法二：git rebase</h3><p>复制被rebase的提交记录到当前分支</p><h2 id="记录一次rebase操作"><a href="#记录一次rebase操作" class="headerlink" title="记录一次rebase操作"></a>记录一次rebase操作</h2><blockquote><p>我要进行合并啦，记录下问题</p></blockquote><h3 id="步骤一：合并之前分支更新到最新"><a href="#步骤一：合并之前分支更新到最新" class="headerlink" title="步骤一：合并之前分支更新到最新"></a>步骤一：合并之前分支更新到最新</h3><p>dev分支 <img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/QQ%E5%9B%BE%E7%89%8720210423152110.png"> add-account-view分支 <img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/QQ%E5%9B%BE%E7%89%8720210423152236-1.png"></p><h3 id="步骤二：login-rebase-dev"><a href="#步骤二：login-rebase-dev" class="headerlink" title="步骤二：login rebase dev"></a>步骤二：login rebase dev</h3><p><img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/QQ%E5%9B%BE%E7%89%8720210423152606.png"> <strong>遇到冲突</strong></p><h3 id="步骤三：解决冲突后，git-add，然后-rebase-–continue"><a href="#步骤三：解决冲突后，git-add，然后-rebase-–continue" class="headerlink" title="步骤三：解决冲突后，git add，然后 rebase –continue"></a>步骤三：解决冲突后，git add，然后 rebase –continue</h3><p><img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/QQ%E5%9B%BE%E7%89%8720210423152920.png"> 若依然存在冲突，则<strong>重复步骤三</strong>，冲突解决完毕后，结果如下： <img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/QQ%E5%9B%BE%E7%89%8720210423153056.png"></p><blockquote><p><em>错误提示</em> 当前add-account-view的状态为，需要拉取39个提交，以及推送67个提交， 按理来说我们正确的合并了dev分支，并解决了相应冲突。 那么问题为什么会出现呢？以及怎么解决这个问题呢？</p></blockquote><h4 id="若根据git状态拉取，则需继续解决冲突，此时冲突跟之前遇到的一样"><a href="#若根据git状态拉取，则需继续解决冲突，此时冲突跟之前遇到的一样" class="headerlink" title="若根据git状态拉取，则需继续解决冲突，此时冲突跟之前遇到的一样"></a>若根据git状态拉取，则需继续解决冲突，此时冲突跟之前遇到的一样</h4><p><img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/I1VLL_8Q5YAQM@44EO.png"></p><h4 id="继续解决重复冲突，完毕后如下"><a href="#继续解决重复冲突，完毕后如下" class="headerlink" title="继续解决重复冲突，完毕后如下"></a>继续解决重复冲突，完毕后如下</h4><p><img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/image-20210423154134815.png"></p><h4 id="回到dev分支，继续rebase"><a href="#回到dev分支，继续rebase" class="headerlink" title="回到dev分支，继续rebase"></a>回到dev分支，继续rebase</h4><p>依然存在同样冲突： <img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/I1VLL_8Q5YAQM@44EO-2.png"> <em>继续解决冲突，完毕，依然需要pull，重新解决冲突，此时问题跟在add-account-view分支上问题一模一样。</em></p><blockquote><p>通过在网上查找资料，参考别人操作： 得知，正确步骤为： <img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/ICXI9IHJVCLZE6OA0SG8.png"></p></blockquote><h3 id="步骤四-直接执行-git-push-–force"><a href="#步骤四-直接执行-git-push-–force" class="headerlink" title="步骤四 直接执行 git push –force"></a>步骤四 直接执行 git push –force</h3><p><img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/QQ%E5%9B%BE%E7%89%8720210423154746.png"></p><h3 id="步骤五-成功rebase"><a href="#步骤五-成功rebase" class="headerlink" title="步骤五 成功rebase"></a>步骤五 成功rebase</h3><h3 id="原理分析"><a href="#原理分析" class="headerlink" title="原理分析"></a>原理分析</h3><p><img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/QQ%E5%9B%BE%E7%89%8720210423155042.png"></p><h3 id="个人理解"><a href="#个人理解" class="headerlink" title="个人理解"></a>个人理解</h3><ol><li>rebase之后，相对远程分支而言，本地基底发生了变化，引发了需要pull一下的提示</li><li>如果确保没问题是可以强制 push的</li></ol><h4 id="举例"><a href="#举例" class="headerlink" title="举例"></a>举例</h4><p>相当于变基之后本地提交是： C1，C2’，C3’,C4,C5;（C2‘ C3’为目标合并分支的提交记录） 远程提交时： C1，C4，C5</p><h4 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h4><p><strong>本地提交的前三个提交跟远程的前三个提交不一致，就会提示拉取代码，此时拉取代码会把C4，C5再拉取一下</strong> 如果拉取就相当于跟我新合并的代码又冲突，还得解决一次，而且<strong>git pull默认是merge</strong>合并 <strong>git pull之后，就相当于又merge合并了一次：</strong> 把提交记录变成了： C1，C4，C5，C2’,C3’ ,C4,C5,可能后边还有其他的合并提交 同名的后一个只是副本这种，还会造成其他的合并提交 <img src="/blog/_posts/工作日志/images/uploads/sites/2/2021/04/QQ%E5%9B%BE%E7%89%8720210423160822.png"> 先强推下account分支，然后dev再rebase account分支，不然如果同时有其他同事也在提交，那就会被覆盖掉。</p></body></html>]]></content>
    
    
      
      
    <summary type="html">&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 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;/h2&gt;&lt;h3 id=&quot;方法一：git-</summary>
      
    
    
    
    <category term="git" scheme="https://joyer-lee.github.io/blog/categories/git/"/>
    
    
  </entry>
  
</feed>
