<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>歪闹日志</title>
  
  <subtitle>人不写文章，跟咸鱼有什么区别？</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://vhtml.github.io/"/>
  <updated>2019-03-24T11:59:11.317Z</updated>
  <id>https://vhtml.github.io/</id>
  
  <author>
    <name>歪闹</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>算法之路——腐烂的橘子</title>
    <link href="https://vhtml.github.io/2019/03/24/algorithm_002/"/>
    <id>https://vhtml.github.io/2019/03/24/algorithm_002/</id>
    <published>2019-03-24T11:41:13.000Z</published>
    <updated>2019-03-24T11:59:11.317Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>在给定的网格中，每个单元格可以有以下三个值之一：</p><ul><li>值 <code>0</code> 代表空单元格；</li><li>值 <code>1</code> 代表新鲜橘子；</li><li>值 <code>2</code> 代表腐烂的橘子。</li></ul><p>每分钟，任何与腐烂的橘子（在 4 个正方向上）相邻的新鲜橘子都会腐烂。</p><p>返回直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能，返回 <code>-1</code>。</p><a id="more"></a><h4 id="示例-1："><a href="#示例-1：" class="headerlink" title="示例 1："></a>示例 1：</h4><p><img src="/images/algorithm/oranges.png" alt=""></p><blockquote><p>输入：[[2,1,1],[1,1,0],[0,1,1]]<br>  输出：4</p></blockquote><h4 id="示例-2："><a href="#示例-2：" class="headerlink" title="示例 2："></a>示例 2：</h4><blockquote><p>输入：[[2,1,1],[0,1,1],[1,0,1]]<br>  输出：-1<br>  解释：左下角的橘子（第 2 行， 第 0 列）永远不会腐烂，因为腐烂只会发生在 4 个正向上。</p></blockquote><h4 id="示例-3："><a href="#示例-3：" class="headerlink" title="示例 3："></a>示例 3：</h4><blockquote><p>输入：[[0,2]]<br>  输出：0<br>  解释：因为 0 分钟时已经没有新鲜橘子了，所以答案就是 0 。</p></blockquote><h4 id="提示："><a href="#提示：" class="headerlink" title="提示："></a>提示：</h4><ol><li><code>1 &lt;= grid.length &lt;= 10</code></li><li><code>1 &lt;= grid[0].length &lt;= 10</code></li><li><code>grid[i][j]</code> 仅为 <code>0</code>、<code>1</code> 或 <code>2</code></li></ol><h3 id="难度"><a href="#难度" class="headerlink" title="难度"></a>难度</h3><p>★☆☆☆</p><h3 id="解答思路"><a href="#解答思路" class="headerlink" title="解答思路"></a>解答思路</h3><ol><li>遍历出所有坏橘子2，存下来。</li><li>隔一分钟用坏橘子感染周边新鲜橘子。</li><li>对比一下和上次的图是否一样<ul><li>如果一样，说明无法再感染，算出新鲜橘子的数量，如果没有新鲜橘子了，说明全部感染，返回分钟数。如果有，说明不可能做到，返回-1。</li><li>如果不一样，继续感染</li></ul></li></ol><p>代码实现如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><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><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param &#123;number[][]&#125; grid</span></span><br><span class="line"><span class="comment"> * @return &#123;number&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">const</span> orangesRotting = <span class="function"><span class="keyword">function</span>(<span class="params">grid</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// 保存上一次的图形</span></span><br><span class="line">  <span class="keyword">let</span> lastGridString = grid.toString()</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (lastGridString.indexOf(<span class="number">1</span>) === <span class="number">-1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> count = <span class="number">0</span></span><br><span class="line">  <span class="keyword">const</span> xLen = grid.length</span><br><span class="line">  <span class="keyword">const</span> yLen = grid[<span class="number">0</span>].length</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 找出坏橘子存下来</span></span><br><span class="line">  <span class="keyword">let</span> laterRottedOranges = []</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; grid.length; i++) &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j &lt; grid[i].length; j++) &#123;</span><br><span class="line">      <span class="keyword">if</span> (grid[i][j] === <span class="number">2</span>) &#123;</span><br><span class="line">        laterRottedOranges.push([i, j])</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> tempRottedOranges = laterRottedOranges.slice(<span class="number">0</span>)</span><br><span class="line">    <span class="comment">// 存储新的被感染的坏橘子</span></span><br><span class="line">    laterRottedOranges = []</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; tempRottedOranges.length; i++) &#123;</span><br><span class="line">      <span class="keyword">let</span> x = tempRottedOranges[i][<span class="number">0</span>]</span><br><span class="line">      <span class="keyword">let</span> y = tempRottedOranges[i][<span class="number">1</span>]</span><br><span class="line">      <span class="keyword">if</span> (x &gt; <span class="number">0</span> &amp;&amp; grid[x - <span class="number">1</span>][y] === <span class="number">1</span>) &#123;</span><br><span class="line">        laterRottedOranges.push([x - <span class="number">1</span>, y])</span><br><span class="line">        grid[x - <span class="number">1</span>][y] = <span class="number">2</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (x &lt; xLen - <span class="number">1</span> &amp;&amp; grid[x + <span class="number">1</span>][y] === <span class="number">1</span>) &#123;</span><br><span class="line">        laterRottedOranges.push([x + <span class="number">1</span>, y])</span><br><span class="line">        grid[x + <span class="number">1</span>][y] = <span class="number">2</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (y &gt; <span class="number">0</span> &amp;&amp; grid[x][y - <span class="number">1</span>] === <span class="number">1</span>) &#123;</span><br><span class="line">        laterRottedOranges.push([x, y - <span class="number">1</span>])</span><br><span class="line">        grid[x][y - <span class="number">1</span>] = <span class="number">2</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (y &lt; yLen - <span class="number">1</span> &amp;&amp; grid[x][y + <span class="number">1</span>] === <span class="number">1</span>) &#123;</span><br><span class="line">        laterRottedOranges.push([x, y + <span class="number">1</span>])</span><br><span class="line">        grid[x][y + <span class="number">1</span>] = <span class="number">2</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 比较是否相等</span></span><br><span class="line">    <span class="keyword">const</span> gridString = grid.toString()</span><br><span class="line">    <span class="keyword">if</span> (gridString !== lastGridString) &#123;</span><br><span class="line">      count++</span><br><span class="line">      lastGridString = gridString</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">break</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 看还有没有=1的</span></span><br><span class="line">  <span class="keyword">if</span> (lastGridString.indexOf(<span class="number">1</span>) &gt; <span class="number">-1</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">-1</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> count</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;题目&quot;&gt;&lt;a href=&quot;#题目&quot; class=&quot;headerlink&quot; title=&quot;题目&quot;&gt;&lt;/a&gt;题目&lt;/h3&gt;&lt;p&gt;在给定的网格中，每个单元格可以有以下三个值之一：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;值 &lt;code&gt;0&lt;/code&gt; 代表空单元格；&lt;/li&gt;
&lt;li&gt;值 &lt;code&gt;1&lt;/code&gt; 代表新鲜橘子；&lt;/li&gt;
&lt;li&gt;值 &lt;code&gt;2&lt;/code&gt; 代表腐烂的橘子。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每分钟，任何与腐烂的橘子（在 4 个正方向上）相邻的新鲜橘子都会腐烂。&lt;/p&gt;
&lt;p&gt;返回直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能，返回 &lt;code&gt;-1&lt;/code&gt;。&lt;/p&gt;
    
    </summary>
    
      <category term="算法之路" scheme="https://vhtml.github.io/categories/%E7%AE%97%E6%B3%95%E4%B9%8B%E8%B7%AF/"/>
    
    
  </entry>
  
  <entry>
    <title>算法之路——设计一个有getMin功能的栈</title>
    <link href="https://vhtml.github.io/2019/01/20/algorithm_001/"/>
    <id>https://vhtml.github.io/2019/01/20/algorithm_001/</id>
    <published>2019-01-20T15:54:52.000Z</published>
    <updated>2019-02-13T10:54:08.586Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>实现一个特殊的栈，在实现栈的基本功能的基础上，再实现返回栈中最小元素的操作。</p><h3 id="要求"><a href="#要求" class="headerlink" title="要求"></a>要求</h3><ol><li>pop、push、getMin操作的时间复杂度都是O(1)。</li><li>设计的栈类型可以使用现成的栈结构。</li></ol><a id="more"></a><h3 id="难度"><a href="#难度" class="headerlink" title="难度"></a>难度</h3><p>★☆☆☆</p><h3 id="解答思路"><a href="#解答思路" class="headerlink" title="解答思路"></a>解答思路</h3><ul><li><p>压入数据规则</p><p>在设计上使用两个栈，一个栈用来保存当前栈中的元素，其功能和一个正常的栈没有区别，这个栈记为stackData；另一个栈用于保存每一步的最小值，这个栈记为stackMin。具体的实现方式如下：</p><p>假设当前数据为newNum，先将其压入stackData，然后判断stackMin是否为空：</p><ul><li>如果为空，则newNum也压入stackMin。</li><li>如果不为空，则比较newNum和stackMin的栈顶元素中哪一个更小：<ul><li>如果newNum更小或两者相等，则newNum也压入stackMIn；</li><li>如果stackMin中栈顶元素小，则stackMin不压入任何内容。</li></ul></li></ul></li><li><p>弹出数据规则</p><p>先在stackData中弹出栈顶元素，记为value。然后比较当前stackMin的栈顶元素和value哪一个更小。</p><p>由压入规则可知，stackMin中存在的元素是从栈底到栈顶逐渐变小的，stackMin栈顶的元素既是stackMin栈的最小值，也是当前stackData的最小值。</p><p>当value等于stackMin的栈顶元素时，stackMin弹出栈顶元素；当value大于stackMin的栈顶元素时，stackMin不弹出栈顶元素；返回value。</p></li><li><p>查询当前栈中的最小值操作</p><p>由上可知，stackMin始终记录着stackData中的最小值，所以，stackMin的栈顶元素始终是当前stackData中的最小值。</p></li></ul><p>代码实现如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyStack</span> </span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span>() &#123;</span><br><span class="line">    <span class="keyword">this</span>.stackData = []</span><br><span class="line">    <span class="keyword">this</span>.stackMin = []</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  push(newNum) &#123;</span><br><span class="line">    <span class="keyword">this</span>.stackData.push(newNum)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="keyword">this</span>.stackMin.length) &#123;</span><br><span class="line">      <span class="keyword">this</span>.stackMin.push(newNum)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (newNum &lt;= <span class="keyword">this</span>.getMin()) &#123;</span><br><span class="line">      <span class="keyword">this</span>.stackMin.push(newNum)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  pop() &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="keyword">this</span>.stackMin.length) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'Your stack is empty.'</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> value = <span class="keyword">this</span>.stackData.pop()</span><br><span class="line">    <span class="keyword">if</span> (value === <span class="keyword">this</span>.getMin()) &#123;</span><br><span class="line">      <span class="keyword">this</span>.stackMin.pop()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> value</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  getMin() &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="keyword">this</span>.stackMin.length) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'Your stack is empty.'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.stackMin[<span class="keyword">this</span>.stackMin.length - <span class="number">1</span>]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;题目&quot;&gt;&lt;a href=&quot;#题目&quot; class=&quot;headerlink&quot; title=&quot;题目&quot;&gt;&lt;/a&gt;题目&lt;/h3&gt;&lt;p&gt;实现一个特殊的栈，在实现栈的基本功能的基础上，再实现返回栈中最小元素的操作。&lt;/p&gt;
&lt;h3 id=&quot;要求&quot;&gt;&lt;a href=&quot;#要求&quot; class=&quot;headerlink&quot; title=&quot;要求&quot;&gt;&lt;/a&gt;要求&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;pop、push、getMin操作的时间复杂度都是O(1)。&lt;/li&gt;
&lt;li&gt;设计的栈类型可以使用现成的栈结构。&lt;/li&gt;
&lt;/ol&gt;
    
    </summary>
    
      <category term="算法之路" scheme="https://vhtml.github.io/categories/%E7%AE%97%E6%B3%95%E4%B9%8B%E8%B7%AF/"/>
    
    
  </entry>
  
  <entry>
    <title>Ajv：高效的JSON模式校验器</title>
    <link href="https://vhtml.github.io/2019/01/16/NPM__ajv/"/>
    <id>https://vhtml.github.io/2019/01/16/NPM__ajv/</id>
    <published>2019-01-16T03:50:47.000Z</published>
    <updated>2019-01-20T07:42:50.239Z</updated>
    
    <content type="html"><![CDATA[<p>一直想写一个优秀开源npm包的分享与学习系列，长久写，持续写。但深知坚持不容易，且万事开头难。</p><p>今天刚好有些闲暇，在看一些webpack loader源码的时候，发现一个不错的包——Ajv，有了一种想学习和分享之的冲动。于是这个系列就有了开头。</p><h3 id="官网"><a href="#官网" class="headerlink" title="官网"></a>官网</h3><p><a href="https://ajv.js.org/" target="_blank" rel="noopener">https://ajv.js.org/</a>，官网上有如下描述：</p><blockquote><p>The fastest JSON-Schema validator for Node.js and browser. Supports draft-04/06/07.</p></blockquote><a id="more"></a><p>JSON-Schema是什么呢？在学习ajv之前我也不知道，甚至没听过。但这丝毫不影响我们使用ajv，因为理解它很简单。</p><h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><p>先来看看ajv在node上怎么使用吧。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Ajv = <span class="built_in">require</span>(<span class="string">'ajv'</span>)</span><br><span class="line"><span class="keyword">const</span> ajv = <span class="keyword">new</span> Ajv(&#123;<span class="attr">allErrors</span>: <span class="literal">true</span>&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 这就是JSON-Schema</span></span><br><span class="line"><span class="keyword">const</span> schema = &#123;</span><br><span class="line">  properties: &#123;</span><br><span class="line">    foo: &#123; <span class="attr">type</span>: <span class="string">'string'</span> &#125;,</span><br><span class="line">    bar: &#123; <span class="attr">type</span>: <span class="string">'number'</span>, <span class="string">'maximum'</span>: <span class="number">3</span> &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> validate = ajv.compile(schema)</span><br><span class="line"></span><br><span class="line">test(&#123;<span class="attr">foo</span>: <span class="string">'abc'</span>, <span class="attr">bar</span>: <span class="number">2</span>&#125;)</span><br><span class="line">test(&#123;<span class="attr">foo</span>: <span class="number">2</span>, <span class="attr">bar</span>: <span class="number">4</span>&#125;)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// 校验JSON数据是否符合schema的定义</span></span><br><span class="line">  <span class="keyword">const</span> valid = validate(data)</span><br><span class="line">  <span class="keyword">if</span> (valid) &#123;</span><br><span class="line">    <span class="comment">// 为true，校验通过</span></span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Valid!'</span>)</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="comment">// 不通过，打印出错误原因</span></span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Invalid: '</span> + ajv.errorsText(validate.errors))</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>怎么样，😎关于JSON-Schema的定义是不是有点眼熟？如果你正在使用Vue或者React，会发现它很像props中对属性类型的定义。又或者你正在使用ORM（如Sequelize），它很像定义Model时对字段的描述。</p><p>实际上，JSON-Schema正是一种基于JSON格式定义JSON数据结构的规范。ajv正是基于JSON-Schema定义来对JSON格式进行校验的工具。JSON-Schema的使用应该是极其广泛的，在任何需要以JSON格式输入输出的地方，如webpack loader的选项配置，对接口返回格式的约束，接口文档的输出（如swagger），你的开发工具的自定义配置，甚至生成随机数据（还记得mockjs吗）等，都是它发挥强大作用的地方。</p><h3 id="周边插件"><a href="#周边插件" class="headerlink" title="周边插件"></a>周边插件</h3><ul><li><a href="https://github.com/epoberezkin/ajv-async" target="_blank" rel="noopener">ajv-async</a> 可以启用异步校验模式</li><li><a href="https://github.com/jessedc/ajv-cli" target="_blank" rel="noopener">ajv-cli</a> 可以让你在命令行上使用ajv</li><li><a href="https://github.com/epoberezkin/ajv-errors" target="_blank" rel="noopener">ajv-errors</a> 可以实现详细的自定义错误信息</li><li><a href="https://github.com/epoberezkin/ajv-i18n" target="_blank" rel="noopener">ajv-i18n</a> 可以国际化错误信息</li><li><a href="https://github.com/epoberezkin/ajv-keywords" target="_blank" rel="noopener">ajv-keywords</a> 扩展JSON-Schema的关键字，很强大</li></ul><p>要学会使用ajv，最好的方式是掌握JSON-Schema，这是后来补上的关于JSON-Schema的详细介绍——<a href="/2019/01/21/JSON_Schema/">传送门</a>。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;一直想写一个优秀开源npm包的分享与学习系列，长久写，持续写。但深知坚持不容易，且万事开头难。&lt;/p&gt;
&lt;p&gt;今天刚好有些闲暇，在看一些webpack loader源码的时候，发现一个不错的包——Ajv，有了一种想学习和分享之的冲动。于是这个系列就有了开头。&lt;/p&gt;
&lt;h3 id=&quot;官网&quot;&gt;&lt;a href=&quot;#官网&quot; class=&quot;headerlink&quot; title=&quot;官网&quot;&gt;&lt;/a&gt;官网&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://ajv.js.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ajv.js.org/&lt;/a&gt;，官网上有如下描述：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The fastest JSON-Schema validator for Node.js and browser. Supports draft-04/06/07.&lt;/p&gt;
&lt;/blockquote&gt;
    
    </summary>
    
      <category term="包罗万象" scheme="https://vhtml.github.io/categories/%E5%8C%85%E7%BD%97%E4%B8%87%E8%B1%A1/"/>
    
    
      <category term="npm" scheme="https://vhtml.github.io/tags/npm/"/>
    
      <category term="json" scheme="https://vhtml.github.io/tags/json/"/>
    
  </entry>
  
  <entry>
    <title>检测“资源”是否初始化完成的简单方法</title>
    <link href="https://vhtml.github.io/2018/07/09/ready-promise/"/>
    <id>https://vhtml.github.io/2018/07/09/ready-promise/</id>
    <published>2018-07-09T08:50:00.000Z</published>
    <updated>2018-12-11T11:55:24.489Z</updated>
    
    <content type="html"><![CDATA[<p>标题实在不知道怎么写了，感觉怎么写都有点不太准确。简单描述下场景。</p><p>比如在hybrid开发时，使用JsBridge提供操作给js，如果提供的操作需要在web页面加载完立即调用（如埋点日志之类的），可能调用失败，即使是在window.onload里调用也未必能获取到，而系统又没有提供准确的监听事件来判断，所以通常的做法可能会是这样的：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// TODO 调用jsBridge提供的方法</span></span><br><span class="line">&#125;, <span class="number">600</span>)</span><br></pre></td></tr></table></figure><p>延迟一小段时间再去执行，这种方法虽然可行，但总觉得很蛋疼。因为虽然JsBridge不会立即加载完成，但不同的系统下或由于缓存的情况下，加载时间各不相同。</p><a id="more"></a><p>为了能较为准确的检测到其是否加载完成，也只好勉为其难的使用定时器去不停地检测。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> timer = setInterval(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 判断方法是否存在</span></span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="built_in">window</span>.jsBridgeAction === <span class="string">'function'</span>) &#123;</span><br><span class="line">    clearInterval(timer)</span><br><span class="line">    <span class="comment">// TODO 做该做的事</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;, <span class="number">50</span>)</span><br></pre></td></tr></table></figure><p>也还好，在此提供一种封装方法，用起来跟onload事件监听似的，皆大欢喜。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><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><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> readyPromise = (variableName, &#123;</span><br><span class="line">  rate = <span class="number">50</span>,</span><br><span class="line">  timeout = <span class="number">1500</span></span><br><span class="line">&#125; = &#123;&#125;) =&gt; &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> variableName !== <span class="string">'string'</span>) &#123;</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'The first argument should be a string'</span>)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> rateTimer, overTimer</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> _GLOBAL = <span class="keyword">new</span> <span class="built_in">Function</span>(<span class="string">'return this'</span>)()</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> _clearTimer = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    clearInterval(rateTimer)</span><br><span class="line">    clearTimeout(overTimer)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (_GLOBAL[variableName]) &#123;</span><br><span class="line">      resolve()</span><br><span class="line">      <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    rateTimer = setInterval(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (_GLOBAL[variableName]) &#123;</span><br><span class="line">        _clearTimer()</span><br><span class="line">        resolve()</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;, rate)</span><br><span class="line"></span><br><span class="line">    overTimer = setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      _clearTimer()</span><br><span class="line">      reject(<span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'timeout'</span>))</span><br><span class="line">    &#125;, timeout)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">readyPromise(<span class="string">'jsBridgeAction'</span>).then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// TODO</span></span><br><span class="line">&#125;).catch(<span class="function"><span class="params">e</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.error(e)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>也可以直接使用<a href="https://github.com/vhtml/ready-promise" target="_blank" rel="noopener">ready-promise</a>库，使用方法稍有不同：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">npm i ready-promise -S</span><br><span class="line">``</span><br><span class="line"></span><br><span class="line">```javascript</span><br><span class="line">import readyPromise from <span class="string">'ready-promise'</span></span><br><span class="line">readyPromise(() =&gt; &#123;</span><br><span class="line">  <span class="built_in">return</span> typeof window.jsBridgeAction === <span class="string">'function'</span></span><br><span class="line">&#125;).<span class="keyword">then</span>(() =&gt; &#123;&#125;).catch(e =&gt; &#123;&#125;)</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;标题实在不知道怎么写了，感觉怎么写都有点不太准确。简单描述下场景。&lt;/p&gt;
&lt;p&gt;比如在hybrid开发时，使用JsBridge提供操作给js，如果提供的操作需要在web页面加载完立即调用（如埋点日志之类的），可能调用失败，即使是在window.onload里调用也未必能获取到，而系统又没有提供准确的监听事件来判断，所以通常的做法可能会是这样的：&lt;/p&gt;
&lt;figure class=&quot;highlight javascript&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;setTimeout(&lt;span class=&quot;function&quot;&gt;&lt;span class=&quot;params&quot;&gt;()&lt;/span&gt; =&amp;gt;&lt;/span&gt; &amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;// TODO 调用jsBridge提供的方法&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&amp;#125;, &lt;span class=&quot;number&quot;&gt;600&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;延迟一小段时间再去执行，这种方法虽然可行，但总觉得很蛋疼。因为虽然JsBridge不会立即加载完成，但不同的系统下或由于缓存的情况下，加载时间各不相同。&lt;/p&gt;
    
    </summary>
    
      <category term="web技术" scheme="https://vhtml.github.io/categories/web%E6%8A%80%E6%9C%AF/"/>
    
    
      <category term="javascript" scheme="https://vhtml.github.io/tags/javascript/"/>
    
      <category term="lib" scheme="https://vhtml.github.io/tags/lib/"/>
    
  </entry>
  
  <entry>
    <title>babel-polyfill和transform-runtime揭秘</title>
    <link href="https://vhtml.github.io/2018/05/02/babel-polyfill-vs-transform-runtime/"/>
    <id>https://vhtml.github.io/2018/05/02/babel-polyfill-vs-transform-runtime/</id>
    <published>2018-05-02T11:30:00.000Z</published>
    <updated>2018-12-13T10:53:51.948Z</updated>
    
    <content type="html"><![CDATA[<p>当前前端的开发，已经基本离不开<code>babel</code>的使用了。</p><p>而<code>babel</code>下两员大将<code>babel-polyfill</code>和<code>transform-runtime</code>也经常出现在各位前端同胞的业务及库的开发中，让我们得以欢快地使用js的各种高级语法以及牛X的api。可虽说是如此常用，很多前端同胞甚至是前端老司机也常常搞不清二者的关系，以至陷入莫名的疑惑当中。</p><p>正在这个时候，一名不愿露面的网友，本着刨根问底的钻(qiu)研(nue)精神，一窥二者的本质，向大家聊一聊两者的关系。</p><a id="more"></a><p>在此之前，让我们先了解一下<a href="https://github.com/zloirock/core-js" target="_blank" rel="noopener">core-js</a>这个库，版本<code>2.5.7</code>。打开它的github主页，如下：</p><p><img src="/images/core-js-partial.png" alt="core-js"></p><p>我们发现，呃，作者正在找工作，这个不是重点。从这段文字中我们知道了<code>core-js</code>是一个模块化的js标准库，包含着各种垫片等。重点在最后一句，<strong>我们可以按需使用，或者不污染全局命名空间地使用它</strong>。</p><p>也就是说我们至少应该有两种方式使用它：</p><ol><li><p>在程序入口的最开始处引入，当成垫片使用，会污染全局命名空间。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">require</span>(<span class="string">'core-js/shim'</span>)</span><br></pre></td></tr></table></figure></li><li><p>当成一个普通的commonjs库使用，不污染全局命名空间。</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> core = <span class="built_in">require</span>(<span class="string">'core-js/library'</span>)</span><br></pre></td></tr></table></figure></li><li><p>实际上，还有第三种，一股脑全引入，同样会污染全局命名空间：</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">require</span>(<span class="string">'core-js'</span>)</span><br></pre></td></tr></table></figure></li></ol><p>好的，回到我们的主角当中。</p><h3 id="babel-polyfill"><a href="#babel-polyfill" class="headerlink" title="babel-polyfill"></a>babel-polyfill</h3><p>我们先来看看<code>babel-polyfill</code>，以版本<code>6.26.3</code>为例，找到安装包的入口文件<code>lib/index.js</code>，简洁的数行代码：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><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">if</span> (global._babelPolyfill) &#123;</span><br><span class="line">  <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">"only one instance of babel-polyfill is allowed"</span>);</span><br><span class="line">&#125;</span><br><span class="line">global._babelPolyfill = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">"core-js/shim"</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="string">"regenerator-runtime/runtime"</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Should be removed in the next major release:</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">"core-js/fn/regexp/escape"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> DEFINE_PROPERTY = <span class="string">"defineProperty"</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">define</span>(<span class="params">O, key, value</span>) </span>&#123;</span><br><span class="line">  O[key] || <span class="built_in">Object</span>[DEFINE_PROPERTY](O, key, &#123;</span><br><span class="line">    writable:     <span class="literal">true</span>,</span><br><span class="line">    configurable: <span class="literal">true</span>,</span><br><span class="line">    value:        value</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">define(<span class="built_in">String</span>.prototype, <span class="string">"padLeft"</span>, <span class="string">""</span>.padStart);</span><br><span class="line">define(<span class="built_in">String</span>.prototype, <span class="string">"padRight"</span>, <span class="string">""</span>.padEnd);</span><br><span class="line"></span><br><span class="line"><span class="comment">// eslint-disable-next-line max-len</span></span><br><span class="line"><span class="string">"pop,reverse,shift,keys,values,entries,indexOf,every,some,forEach,map,filter,find,findIndex,includes,join,slice,concat,push,splice,unshift,sort,lastIndexOf,reduce,reduceRight,copyWithin,fill"</span>.split(<span class="string">","</span>).forEach(<span class="function"><span class="keyword">function</span>(<span class="params">key</span>) </span>&#123;</span><br><span class="line">  [][key] &amp;&amp; define(<span class="built_in">Array</span>, key, <span class="built_in">Function</span>.call.bind([][key]));</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>注释后面的就不用看了，将在下一个主版本发布时移除掉。然后我们看到只引入了两个库<code>core-js/shim</code>和<code>regenerator-runtime/runtime</code>。前者根据<code>core-js</code>的第一条使用方式，是作为js垫片使用的。后者会提供一个全局函数<code>regeneratorRuntime</code>，这个就厉害了 ，我们之所以能够欢快的使用<code>async</code>和<code>await</code>，全是它的功劳。到此我们大概知道了<code>babel-polyfill</code>实际上是一种垫片技术，保证了js在各版本下的一致性。</p><h3 id="babel-plugin-transform-runtime"><a href="#babel-plugin-transform-runtime" class="headerlink" title="babel-plugin-transform-runtime"></a>babel-plugin-transform-runtime</h3><p>再来看看<code>babel-plugin-transform-runtime</code>，以<code>6.23.0</code>为例，这是一个babel插件，依赖<code>babel-runtime</code>，而<code>babel-runtime</code>又依赖<code>core-js</code>和<code>regenerator-runtime</code>。是不是隐约觉得<code>babel-polyfill</code>和<code>babel-plugin-transform-runtime</code>已经产生了某种联系？</p><p>该插件中有一个<a href="https://github.com/jakwuh/babel-plugin-transform-runtime/blob/master/src/definitions.js" target="_blank" rel="noopener">definitions.js</a>文件，定义了一些builtins（即浏览器内建对象、方法），及一些如<code>Array</code>、<code>Object</code>、<code>Math</code>、<code>String</code>、<code>Number</code>等类的类方法的映射路径。这些路径如何映射，又映射到哪里呢？</p><p>依<code>Array</code>的<code>includes</code>方法举例说明，<a href="https://github.com/jakwuh/babel-plugin-transform-runtime/blob/master/src/definitions.js" target="_blank" rel="noopener">definitions.js</a>中这样定义到：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="comment">// builtins: &#123;</span></span><br><span class="line">  <span class="comment">//   ...</span></span><br><span class="line">  <span class="comment">// &#125;,</span></span><br><span class="line">  methods: &#123;</span><br><span class="line">    <span class="built_in">Array</span>: &#123;</span><br><span class="line">      <span class="comment">// ...</span></span><br><span class="line">      includes: <span class="string">"array/includes"</span>,</span><br><span class="line">      <span class="comment">// ...</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>babel</code>插件，是对<code>babel</code>转换后的AST（抽象语法树）进行的一系列处理，该插件对我们代码中用到的类方法的处理如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> moduleName = getRuntimeModuleName(state.opts);</span><br><span class="line">path.replaceWith(</span><br><span class="line">  <span class="keyword">this</span>.addDefaultImport(</span><br><span class="line">    <span class="string">`<span class="subst">$&#123;moduleName&#125;</span>/core-js/<span class="subst">$&#123;methods[prop.name]&#125;</span>`</span>,</span><br><span class="line">    <span class="string">`<span class="subst">$&#123;obj.name&#125;</span>$<span class="subst">$&#123;prop.name&#125;</span>`</span>,</span><br><span class="line">  ),</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>其中<code>moduleName</code>默认是<code>babel-runtime</code>，<code>${moduleName}/core-js/${methods[prop.name]}</code>代入变量还原后就是<code>babel-runtime/core-js/array/includes</code>。找到对应路径的文件，代码如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123; <span class="string">"default"</span>: <span class="built_in">require</span>(<span class="string">"core-js/library/fn/array/includes"</span>), <span class="attr">__esModule</span>: <span class="literal">true</span> &#125;;</span><br></pre></td></tr></table></figure><p>引用了<code>core-js/library</code>，根据<code>core-js</code>的第二条使用方式 —— 当成一个普通的commonjs库使用，不污染全局命名空间。而且可以针对某个方法或builtins单独引入。</p><p>这里还有个疑问，看过<code>transform-runtime</code>使用文档的会知道，它并不支持实例方法，如<code>[1, 2, 3].includes(1)</code>将无法起作用，那上面的<code>Array</code>的<code>includes</code>又是什么情况呢？事实上，它仅仅是提供了一个类方法的使用，及<code>Array.includes</code>，使用方式<code>Array.includes([1, 2, 3], 1)</code>，第一个参数接收一个数组实例。</p><p>例如，使用<code>transform-runtime</code>将</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> a = [<span class="number">1</span>, <span class="number">3</span>]</span><br><span class="line"><span class="comment">// 类方法</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="built_in">Array</span>.includes(a, <span class="number">1</span>))</span><br><span class="line"><span class="comment">// 实例方法</span></span><br><span class="line"><span class="built_in">console</span>.log(a.includes(<span class="number">1</span>))</span><br></pre></td></tr></table></figure><p>转换为</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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="meta">"use strict"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> _includes = <span class="built_in">require</span>(<span class="string">"babel-runtime/core-js/array/includes"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> _includes2 = _interopRequireDefault(_includes);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_interopRequireDefault</span>(<span class="params">obj</span>) </span>&#123; <span class="keyword">return</span> obj &amp;&amp; obj.__esModule ? obj : &#123; <span class="attr">default</span>: obj &#125;; &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> a = [<span class="number">1</span>, <span class="number">3</span>];</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log((<span class="number">0</span>, _includes2.default)(a, <span class="number">1</span>));</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(a.includes(<span class="number">1</span>));</span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>现在我们总结下两者的区别与应用场景：</p><ul><li><code>babel-polyfill</code> 提供完整的补丁，保证各浏览器下的一致性，但体积大，会污染全局变量，适合应用于业务开发当中，开发人员无需过多关注兼容性问题。</li><li><code>transform-runtime</code> 按需提供，不支持实例的方法，不污染全局变量，适合于库的开发</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;当前前端的开发，已经基本离不开&lt;code&gt;babel&lt;/code&gt;的使用了。&lt;/p&gt;
&lt;p&gt;而&lt;code&gt;babel&lt;/code&gt;下两员大将&lt;code&gt;babel-polyfill&lt;/code&gt;和&lt;code&gt;transform-runtime&lt;/code&gt;也经常出现在各位前端同胞的业务及库的开发中，让我们得以欢快地使用js的各种高级语法以及牛X的api。可虽说是如此常用，很多前端同胞甚至是前端老司机也常常搞不清二者的关系，以至陷入莫名的疑惑当中。&lt;/p&gt;
&lt;p&gt;正在这个时候，一名不愿露面的网友，本着刨根问底的钻(qiu)研(nue)精神，一窥二者的本质，向大家聊一聊两者的关系。&lt;/p&gt;
    
    </summary>
    
      <category term="web技术" scheme="https://vhtml.github.io/categories/web%E6%8A%80%E6%9C%AF/"/>
    
    
      <category term="javascript" scheme="https://vhtml.github.io/tags/javascript/"/>
    
      <category term="lib" scheme="https://vhtml.github.io/tags/lib/"/>
    
      <category term="babel" scheme="https://vhtml.github.io/tags/babel/"/>
    
  </entry>
  
  <entry>
    <title>flex布局学习之实战篇</title>
    <link href="https://vhtml.github.io/2017/12/19/flex-practice/"/>
    <id>https://vhtml.github.io/2017/12/19/flex-practice/</id>
    <published>2017-12-19T07:19:13.000Z</published>
    <updated>2019-01-17T03:47:52.023Z</updated>
    
    <content type="html"><![CDATA[<p><a href="/2017/12/17/flex-grammar/">上一篇文章</a>学习了Flex布局的语法，今天来个经典的布局实例练练手。</p><h3 id="圣杯布局"><a href="#圣杯布局" class="headerlink" title="圣杯布局"></a>圣杯布局</h3><p>圣杯布局由页头 (header)，中间部分 (center)，页脚 (footer)，和三栏组成。中间的一栏是主要内容，左边和右边提供如广告、导航的链接。</p><p>大部分的 CSS 解决方案都是以下列为目标：</p><ul><li>边栏应流动居中，定宽。</li><li>中间一栏 (主要内容) 在 HTML 源码中应该首先元素出现。</li><li>所有栏同高，忽略实际高度。</li><li>使用的 HTML 标记尽量少。</li><li>当页面内容不够充满页面时，页脚应“粘”在底部。</li></ul><a id="more"></a><h4 id="html代码"><a href="#html代码" class="headerlink" title="html代码"></a>html代码</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"header"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"container"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"center"</span>&gt;</span>一些内容<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"left"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"right"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"footer"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>不幸的是，这些自然的需求由于原生css的限制，当前经典的圣杯布局的解决方案都不能完美满足以上所有的要点。</p><p>有了 Flexbox 布局，终极的解决方案终于成为可能。</p><p>我们先看传统的实现方式：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><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><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#app</span> &#123;</span><br><span class="line">  <span class="attribute">position</span>: relative;</span><br><span class="line">  <span class="attribute">min-height</span>: <span class="number">100vh</span>;</span><br><span class="line">  <span class="attribute">padding-bottom</span>: <span class="number">100px</span>;</span><br><span class="line">  <span class="attribute">box-sizing</span>: border-box;</span><br><span class="line">  <span class="attribute">min-width</span>: <span class="number">600px</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#ddd</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.header</span> &#123;</span><br><span class="line">  <span class="attribute">position</span>: relative;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">100px</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#444</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.container</span> &#123;</span><br><span class="line">  <span class="attribute">padding-left</span>: <span class="number">200px</span>;</span><br><span class="line">  <span class="attribute">padding-right</span>: <span class="number">150px</span>;</span><br><span class="line">  <span class="attribute">overflow</span>: hidden;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.center</span>, <span class="selector-class">.left</span>, <span class="selector-class">.right</span> &#123;</span><br><span class="line">  <span class="attribute">position</span>: relative;</span><br><span class="line">  <span class="attribute">float</span>: left;</span><br><span class="line">  <span class="comment">/*等高的实现*/</span></span><br><span class="line">  <span class="attribute">padding-bottom</span>: <span class="number">20000px</span>;</span><br><span class="line">  <span class="attribute">margin-bottom</span>: -<span class="number">20000px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.container</span> <span class="selector-class">.center</span> &#123;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">100%</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: silver;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.container</span> <span class="selector-class">.left</span> &#123;</span><br><span class="line">  <span class="attribute">margin-left</span>: -<span class="number">100%</span>;</span><br><span class="line">  <span class="attribute">left</span>: -<span class="number">200px</span>;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">200px</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: blue;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.container</span> <span class="selector-class">.right</span> &#123;</span><br><span class="line">  <span class="attribute">margin-left</span>: -<span class="number">150px</span>;</span><br><span class="line">  <span class="attribute">right</span>: -<span class="number">150px</span>;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">150px</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: orange;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.footer</span> &#123;</span><br><span class="line">  <span class="attribute">position</span>: absolute;</span><br><span class="line">  <span class="attribute">left</span>: <span class="number">0</span>;</span><br><span class="line">  <span class="attribute">bottom</span>: <span class="number">0</span>;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">100%</span>;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">100px</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#444</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实现非常繁琐复杂，不易理解，而且使用了一些奇淫巧技实现列的等高效果，稳定性上难以保证。效果如图：</p><p><img src="/images/flex/holy-grail-classic.png" alt=""></p><p>再看flex的实现：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#app</span> &#123;</span><br><span class="line">  <span class="attribute">display</span>: flex;</span><br><span class="line">  <span class="attribute">flex-direction</span>: column;</span><br><span class="line">  <span class="attribute">min-height</span>: <span class="number">100vh</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.header</span> &#123;</span><br><span class="line">  <span class="attribute">position</span>: relative;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">100px</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#444</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.container</span> &#123;</span><br><span class="line">  <span class="attribute">flex</span>: <span class="number">1</span>;</span><br><span class="line">  <span class="attribute">display</span>: flex;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.container</span> <span class="selector-class">.center</span> &#123;</span><br><span class="line">  <span class="attribute">flex</span>: <span class="number">1</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: silver;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.container</span> <span class="selector-class">.left</span> &#123;</span><br><span class="line">  <span class="attribute">flex</span>: <span class="number">0</span> <span class="number">0</span> <span class="number">200px</span>;</span><br><span class="line">  <span class="attribute">order</span>: -<span class="number">1</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: blue;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.container</span> <span class="selector-class">.right</span> &#123;</span><br><span class="line">  <span class="attribute">flex</span>: <span class="number">0</span> <span class="number">0</span> <span class="number">150px</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: orange;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.footer</span> &#123;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">100px</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#444</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>简洁明了，实现方式及效果堪称完美，如图：</p><p><img src="/images/flex/holy-grail-flex.png" alt=""></p><p>参考：</p><ol><li><a href="https://alistapart.com/article/holygrail" target="_blank" rel="noopener">In Search of the Holy Grail</a></li><li><a href="https://philipwalton.github.io/solved-by-flexbox/" target="_blank" rel="noopener">Solved by Flexbox</a></li></ol>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;/2017/12/17/flex-grammar/&quot;&gt;上一篇文章&lt;/a&gt;学习了Flex布局的语法，今天来个经典的布局实例练练手。&lt;/p&gt;
&lt;h3 id=&quot;圣杯布局&quot;&gt;&lt;a href=&quot;#圣杯布局&quot; class=&quot;headerlink&quot; title=&quot;圣杯布局&quot;&gt;&lt;/a&gt;圣杯布局&lt;/h3&gt;&lt;p&gt;圣杯布局由页头 (header)，中间部分 (center)，页脚 (footer)，和三栏组成。中间的一栏是主要内容，左边和右边提供如广告、导航的链接。&lt;/p&gt;
&lt;p&gt;大部分的 CSS 解决方案都是以下列为目标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;边栏应流动居中，定宽。&lt;/li&gt;
&lt;li&gt;中间一栏 (主要内容) 在 HTML 源码中应该首先元素出现。&lt;/li&gt;
&lt;li&gt;所有栏同高，忽略实际高度。&lt;/li&gt;
&lt;li&gt;使用的 HTML 标记尽量少。&lt;/li&gt;
&lt;li&gt;当页面内容不够充满页面时，页脚应“粘”在底部。&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://vhtml.github.io/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="css3" scheme="https://vhtml.github.io/tags/css3/"/>
    
  </entry>
  
  <entry>
    <title>flex布局学习之语法篇</title>
    <link href="https://vhtml.github.io/2017/12/17/flex-grammar/"/>
    <id>https://vhtml.github.io/2017/12/17/flex-grammar/</id>
    <published>2017-12-17T05:33:49.000Z</published>
    <updated>2019-01-14T18:09:28.946Z</updated>
    
    <content type="html"><![CDATA[<p>Flex布局也已经用了挺久了，但总感觉用得不够透，于是抽空再系统学习下。</p><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><p>如下即定义了一个flex容器，内联或块取决于给定的值。它的所有直接子元素将自动成为容器成员。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.box</span> &#123;</span><br><span class="line">  <span class="attribute">display</span>: flex; <span class="comment">/* or inline-flex */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意：设为 Flex 布局以后，子元素的float、clear和vertical-align属性将失效。</p><a id="more"></a><h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h2><p><img src="/images/flex/CSS3-Flexbox-Model.webp" alt=""></p><p>容器默认存在两根轴：水平的主轴（main axis）和垂直的交叉轴（cross axis）。主轴的开始位置（与边框的交叉点）叫做<code>main start</code>，结束位置叫做<code>main end</code>；交叉轴的开始位置叫做<code>cross start</code>，结束位置叫做<code>cross end</code>。</p><p>项目默认沿主轴排列。单个项目占据的主轴空间叫做<code>main size</code>，占据的交叉轴空间叫做<code>cross size</code>。</p><h2 id="容器属性"><a href="#容器属性" class="headerlink" title="容器属性"></a>容器属性</h2><h3 id="flex-direction"><a href="#flex-direction" class="headerlink" title="flex-direction"></a>flex-direction</h3><p><code>flex-direction</code>属性决定主轴的方向。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-box</span> &#123;</span><br><span class="line">  <span class="attribute">flex-direction</span>: row | row-reverse | column | column-reverse;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/images/flex/flex-direction.svg" alt=""></p><ul><li><code>row</code>（默认值）：主轴为水平方向，起点在左端。</li><li><code>row-reverse</code>：主轴为水平方向，起点在右端。</li><li><code>column</code>：主轴为垂直方向，起点在上沿。</li><li><code>column-reverse</code>：主轴为垂直方向，起点在下沿。</li></ul><h3 id="flex-wrap"><a href="#flex-wrap" class="headerlink" title="flex-wrap"></a>flex-wrap</h3><p>默认情况下，项目都排在一条线上，你可以通过这个属性来改变它。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-box</span> &#123;</span><br><span class="line">  <span class="attribute">flex-wrap</span>: nowrap | wrap | wrap-reverse;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/images/flex/flex-wrap.svg" alt=""></p><ul><li><code>nowrap</code>（默认）：不换行。</li><li><code>wrap</code>：换行，从上到下，即第一行在上方。</li><li><code>wrap-reverse</code>：换行，从下到上，即第一行在下方。</li></ul><h3 id="flex-flow"><a href="#flex-flow" class="headerlink" title="flex-flow"></a>flex-flow</h3><p><code>flex-flow</code>属性是<code>flex-direction</code>属性和<code>flex-wrap</code>属性的简写形式，默认值为<code>row nowrap</code>。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-box</span> &#123;</span><br><span class="line">  <span class="attribute">flex-flow</span>: &lt;flex-direction&gt; || &lt;flex-wrap&gt;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="justify-content"><a href="#justify-content" class="headerlink" title="justify-content"></a>justify-content</h3><p>定义了项目在主轴上的对齐方式。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-box</span> &#123;</span><br><span class="line">  <span class="attribute">justify-content</span>: flex-start | flex-end | center | space-between | space-around | space-evenly;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/images/flex/justify-content.svg" alt=""></p><ul><li><code>flex-start</code>（默认值）：左对齐</li><li><code>flex-end</code>：右对齐</li><li><code>center</code>：居中</li><li><code>space-between</code>：两端对齐，项目之间的间隔都相等。</li><li><code>space-around</code>：每个项目两侧的间隔相等。所以，项目之间的间隔比项目与边框的间隔大一倍。</li><li><code>space-evenly</code>：每个项目之间的间隔相等（包括到边框的间隔）。</li></ul><h3 id="align-items"><a href="#align-items" class="headerlink" title="align-items"></a>align-items</h3><p>定义了项目在交叉轴上的对齐方式。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-box</span> &#123;</span><br><span class="line">  <span class="attribute">align-items</span>: flex-start | flex-end | center | baseline | stretch;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/images/flex/align-items.svg" alt=""></p><ul><li><code>flex-start</code>：交叉轴的起点对齐。</li><li><code>flex-end</code>：交叉轴的终点对齐。</li><li><code>center</code>：交叉轴的中点对齐。</li><li><code>baseline</code>: 项目的第一行文字的基线对齐。</li><li><code>stretch</code>（默认值）：如果项目未设置高度或设为auto，将占满整个容器的高度。</li></ul><h3 id="align-content"><a href="#align-content" class="headerlink" title="align-content"></a>align-content</h3><p>该属性定义了多根轴线在交叉轴上的对齐方式。如果项目只有一根轴线，该属性不起作用。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-box</span> &#123;</span><br><span class="line">  <span class="attribute">align-content</span>: flex-start | flex-end | center | space-between | space-around | stretch;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/images/flex/align-content.svg" alt=""></p><ul><li><code>flex-start</code>：与交叉轴的起点对齐。</li><li><code>flex-end</code>：与交叉轴的终点对齐。</li><li><code>center</code>：与交叉轴的中点对齐。</li><li><code>space-between</code>：与交叉轴两端对齐，轴线之间的间隔平均分布。</li><li><code>space-around</code>：每根轴线两侧的间隔都相等。所以，轴线之间的间隔比轴线与边框的间隔大一倍。</li><li><code>stretch</code>（默认值）：轴线占满整个交叉轴。</li></ul><h2 id="项目属性"><a href="#项目属性" class="headerlink" title="项目属性"></a>项目属性</h2><h3 id="order"><a href="#order" class="headerlink" title="order"></a>order</h3><p>该属性定义项目的排列顺序。数值越小，排列越靠前，默认为0。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-item</span> &#123;</span><br><span class="line">  <span class="attribute">order</span>: &lt;integer&gt;; <span class="comment">/* default is 0 */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/images/flex/order.svg" alt=""></p><h3 id="flex-grow"><a href="#flex-grow" class="headerlink" title="flex-grow"></a>flex-grow</h3><p>该属性定义项目的放大比例。默认为0，即如果存在剩余空间，也不放大。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-item</span> &#123;</span><br><span class="line">  <span class="attribute">flex-grow</span>: &lt;number&gt;; <span class="comment">/* default 0 */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/images/flex/flex-grow.svg" alt=""></p><p>如果所有项目的<code>flex-grow</code>属性都为1，则它们将等分剩余空间（如果有的话）。如果一个项目的<code>flex-grow</code>属性为2，其他项目都为1，则前者占据的剩余空间将比其他项多一倍。</p><p>负值对该属性无效。</p><h3 id="flex-shrink"><a href="#flex-shrink" class="headerlink" title="flex-shrink"></a>flex-shrink</h3><p>该属性定义了项目的缩小比例，默认为1，即如果空间不足，该项目将缩小。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-item</span> &#123;</span><br><span class="line">  <span class="attribute">flex-shrink</span>: &lt;number&gt;; <span class="comment">/* default 1 */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果所有项目的<code>flex-shrink</code>属性都为1，当空间不足时，都将等比例缩小。如果一个项目的<code>flex-shrink</code>属性为0，其他项目都为1，则空间不足时，前者不缩小。</p><p>负值对该属性无效。</p><h3 id="flex-basis"><a href="#flex-basis" class="headerlink" title="flex-basis"></a>flex-basis</h3><p>该属性定义了在分配多余空间之前，项目占据的主轴空间（main size）。浏览器根据这个属性，计算主轴是否有多余空间。它的默认值为<code>auto</code>，即项目的本来大小。它可以是一个长度（如20%，5rem等）或关键字。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-item</span> &#123;</span><br><span class="line">  <span class="attribute">flex-basis</span>: &lt;length&gt; | auto; <span class="comment">/* default auto */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="flex"><a href="#flex" class="headerlink" title="flex"></a>flex</h3><p>该属性是<code>flex-grow</code>, <code>flex-shrink</code> 和 <code>flex-basis</code>的简写，默认值为<code>0 1 auto</code>。后两个属性可选。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-item</span> &#123;</span><br><span class="line">  <span class="attribute">flex</span>: none | [ &lt;<span class="string">'flex-grow'</span>&gt; &lt;<span class="string">'flex-shrink'</span>&gt;? || &lt;<span class="string">'flex-basis'</span>&gt; ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>该属性有两个快捷值：<code>auto (1 1 auto)</code> 和 <code>none (0 0 auto)</code>。</p><h3 id="align-self"><a href="#align-self" class="headerlink" title="align-self"></a>align-self</h3><p>该属性允许单个项目有与其他项目不一样的对齐方式，可覆盖<code>align-items</code>属性。默认值为<code>auto</code>，表示继承父元素的<code>align-items</code>属性，如果没有父元素，则等同于<code>stretch</code>。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.flex-item</span> &#123;</span><br><span class="line">  <span class="attribute">align-self</span>: auto | flex-start | flex-end | center | baseline | stretch;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/images/flex/align-self.svg" alt=""></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Flex布局也已经用了挺久了，但总感觉用得不够透，于是抽空再系统学习下。&lt;/p&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;如下即定义了一个flex容器，内联或块取决于给定的值。它的所有直接子元素将自动成为容器成员。&lt;/p&gt;
&lt;figure class=&quot;highlight css&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;selector-class&quot;&gt;.box&lt;/span&gt; &amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attribute&quot;&gt;display&lt;/span&gt;: flex; &lt;span class=&quot;comment&quot;&gt;/* or inline-flex */&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;注意：设为 Flex 布局以后，子元素的float、clear和vertical-align属性将失效。&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://vhtml.github.io/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="css3" scheme="https://vhtml.github.io/tags/css3/"/>
    
  </entry>
  
  <entry>
    <title>Vue中nextTick方法的实现</title>
    <link href="https://vhtml.github.io/2017/06/05/js-nextTick/"/>
    <id>https://vhtml.github.io/2017/06/05/js-nextTick/</id>
    <published>2017-06-05T14:15:00.000Z</published>
    <updated>2018-12-13T10:53:47.685Z</updated>
    
    <content type="html"><![CDATA[<p>先来看一道题：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">1</span>)</span><br><span class="line">&#125;, <span class="number">0</span>)</span><br><span class="line"><span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">2</span>)</span><br><span class="line">  resolve()</span><br><span class="line">&#125;).then(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">3</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">4</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输出结果是 2 4 3 1</span></span><br></pre></td></tr></table></figure><p>大致原因是，浏览器环境中有一个事件循环，它又包含多个任务队列，任务队列又分为两种：</p><ul><li><p>macro-task</p><p>像script(整体代码)、setTimeout、setInterval、I/O、UI rendering等。</p></li><li><p>micro-task</p><p>如Promises（说的是原生的，polyfill在浏览器端通常是使用setTimeout实现的）、MutationObserver等。</p></li></ul><p>JavaScript引擎首先从macrotask queue中取出第一个任务（通常是当前代码段），执行完毕后，将microtask queue中的所有任务取出，按顺序全部执行；然后再从macrotask queue中取下一个，执行完毕后，再次将microtask queue中的全部取出；循环往复，直到两个queue中的任务都取完。</p><p>为什么要说这些呢？ 因为Vue文档里这么说了：</p><p><img src="/images/next-tick-img.png" alt="歪闹日志"></p><p>正是因为Vue里做了这样的优化，当Model层数据发生改变时，dom不会立刻去响应变化。所以当需要正确地获取响应了数据变化之后的DOM时，就要在DOM更新之后去获取。</p><p>而如何在当前事件队列执行完毕后尽快响应回调，才是今天要说的内容。借助开头所说的两种任务队列，要实现这个功能不难。Vue中用到了Promise.then和MutationObserver，只有当执行环境不支持时，才降级使用setTimeout代替。</p><p>先来个简单的Promises版的实现：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> nextTick = <span class="function"><span class="keyword">function</span> (<span class="params">fn</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> p = <span class="built_in">Promise</span>.resolve()</span><br><span class="line">  p.then(fn).catch(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.error(err)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 测试一下</span></span><br><span class="line">setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">1</span>)</span><br><span class="line">&#125;, <span class="number">0</span>)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">2</span>)</span><br><span class="line">nextTick(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;<span class="built_in">console</span>.log(<span class="number">3</span>)&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">4</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 结果是 2 4 3 1</span></span><br></pre></td></tr></table></figure><p>再看看<a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver" target="_blank">MutationObserver</a>，它需要监听DOM的变化，我们可以做点小动作。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> nextTick = <span class="function"><span class="keyword">function</span> (<span class="params">fn</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> counter = <span class="number">1</span></span><br><span class="line">  <span class="keyword">var</span> observer = <span class="keyword">new</span> MutationObserver(fn) <span class="comment">// 创建监听对象，并传入回调函数</span></span><br><span class="line">  <span class="keyword">var</span> textNode = <span class="built_in">document</span>.createTextNode(counter) <span class="comment">// 创建一个文本接点</span></span><br><span class="line">  observer.observe(textNode, &#123;</span><br><span class="line">    characterData: <span class="literal">true</span> <span class="comment">// 监听文本接点的字符变化</span></span><br><span class="line">  &#125;)</span><br><span class="line">  counter = (counter + <span class="number">1</span>) % <span class="number">2</span></span><br><span class="line">  textNode.data = counter <span class="comment">// 改变文本接点的字符数据</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 需要在浏览器环境下测试</span></span><br><span class="line">setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">1</span>)</span><br><span class="line">&#125;, <span class="number">0</span>)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">2</span>)</span><br><span class="line">nextTick(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;<span class="built_in">console</span>.log(<span class="number">3</span>)&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">4</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 结果是 2 4 3 1</span></span><br></pre></td></tr></table></figure><p>以上实现的nextTick方法已经基本可以满足需求了。只是每次执行的时候都要重新建立一个新的microtask queue。我们可以对其做一个优化，使得同一队列的几个nextTick的回调在一个microtask queue里执行。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> nextTick = (<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> callbacks = []</span><br><span class="line">  <span class="keyword">let</span> pending = <span class="literal">false</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">nextTickHandler</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    pending = <span class="literal">false</span> <span class="comment">// 取消pending</span></span><br><span class="line">    <span class="keyword">const</span> copies = callbacks.slice(<span class="number">0</span>) <span class="comment">// copy执行队列</span></span><br><span class="line">    callbacks.length = <span class="number">0</span> <span class="comment">// 清空执行队列</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; copies.length; i++) &#123;</span><br><span class="line">      copies[i]()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> p = <span class="built_in">Promise</span>.resolve()</span><br><span class="line">  <span class="keyword">let</span> timerFunc = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    p.then(nextTickHandler).catch(<span class="function"><span class="params">err</span> =&gt;</span> &#123; <span class="built_in">console</span>.error(err) &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="title">queueNextTick</span> (<span class="params">cb, ctx</span>) </span>&#123;</span><br><span class="line">    callbacks.push(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (cb) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">          cb.call(ctx)</span><br><span class="line">        &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">          <span class="built_in">console</span>.warn(<span class="string">`error in nextTick: "<span class="subst">$&#123;e.toString()&#125;</span>"`</span>, ctx)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">if</span> (!pending) &#123;</span><br><span class="line">      pending = <span class="literal">true</span></span><br><span class="line">      timerFunc()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)()</span><br></pre></td></tr></table></figure><p>实现方式大概就是这样吧。Vue里还做了一些兼容处理，仅此而已。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;先来看一道题：&lt;/p&gt;
&lt;figure class=&quot;highlight javascript&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/
      
    
    </summary>
    
      <category term="web技术" scheme="https://vhtml.github.io/categories/web%E6%8A%80%E6%9C%AF/"/>
    
    
      <category term="javascript" scheme="https://vhtml.github.io/tags/javascript/"/>
    
      <category term="vue" scheme="https://vhtml.github.io/tags/vue/"/>
    
  </entry>
  
  <entry>
    <title>js缓存技术的实现</title>
    <link href="https://vhtml.github.io/2017/03/27/js-cache/"/>
    <id>https://vhtml.github.io/2017/03/27/js-cache/</id>
    <published>2017-03-27T07:52:00.000Z</published>
    <updated>2018-12-13T10:54:14.531Z</updated>
    
    <content type="html"><![CDATA[<p>在编写javascript代码时，适当地使用缓存技术可以提高数据的重复使用率，以达到优化性能的目的。</p><p>最直接最暴力的做法是，直接创建一个没有原型的空对象，然后一股脑的往里塞数据：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> _data = <span class="built_in">Object</span>.create(<span class="literal">null</span>) <span class="comment">// 这是我们实现的缓存对象（捂脸）</span></span><br><span class="line">_data[<span class="string">'foo'</span>] = <span class="number">123</span></span><br><span class="line">_data[<span class="string">'bar'</span>] = <span class="string">'hello kitty'</span></span><br><span class="line">_data[<span class="string">'author'</span>] = &#123;<span class="attr">name</span>: <span class="string">'歪闹'</span>, <span class="attr">blog</span>: <span class="string">'http://iwhynot.me'</span>&#125;</span><br></pre></td></tr></table></figure><a id="more"></a><p>使用的时候也很方便，直接读取缓存对象的属性值，有就拿来用，没有就去求值然后再按上面的方法存取。</p><p>诚然，这样做也可以满足大多数的需求，但是作为面向新世纪的fronter，我们应该要有更高的追求。</p><p><img src="/images/face-1460430918.jpg" width="120" alt="歪闹日志"></p><p>先来实现一个能记录数据size的缓存对象</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Cache</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.size = <span class="number">0</span></span><br><span class="line">  <span class="keyword">this</span>._data = <span class="built_in">Object</span>.create(<span class="literal">null</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> p = Cache.prototype</span><br><span class="line">p.put = <span class="function"><span class="keyword">function</span> (<span class="params">key, value</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> entry = <span class="keyword">this</span>.get(key, <span class="literal">true</span>)</span><br><span class="line">  <span class="keyword">if</span> (!entry) &#123;</span><br><span class="line">    <span class="keyword">this</span>.size++</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">this</span>._data[key] = &#123;</span><br><span class="line">    key: key,</span><br><span class="line">    value: value</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">p.get = <span class="function"><span class="keyword">function</span> (<span class="params">key, returnEntry</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> entry = <span class="keyword">this</span>._data[key]</span><br><span class="line">  <span class="keyword">if</span> (entry === <span class="literal">undefined</span>) <span class="keyword">return</span></span><br><span class="line">  <span class="keyword">return</span> returnEntry ? entry : entry.value</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>现在可以愉快的存取数据了。</p><figure class="highlight lasso"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">var</span> <span class="keyword">cache</span> = <span class="literal">new</span> <span class="keyword">Cache</span>()</span><br><span class="line"><span class="keyword">cache</span>.put(<span class="string">'foo'</span>, <span class="number">123</span>)</span><br><span class="line"><span class="keyword">cache</span>.put(<span class="string">'author'</span>, &#123;name: <span class="string">'歪闹'</span>, blog: <span class="string">'http://iwhynot.me'</span>&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">cache</span>.size <span class="comment">// 2</span></span><br><span class="line"><span class="keyword">cache</span>.get(<span class="string">'foo'</span>) <span class="comment">// 123</span></span><br></pre></td></tr></table></figure><p>写到这里发现，搞了半天就只是实现了个阉割版的数组功能。其实不然，数组存数据的确很方便，但是取数据就没那么好玩了，要一个个去找，效率就不高了。</p><p>这时我们发现这个缓存对象看起来可以存无限多的数据，很多数据已经没用了，还存留着浪费内存。我们再来加一个大小限制，超过限制就把最先插入的缓存删掉以给后来者腾点空间。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><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="function"><span class="keyword">function</span> <span class="title">Cache</span> (<span class="params">limit</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.size = <span class="number">0</span></span><br><span class="line">  <span class="keyword">this</span>.limit = limit</span><br><span class="line">  <span class="keyword">this</span>._keys = [] <span class="comment">// 保存存储的数据key值</span></span><br><span class="line">  <span class="keyword">this</span>._data = <span class="built_in">Object</span>.create(<span class="literal">null</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> p = Cache.prototype</span><br><span class="line">p.put = <span class="function"><span class="keyword">function</span> (<span class="params">key, value</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> removed</span><br><span class="line">  <span class="keyword">var</span> entry = <span class="keyword">this</span>.get(key, <span class="literal">true</span>)</span><br><span class="line">  <span class="keyword">if</span> (!entry) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.size === <span class="keyword">this</span>.limit) &#123;</span><br><span class="line">      removed = <span class="keyword">this</span>.shift()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">this</span>._keys.push(key)</span><br><span class="line">    <span class="keyword">this</span>.size++</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">this</span>._data[key] = &#123;</span><br><span class="line">    key: key,</span><br><span class="line">    value: value</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> removed</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">p.shift = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> head</span><br><span class="line">  <span class="keyword">var</span> key = <span class="keyword">this</span>._keys.shift()</span><br><span class="line">  <span class="keyword">if</span> (key !== <span class="literal">undefined</span>) &#123;</span><br><span class="line">    <span class="keyword">delete</span> <span class="keyword">this</span>._data[key]</span><br><span class="line">    <span class="keyword">this</span>.size--</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> head</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">p.get = <span class="function"><span class="keyword">function</span> (<span class="params">key, returnEntry</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> entry = <span class="keyword">this</span>._data[key]</span><br><span class="line">  <span class="keyword">if</span> (entry === <span class="literal">undefined</span>) <span class="keyword">return</span></span><br><span class="line">  <span class="keyword">return</span> returnEntry ? entry : entry.value</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>一切看起来很不错的样子。可这种方式有个不好的地方，后来的数据总会挤走先来的数据，而不管数据的使用频率。所以根据LRU最近最少使用算法，我们来实现更合理的链表存储方式。</p><p><img src="/images/lru-img.png" width="150" alt="歪闹日志"></p><pre><code>1. 新数据插入到链表头部；2. 每当缓存命中（即缓存数据被访问），则将数据移到链表头部；3. 当链表满的时候，将链表尾部的数据丢弃。</code></pre><p>最终的代码实现（最新插入的数据放在了尾部，原理一样）：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><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><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Cache</span> (<span class="params">limit</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.size = <span class="number">0</span></span><br><span class="line">  <span class="keyword">this</span>.limit = limit</span><br><span class="line">  <span class="keyword">this</span>.head = <span class="keyword">this</span>.tail = <span class="literal">undefined</span></span><br><span class="line">  <span class="keyword">this</span>._data = <span class="built_in">Object</span>.create(<span class="literal">null</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> p = Cache.prototype</span><br><span class="line"></span><br><span class="line">p.put = <span class="function"><span class="keyword">function</span> (<span class="params">key, value</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> removed</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> entry = <span class="keyword">this</span>.get(key, <span class="literal">true</span>)</span><br><span class="line">  <span class="keyword">if</span> (!entry) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.size === <span class="keyword">this</span>.limit) &#123;</span><br><span class="line">      removed = <span class="keyword">this</span>.shift()</span><br><span class="line">    &#125;</span><br><span class="line">    entry = &#123;</span><br><span class="line">      key: key</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.tail) &#123;</span><br><span class="line">      <span class="keyword">this</span>.tail.newer = entry</span><br><span class="line">      entry.older = <span class="keyword">this</span>.tail</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">this</span>.head = entry</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">this</span>._data[key] = entry</span><br><span class="line">    <span class="keyword">this</span>.tail = entry</span><br><span class="line">    <span class="keyword">this</span>.size++</span><br><span class="line">  &#125;</span><br><span class="line">  entry.value = value</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> removed</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">p.shift = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> entry = <span class="keyword">this</span>.head</span><br><span class="line">  <span class="keyword">if</span> (entry) &#123;</span><br><span class="line">    <span class="keyword">this</span>.head = entry.newer</span><br><span class="line">    <span class="keyword">this</span>.head.older = <span class="literal">undefined</span></span><br><span class="line">    entry.newer = entry.older = <span class="literal">undefined</span></span><br><span class="line">    <span class="keyword">this</span>._data[entry.key] = <span class="literal">undefined</span></span><br><span class="line">    <span class="keyword">this</span>.size--</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> entry</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">p.get = <span class="function"><span class="keyword">function</span> (<span class="params">key, returnEntry</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> entry = <span class="keyword">this</span>._data[key]</span><br><span class="line">  <span class="keyword">if</span> (entry === <span class="literal">undefined</span>) <span class="keyword">return</span></span><br><span class="line">  <span class="keyword">if</span> (entry === <span class="keyword">this</span>.tail) &#123;</span><br><span class="line">    <span class="keyword">return</span> returnEntry ? entry : entry.value</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (entry.newer) &#123;</span><br><span class="line">    <span class="keyword">if</span> (entry === <span class="keyword">this</span>.head) &#123;</span><br><span class="line">      <span class="keyword">this</span>.head = entry.newer</span><br><span class="line">    &#125;</span><br><span class="line">    entry.newer.older = entry.older</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (entry.older) &#123;</span><br><span class="line">    entry.older.newer = entry.newer</span><br><span class="line">  &#125;</span><br><span class="line">  entry.newer = <span class="literal">undefined</span></span><br><span class="line">  entry.older = <span class="keyword">this</span>.tail</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">this</span>.tail) &#123;</span><br><span class="line">    <span class="keyword">this</span>.tail.newer = entry</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">this</span>.tail = entry</span><br><span class="line">  <span class="keyword">return</span> returnEntry ? entry : entry.value</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在编写javascript代码时，适当地使用缓存技术可以提高数据的重复使用率，以达到优化性能的目的。&lt;/p&gt;
&lt;p&gt;最直接最暴力的做法是，直接创建一个没有原型的空对象，然后一股脑的往里塞数据：&lt;/p&gt;
&lt;figure class=&quot;highlight javascript&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; _data = &lt;span class=&quot;built_in&quot;&gt;Object&lt;/span&gt;.create(&lt;span class=&quot;literal&quot;&gt;null&lt;/span&gt;) &lt;span class=&quot;comment&quot;&gt;// 这是我们实现的缓存对象（捂脸）&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;_data[&lt;span class=&quot;string&quot;&gt;&#39;foo&#39;&lt;/span&gt;] = &lt;span class=&quot;number&quot;&gt;123&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;_data[&lt;span class=&quot;string&quot;&gt;&#39;bar&#39;&lt;/span&gt;] = &lt;span class=&quot;string&quot;&gt;&#39;hello kitty&#39;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;_data[&lt;span class=&quot;string&quot;&gt;&#39;author&#39;&lt;/span&gt;] = &amp;#123;&lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&#39;歪闹&#39;&lt;/span&gt;, &lt;span class=&quot;attr&quot;&gt;blog&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&#39;http://iwhynot.me&#39;&lt;/span&gt;&amp;#125;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
      <category term="web技术" scheme="https://vhtml.github.io/categories/web%E6%8A%80%E6%9C%AF/"/>
    
    
      <category term="javascript" scheme="https://vhtml.github.io/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>使用属性表达式获取对象属性值</title>
    <link href="https://vhtml.github.io/2017/03/22/get-object-value/"/>
    <id>https://vhtml.github.io/2017/03/22/get-object-value/</id>
    <published>2017-03-22T06:15:00.000Z</published>
    <updated>2018-07-09T07:26:50.000Z</updated>
    
    <content type="html"><![CDATA[<p>在Vue1.x版本里有个<code>vm.$get(expression)</code>方法，可以根据表达式获取vm上绑定的数据的值，并能进行一些简单的算术运算。在Vue2的版本里，这个方法被废弃了。但是在一些特殊场景下，我们可能还是需要这样一种方便获取对象属性值的方法。</p><a id="more"></a><p>比如有下面这样一个对象：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">  aa: <span class="number">1</span>,</span><br><span class="line">  bb: &#123;</span><br><span class="line">    xx: <span class="number">0</span>,</span><br><span class="line">    oo: <span class="literal">null</span>,</span><br><span class="line">    yy: <span class="number">2</span>,</span><br><span class="line">    zz: &#123;</span><br><span class="line">      ww: <span class="number">6</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>我们想实现一个方法：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> getObjectValue = <span class="function"><span class="keyword">function</span> (<span class="params">o, exp</span>) </span>&#123;</span><br><span class="line"><span class="comment">// todo</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>只需这样调用就可以直接输出对象的属性值：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">getObjectValue(obj, <span class="string">'aa'</span>) <span class="comment">// 1</span></span><br><span class="line">getObjectValue(obj, <span class="string">'bb.xx'</span>) <span class="comment">// 0</span></span><br><span class="line">getObjectValue(obj, <span class="string">'bb.zz.ww'</span>) <span class="comment">// 6</span></span><br><span class="line">getObjectValue(obj, <span class="string">'bb.oo'</span>) <span class="comment">//null</span></span><br><span class="line">getObjectValue(obj, <span class="string">'bb.oo.bar'</span>) <span class="comment">// undefined  当获取一个不存在的属性值时</span></span><br></pre></td></tr></table></figure><p>完整的代码实现如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> getObjectValue = (<span class="function"><span class="keyword">function</span> (<span class="params">undefined</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params">o, exp</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (o == <span class="literal">null</span> || <span class="keyword">typeof</span> exp !== <span class="string">'string'</span>) <span class="keyword">return</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> parts = exp.trim().split(<span class="string">'.'</span>)</span><br><span class="line">    <span class="keyword">var</span> len = parts.length</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">      <span class="keyword">if</span> (o[parts[i]] !== <span class="literal">undefined</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (o[parts[i]] === <span class="literal">null</span>) &#123;</span><br><span class="line">          <span class="keyword">return</span> i &lt; len - <span class="number">1</span> ? <span class="literal">undefined</span> : <span class="literal">null</span></span><br><span class="line">        &#125;</span><br><span class="line">        o = o[parts[i]]</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> o</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)()</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在Vue1.x版本里有个&lt;code&gt;vm.$get(expression)&lt;/code&gt;方法，可以根据表达式获取vm上绑定的数据的值，并能进行一些简单的算术运算。在Vue2的版本里，这个方法被废弃了。但是在一些特殊场景下，我们可能还是需要这样一种方便获取对象属性值的方法。&lt;/p&gt;
    
    </summary>
    
      <category term="web技术" scheme="https://vhtml.github.io/categories/web%E6%8A%80%E6%9C%AF/"/>
    
    
      <category term="javascript" scheme="https://vhtml.github.io/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>基于webpack的前端工程化开发之多页站点篇（二）</title>
    <link href="https://vhtml.github.io/2016/02/29/webpack-2/"/>
    <id>https://vhtml.github.io/2016/02/29/webpack-2/</id>
    <published>2016-02-29T08:31:09.000Z</published>
    <updated>2018-07-09T07:26:50.000Z</updated>
    
    <content type="html"><![CDATA[<p>这篇，我们要解决上篇留下的两个问题：</p><ul><li>webpack如何自动发现entry文件及进行相应的模板配置</li><li>如何直接处理后端模板的样式、脚本自动引入问题</li></ul><p>以express项目为例，使用express-generator构建一个初始项目，然后再添加需要的目录，最终的目录架构如下：</p><a id="more"></a><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">- website</span><br><span class="line">- bin<span class="comment">#express项目启动文件</span></span><br><span class="line">- <span class="class"><span class="keyword">lib</span><span class="comment">#express项目开发所需的库</span></span></span><br><span class="line">+ routes<span class="comment">#express项目路由</span></span><br><span class="line">    - src<span class="comment">#前端源码开发目录</span></span><br><span class="line">        - styles<span class="comment">#css目录，按照页面（模块）、通用、第三方三个级别进行组织</span></span><br><span class="line">            + page</span><br><span class="line">            + common</span><br><span class="line">            + <span class="class"><span class="keyword">lib</span></span></span><br><span class="line">        + imgs<span class="comment">#图片资源</span></span><br><span class="line">        - scripts<span class="comment">#JS脚本，按照page、components进行组织</span></span><br><span class="line">            + page</span><br><span class="line">            + components</span><br><span class="line">        + views<span class="comment">#HTML模板</span></span><br><span class="line">    - public<span class="comment">#webpack编译打包输出目录的静态文件，express工程的静态目录</span></span><br><span class="line">        + styles                </span><br><span class="line">        + scripts</span><br><span class="line">        + imgs</span><br><span class="line">    + views<span class="comment">#webpack编译输出的模板静态文件，express工程的视图模板 </span></span><br><span class="line">    + node_modules<span class="comment">#所使用的nodejs模块</span></span><br><span class="line">    package.json<span class="comment">#项目配置</span></span><br><span class="line">    webpack.config.js<span class="comment">#webpack配置</span></span><br><span class="line">    README.md<span class="comment">#项目说明</span></span><br></pre></td></tr></table></figure><blockquote><p>你同样可以根据个人喜好自由设计目录结构。完整的源码示例前往<a href="https://github.com/vhtml/webpack-MultiplePage" target="_blank" rel="noopener">https://github.com/vhtml/webpack-MultiplePage</a>。</p></blockquote><p>package.json里最终的声明依赖如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><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="string">"devDependencies"</span>: &#123;</span><br><span class="line">    <span class="string">"css-loader"</span>: <span class="string">"^0.23.1"</span>,</span><br><span class="line">    <span class="string">"extract-text-webpack-plugin"</span>: <span class="string">"^1.0.1"</span>,</span><br><span class="line">    <span class="string">"file-loader"</span>: <span class="string">"^0.8.5"</span>,</span><br><span class="line">    <span class="string">"glob"</span>: <span class="string">"^7.0.0"</span>,</span><br><span class="line">    <span class="string">"html-loader"</span>: <span class="string">"^0.4.3"</span>,</span><br><span class="line">    <span class="string">"html-webpack-plugin"</span>: <span class="string">"^2.9.0"</span>,</span><br><span class="line">    <span class="string">"jquery"</span>: <span class="string">"^1.12.0"</span>,</span><br><span class="line">    <span class="string">"less"</span>: <span class="string">"^2.6.0"</span>,</span><br><span class="line">    <span class="string">"less-loader"</span>: <span class="string">"^2.2.2"</span>,</span><br><span class="line">    <span class="string">"style-loader"</span>: <span class="string">"^0.13.0"</span>,</span><br><span class="line">    <span class="string">"url-loader"</span>: <span class="string">"^0.5.7"</span>,</span><br><span class="line">    <span class="string">"webpack"</span>: <span class="string">"^1.12.13"</span>,</span><br><span class="line">    <span class="string">"webpack-dev-server"</span>: <span class="string">"^1.14.1"</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看出，比上篇多了一个glob依赖，它是一个根据模式匹配获取文件列表的node模块。有关glob的详细用法可以在这里看到——<a href="https://github.com/isaacs/node-glob" target="_blank" rel="noopener">https://github.com/isaacs/node-glob</a>。利用glob模块可以很方便的获取src/scripts/page路径下的所有js入口文件。同理，可以实现自动的进行与入口文件相对应的模板配置。最终的webpack配置如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><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><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);</span><br><span class="line"><span class="keyword">var</span> glob = <span class="built_in">require</span>(<span class="string">'glob'</span>);</span><br><span class="line"><span class="keyword">var</span> webpack = <span class="built_in">require</span>(<span class="string">'webpack'</span>);</span><br><span class="line"><span class="keyword">var</span> ExtractTextPlugin = <span class="built_in">require</span>(<span class="string">'extract-text-webpack-plugin'</span>);</span><br><span class="line"><span class="keyword">var</span> HtmlWebpackPlugin = <span class="built_in">require</span>(<span class="string">'html-webpack-plugin'</span>);</span><br><span class="line"><span class="keyword">var</span> CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;</span><br><span class="line"><span class="keyword">var</span> UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> debug = process.env.NODE_ENV !== <span class="string">'production'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> entries = getEntry(<span class="string">'src/scripts/page/**/*.js'</span>, <span class="string">'src/scripts/page/'</span>);</span><br><span class="line"><span class="keyword">var</span> chunks = <span class="built_in">Object</span>.keys(entries);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> config = &#123;</span><br><span class="line">entry: entries,</span><br><span class="line">output: &#123;</span><br><span class="line">path: path.join(__dirname, <span class="string">'public'</span>),</span><br><span class="line">publicPath: <span class="string">'/static/'</span>,</span><br><span class="line">filename: <span class="string">'scripts/[name].js'</span>,</span><br><span class="line">chunkFilename: <span class="string">'scripts/[id].chunk.js'</span></span><br><span class="line">&#125;,</span><br><span class="line"><span class="built_in">module</span>: &#123;</span><br><span class="line">loaders: [ <span class="comment">//加载器</span></span><br><span class="line">&#123;</span><br><span class="line">test: <span class="regexp">/\.css$/</span>,</span><br><span class="line">loader: ExtractTextPlugin.extract(<span class="string">'style'</span>, <span class="string">'css'</span>)</span><br><span class="line">&#125;, &#123;</span><br><span class="line">test: <span class="regexp">/\.less$/</span>,</span><br><span class="line">loader: ExtractTextPlugin.extract(<span class="string">'css!less'</span>)</span><br><span class="line">&#125;, &#123;</span><br><span class="line">test: <span class="regexp">/\.html$/</span>,</span><br><span class="line">loader: <span class="string">"html"</span></span><br><span class="line">&#125;, &#123;</span><br><span class="line">test: <span class="regexp">/\.(woff|woff2|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/</span>,</span><br><span class="line">loader: <span class="string">'file-loader?name=fonts/[name].[ext]'</span></span><br><span class="line">&#125;, &#123;</span><br><span class="line">test: <span class="regexp">/\.(png|jpe?g|gif)$/</span>,</span><br><span class="line">loader: <span class="string">'url-loader?limit=8192&amp;name=imgs/[name]-[hash].[ext]'</span></span><br><span class="line">&#125;</span><br><span class="line">]</span><br><span class="line">&#125;,</span><br><span class="line">plugins: [</span><br><span class="line"><span class="keyword">new</span> webpack.ProvidePlugin(&#123; <span class="comment">//加载jq</span></span><br><span class="line">$: <span class="string">'jquery'</span></span><br><span class="line">&#125;),</span><br><span class="line"><span class="keyword">new</span> CommonsChunkPlugin(&#123;</span><br><span class="line">name: <span class="string">'vendors'</span>, <span class="comment">// 将公共模块提取，生成名为`vendors`的chunk</span></span><br><span class="line">chunks: chunks,</span><br><span class="line">minChunks: chunks.length <span class="comment">// 提取所有entry共同依赖的模块</span></span><br><span class="line">&#125;),</span><br><span class="line"><span class="keyword">new</span> ExtractTextPlugin(<span class="string">'styles/[name].css'</span>), <span class="comment">//单独使用link标签加载css并设置路径，相对于output配置中的publickPath</span></span><br><span class="line">debug ? <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;&#125; : <span class="keyword">new</span> UglifyJsPlugin(&#123; <span class="comment">//压缩代码</span></span><br><span class="line">compress: &#123;</span><br><span class="line">warnings: <span class="literal">false</span></span><br><span class="line">&#125;,</span><br><span class="line">except: [<span class="string">'$super'</span>, <span class="string">'$'</span>, <span class="string">'exports'</span>, <span class="string">'require'</span>] <span class="comment">//排除关键字</span></span><br><span class="line">&#125;),</span><br><span class="line"><span class="keyword">new</span> webpack.HotModuleReplacementPlugin() <span class="comment">//热加载</span></span><br><span class="line">],</span><br><span class="line">devServer: &#123;</span><br><span class="line">publicPath:<span class="string">'http://localhost:8080/static/'</span>,</span><br><span class="line">proxy: &#123;</span><br><span class="line"><span class="string">"*"</span>: <span class="string">"http://localhost:54999"</span></span><br><span class="line">&#125;,</span><br><span class="line">inline: <span class="literal">true</span>,</span><br><span class="line">hot: <span class="literal">true</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> pages = <span class="built_in">Object</span>.keys(getEntry(<span class="string">'src/views/**/*.html'</span>, <span class="string">'src/views/'</span>));</span><br><span class="line">pages.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">pathname</span>) </span>&#123;</span><br><span class="line"><span class="keyword">var</span> conf = &#123;</span><br><span class="line">filename: <span class="string">'../views/'</span> + pathname + <span class="string">'.html'</span>, <span class="comment">//生成的html存放路径，相对于path</span></span><br><span class="line">template: <span class="string">'src/views/'</span> + pathname + <span class="string">'.html'</span>, <span class="comment">//html模板路径</span></span><br><span class="line">inject: <span class="literal">false</span>,<span class="comment">//js插入的位置，true/'head'/'body'/false</span></span><br><span class="line">minify: &#123; <span class="comment">//压缩HTML文件</span></span><br><span class="line">removeComments: <span class="literal">true</span>, <span class="comment">//移除HTML中的注释</span></span><br><span class="line">collapseWhitespace: <span class="literal">false</span> <span class="comment">//删除空白符与换行符</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">if</span> (pathname <span class="keyword">in</span> config.entry) &#123;</span><br><span class="line">conf.inject = <span class="string">'body'</span>;</span><br><span class="line">conf.chunks = [<span class="string">'vendors'</span>, pathname];</span><br><span class="line">conf.hash = <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br><span class="line">config.plugins.push(<span class="keyword">new</span> HtmlWebpackPlugin(conf));</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = config;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getEntry</span>(<span class="params">globPath, pathDir</span>) </span>&#123;</span><br><span class="line"><span class="keyword">var</span> files = glob.sync(globPath);</span><br><span class="line"><span class="keyword">var</span> entries = &#123;&#125;,</span><br><span class="line">entry, dirname, basename, pathname, extname;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; files.length; i++) &#123;</span><br><span class="line">entry = files[i];</span><br><span class="line">dirname = path.dirname(entry);</span><br><span class="line">extname = path.extname(entry);</span><br><span class="line">basename = path.basename(entry, extname);</span><br><span class="line">pathname = path.join(dirname, basename);</span><br><span class="line">pathname = pathDir ? pathname.replace(<span class="keyword">new</span> <span class="built_in">RegExp</span>(<span class="string">'^'</span> + pathDir), <span class="string">''</span>) : pathname;</span><br><span class="line">entries[pathname] = <span class="string">'./'</span> + entry;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> entries;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里还要说说如何直接处理后端模板的问题。一开始本菜也是对这个问题进行了苦苦的探索，觉得可能真的实现不了，一度要放弃，并打算采用先纯静态打包再改写成后端模板的方式（因为貌似还没有这样的loader可以很智能的处理模板include的问题以及在非html模板中自动引入css和js）。但是这样做真的很蛋疼啊有木有！明明是一件事为什么要拆成两件事去做呢？！</p><p>如果你也进行过这样一番探索，你可能接触过像jade-loader、ejs-loader、ejs-compiled-loader等这样的webpack loader。无奈它们统统都不是我要找的，它们只是编译了模板而没有保留模板原有的生态，也不能自动地引入css和js。我也曾试过自己写loader将ejs模板先转成html模板（只处理include标签，其余原样保留）再用html-loader去处理，但又破坏了模板的可复用性，失去了灵活性。</p><p>好吧，其实只是想原样输出src/views中的模板，然后像上篇中那样自动引入css和js，仅此而已。没想到差一点钻了死胡同，想得过于复杂了。</p><p>我们应该先知道一个事实，html-webpack-plugin插件实现自动引入css和js的原理，是在模板中对应的成对head和body标签中进行解析插入。如果没有head和body标签，它会分别在模板头和尾生成这两个标签并插入link和script标签来引入css和js。而至于你的模板里写了什么，它是不会关心的。明白了这个原理，要完成“大业”就为期不远了。我们应该先改一改写模板的方式，模板结构一定要是类html的，不能是jade这种（还好我并不喜欢用jade）。以artTemplate模板为例，如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">&#123;&#123;include './common/meta'&#125;&#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">&#123;&#123;include './common/header'&#125;&#125;</span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-bd"</span>&gt;</span></span><br><span class="line">&#123;&#123;include './common/_content'&#125;&#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">&#123;&#123;include './common/footer'&#125;&#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>是的，没错，只要保留完整的head、body结构即可。然后根据上述的webpack配置，将与入口js对应的模板插入link和script标签并输出到./views目录中，其余模板原样输出到./views目录或相应的子目录下即可。</p><p>到此，“大业”完成。</p><p>假如你有更好的解决方案，欢迎一起分享。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;这篇，我们要解决上篇留下的两个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;webpack如何自动发现entry文件及进行相应的模板配置&lt;/li&gt;
&lt;li&gt;如何直接处理后端模板的样式、脚本自动引入问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以express项目为例，使用express-generator构建一个初始项目，然后再添加需要的目录，最终的目录架构如下：&lt;/p&gt;
    
    </summary>
    
      <category term="web技术" scheme="https://vhtml.github.io/categories/web%E6%8A%80%E6%9C%AF/"/>
    
    
      <category term="webpack" scheme="https://vhtml.github.io/tags/webpack/"/>
    
      <category term="前端工程化" scheme="https://vhtml.github.io/tags/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>基于webpack的前端工程化开发之多页站点篇（一）</title>
    <link href="https://vhtml.github.io/2016/02/26/webpack-1/"/>
    <id>https://vhtml.github.io/2016/02/26/webpack-1/</id>
    <published>2016-02-26T10:53:05.000Z</published>
    <updated>2018-07-09T07:26:50.000Z</updated>
    
    <content type="html"><![CDATA[<p>在最初接触webpack的较长一段时间里，我（也可能很多人）都觉得webpack是专为单页应用而量身打造的，比如webpack+react、webpack+vue等，都可以近乎完美的解决各种资源的依赖加载、打包的问题。甚至css都是打包在js里去动态添加到dom文档中去。</p><p>后来想想，这么好的工具这么好的方案为什么不能用在website（普通的web站点，姑且叫做website吧）中呢？</p><ul><li><p>首先对于普通的web站点，我们更倾向于将css独立出来，因为对于website来说，css还是要最先加载出来比较好。</p></li><li><p>再然后js我们也只想加载需要的部分，而不是一个大大的打包了所有js模块的包。</p></li></ul><a id="more"></a><p>在很多webpack入门级的demo里，无论是单入口的还是多入口的，都没有解决上面两个问题。入门毕竟是入门，要晋级还是只能靠自己。幸运的是，有很多优秀的工程师已为我们铺好了路，让我们在前端工程化的道路上少走很多的弯路。如果你也一样曾迷茫过，请不要走开，希望这里能为你答疑解惑。</p><p>好吧，以上通通是废话，接下来上干货。</p><hr><p>首先开始构建我们的项目目录结构。</p><h4 id="初始化项目、安装依赖"><a href="#初始化项目、安装依赖" class="headerlink" title="初始化项目、安装依赖"></a>初始化项目、安装依赖</h4><p>使用<code>npm init</code>初始化项目就不多说了，生成package.json文件。</p><p>使用<code>npm install plugins --save-dev</code>安装项目所需依赖。最终package.json的依赖声明如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><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="string">"devDependencies"</span>: &#123;</span><br><span class="line"><span class="string">"css-loader"</span>: <span class="string">"^0.23.1"</span>,</span><br><span class="line"><span class="string">"extract-text-webpack-plugin"</span>: <span class="string">"^1.0.1"</span>,</span><br><span class="line"><span class="string">"file-loader"</span>: <span class="string">"^0.8.5"</span>,</span><br><span class="line"><span class="string">"html-loader"</span>: <span class="string">"^0.4.3"</span>,</span><br><span class="line"><span class="string">"html-webpack-plugin"</span>: <span class="string">"^2.9.0"</span>,</span><br><span class="line"><span class="string">"jquery"</span>: <span class="string">"^1.12.0"</span>,</span><br><span class="line"><span class="string">"less"</span>: <span class="string">"^2.6.0"</span>,</span><br><span class="line"><span class="string">"less-loader"</span>: <span class="string">"^2.2.2"</span>,</span><br><span class="line"><span class="string">"style-loader"</span>: <span class="string">"^0.13.0"</span>,</span><br><span class="line"><span class="string">"url-loader"</span>: <span class="string">"^0.5.7"</span>,</span><br><span class="line"><span class="string">"webpack"</span>: <span class="string">"^1.12.13"</span>,</span><br><span class="line"><span class="string">"webpack-dev-server"</span>: <span class="string">"^1.14.1"</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="主要目录结构"><a href="#主要目录结构" class="headerlink" title="主要目录结构"></a>主要目录结构</h4><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">- website</span><br><span class="line">    - src                <span class="comment">#代码开发目录</span></span><br><span class="line">        - css            <span class="comment">#css目录，按照页面（模块）、通用、第三方三个级别进行组织</span></span><br><span class="line">            + page</span><br><span class="line">            + common</span><br><span class="line">            + <span class="class"><span class="keyword">lib</span></span></span><br><span class="line">        + img            <span class="comment">#图片资源</span></span><br><span class="line">        - js             <span class="comment">#JS脚本，按照page、components进行组织</span></span><br><span class="line">            + page</span><br><span class="line">            + components</span><br><span class="line">        + view           <span class="comment">#HTML模板</span></span><br><span class="line">    - dist               <span class="comment">#webpack编译打包输出目录，无需建立目录可由webpack根据配置自动生成</span></span><br><span class="line">        + css                </span><br><span class="line">        + js</span><br><span class="line">        + view</span><br><span class="line">    + node_modules       <span class="comment">#所使用的nodejs模块</span></span><br><span class="line">    package.json         <span class="comment">#项目配置</span></span><br><span class="line">    webpack.config.js    <span class="comment">#webpack配置</span></span><br><span class="line">    README.md            <span class="comment">#项目说明</span></span><br></pre></td></tr></table></figure><blockquote><p>假如你是一名纯粹的前端工程师，使用webpack构建website的目录结构大概就这样了，当然你也可以根据自己的喜好自由设计目录结构。</p><p>详细的代码全貌可以提前在这里“窥看”——<a href="https://github.com/vhtml/webpack-MultiPage-static" target="_blank" rel="noopener">https://github.com/vhtml/webpack-MultiPage-static</a>。</p></blockquote><p>目录组织好，我们就可以开始撸代码了。</p><h4 id="开发页面"><a href="#开发页面" class="headerlink" title="开发页面"></a>开发页面</h4><p>在src/js/page目录下建立index.js文件，在src/view目录下建立index.html文件。入口js和模板文件名对应。</p><p>index.js内容如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//引入css</span></span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/lib/reset.css"</span>);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/common/global.css"</span>);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/common/grid.css"</span>);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/page/index.less"</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">$(<span class="string">'.g-bd'</span>).append(<span class="string">'&lt;p class="text"&gt;这是由js生成的一句话。&lt;/p&gt;'</span>);</span><br></pre></td></tr></table></figure><p>index.html 内容如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">title</span>&gt;</span>首页<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"description"</span> <span class="attr">content</span>=<span class="string">"基于webpack的前端工程化开发解决方案探索"</span>/&gt;</span></span><br><span class="line"><span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">        描述：head中无需再引入css以及facicon，webpack将根据入口JS文件的要求自动实现按需加载或者生成style标签</span></span><br><span class="line"><span class="comment">    --&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-hd"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-bd"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">value</span>=<span class="string">"弹窗"</span> <span class="attr">class</span>=<span class="string">"btn"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">p</span> <span class="attr">class</span>=<span class="string">"img"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">"../img/4.png"</span> <span class="attr">alt</span>=<span class="string">""</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-ft"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">        描述：body中同样无需单独引入JS文件，webpack会根据入口JS文件自动实现按需加载或者生成script标签，还可以生成对应的hash值</span></span><br><span class="line"><span class="comment">    --&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>就是这样一个简单的HTML模板，我们甚至没有引入任何CSS和JS，通过webpack打包就可以自动帮我们引入。</p><p>由于是做website，在此之前相信你对单页应用打包已经有过了解，我就不客气了，再来两个页面压压惊。</p><p>about.js:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//引入css</span></span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/lib/reset.css"</span>);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/common/global.css"</span>);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/common/grid.css"</span>);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/page/about.less"</span>);</span><br><span class="line"></span><br><span class="line">$(<span class="string">'#about'</span>).html(<span class="string">'这是一个关于webpack构建工程的栗子'</span>);</span><br></pre></td></tr></table></figure><p>about.html:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">title</span>&gt;</span>关于<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"description"</span> <span class="attr">content</span>=<span class="string">"基于webpack的前端工程化开发解决方案探索"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-hd"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-bd"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"about"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-ft"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>list.js:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><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="comment">//引入css</span></span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/lib/reset.css"</span>);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/common/global.css"</span>);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/common/grid.css"</span>);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">"../../css/page/list.less"</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> html = <span class="string">''</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>;i&lt;<span class="number">5</span>;i++)&#123;</span><br><span class="line">html += <span class="string">'&lt;li&gt;列表'</span>+(i+<span class="number">1</span>)+<span class="string">'&lt;/li&gt;'</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">$(<span class="string">'#list'</span>).html(html);</span><br></pre></td></tr></table></figure><p>list.html:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">title</span>&gt;</span>列表页<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"description"</span> <span class="attr">content</span>=<span class="string">"基于webpack的前端工程化开发解决方案探索"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-hd"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-bd"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">ul</span> <span class="attr">id</span>=<span class="string">"list"</span>&gt;</span><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-ft"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>OK，太棒了！！！</p><h4 id="webpack配置"><a href="#webpack配置" class="headerlink" title="webpack配置"></a>webpack配置</h4><p>这里是关键，在webpack.config.js里，我们将进行一些配置，来完成我们的需求，一开始或许有点难理解，但等你真的掌握了，你便会惊呼它的神奇。配置中我写了详细的注释，要想彻底理解，还需多实践，多查阅文档，必要时看看源码，呜呼，学习之路漫漫兮。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><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><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);</span><br><span class="line"><span class="keyword">var</span> webpack = <span class="built_in">require</span>(<span class="string">'webpack'</span>);</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">extract-text-webpack-plugin插件，</span></span><br><span class="line"><span class="comment">有了它就可以将你的样式提取到单独的css文件里，</span></span><br><span class="line"><span class="comment">妈妈再也不用担心样式会被打包到js文件里了。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> ExtractTextPlugin = <span class="built_in">require</span>(<span class="string">'extract-text-webpack-plugin'</span>);</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">html-webpack-plugin插件，重中之重，webpack中生成HTML的插件，</span></span><br><span class="line"><span class="comment">具体可以去这里查看https://www.npmjs.com/package/html-webpack-plugin</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> HtmlWebpackPlugin = <span class="built_in">require</span>(<span class="string">'html-webpack-plugin'</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">entry: &#123; <span class="comment">//配置入口文件，有几个写几个</span></span><br><span class="line">index: <span class="string">'./src/js/page/index.js'</span>,</span><br><span class="line">list: <span class="string">'./src/js/page/list.js'</span>,</span><br><span class="line">about: <span class="string">'./src/js/page/about.js'</span>,</span><br><span class="line">&#125;,</span><br><span class="line">output: &#123; </span><br><span class="line">path: path.join(__dirname, <span class="string">'dist'</span>), <span class="comment">//输出目录的配置，模板、样式、脚本、图片等资源的路径配置都相对于它</span></span><br><span class="line">publicPath: <span class="string">'/dist/'</span>,<span class="comment">//模板、样式、脚本、图片等资源对应的server上的路径</span></span><br><span class="line">filename: <span class="string">'js/[name].js'</span>,<span class="comment">//每个页面对应的主js的生成配置</span></span><br><span class="line">chunkFilename: <span class="string">'js/[id].chunk.js'</span>   <span class="comment">//chunk生成的配置</span></span><br><span class="line">&#125;,</span><br><span class="line"><span class="built_in">module</span>: &#123;</span><br><span class="line">loaders: [ <span class="comment">//加载器，关于各个加载器的参数配置，可自行搜索之。</span></span><br><span class="line">&#123;</span><br><span class="line">test: <span class="regexp">/\.css$/</span>,</span><br><span class="line"><span class="comment">//配置css的抽取器、加载器。'-loader'可以省去</span></span><br><span class="line">loader: ExtractTextPlugin.extract(<span class="string">'style-loader'</span>, <span class="string">'css-loader'</span>) </span><br><span class="line">&#125;, &#123;</span><br><span class="line">test: <span class="regexp">/\.less$/</span>,</span><br><span class="line"><span class="comment">//配置less的抽取器、加载器。中间!有必要解释一下，</span></span><br><span class="line"><span class="comment">//根据从右到左的顺序依次调用less、css加载器，前一个的输出是后一个的输入</span></span><br><span class="line"><span class="comment">//你也可以开发自己的loader哟。有关loader的写法可自行谷歌之。</span></span><br><span class="line">loader: ExtractTextPlugin.extract(<span class="string">'css!less'</span>)</span><br><span class="line">&#125;, &#123;</span><br><span class="line"><span class="comment">//html模板加载器，可以处理引用的静态资源，默认配置参数attrs=img:src，处理图片的src引用的资源</span></span><br><span class="line"><span class="comment">//比如你配置，attrs=img:src img:data-src就可以一并处理data-src引用的资源了，就像下面这样</span></span><br><span class="line">test: <span class="regexp">/\.html$/</span>,</span><br><span class="line">loader: <span class="string">"html?attrs=img:src img:data-src"</span></span><br><span class="line">&#125;, &#123;</span><br><span class="line"><span class="comment">//文件加载器，处理文件静态资源</span></span><br><span class="line">test: <span class="regexp">/\.(woff|woff2|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/</span>,</span><br><span class="line">loader: <span class="string">'file-loader?name=./fonts/[name].[ext]'</span></span><br><span class="line">&#125;, &#123;</span><br><span class="line"><span class="comment">//图片加载器，雷同file-loader，更适合图片，可以将较小的图片转成base64，减少http请求</span></span><br><span class="line"><span class="comment">//如下配置，将小于8192byte的图片转成base64码</span></span><br><span class="line">test: <span class="regexp">/\.(png|jpg|gif)$/</span>,</span><br><span class="line">loader: <span class="string">'url-loader?limit=8192&amp;name=./img/[hash].[ext]'</span></span><br><span class="line">&#125;</span><br><span class="line">]</span><br><span class="line">&#125;,</span><br><span class="line">plugins: [</span><br><span class="line"><span class="keyword">new</span> webpack.ProvidePlugin(&#123; <span class="comment">//加载jq</span></span><br><span class="line">$: <span class="string">'jquery'</span></span><br><span class="line">&#125;),</span><br><span class="line"><span class="keyword">new</span> webpack.optimize.CommonsChunkPlugin(&#123;</span><br><span class="line">name: <span class="string">'vendors'</span>, <span class="comment">// 将公共模块提取，生成名为`vendors`的chunk</span></span><br><span class="line">chunks: [<span class="string">'index'</span>,<span class="string">'list'</span>,<span class="string">'about'</span>], <span class="comment">//提取哪些模块共有的部分</span></span><br><span class="line">minChunks: <span class="number">3</span> <span class="comment">// 提取至少3个模块共有的部分</span></span><br><span class="line">&#125;),</span><br><span class="line"><span class="keyword">new</span> ExtractTextPlugin(<span class="string">'css/[name].css'</span>), <span class="comment">//单独使用link标签加载css并设置路径，相对于output配置中的publickPath</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//HtmlWebpackPlugin，模板生成相关的配置，每个对于一个页面的配置，有几个写几个</span></span><br><span class="line"><span class="keyword">new</span> HtmlWebpackPlugin(&#123; <span class="comment">//根据模板插入css/js等生成最终HTML</span></span><br><span class="line">favicon: <span class="string">'./src/img/favicon.ico'</span>, <span class="comment">//favicon路径，通过webpack引入同时可以生成hash值</span></span><br><span class="line">filename: <span class="string">'./view/index.html'</span>, <span class="comment">//生成的html存放路径，相对于path</span></span><br><span class="line">template: <span class="string">'./src/view/index.html'</span>, <span class="comment">//html模板路径</span></span><br><span class="line">inject: <span class="string">'body'</span>, <span class="comment">//js插入的位置，true/'head'/'body'/false</span></span><br><span class="line">hash: <span class="literal">true</span>, <span class="comment">//为静态资源生成hash值</span></span><br><span class="line">chunks: [<span class="string">'vendors'</span>, <span class="string">'index'</span>],<span class="comment">//需要引入的chunk，不配置就会引入所有页面的资源</span></span><br><span class="line">minify: &#123; <span class="comment">//压缩HTML文件</span></span><br><span class="line">removeComments: <span class="literal">true</span>, <span class="comment">//移除HTML中的注释</span></span><br><span class="line">collapseWhitespace: <span class="literal">false</span> <span class="comment">//删除空白符与换行符</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;),</span><br><span class="line"><span class="keyword">new</span> HtmlWebpackPlugin(&#123; <span class="comment">//根据模板插入css/js等生成最终HTML</span></span><br><span class="line">favicon: <span class="string">'./src/img/favicon.ico'</span>, <span class="comment">//favicon路径，通过webpack引入同时可以生成hash值</span></span><br><span class="line">filename: <span class="string">'./view/list.html'</span>, <span class="comment">//生成的html存放路径，相对于path</span></span><br><span class="line">template: <span class="string">'./src/view/list.html'</span>, <span class="comment">//html模板路径</span></span><br><span class="line">inject: <span class="literal">true</span>, <span class="comment">//js插入的位置，true/'head'/'body'/false</span></span><br><span class="line">hash: <span class="literal">true</span>, <span class="comment">//为静态资源生成hash值</span></span><br><span class="line">chunks: [<span class="string">'vendors'</span>, <span class="string">'list'</span>],<span class="comment">//需要引入的chunk，不配置就会引入所有页面的资源</span></span><br><span class="line">minify: &#123; <span class="comment">//压缩HTML文件</span></span><br><span class="line">removeComments: <span class="literal">true</span>, <span class="comment">//移除HTML中的注释</span></span><br><span class="line">collapseWhitespace: <span class="literal">false</span> <span class="comment">//删除空白符与换行符</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;),</span><br><span class="line"><span class="keyword">new</span> HtmlWebpackPlugin(&#123; <span class="comment">//根据模板插入css/js等生成最终HTML</span></span><br><span class="line">favicon: <span class="string">'./src/img/favicon.ico'</span>, <span class="comment">//favicon路径，通过webpack引入同时可以生成hash值</span></span><br><span class="line">filename: <span class="string">'./view/about.html'</span>, <span class="comment">//生成的html存放路径，相对于path</span></span><br><span class="line">template: <span class="string">'./src/view/about.html'</span>, <span class="comment">//html模板路径</span></span><br><span class="line">inject: <span class="literal">true</span>, <span class="comment">//js插入的位置，true/'head'/'body'/false</span></span><br><span class="line">hash: <span class="literal">true</span>, <span class="comment">//为静态资源生成hash值</span></span><br><span class="line">chunks: [<span class="string">'vendors'</span>, <span class="string">'about'</span>],<span class="comment">//需要引入的chunk，不配置就会引入所有页面的资源</span></span><br><span class="line">minify: &#123; <span class="comment">//压缩HTML文件</span></span><br><span class="line">removeComments: <span class="literal">true</span>, <span class="comment">//移除HTML中的注释</span></span><br><span class="line">collapseWhitespace: <span class="literal">false</span> <span class="comment">//删除空白符与换行符</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;),</span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> webpack.HotModuleReplacementPlugin() <span class="comment">//热加载</span></span><br><span class="line">],</span><br><span class="line"><span class="comment">//使用webpack-dev-server，提高开发效率</span></span><br><span class="line">devServer: &#123;</span><br><span class="line">contentBase: <span class="string">'./'</span>,</span><br><span class="line">host: <span class="string">'localhost'</span>,</span><br><span class="line">port: <span class="number">9090</span>, <span class="comment">//默认8080</span></span><br><span class="line">inline: <span class="literal">true</span>, <span class="comment">//可以监控js变化</span></span><br><span class="line">hot: <span class="literal">true</span>, <span class="comment">//热启动</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>好了，完成以上的这些配置之后，执行<code>webpack</code>打包命令完成项目打包。</p><p>此时，前往/dist/view目录下查看生成的list.html文件，如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">title</span>&gt;</span>列表页<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"description"</span> <span class="attr">content</span>=<span class="string">"基于webpack的前端工程化开发解决方案探索"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"shortcut icon"</span> <span class="attr">href</span>=<span class="string">"/dist/favicon.ico"</span>&gt;</span><span class="tag">&lt;<span class="name">link</span> <span class="attr">href</span>=<span class="string">"/dist/css/vendors.css?02568e631b7717b7149a"</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span>&gt;</span><span class="tag">&lt;<span class="name">link</span> <span class="attr">href</span>=<span class="string">"/dist/css/list.css?02568e631b7717b7149a"</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span>&gt;</span><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-hd"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-bd"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">ul</span> <span class="attr">id</span>=<span class="string">"list"</span>&gt;</span><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"g-ft"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"/dist/js/vendors.js?02568e631b7717b7149a"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"/dist/js/list.js?02568e631b7717b7149a"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>可以看到生成的文件除了保留原模板中的内容以外，还根据入口文件list.js的定义，自动添加需要引入CSS与JS文件，以及favicon，同时还添加了相应的hash值。</p><p>执行<code>webpack-dev-server</code>启动devServer，打开<a href="http://localhost:9090/dist/view/index.html" target="_blank" rel="noopener">http://localhost:9090/dist/view/index.html</a> 就可以进行页面的预览了。说明我们的资源路径生成也是没有问题的。</p><p>好了，纯静态的webpack前端构建过程就是这样了。然而你可能还有疑问。</p><ul><li>假如你是个懒人，可能会觉得目前的配置不够智能，每增加一个页面，就得再手动添加入口文件及模板配置。</li><li>假如你是个全栈工程师或者以nodejs做中间层的开发者，你的模板不是纯粹的html，但是又需要像html模板那样能自动根据需要添加css与js文件。</li></ul><p>还等什么，快来这里看看吧——<a href="https://github.com/vhtml/webpack-MultiplePage" target="_blank" rel="noopener">基于webpack的前端工程化开发之多页站点篇（二）</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在最初接触webpack的较长一段时间里，我（也可能很多人）都觉得webpack是专为单页应用而量身打造的，比如webpack+react、webpack+vue等，都可以近乎完美的解决各种资源的依赖加载、打包的问题。甚至css都是打包在js里去动态添加到dom文档中去。&lt;/p&gt;
&lt;p&gt;后来想想，这么好的工具这么好的方案为什么不能用在website（普通的web站点，姑且叫做website吧）中呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;首先对于普通的web站点，我们更倾向于将css独立出来，因为对于website来说，css还是要最先加载出来比较好。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;再然后js我们也只想加载需要的部分，而不是一个大大的打包了所有js模块的包。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
      <category term="web技术" scheme="https://vhtml.github.io/categories/web%E6%8A%80%E6%9C%AF/"/>
    
    
      <category term="webpack" scheme="https://vhtml.github.io/tags/webpack/"/>
    
      <category term="前端工程化" scheme="https://vhtml.github.io/tags/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>你未必知道的JSON.parse和JSON.stringify</title>
    <link href="https://vhtml.github.io/2016/02/16/JSON/"/>
    <id>https://vhtml.github.io/2016/02/16/JSON/</id>
    <published>2016-02-16T08:15:04.000Z</published>
    <updated>2018-07-09T07:26:50.000Z</updated>
    
    <content type="html"><![CDATA[<h3 id="JSON-parse"><a href="#JSON-parse" class="headerlink" title="JSON.parse()"></a>JSON.parse()</h3><p>解析JSON格式的字符串。</p><p>我们通常的使用语法是：<code>JSON.parse(s)</code>。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> o = <span class="built_in">JSON</span>.parse(<span class="string">'&#123;"a":1,"b":2&#125;'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(o);</span><br><span class="line"><span class="comment">//Object &#123;a: 1, b: 2&#125;</span></span><br></pre></td></tr></table></figure><p>其实它还能接收第二个参数：<code>JSON.parse(s, reviver)</code>。</p><a id="more"></a><blockquote><p>reviver是用来转换解析值的可选函数。如果指定了reviver函数，该函数会为从s中解析的每一个原始值（不是包含这些原始值的对象或数组）调用一次。reviver接收两个参数，第一个参数是属性名——对象的属性名或转换成字符串的数组序号。第二个参数是对象属性或数组元素的原始值。reviver会作为包含原始值的对象或数组的方法来调用。在特殊情况下，如果字符串s表示的是原始值而不是更常见的对象或数组时，那么该原始值会存放在一个新创建对象的属性中，属性名是空字符串。这时，reviver会在这个新创建的对象上调用一次，第一个参数是空字符串，第二个参数则是该原始值。</p></blockquote><blockquote><p>reviver函数的返回值会成为属性的新值。如果reviver返回第二个参数，该属性保持不变。如果reviver返回undefined（或不返回），则会从对象或数组中删除该属性，处理完后才由JSON.parse()返回给用户。</p></blockquote><p>示例：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> text = <span class="string">'&#123;"a":1,"_b":2,"t":1455591901242&#125;'</span>;</span><br><span class="line"><span class="keyword">var</span> data = <span class="built_in">JSON</span>.parse(text, <span class="function"><span class="keyword">function</span>(<span class="params">name, value</span>)</span>&#123;</span><br><span class="line"><span class="comment">//移除掉所有属性名以下划线开头的属性</span></span><br><span class="line"><span class="keyword">if</span>(name[<span class="number">0</span>] == <span class="string">'_'</span>) <span class="keyword">return</span>;</span><br><span class="line"><span class="comment">//如果属性名是t，并且值为整数，则转换为Date</span></span><br><span class="line"><span class="keyword">if</span>(name == <span class="string">'t'</span> &amp;&amp; <span class="regexp">/^-?\d+$/</span>.test(value))</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Date</span>(value);</span><br><span class="line"><span class="comment">//否则，原样返回</span></span><br><span class="line"><span class="keyword">return</span> value;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="JSON-stringify"><a href="#JSON-stringify" class="headerlink" title="JSON.stringify()"></a>JSON.stringify()</h3><p>序列化对象、数组或原始值。序列化后生成的字符串可以被JSON.parse()解析。</p><p>我们通常这样使用：<code>JSON.stringify(o)</code>。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> s = <span class="built_in">JSON</span>.stringify(&#123;<span class="attr">a</span>:<span class="number">1</span>,<span class="attr">b</span>:<span class="number">2</span>&#125;);</span><br><span class="line"><span class="built_in">console</span>.log(s);<span class="comment">//&#123;"a":1,"b":2&#125;</span></span><br></pre></td></tr></table></figure><p>当JSON.stringify()遇到带有名为toJSON()的方法的对象或数组时，它会调用该对象上的toJSON()方法。例如：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Object</span>.prototype.toJSON = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"><span class="keyword">return</span> <span class="string">'hehe'</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> s = <span class="built_in">JSON</span>.stringify(&#123;<span class="attr">a</span>:<span class="number">1</span>,<span class="attr">b</span>:<span class="number">2</span>&#125;);</span><br><span class="line"><span class="built_in">console</span>.log(s);<span class="comment">//"hehe"</span></span><br></pre></td></tr></table></figure><p>其实它也能接收第二个参数：<code>JSON.stringify(o, filter)</code>。</p><blockquote><p>该参数可以是一个可选函数，用来在字符串化前做一些替换；也可以是一个数组，包含那些需要字符串化的属性名。该参数可以在字符串化的过程中添加过滤操作。如果该参数是函数，则它是一个replacer函数，与上面介绍的toJSON()类似。如果指定replacer函数，该函数会在每一个需要字符串化的值上调用，this指向定义该值的对象或数组。replacer函数的第一个参数是该对象中的对象属性名或数组序号，第二个参数是值本身。replacer函数的返回值会替换需要字符串化的值。如果replacer函数返回undefined则会被忽略。</p><p>如果JSON.stringify()的第二个参数是一个数组，该数组会作为对象属性名。只有属性名包含在数组里的值才会被序列号，其他被忽略。</p></blockquote><p>示例：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> o = &#123;</span><br><span class="line">a: <span class="number">1</span>,</span><br><span class="line">b: <span class="number">2</span>,</span><br><span class="line">t: <span class="regexp">/\d+/</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//指定要序列化的字段</span></span><br><span class="line"><span class="keyword">var</span> text = <span class="built_in">JSON</span>.stringify(o, [<span class="string">'a'</span>,<span class="string">'b'</span>]);</span><br><span class="line"><span class="built_in">console</span>.log(text); <span class="comment">//&#123;"a":1,"b":2&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//指定replacer函数，使RegExp得以序列化</span></span><br><span class="line"><span class="keyword">var</span> text2 = <span class="built_in">JSON</span>.stringify(o, <span class="function"><span class="keyword">function</span>(<span class="params">key, value</span>)</span>&#123;</span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">typeof</span> value);</span><br><span class="line"><span class="keyword">if</span>(value.constructor === <span class="built_in">RegExp</span>)&#123;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> value.toString();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> value;</span><br><span class="line">&#125;);</span><br><span class="line"><span class="built_in">console</span>.log(text2); <span class="comment">//&#123;"a":1,"b":2,"t":"\\d+"&#125;</span></span><br><span class="line"><span class="comment">//或使用toJSON实现同样的替换</span></span><br><span class="line"><span class="built_in">RegExp</span>.prototype.toJSON = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;<span class="keyword">return</span> <span class="keyword">this</span>.toString();&#125;</span><br></pre></td></tr></table></figure><p>JSON.stringify还能接收第三个参数：<code>JSON.stringify(o, filter, indent)</code>。</p><blockquote><p>使用indent参数可以指定缩进字符串或用来缩进的空格个数。</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> t = <span class="built_in">JSON</span>.stringify(&#123;<span class="attr">a</span>:<span class="number">1</span>,<span class="attr">b</span>:<span class="number">2</span>&#125;,<span class="literal">null</span>,<span class="number">4</span>);</span><br><span class="line"><span class="built_in">console</span>.log(t);</span><br><span class="line"><span class="comment">//string</span></span><br><span class="line"><span class="comment">//&#123;</span></span><br><span class="line"><span class="comment">//    "a": 1,</span></span><br><span class="line"><span class="comment">//    "b": 2</span></span><br><span class="line"><span class="comment">//&#125;</span></span><br></pre></td></tr></table></figure><p>小技巧：使用JSON.parse和JSON.stringify实现的简单的对象深度复制。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">cloneObject</span>(<span class="params">o</span>)</span>&#123; </span><br><span class="line"><span class="keyword">return</span> <span class="built_in">JSON</span>.parse(<span class="built_in">JSON</span>.stringify(o));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;JSON-parse&quot;&gt;&lt;a href=&quot;#JSON-parse&quot; class=&quot;headerlink&quot; title=&quot;JSON.parse()&quot;&gt;&lt;/a&gt;JSON.parse()&lt;/h3&gt;&lt;p&gt;解析JSON格式的字符串。&lt;/p&gt;
&lt;p&gt;我们通常的使用语法是：&lt;code&gt;JSON.parse(s)&lt;/code&gt;。&lt;/p&gt;
&lt;figure class=&quot;highlight javascript&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; o = &lt;span class=&quot;built_in&quot;&gt;JSON&lt;/span&gt;.parse(&lt;span class=&quot;string&quot;&gt;&#39;&amp;#123;&quot;a&quot;:1,&quot;b&quot;:2&amp;#125;&#39;&lt;/span&gt;);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;console&lt;/span&gt;.log(o);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;//Object &amp;#123;a: 1, b: 2&amp;#125;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;其实它还能接收第二个参数：&lt;code&gt;JSON.parse(s, reviver)&lt;/code&gt;。&lt;/p&gt;
    
    </summary>
    
      <category term="web技术" scheme="https://vhtml.github.io/categories/web%E6%8A%80%E6%9C%AF/"/>
    
    
      <category term="javascript" scheme="https://vhtml.github.io/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>《高效率Javascript》阅读笔记</title>
    <link href="https://vhtml.github.io/2016/01/25/effect-js/"/>
    <id>https://vhtml.github.io/2016/01/25/effect-js/</id>
    <published>2016-01-25T09:59:55.000Z</published>
    <updated>2018-07-09T07:26:50.000Z</updated>
    
    <content type="html"><![CDATA[<p>以下是阅读《Effective Javascript》一书所做的一些简单的笔记（部分内容并不适合ES6）：</p><h4 id="一、让自己习惯javascript"><a href="#一、让自己习惯javascript" class="headerlink" title="一、让自己习惯javascript"></a>一、让自己习惯javascript</h4><a id="more"></a><ol><li><p>在代码中使用严格模式</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"><span class="meta">'use strict'</span>;</span><br><span class="line"><span class="comment">//your code</span></span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure></li><li><p>小心js中的浮点数</p><p> <code>0.1+0.2+0.3 != 0.1+(0.2+0.3)</code></p><p> 转换为整数计算</p><p> <code>1+2+3 == 1+(2+3)</code></p><p> 浮点数有舍入误差，整数不会</p></li><li><p>当心隐式的强制转换</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>+<span class="literal">true</span> <span class="comment">//2</span></span><br><span class="line"><span class="number">1</span>+<span class="number">2</span> <span class="comment">//3</span></span><br><span class="line"><span class="number">1</span>+<span class="string">'2'</span> <span class="comment">//12</span></span><br><span class="line"><span class="number">1</span>+<span class="number">2</span>+<span class="string">'3'</span> <span class="comment">//33</span></span><br><span class="line"><span class="number">1</span>+<span class="string">'2'</span>+<span class="number">3</span> <span class="comment">//123</span></span><br></pre></td></tr></table></figure><p> 判断NaN</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">isNaN</span>(<span class="literal">NaN</span>) <span class="comment">//true</span></span><br><span class="line"><span class="built_in">isNaN</span>(<span class="string">'foo'</span>) <span class="comment">//true</span></span><br></pre></td></tr></table></figure><p> 看来标准库函数isNaN也不是很可靠，其会进行隐式类型转换，对于确定是数字的可以使用该方法。</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//使用原理：NaN是js中唯一一个不等于其自身的值</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isReallyNaN</span>(<span class="params">x</span>)</span>&#123;</span><br><span class="line"><span class="keyword">return</span> x !== x;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>原始类型优于封装对象</p><p> 对原始值设置属性，毫无作用，因为每次隐式封装，都会产生一个新的对象。</p><ul><li>获取或设置原始类型值的属性会隐式的创建封装对象。</li><li><p>当做相等比较时，原始类型的封装对象与其原始值行为不一样。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">'xx'</span>.someProperty = <span class="string">'11'</span>;</span><br><span class="line"><span class="string">'xx'</span>.someProperty <span class="comment">//undefined</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> x = <span class="string">'111'</span>;</span><br><span class="line">x.ss = <span class="string">'222'</span>;</span><br><span class="line">x.ss; <span class="comment">//undefined</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> s = <span class="keyword">new</span> <span class="built_in">String</span>(<span class="string">'dd'</span>);</span><br><span class="line">s.n = <span class="number">1</span>;</span><br><span class="line">s.n; <span class="comment">//1</span></span><br></pre></td></tr></table></figure></li></ul></li><li><p>避免对混合类型使用<code>==</code>运算符</p><blockquote><p>显示地定义转换的逻辑能确保你不会混淆<code>==</code>运算符的强制转换规则</p></blockquote></li><li><p>了解分号插入的局限</p></li><li><p>视字符串为16位的代码单元系列</p></li></ol><h4 id="二、变量作用域"><a href="#二、变量作用域" class="headerlink" title="二、变量作用域"></a>二、变量作用域</h4><ol start="8"><li><p>尽量少用全局对象</p></li><li><p>始终声明局部变量</p></li><li><p>避免使用with</p></li><li><p>熟练掌握闭包</p><p>掌握闭包的三个基本事实：</p><ol><li>js允许你引用在函数以外定义的变量。</li><li>即使外部函数已经返回，当前函数仍然可以引用在外部函数所定义的变量。</li><li>闭包可以更新外部变量的值。</li></ol><blockquote><p>函数可以引用定义在其外部作用域的变量。<br>闭包比创建他的函数有更长的生命周期。<br>闭包在内部存储其外部变量的引用，并能读写这些变量。</p></blockquote></li><li><p>理解变量声明提升</p></li><li><p>使用立即调用的函数表达式创建局部作用域</p><blockquote><p>闭包通过引用而不是值捕获它们的外部变量。</p></blockquote></li><li><p>当心命名函数表达式笨拙的作用域</p></li><li><p>当心局部块函数声明笨拙的作用域</p></li><li><p>避免使用eval创建局部变量</p><blockquote><p>容易造成变量污染</p></blockquote></li><li><p>间接调用eval函数优于直接调用</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> x = <span class="string">'global'</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"><span class="keyword">var</span> x = <span class="string">'local'</span>;</span><br><span class="line"><span class="keyword">var</span> f = <span class="built_in">eval</span>;</span><br><span class="line"><span class="keyword">return</span> f(<span class="string">'x'</span>); <span class="comment">//非直接调用</span></span><br><span class="line">&#125;</span><br><span class="line">test(); <span class="comment">// "global"</span></span><br></pre></td></tr></table></figure><blockquote><p>编写简介调用eval函数的一种简洁方式是使用表达式序列运算符(,)和一个明显毫无意义的数字字面量。<code>(0,eval)(src)</code></p></blockquote></li></ol><h4 id="三、使用函数"><a href="#三、使用函数" class="headerlink" title="三、使用函数"></a>三、使用函数</h4><ol start="18"><li><p>理解函数调用、方法调用和构造函数调用之间的区别</p></li><li><p>熟练掌握高阶函数</p><blockquote><p>高阶函数是那些将函数作为参数或返回值的函数<br>熟悉掌握现有库中的高阶函数<br>学会发现可以被高阶函数所取代的常见的编码模式</p></blockquote></li><li><p>使用call方法自定义接收者来调用方法</p></li><li><p>使用apply方法通过不同数量的参数调用函数</p></li><li><p>使用arguments创建可变参数的函数</p></li><li><p>永远不要修改arguments对象</p><blockquote><p>可使用[].slice.call(arguments)将arguments对象复制到一个真正的数组中再进行修改。</p></blockquote></li><li><p>使用变量保存arguments的引用</p></li><li><p>使用bind方法提取具有确定接收者的方法</p><p>bind创建一个新函数而不是修改了原函数</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> x=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line">x.bind(<span class="built_in">document</span>) === x;<span class="comment">//false</span></span><br></pre></td></tr></table></figure></li><li><p>使用bind方法实现函数柯里化</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">simpleURL</span>(<span class="params">protocal, domain, path</span>)</span>&#123;</span><br><span class="line"><span class="keyword">return</span> protocal+<span class="string">'//'</span>+domain+<span class="string">'/'</span>+path;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> urls = paths.map(<span class="function"><span class="keyword">function</span>(<span class="params">path</span>)</span>&#123;</span><br><span class="line">simple(<span class="string">'http'</span>,siteDomain,path);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">var</span> urls = paths.map(simpleURL.bind(<span class="literal">null</span>,<span class="string">'http'</span>,siteDomain));</span><br></pre></td></tr></table></figure></li><li><p>使用闭包而不是字符串来封装代码</p></li><li><p>不要信赖函数对象的toString方法</p><blockquote><p>当调用函数的<code>toString</code>方法时，并没有要求js引擎输出函数的源码，且不同引擎输出结果可能不同。<br><code>toString</code>方法的输出结果并不会暴露存储在闭包中的局部变量值。</p></blockquote></li><li><p>避免使用非标准的栈检查属性。</p><blockquote><p>避免使用非标准的arguments.callee和arguments.caller属性，因为他们不具有良好的移植性。<br>避免使用非标准的函数对象caller属性，因为在包含全栈信息方面，它是不可靠的，例如函数自身循环引用。</p></blockquote></li></ol><h4 id="四、对象和原型"><a href="#四、对象和原型" class="headerlink" title="四、对象和原型"></a>四、对象和原型</h4><ol start="30"><li><p>理解prototype、getPrototypeOf、<strong>proto</strong>之间的不同</p><blockquote><p>C.prototype属性的new C()创建的对象的原型。<br>Object.getPrototypeOf(obj)是ES5中检索对象原型的标准方法。<br>obj.<strong>proto</strong>是检索对象原型的非标准方法。<br>类是由一个构造函数和一个关联的原型组成的一种设计模式。</p></blockquote></li><li><p>使用Object.getPrototypeOf函数而不要使用<strong>proto</strong>属性</p><blockquote><p>对于不支持ES5 API的可以使用该属性</p></blockquote></li><li><p>使用不要修改<strong>proto</strong>属性</p></li><li><p>使构造函数与new操作符无关</p><p>使用Object.create函数，该函数需要一个原型对象作为参数，并返回一个继承自该原型对象的新对象。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(<span class="keyword">typeof</span> <span class="built_in">Object</span>.create === <span class="string">'undefined'</span>)&#123;</span><br><span class="line"><span class="built_in">Object</span>.create = <span class="function"><span class="keyword">function</span>(<span class="params">prototype</span>)</span>&#123;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">C</span>(<span class="params"></span>)</span>&#123;&#125;</span><br><span class="line">C.prototype = prototype;</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> C();</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">User</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line"><span class="keyword">var</span> self = <span class="keyword">this</span> <span class="keyword">instanceof</span> User</span><br><span class="line">? <span class="keyword">this</span></span><br><span class="line">: <span class="built_in">Object</span>.create(User.prototype);</span><br><span class="line">self.name = name;</span><br><span class="line"><span class="keyword">return</span> self;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>在原型中存储方法</p></li><li><p>使用闭包存储私有数据</p></li><li><p>只将实例对象存储在实例对象中</p><blockquote><p>共享可变数据可能会出问题，因为原型是被其所有的实例共享的。<br>将可变的实例状态存储在实例对象中。</p></blockquote></li><li><p>认识到this变量的隐式绑定问题。</p><p>例如在map、forEach参数调用中：</p><blockquote><p>this变量的作用域总是由其最近的封闭函数所确定。<br>使用一个局部变量（self,me,that）使得this绑定对于内部函数是可用的。<br>map、forEach都提供第三个参数作为其回调函数的this绑定。<br>在回调函数中使用bind绑定。<br>使用局部变量缓存this。</p></blockquote><pre><code>[].map(fn, o);[].forEach(fn,o);[].map(fn.bind(this));[].forEach(fn.bind(this));</code></pre></li><li><p>在子类的构造函数中调用父类的构造函数</p><p>说白了，就是面向对象的继承和多态。</p><blockquote><p>在子类构造函数中显示的传入this作为显示的接收者调用父类构造函数。<br>使用Object.create函数来构造子类的原型对象以避免调用父类的构造函数。</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Actor</span>(<span class="params">scene,x,y</span>)</span>&#123;</span><br><span class="line"><span class="keyword">this</span>.scene = scene;</span><br><span class="line"><span class="keyword">this</span>.x = x;</span><br><span class="line"><span class="keyword">this</span>.y = y;</span><br><span class="line">scene.register(<span class="keyword">this</span>);</span><br><span class="line">&#125;</span><br><span class="line">Actor.prototype.moveTo = <span class="function"><span class="keyword">function</span>(<span class="params">x,y</span>)</span>&#123;</span><br><span class="line"><span class="keyword">this</span>.x = x;</span><br><span class="line"><span class="keyword">this</span>.y = y;</span><br><span class="line"><span class="keyword">this</span>.scene.draw();</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SpaceShip</span>(<span class="params">scene,x,y</span>)</span>&#123;</span><br><span class="line">Actor.call(<span class="keyword">this</span>,scene,x,y);</span><br><span class="line"><span class="keyword">this</span>.points = <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line">SpaceShip.prototype = <span class="built_in">Object</span>.create(Actor.prototype);</span><br></pre></td></tr></table></figure></li><li><p>不要重用父类的属性名</p><blockquote><p>如果在继承体系中的两个类指向相同的属性名，那么它们指向的是同一个属性。</p></blockquote></li><li><p>避免继承标准类</p><blockquote><p>继承标准类往往会由于一些特殊的内部属性（如[[Class]]）而被破坏。<br>使用属性委托优于继承标准类。</p></blockquote></li><li><p>将原型视为实现细节</p><blockquote><p>js提供了便利的内省机制(introspection mechanisms)来检查对象的细节。<code>Object.prototype.hasOwnProperty/Object.getPrototypeOf</code> </p></blockquote></li><li><p>避免使用轻率的猴子补丁</p><p>由于对象共享原型，因为每一个对象都可以增加、删除或修改原型的属性。</p><blockquote><p>避免使用轻率的猴子补丁。<br>记录程序库所执行的所有猴子补丁。<br>考虑通过将修改置于一个导出函数中，使猴子补丁成为可选的。<br>使用猴子补丁为缺失的标准API提供polyfills。</p></blockquote><p>一个较为靠谱的做法是</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(<span class="keyword">typeof</span> <span class="built_in">Array</span>.prototype.map !==<span class="string">'function'</span>)&#123;</span><br><span class="line"><span class="built_in">Array</span>.prototype.map = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;&#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h4 id="五、数组和字典"><a href="#五、数组和字典" class="headerlink" title="五、数组和字典"></a>五、数组和字典</h4><ol start="43"><li><p>使用Object的直接实例构造轻量级的字典</p><p>JavaScript对象的核心是一个字符串属性名称与属性值的映射表。这使得使用对象实现字典易如反掌，因为字典就是可变长的字符串与值的映射集合。配合对象枚举利器：for…in循环。</p></li><li><p>使用null原型以防止原型污染</p><blockquote><p>在ES5环境中，使用<code>Object.create(null)</code>创建的自由原型的空对象是不太容易被污染的。<br>在一些较老的环境中，考虑使用{<strong>proto</strong>:null}。<br>但要注意<strong>proto</strong>既不标准也不完全可移植，将来可能会去除。</p></blockquote></li><li><p>使用hasOwnProperty方法以避免原型污染。</p><blockquote><p>使用词法作用域和call方法避免覆盖hasOwnProperty方法。<br>使用字典类避免将’<strong>proto</strong>‘作为key来使用。</p></blockquote><p>终极词典代码实现：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Dict</span>(<span class="params">elements</span>)</span>&#123;</span><br><span class="line"><span class="keyword">this</span>.elements = elements;</span><br><span class="line"><span class="keyword">this</span>.hasSpecialProto = <span class="literal">false</span>;</span><br><span class="line"><span class="keyword">this</span>.specialProto = <span class="literal">undefined</span>;</span><br><span class="line">&#125;</span><br><span class="line">Dict.prototype.has = <span class="function"><span class="keyword">function</span>(<span class="params">key</span>)</span>&#123;</span><br><span class="line"><span class="keyword">if</span>(key === <span class="string">'__proto__'</span>)&#123;</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">this</span>.hasSpecialProto;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> &#123;&#125;.hasOwnProperty.call(<span class="keyword">this</span>.elements,key);</span><br><span class="line">&#125;;</span><br><span class="line">Dict.prototype.get = <span class="function"><span class="keyword">function</span>(<span class="params">key</span>)</span>&#123;</span><br><span class="line"><span class="keyword">if</span>(key === <span class="string">'__proto__'</span>)&#123;</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">this</span>.specialProto;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">this</span>.has(key)?<span class="keyword">this</span>.elements[key]:<span class="literal">undefined</span>;</span><br><span class="line">&#125;;</span><br><span class="line">Dict.prototype.set = <span class="function"><span class="keyword">function</span>(<span class="params">key, val</span>)</span>&#123;</span><br><span class="line"><span class="keyword">if</span>(key === <span class="string">'__proto__'</span>)&#123;</span><br><span class="line"><span class="keyword">this</span>.hasSpecialProto = <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">this</span>.specialProto = val;</span><br><span class="line">&#125;<span class="keyword">else</span>&#123;</span><br><span class="line"><span class="keyword">this</span>.elements[key] = val;</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line">Dict.prototype.remove = <span class="function"><span class="keyword">function</span>(<span class="params">key</span>)</span>&#123;</span><br><span class="line"><span class="keyword">if</span>(key === <span class="string">'__proto__'</span>)&#123;</span><br><span class="line"><span class="keyword">this</span>.hasSpecialProto = <span class="literal">false</span>;</span><br><span class="line"><span class="keyword">this</span>.specialProto = <span class="literal">undefined</span>;</span><br><span class="line">&#125;<span class="keyword">else</span>&#123;</span><br><span class="line"><span class="keyword">delete</span> <span class="keyword">this</span>.elements[key];</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">var</span> dict = <span class="keyword">new</span> Dict();</span><br><span class="line">dict.set(<span class="string">'__proto__'</span>,<span class="number">1</span>);</span><br><span class="line"><span class="built_in">console</span>.log(dict.has(<span class="string">'__proto__'</span>));</span><br></pre></td></tr></table></figure></li><li><p>使用数组而不要使用字典来存储有序集合</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ratings = &#123;</span><br><span class="line"><span class="string">'haha'</span>:<span class="number">0.8</span>,</span><br><span class="line"><span class="string">'xixi'</span>:<span class="number">0.7</span>,</span><br><span class="line"><span class="string">'21'</span>:<span class="number">0.6</span>,</span><br><span class="line"><span class="string">'hehe'</span>:<span class="number">0.9</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">var</span> total = <span class="number">0</span>,count=<span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> key <span class="keyword">in</span> ratings)&#123;</span><br><span class="line">total += ratings[key];</span><br><span class="line"><span class="built_in">console</span>.log(key);</span><br><span class="line">count++;</span><br><span class="line">&#125;</span><br><span class="line">total /= count;</span><br><span class="line"><span class="built_in">console</span>.log(total);</span><br></pre></td></tr></table></figure><blockquote><p>使用for…in循环来枚举对象属性应当与顺序无关。<br>如果聚集运算字典中的数据，确保聚集操作与顺序无关。<br>使用数组而不是字典来存储有序集合。</p></blockquote></li><li><p>绝对不要在Object.prototype中增加可枚举的属性</p><blockquote><p>使用<code>Object.defineProperty</code>方法定义不可枚举属性。<br>使用<code>{}.hasOwnProperty</code>判断是否是原型上的方法。</p></blockquote></li><li><p>避免在枚举期间修改对象</p></li><li><p>数组迭代要优先使用for循环而不是for…in循环</p></li><li><p>迭代方法优于循环</p><blockquote><p>使用迭代方法（forEach,map,filter）替代for循环使得代码更可读，并且避免了重复循环控制逻辑。<br>使用自定义的迭代函数来抽象未被标准库支持的常见循环模式。<br>在需要提前终止循环的情况下，仍然推荐使用传统的循环。some和every方法也可用于提前退出。</p></blockquote></li><li><p>在类数组对象上复用通用的数组方法</p><blockquote><p>对于类数组对象，通过提取方法对象并使用其call方法来复用通用的Array方法。<br>任意一个具有索引属性和恰当length属性的对象都可以使用通用的Array方法。</p></blockquote></li><li><p>数组字面量优于数组构造函数</p></li></ol><h4 id="六、库和API设计"><a href="#六、库和API设计" class="headerlink" title="六、库和API设计"></a>六、库和API设计</h4><ol start="53"><li><p>保持一致的约定</p></li><li><p>将undefined看做”没有值”</p><blockquote><p>避免使用undefined表示任何非特定值<br>使用描述性的字符串值或命名布尔属性的对象，而不要使用undefined或null来表示特定应用标志<br>提供参数默认值应当采用测试undefined的方式，而不是检查arguments.length<br>在允许0、NaN或空字符串为有效参数的地方，绝不要通过真值测试来实现参数默认值</p></blockquote></li><li><p>接收关键字参数的选项对象</p><blockquote><p>使用选项对象使得API更具可读性、更容易记忆<br>所有通过选项对象提供的参数应当被视为可选的<br>使用extend函数抽象出从选项对象中提取值的逻辑</p></blockquote></li><li><p>避免不必要的状态</p><blockquote><p>尽可能地使用无状态的API<br>如果API是由状态的，标示出每个操作与哪些状态由关联</p></blockquote></li><li><p>使用结构类型设计灵活的接口</p></li><li><p>区分数据对象和类数组对象</p></li><li><p>避免过度的强制转换</p></li><li><p>支持方法链</p><blockquote><p>使用方法链来连接无状态的操作<br>通过在无状态的方法中返回新对象来支持方法链<br>通过在有状态的方法中返回this来支持方法链</p></blockquote></li></ol><h4 id="七、并发"><a href="#七、并发" class="headerlink" title="七、并发"></a>七、并发</h4><ol start="61"><li><p>不要阻塞I/O事件队列</p></li><li><p>在异步序列中使用嵌套或命名的回调函数</p><blockquote><p>使用嵌套或命名的回调函数按顺序地执行多个异步操作<br>尝试在过多的嵌套的回调函数和尴尬的命名的非嵌套回调函数之间取得平衡<br>避免将可被并行执行的操作顺序化</p></blockquote></li><li><p>当心丢弃错误</p></li><li><p>对异步循环使用递归</p><blockquote><p>循环不能是异步的<br>使用递归函数在事件循环的单独轮次中执行迭代<br>在事件循环的单独轮次中执行递归，并不会导致调用栈溢出</p></blockquote></li><li><p>不要在计算时阻塞事件队列</p><blockquote><p>避免在主事件队列中执行代价高昂的算法<br>在支持Worker API的平台，该API可以用来在一个独立的事件队列中运行长计算程序</p></blockquote></li><li><p>使用计数器来执行并行操作</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">downloadAllAsync</span>(<span class="params">urls, onsuccess</span>)</span>&#123;</span><br><span class="line"><span class="keyword">var</span> pending = urls.length;</span><br><span class="line"><span class="keyword">var</span> result = [];</span><br><span class="line"><span class="keyword">if</span>(pending === <span class="number">0</span>)&#123;</span><br><span class="line">setTimeout(onsuccess.bind(<span class="literal">null</span>, result),<span class="number">0</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//for(var i=0;i&lt;pending;i++)&#123;</span></span><br><span class="line"><span class="comment">//console.log(urls[i],i);</span></span><br><span class="line"><span class="comment">//downloadAsync(url,function(urls[i])&#123;</span></span><br><span class="line"><span class="comment">//result[i] = text;</span></span><br><span class="line"><span class="comment">//console.log(i,text);</span></span><br><span class="line"><span class="comment">//pending--;</span></span><br><span class="line"><span class="comment">//if(pending === 0)&#123;</span></span><br><span class="line"><span class="comment">//onsuccess(result);</span></span><br><span class="line"><span class="comment">//&#125;</span></span><br><span class="line"><span class="comment">//&#125;);</span></span><br><span class="line"><span class="comment">//&#125;</span></span><br><span class="line">urls.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">url, i</span>)</span>&#123;</span><br><span class="line"><span class="built_in">console</span>.log(url,i);</span><br><span class="line">downloadAsync(url, <span class="function"><span class="keyword">function</span>(<span class="params">text</span>)</span>&#123;</span><br><span class="line">result[i] = text;</span><br><span class="line"><span class="built_in">console</span>.log(i,text);</span><br><span class="line">pending--;</span><br><span class="line"><span class="keyword">if</span>(pending === <span class="number">0</span>)&#123;</span><br><span class="line">onsuccess(result);</span><br><span class="line">&#125;</span><br><span class="line">&#125;);</span><br><span class="line">&#125;);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">downloadAsync</span>(<span class="params">url, fnSuc</span>)</span>&#123;</span><br><span class="line">setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">fnSuc(url);</span><br><span class="line">&#125;,<span class="built_in">Math</span>.random()*<span class="number">10000</span>);</span><br><span class="line">&#125;</span><br><span class="line">downloadAllAsync([<span class="number">1</span>,<span class="number">3</span>,<span class="number">5</span>],<span class="function"><span class="keyword">function</span>(<span class="params">x</span>)</span>&#123;</span><br><span class="line"><span class="built_in">console</span>.log(x);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li><li><p>绝不要同步地调用异步的回调函数</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> cache = <span class="keyword">new</span> Dict();</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">downloadCachingAsync</span>(<span class="params">url, onsuccess, onerror</span>)</span>&#123;</span><br><span class="line"><span class="keyword">if</span>(cache.has(url)&#123;</span><br><span class="line"><span class="keyword">var</span> cached = cache.get(url);</span><br><span class="line">setTimeout(onsuccess.bind(<span class="literal">null</span>,cached),<span class="number">0</span>);</span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> downloadAsync(url, <span class="function"><span class="keyword">function</span>(<span class="params">file</span>)</span>&#123;</span><br><span class="line">cache.set(url, file);</span><br><span class="line">onsuccess(file);</span><br><span class="line">&#125;,onerror);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>即使可以立即得到数据，也绝不要同步地调用异步回调函数。<br>同步地调用异步的回调函数扰乱了预期的操作序列，并可能导致意想不到的交错代码。<br>同步地调用异步的回调函数可能导致栈溢出或错误地处理异常。<br>使用异步的API，比如setTimeout函数来调度异步回调函数，使其运行于另一个回合。</p></blockquote></li><li><p>使用promise模式清洁异步逻辑</p></li></ol>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;以下是阅读《Effective Javascript》一书所做的一些简单的笔记（部分内容并不适合ES6）：&lt;/p&gt;
&lt;h4 id=&quot;一、让自己习惯javascript&quot;&gt;&lt;a href=&quot;#一、让自己习惯javascript&quot; class=&quot;headerlink&quot; title=&quot;一、让自己习惯javascript&quot;&gt;&lt;/a&gt;一、让自己习惯javascript&lt;/h4&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://vhtml.github.io/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="javascript" scheme="https://vhtml.github.io/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>redis学习实践</title>
    <link href="https://vhtml.github.io/2016/01/19/redis-study/"/>
    <id>https://vhtml.github.io/2016/01/19/redis-study/</id>
    <published>2016-01-19T07:30:31.000Z</published>
    <updated>2018-07-09T07:26:50.000Z</updated>
    
    <content type="html"><![CDATA[<p>Redis 是一个高性能的key-value数据库。既可内存存储又可持久化，着实牛逼。它提供五种数据类型：string, hash, list, set及zset(sorted set)。</p><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p>好烦，每次学习一项新工具，总要先捣腾好一阵子安装和配置。其实我已经迫不及待地想要一窥其风骚的走位和操作了。可是稍安勿躁，该做的还是一步都不能省哪！</p><a id="more"></a><p>获取源码、解压、进入源码目录、编译安装：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ wget http://download.redis.io/releases/redis-3.0.6.tar.gz</span><br><span class="line">$ tar xzf redis-3.0.6.tar.gz</span><br><span class="line">$ <span class="built_in">cd</span> redis-3.0.6</span><br><span class="line">$ make</span><br></pre></td></tr></table></figure><p>编译好后执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ src/redis-server &amp;</span><br></pre></td></tr></table></figure><p>启动客户端shell：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">$ src/redis-cli</span><br><span class="line">127.0.0.1:6379&gt; <span class="built_in">set</span> foo bar</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; get foo</span><br><span class="line"><span class="string">"bar"</span></span><br><span class="line">redis&gt;</span><br></pre></td></tr></table></figure><p>我擦，我没有看错吧，已经可以进行存取了！简单到辱没智商哪！</p><h3 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h3><p>没想到，这么快就步入正题了，开头说过，redis是一种高性能key-value存储系统，有五种数据类型，跟mysql一样，redis中的操作指令并不区分大小写。</p><ol><li><p>字符串(string)</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; <span class="built_in">set</span> mynum <span class="string">"2"</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; get mynum</span><br><span class="line"><span class="string">"2"</span></span><br><span class="line">127.0.0.1:6379&gt; incr mynum</span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6379&gt; get mynum</span><br><span class="line"><span class="string">"3"</span></span><br><span class="line">127.0.0.1:6379&gt; incrby mynum 5</span><br><span class="line"><span class="string">"8"</span></span><br></pre></td></tr></table></figure><p> <code>set key value</code> 存储一个键值对，<code>get key</code> 获取一个键值对。</p><p> 可知，在遇到数值操作时，redis会将字符串类型转成数值。<code>incr</code>等指令本身具有原子操作的特性，我们可以利用redis的<code>incr</code>、<code>incrby</code>、<code>decr</code>、<code>decrby</code>等指令来实现原子计数的效果。</p></li><li><p>字符串列表(list)</p><p> redis中的list在底层实现上不是数组而是链表，这说明了什么呢？说明了在list上插入一个新元素（无论行首行尾行中），其时间复杂度为O(1)。比如用<code>lpush</code>在10个元素的list头部插入新元素，和在上千万元素的list头部插入新元素的速度是相同的。</p><p> 然而有利总有弊嘛，list取元素的速度就没数组那么快了，时间复杂度为O(n)。</p><p> list的常用操作包括<code>lpush</code>、<code>rpush</code>、<code>lrange</code>等。我们可以用<code>lpush</code>在list的左侧插入一个新元素，用<code>rpush</code>在list的右侧插入一个新元素，用<code>lrange</code>命令从list中指定一个范围来提取元素。例如：</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#新建一个list叫做mylist，并在列表头部插入元素"1" </span></span><br><span class="line">127.0.0.1:6379&gt; lpush mylist <span class="string">"1"</span>  </span><br><span class="line"><span class="comment">#返回当前mylist中的元素个数 </span></span><br><span class="line">(<span class="built_in">integer</span>) 1  </span><br><span class="line"><span class="comment">#在mylist右侧插入元素"2" </span></span><br><span class="line">127.0.0.1:6379&gt; rpush mylist <span class="string">"2"</span>  </span><br><span class="line">(<span class="built_in">integer</span>) 2 </span><br><span class="line"><span class="comment">#在mylist左侧插入元素"0" </span></span><br><span class="line">127.0.0.1:6379&gt; lpush mylist <span class="string">"0"</span>  </span><br><span class="line">(<span class="built_in">integer</span>) 3 </span><br><span class="line"><span class="comment">#列出mylist中从编号0到编号1的元素 </span></span><br><span class="line">127.0.0.1:6379&gt; lrange mylist 0 1  </span><br><span class="line">1) <span class="string">"0"</span> </span><br><span class="line">2) <span class="string">"1"</span> </span><br><span class="line"><span class="comment">#列出mylist中从编号0到倒数第一个元素 </span></span><br><span class="line">127.0.0.1:6379&gt; lrange mylist 0 -1  </span><br><span class="line">1) <span class="string">"0"</span> </span><br><span class="line">2) <span class="string">"1"</span> </span><br><span class="line">3) <span class="string">"2"</span></span><br></pre></td></tr></table></figure><p> list的应用相当广泛，例如：</p><ol><li>可以利用list来实现一个消息队列，而且可以确保先后顺序，不必像mysql那样还需要通过<code>order by</code>来进行排序。</li><li>利用lrange可以很方便的实现分页功能。</li><li>在博客系统中，每篇博文的评论也可以存入一个单独的list中。</li></ol></li><li><p>字符串集合(set)</p><p> redis的集合，是一种无序的集合，集合中的元素没有先后顺序，集合中没有重复元素。</p><p> 集合相关的操作也很丰富，如添加新元素(sadd)、删除已有元素(srem)、取交集(sinter)、取并集(sunion)、取差集(sdiff)、返回集合大小(scard)等。</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">#向集合myset中加入一个新元素"one"，返回1存储成功，返回0表示元素已存在不能再存储</span></span><br><span class="line">127.0.0.1:6379&gt; sadd myset <span class="string">"one"</span>  </span><br><span class="line">(<span class="built_in">integer</span>) 1 </span><br><span class="line">127.0.0.1:6379&gt; sadd myset <span class="string">"two"</span> </span><br><span class="line">(<span class="built_in">integer</span>) 1 </span><br><span class="line">127.0.0.1:6379&gt; sadd myset <span class="string">"two"</span> </span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line"><span class="comment">#列出集合myset中的所有元素 </span></span><br><span class="line">127.0.0.1:6379&gt; smembers myset  </span><br><span class="line">1) <span class="string">"one"</span> </span><br><span class="line">2) <span class="string">"two"</span> </span><br><span class="line"><span class="comment">#判断元素'one'是否在集合myset中，返回1表示存在 </span></span><br><span class="line">127.0.0.1:6379&gt; sismember myset <span class="string">"one"</span>  </span><br><span class="line">(<span class="built_in">integer</span>) 1 </span><br><span class="line"><span class="comment">#判断元素'three'是否在集合myset中，返回0表示不存在 </span></span><br><span class="line">127.0.0.1:6379&gt; sismember myset <span class="string">"three"</span>  </span><br><span class="line">(<span class="built_in">integer</span>) 0 </span><br><span class="line"><span class="comment">#新建一个新的集合yourset </span></span><br><span class="line">127.0.0.1:6379&gt; sadd yourset <span class="string">"1"</span>  </span><br><span class="line">(<span class="built_in">integer</span>) 1 </span><br><span class="line">127.0.0.1:6379&gt; sadd yourset <span class="string">"2"</span> </span><br><span class="line">(<span class="built_in">integer</span>) 1 </span><br><span class="line">127.0.0.1:6379&gt; smembers yourset </span><br><span class="line">1) <span class="string">"1"</span> </span><br><span class="line">2) <span class="string">"2"</span> </span><br><span class="line"><span class="comment">#对两个集合求并集 </span></span><br><span class="line">127.0.0.1:6379&gt; sunion myset yourset  </span><br><span class="line">1) <span class="string">"1"</span> </span><br><span class="line">2) <span class="string">"one"</span> </span><br><span class="line">3) <span class="string">"2"</span> </span><br><span class="line">4) <span class="string">"two"</span> </span><br><span class="line"><span class="comment">#求集合大小</span></span><br><span class="line">127.0.0.1:6379&gt; scard yourset</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br></pre></td></tr></table></figure><p> 常见的投票功能可以使用集合来实现，比如有个投票功能，每个用户只能投一次，将投过票的用户的id存在集合里，获取集合的大小可以获取投票数。</p></li><li><p>有序字符串集合(sorted set)</p><p> redis体贴地提供了有序集合，其中的每个元素都关联一个序号(score)，这是排序的依据。</p><p> 通常，我们将有序集合叫做zset，是因为在redis中，有序集合相关的操作指令都是以z开头的，如zrange、zadd、zrevrange、zrangebyscore等。</p><p> 话不多说，看栗子吧：</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">#向myzset中新增一个元素'java'，赋予序号1</span></span><br><span class="line">127.0.0.1:6379&gt; zadd myzset 1 java</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line"><span class="comment">#向myzset中新增一个元素'python'，赋予序号3</span></span><br><span class="line">127.0.0.1:6379&gt; zadd myzset 3 python</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line"><span class="comment">#向myzset中新增一个元素'php'，赋予序号2</span></span><br><span class="line">127.0.0.1:6379&gt; zadd myzset 2 php</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line"><span class="comment">#列出myzset的所有元素，同时列出其序号，可以看出myzset是有序的。 </span></span><br><span class="line">127.0.0.1:6379&gt; zrange myzset 0 -1 withscores</span><br><span class="line">1) <span class="string">"java"</span></span><br><span class="line">2) <span class="string">"1"</span></span><br><span class="line">3) <span class="string">"php"</span></span><br><span class="line">4) <span class="string">"2"</span></span><br><span class="line">5) <span class="string">"python"</span></span><br><span class="line">6) <span class="string">"3"</span></span><br><span class="line"><span class="comment">#只列出myzset的元素 </span></span><br><span class="line">127.0.0.1:6379&gt; zrange myzset 0 -1</span><br><span class="line">1) <span class="string">"java"</span></span><br><span class="line">2) <span class="string">"php"</span></span><br><span class="line">3) <span class="string">"python"</span></span><br></pre></td></tr></table></figure><p> 说个使用场景吧。比如你的博客文章，以发布时的时间戳为score，以文章id为值存入zset中，就可以按时间顺序进行正序或倒序(zrevrange)的排列了，还可以获取指定时间区间的博客文章(使用zrangebyscore)。</p></li><li><p>哈希(hash)</p><p> hash存的是字符串和字符串值之间的映射，比如一个用户要存储其全名、姓氏、年龄等，就特别适合使用哈希。举个栗子：</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">#建立hash，并赋值</span></span><br><span class="line">127.0.0.1:6379&gt; hmset user:001 username iwhynot password memeda age 25</span><br><span class="line">OK</span><br><span class="line"><span class="comment">#列出hash的内容</span></span><br><span class="line">127.0.0.1:6379&gt; hgetall user:001</span><br><span class="line">1) <span class="string">"username"</span></span><br><span class="line">2) <span class="string">"iwhynot"</span></span><br><span class="line">3) <span class="string">"password"</span></span><br><span class="line">4) <span class="string">"memeda"</span></span><br><span class="line">5) <span class="string">"age"</span></span><br><span class="line">6) <span class="string">"25"</span></span><br><span class="line"><span class="comment">#更改hash的某一个值</span></span><br><span class="line">127.0.0.1:6379&gt; hset user:001 password 12345</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line"><span class="comment">#再次列出hash的内容</span></span><br><span class="line">127.0.0.1:6379&gt; hgetall user:001</span><br><span class="line">1) <span class="string">"username"</span></span><br><span class="line">2) <span class="string">"iwhynot"</span></span><br><span class="line">3) <span class="string">"password"</span></span><br><span class="line">4) <span class="string">"12345"</span></span><br><span class="line">5) <span class="string">"age"</span></span><br><span class="line">6) <span class="string">"25"</span></span><br><span class="line"><span class="comment">#获取hash的某一个键的值</span></span><br><span class="line">127.0.0.1:6379&gt; hget user:001 password</span><br><span class="line"><span class="string">"12345"</span></span><br></pre></td></tr></table></figure></li></ol><p>另外，说一下一些常用的命令：</p><ul><li><code>TYPE key</code> — 用来获取某key的类型</li><li><code>KEYS pattern</code> — 匹配所有符合模式的key，比如KEYS * 就列出所有的key了，当然，复杂度O(n)</li><li><code>RANDOMKEY</code> - 返回随机的一个key</li><li><code>RENAME oldkey newkey</code> — key也可以改名</li></ul><p>列表操作，精华</p><ul><li><code>RPUSH key string</code> — 将某个值加入到一个key列表末尾</li><li><code>LPUSH key string</code> — 将某个值加入到一个key列表头部</li><li><code>LLEN key</code> — 列表长度</li><li><code>LRANGE key start end</code> — 返回列表中某个范围的值，相当于mysql里面的分页查询那样</li><li><code>LTRIM key start end</code> — 只保留列表中某个范围的值</li><li><code>LINDEX key index</code> — 获取列表中特定索引号的值，要注意是O(n)复杂度</li><li><code>LSET key index value</code> — 设置列表中某个位置的值</li><li><code>LPOP key</code></li><li><code>RPOP key</code> — 和上面的LPOP一样，就是类似栈或队列的那种取头取尾指令，可以当成消息队列来使用了</li></ul><p>集合操作</p><ul><li><code>SADD key member</code> — 增加元素</li><li><code>SREM key member</code> — 删除元素</li><li><code>SCARD key</code> — 返回集合大小</li><li><code>SISMEMBER key member</code> — 判断某个值是否在集合中</li><li><code>SINTER key1 key2 ... keyN</code> — 获取多个集合的交集元素</li><li><code>SMEMBERS key</code> — 列出集合的所有元素</li></ul><p>详尽的指令介绍可以在这里尽情查看。<a href="http://redis.io/commands" target="_blank" rel="noopener">http://redis.io/commands</a>。</p><h3 id="redis配置"><a href="#redis配置" class="headerlink" title="redis配置"></a>redis配置</h3><p>当然，配置是一个很核心的部分。然而，我并不想多说。</p><p>默认安装的redis.conf配置文件，里面的英文注释已经非常详细了，就不需要我翻译了（其实是我英文不好）。</p><h3 id="redis在nodejs中的使用"><a href="#redis在nodejs中的使用" class="headerlink" title="redis在nodejs中的使用"></a>redis在nodejs中的使用</h3><p>安装node_redis模块：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ npm install redis</span><br></pre></td></tr></table></figure><p>使用：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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="keyword">var</span> redis = <span class="built_in">require</span>(<span class="string">"redis"</span>),</span><br><span class="line">    client = redis.createClient();</span><br><span class="line"></span><br><span class="line">client.on(<span class="string">"error"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">err</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"Error "</span> + err);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">client.set(<span class="string">"string key"</span>, <span class="string">"string val"</span>, redis.print);</span><br><span class="line">client.hset(<span class="string">"hash key"</span>, <span class="string">"hashtest 1"</span>, <span class="string">"some value"</span>, redis.print);</span><br><span class="line">client.hset([<span class="string">"hash key"</span>, <span class="string">"hashtest 2"</span>, <span class="string">"some other value"</span>], redis.print);</span><br><span class="line">client.hkeys(<span class="string">"hash key"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">err, replies</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(replies.length + <span class="string">" replies:"</span>);</span><br><span class="line">    replies.forEach(<span class="function"><span class="keyword">function</span> (<span class="params">reply, i</span>) </span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">"    "</span> + i + <span class="string">": "</span> + reply);</span><br><span class="line">    &#125;);</span><br><span class="line">    client.quit();</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>更多风骚的用法，查看这里吧<a href="https://github.com/NodeRedis/node_redis" target="_blank" rel="noopener">https://github.com/NodeRedis/node_redis</a>。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Redis 是一个高性能的key-value数据库。既可内存存储又可持久化，着实牛逼。它提供五种数据类型：string, hash, list, set及zset(sorted set)。&lt;/p&gt;
&lt;h3 id=&quot;安装&quot;&gt;&lt;a href=&quot;#安装&quot; class=&quot;headerlink&quot; title=&quot;安装&quot;&gt;&lt;/a&gt;安装&lt;/h3&gt;&lt;p&gt;好烦，每次学习一项新工具，总要先捣腾好一阵子安装和配置。其实我已经迫不及待地想要一窥其风骚的走位和操作了。可是稍安勿躁，该做的还是一步都不能省哪！&lt;/p&gt;
    
    </summary>
    
      <category term="web技术" scheme="https://vhtml.github.io/categories/web%E6%8A%80%E6%9C%AF/"/>
    
    
      <category term="redis" scheme="https://vhtml.github.io/tags/redis/"/>
    
      <category term="数据库" scheme="https://vhtml.github.io/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>学写博客先学markdown</title>
    <link href="https://vhtml.github.io/2016/01/06/markdown/"/>
    <id>https://vhtml.github.io/2016/01/06/markdown/</id>
    <published>2016-01-06T08:05:55.000Z</published>
    <updated>2018-07-09T07:26:50.000Z</updated>
    
    <content type="html"><![CDATA[<p>Now，开始吧。。。</p><h2 id="区块元素"><a href="#区块元素" class="headerlink" title="区块元素"></a>区块元素</h2><h4 id="段落与换行"><a href="#段落与换行" class="headerlink" title="段落与换行"></a>段落与换行</h4><p>一个 Markdown 段落是由一个或多个连续的文本行组成，它的前后要有一个以上的空行（空行的定义是显示上看起来像是空的，便会被视为空行。比方说，若某一行只包含空格和制表符，则该行也会被视为空行）。普通段落不该用空格或制表符来缩进。</p><a id="more"></a><p>如：</p><pre><code>这是一个段落。</code></pre><p>长这样：</p><p>这是一个段落。</p><h4 id="标题"><a href="#标题" class="headerlink" title="标题"></a>标题</h4><p>Markdown 支持两种标题的语法，类 Setext 和类 atx 形式。这里只讲类atx形式。</p><p>类 Atx 形式则是在行首插入 1 到 6 个 # ，对应到标题 1 到 6 阶，#后跟的文字之间最好有一个以上的空格（有的markdown解析程序不解析无空格的），例如：</p><pre><code># h1## h2### h3#### h4##### h5###### h6</code></pre><p>长这样：</p><h1 id="h1"><a href="#h1" class="headerlink" title="h1"></a>h1</h1><h2 id="h2"><a href="#h2" class="headerlink" title="h2"></a>h2</h2><h3 id="h3"><a href="#h3" class="headerlink" title="h3"></a>h3</h3><h4 id="h4"><a href="#h4" class="headerlink" title="h4"></a>h4</h4><h5 id="h5"><a href="#h5" class="headerlink" title="h5"></a>h5</h5><h6 id="h6"><a href="#h6" class="headerlink" title="h6"></a>h6</h6><h4 id="区块引用Blockquotes"><a href="#区块引用Blockquotes" class="headerlink" title="区块引用Blockquotes"></a>区块引用Blockquotes</h4><p>Markdown 标记区块引用是使用类似 email 中用 <code>&gt;</code> 的引用方式。即在每行的最前面加上 <code>&gt;</code>，或者在整个段落的第一行最前面加。如：</p><pre><code>&gt; 这是一行引用&gt; 这是另一行引用&gt;这是一段引用。是啊是啊。</code></pre><p>长这样：</p><blockquote><p>这是一行引用</p><p>这是另一行引用</p></blockquote><blockquote><p>这是一段引用。<br>是啊是啊。</p></blockquote><p>区块引用可以嵌套（例如：引用内的引用），只要根据层次加上不同数量的 <code>&gt;</code>，如：</p><pre><code>&gt; 这是第一级引用。&gt;&gt; 这是第二级引用。</code></pre><p>长这样：</p><blockquote><p>这是第一级引用。</p><blockquote><p>这是第二级引用。</p></blockquote></blockquote><h4 id="列表"><a href="#列表" class="headerlink" title="列表"></a>列表</h4><p>无序列表使用星号、加号或是减号作为列表标记，如：</p><pre><code>* red* green* blue---+ red+ green+ blue---- red- green- blue</code></pre><p>长这样：</p><ul><li>red</li><li>green</li><li>blue</li></ul><hr><ul><li>red</li><li>green</li><li>blue</li></ul><hr><ul><li>red</li><li>green</li><li>blue</li></ul><p>有序列表使用数字接着一个英文句点，数字可以无序，为任意数字，如：</p><pre><code>5. red2. green3. blue</code></pre><p>长这样：</p><ol start="5"><li>red</li><li>green</li><li>blue</li></ol><p>列表项目可以包含多个段落，每个项目下的段落都必须缩进4个空格或是1个制表符，如：</p><pre><code>1.  this is a list item    haha    xixi2.  yes, it is.    hehe</code></pre><p>长这样：</p><ol><li><p>this is a list item</p><p>haha</p><p>xixi</p></li><li><p>yes, it is.</p><p>hehe</p></li></ol><p>如果要在列表项目内放进引用，那<code>&gt;</code>就需要缩进，如：</p><pre><code>* 一个带引用的列表：    &gt; 这是一个在列表里的引用</code></pre><p>长这样：</p><ul><li><p>一个带引用的列表：</p><blockquote><p>这是一个在列表里的引用</p></blockquote></li></ul><p>如果要放代码区块的话，该区块就需要缩进两次，也就是8个空格或是2个制表符，如：</p><pre><code>* 看代码        function test(){                alert(&apos;test&apos;);        }</code></pre><p>长这样：</p><ul><li><p>看代码</p><pre><code>function test(){    alert(&apos;test&apos;);}</code></pre></li></ul><p>有时遇到这样的写法：</p><pre><code>1990. 我的出生年</code></pre><p>会变成这样：</p><ol start="1990"><li>我的出生年</li></ol><p>也就是在行首出现数字-句点-空白，又不想被markdown解析，要避免这样的状况，可以在句点前面加上反斜杠。</p><pre><code>1990\. 我的出生年</code></pre><p>然后长这样：</p><p>1990. 我的出生年</p><p><br><br>ok，终于聊到重点啦：</p><h4 id="代码区块"><a href="#代码区块" class="headerlink" title="代码区块"></a>代码区块</h4><p>和程序相关的写作或是标签语言原始码通常会有已经排版好的代码区块，通常这些区块我们并不希望它以一般段落文件的方式去排版，而是照原来的样子显示，Markdown会用<code>&lt;pre&gt;</code>和<code>&lt;code&gt;</code>标签把代码区块包起来。</p><p>要在markdown中建立区块代码很简单，只要简单地缩进4个空格或是1个制表符就可以，如：</p><pre><code>这是一个普通段落。    alert(&quot;这是一段代码&quot;)</code></pre><p>长这样：</p><p>这是一个普通段落。</p><pre><code>alert(&quot;这是一段代码&quot;)</code></pre><p>再如：</p><pre><code>function say(){    console.log(&apos;hello markdown&apos;);}</code></pre><p>一个代码区块会一直持续到没有缩进的那一行（或是文件结尾）。</p><p>在代码区块里，特殊标记会实例化成HTML实体：</p><pre><code>&lt;div class=&quot;head&quot;&gt;    header&lt;/div&gt;</code></pre><p>这样，html代码就可以以你期望的方式原样输出了。</p><p>在代码区块中，一般的markdown语法也不会被转换，这样就可以方便的以markdown语法撰写markdown语法相关的文件。</p><h4 id="分割线"><a href="#分割线" class="headerlink" title="分割线"></a>分割线</h4><p>你可以在一行中用三个以上的星号、减号、底线来建立一个分割线，行内不能有其他东西。你也可以在星号或是减号中间插入空格。如：</p><pre><code>---**********___--------------------</code></pre><p>便会生成：</p><hr><hr><hr><hr><hr><h2 id="区段元素"><a href="#区段元素" class="headerlink" title="区段元素"></a>区段元素</h2><h4 id="链接"><a href="#链接" class="headerlink" title="链接"></a>链接</h4><p>markdown支持两种形式的链接语法： 行内式和参考式两种形式。</p><p>不管是哪一种，链接文字都是用[方括号]来标记。</p><p>要建立一个<strong>行内式</strong>的链接，只要在方括号后面紧跟着圆括号并插入网址链接即可，如果你还想要加上链接的title文字，只要在网址后面，用双引号把title文字包起来即可，如：</p><pre><code>这是一个[示例](http://www.iwhynot.me/ &quot;title&quot;)行内式链接.[这个链接](http://www.iwhynot.me/)没有标题</code></pre><p>长这样：</p><p>这是一个<a href="http://www.iwhynot.me/" title="title" target="_blank" rel="noopener">示例</a>行内式链接.</p><p><a href="http://www.iwhynot.me/" target="_blank" rel="noopener">这个链接</a>没有标题</p><p><strong>参考式</strong>的链接是在链接文字的括号后面再接上另一个方括号，而在第二个方括号里面要填入用以辨识链接的标记，之后再定义标记链接：</p><p>链接内容定义形式为：</p><ul><li>方括号，里面输入链接文字</li><li>接着一个冒号</li><li>接着一个以上的空格或制表符</li><li>接着链接的网址</li><li>选择性地接着title内容，可以用单引号、双引号或是括弧包着</li></ul><p>举个栗子：</p><pre><code>上网搜索用[Google][1]，还是用[百度][2]呢？[1]: http://google.com/ &quot;Google&quot;[2]: http://baidu.com/ &quot;百度&quot;</code></pre><p>生成：</p><p>上网搜索用<a href="http://google.com/" title="Google" target="_blank" rel="noopener">Google</a>，还是用<a href="http://baidu.com/" title="百度" target="_blank" rel="noopener">百度</a>呢？</p><h4 id="强调"><a href="#强调" class="headerlink" title="强调"></a>强调</h4><p>markdown使用星号(<em>)和下划线(_)作为标记强调字词的符号，被`</em><code>或</code><em><code>包围的字词会被转成用</code><em><code>标签包围，用两个</code>*<code>或</code></em><code>包起来的，会被转成</code><strong>`，如：</strong></em></p><pre><code>*单星号包住*_单下划线包住_**双星号包住**__双下划线包住__</code></pre><p>生成：</p><p><em>单星号包住</em></p><p><em>单下划线包住</em></p><p><strong>双星号包住</strong></p><p><strong>双下划线包住</strong></p><h4 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h4><p>如果要标记一小段行内代码，你可以用反引号把它包起来(<code>`</code>)，如：</p><pre><code>`span`是内联元素</code></pre><p>生成：</p><p><code>span</code>是内联元素</p><p>如果要在代码区段内插入反引号，可以用多个反引号来开启和结束代码区段：</p><pre><code>``(`)``</code></pre><p>生成：</p><p><code>(`)</code></p><p>代码区段的起始和结束端都可以放入一个空白，这样就可以在区段的一开始就插入反引号：</p><pre><code>`` ` ``</code></pre><p>生成：</p><p><code>`</code></p><p>在代码区段里，<code>&amp;</code>和方括号会被自动转成html实体，方便插入html原始码，如：</p><pre><code>这是一个`&lt;span&gt;`标签</code></pre><p>生成：</p><p>这是一个<code>&lt;span&gt;</code>标签</p><h4 id="图片"><a href="#图片" class="headerlink" title="图片"></a>图片</h4><p>跟链接一样，分为<u>行内式</u>和<u>参考式</u>：</p><p>行内式的看起来是这样的：</p><pre><code>![Alt text](/path/to/img.jpg)![Alt text](/path/to/img.jpg &quot;optional title&quot;)</code></pre><p>详述如下：</p><blockquote><ul><li>一个惊叹号<code>!</code></li><li>接着一个方括号，里面放上图片的替代文字</li><li>接着一个小括号，里面放上图片的网址，最后还可以用引号包住并加上选择性的’title’文字。</li></ul></blockquote><p>参考式的图片语法像这样：</p><pre><code>![Alt text][id]</code></pre><p>id是图片参考的名称，图片参考的定义方式和链接参考一样：</p><pre><code>[id]: url/to/image &quot;optional title attribute&quot;</code></pre><p>到目前为止，markdown还没有办法指定图片的宽高，如果需要的话，可以使用普通的<code>&lt;img&gt;</code>标签。</p><h2 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h2><h4 id="自动链接"><a href="#自动链接" class="headerlink" title="自动链接"></a>自动链接</h4><p>markdown支持以比较简短的自动链接形式来处理网址和电子邮件信箱，只要是用尖括号包起来，markdown就会自动把它转成链接。如：</p><pre><code>&lt;http://www.iwhynot.me&gt;</code></pre><p>生成：</p><p><a href="http://www.iwhynot.me" target="_blank" rel="noopener">http://www.iwhynot.me</a></p><p>邮件的自动链接也很类似，只是markdown会先做一个编码转换的过程，把文字字符转成16进位码的html实体，以糊弄一些不好的邮址收集机器人，如：</p><pre><code>&lt;address@example.com&gt;</code></pre><p>生成：</p><p><a href="mailto:&#97;&#100;&#x64;&#x72;&#101;&#115;&#115;&#64;&#101;&#120;&#x61;&#x6d;&#x70;&#108;&#x65;&#x2e;&#x63;&#x6f;&#x6d;" target="_blank" rel="noopener">&#97;&#100;&#x64;&#x72;&#101;&#115;&#115;&#64;&#101;&#120;&#x61;&#x6d;&#x70;&#108;&#x65;&#x2e;&#x63;&#x6f;&#x6d;</a></p><h4 id="反斜杠"><a href="#反斜杠" class="headerlink" title="反斜杠"></a>反斜杠</h4><p>markdown可以利用反斜杠来插入一些在语法中有其它意义的符号，如：</p><pre><code>\*本来是强调的星号\*</code></pre><p>生成：</p><p>*本来是强调的星号*</p><p>markdown支持以下这些符号前面加上反斜杠来帮助插入普通的符号：</p><pre><code>\ 反斜线` 反引号* 星号_ 下划线{} 花括号[] 方括号() 括弧# 井号+ 加号- 减号. 英文点号! 惊叹号</code></pre><p>OK，就这些了，参考<a href="http://wowubuntu.com/markdown/" target="_blank" rel="noopener">Markdown中文版语法说明</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Now，开始吧。。。&lt;/p&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; class=&quot;headerlink&quot; title=&quot;段落与换行&quot;&gt;&lt;/a&gt;段落与换行&lt;/h4&gt;&lt;p&gt;一个 Markdown 段落是由一个或多个连续的文本行组成，它的前后要有一个以上的空行（空行的定义是显示上看起来像是空的，便会被视为空行。比方说，若某一行只包含空格和制表符，则该行也会被视为空行）。普通段落不该用空格或制表符来缩进。&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://vhtml.github.io/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="markdown" scheme="https://vhtml.github.io/tags/markdown/"/>
    
  </entry>
  
</feed>
