<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Hulk's Blog RSS Feed]]></title><description><![CDATA[A blog by Hulk]]></description><link>http://huangbowen.cn/blog</link><generator>GatsbyJS</generator><lastBuildDate>Thu, 11 Jun 2026 10:16:18 GMT</lastBuildDate><item><title><![CDATA[No title]]></title><link>http://huangbowen.cn/blog/learn-browser/exe/</link><guid isPermaLink="false">http://huangbowen.cn/blog/learn-browser/exe/</guid><content:encoded>&lt;h3&gt;js 代码是怎么执行的（先编译，再执行）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript 代码执行过程中，需要先做变量提升，而之所以需要实现变量提升，是因为 JavaScript 代码在执行之前需要先编译。在编译阶段，变量和函数会被存放到变量环境中，变量的默认值会被设置为 undefined；&lt;/li&gt;
&lt;li&gt;在代码执行阶段，JavaScript 引擎会从变量环境中去查找自定义的变量和函数。如果在编译阶段，存在两个相同的函数，那么最终存放在变量环境中的是最后定义的那个，这是因为后定义的会覆盖掉之前定义的。以上就是今天所讲的主要内容，&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，学习这些内容并不是让你掌握一些 JavaScript 小技巧，其主要目的是让你清楚 JavaScript 的执行机制：先编译，再执行。&lt;/p&gt;
&lt;h3&gt;执行栈？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;每调用一个函数，JavaScript 引擎会为其创建执行上下文，并把该执行上下文压入调用栈，然后 JavaScript 引擎开始执行函数代码。&lt;/li&gt;
&lt;li&gt;如果在一个函数 A 中调用了另外一个函数 B，那么 JavaScript 引擎会为 B 函数创建执行上下文，并将 B 函数的执行上下文压入栈顶。&lt;/li&gt;
&lt;li&gt;当前函数执行完毕后，JavaScript 引擎会将该函数的执行上下文弹出栈。&lt;/li&gt;
&lt;li&gt;当分配的调用栈空间被占满时，会引发“堆栈溢出”问题。&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/learn-browser/exe/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[No title]]></title><link>http://huangbowen.cn/blog/learn-browser/gc/</link><guid isPermaLink="false">http://huangbowen.cn/blog/learn-browser/gc/</guid><content:encoded>&lt;h3&gt;垃圾回收&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;新生代（存放比较小，很快被回收）[副垃圾回收器]
&lt;ul&gt;
&lt;li&gt;经历两次新生代就放进老生区（对象晋升策略）&lt;/li&gt;
&lt;li&gt;Scavenge 算法来处理。是把新生代空间对半划分为两个区域，一半是对象区域，一半是空闲区域，回收时直接把对象区域可用的对象挪动到空闲区，原对象区域之间清空，循环往复&lt;/li&gt;
&lt;li&gt;新加入的对象都会存放到对象区域，当对象区域快被写满时，就需要执行一次垃圾清理操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;老生代
&lt;ul&gt;
&lt;li&gt;标记 - 清除 -整理&lt;/li&gt;
&lt;li&gt;清除算法里的是一样的，但后续步骤不是直接对可回收对象进行清理，而是让所有存活的对象都向一端移动，然后直接清理掉端边界以外的内存&lt;/li&gt;
&lt;li&gt;为了降低老生代的垃圾回收而造成的卡顿，V8 将标记过程分为一个个的子标记过程，同时让垃圾回收标记和 JavaScript 应用逻辑交替进行，直到标记阶段完成，我们把这个算法称为增量标记（Incremental Marking）算法。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/learn-browser/gc/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[Why should we use pnpm?]]></title><link>http://huangbowen.cn/blog/pnpm/</link><guid isPermaLink="false">http://huangbowen.cn/blog/pnpm/</guid><pubDate>Thu, 13 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;npm 1/2 时代&lt;/h2&gt;
&lt;p&gt;http2针对头部字段，使用HPACK压缩算法，对请求头进行压缩。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;磁盘空间占用：每个依赖都会安装自己的依赖，导致了大量的重复，特别是在多个包共享同一依赖的场景下&lt;/li&gt;
&lt;li&gt;深层嵌套问题：这种嵌套结构在文件系统中造成了非常长的路径，然而大多数 Windows 工具、实用程序和 shell 最多只能处理长达 260 个字符的文件和文件夹路径。一旦超过，安装脚本就会开始出错，而且无法再使用常规方法删除 node_modules 文件夹&lt;/li&gt;
&lt;li&gt;安装和更新缓慢：每次安装或更新依赖时，npm 需要处理和解析整个依赖树，过程非常缓慢。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;http://huangbowen.cn/blog/static/104c32ce166f949fc4ec93df08b80de7/8d4d1/npm.webp&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 36.486486486486484%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/webp;base64,UklGRkIAAABXRUJQVlA4IDYAAADwAgCdASoUAAcAPtFUo0uoJKMhsAgBABoJaQAAetCOQAD+8k+N8q67s5y8xW3Q1jSBx0o8cAA=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Image text&quot;
        title=&quot;Image text&quot;
        src=&quot;http://huangbowen.cn/blog/static/104c32ce166f949fc4ec93df08b80de7/5ca24/npm.webp&quot;
        srcset=&quot;http://huangbowen.cn/blog/static/104c32ce166f949fc4ec93df08b80de7/cbe2e/npm.webp 148w,http://huangbowen.cn/blog/static/104c32ce166f949fc4ec93df08b80de7/3084c/npm.webp 295w,http://huangbowen.cn/blog/static/104c32ce166f949fc4ec93df08b80de7/5ca24/npm.webp 590w,http://huangbowen.cn/blog/static/104c32ce166f949fc4ec93df08b80de7/dad35/npm.webp 885w,http://huangbowen.cn/blog/static/104c32ce166f949fc4ec93df08b80de7/2baf0/npm.webp 1180w,http://huangbowen.cn/blog/static/104c32ce166f949fc4ec93df08b80de7/8d4d1/npm.webp 1741w&quot;
        sizes=&quot;(max-width: 590px) 100vw, 590px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;npm3&lt;/h2&gt;
&lt;p&gt;过将依赖扁平化，尽可能地减少了重复的包版本，有效减少了项目的总体积，同时也避免了 npm 早期的深层嵌套问题。
&lt;img src=&quot;./npm3.png&quot; alt=&quot;Image text&quot;&gt;&lt;/p&gt;
&lt;h2&gt;yarn&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;性能提升：yarn 在发布之初就强调了性能优势，特别是在安装依赖时。它通过并行安装依赖和缓存已下载的包来加速这一过程，减少了安装时间。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更好的依赖管理：yarn 引入了 yarn.lock 文件，这个锁文件确保了依赖的一致性。无论是在哪个环境下运行yarn install，都能确保安装相同版本的依赖，解决了因版本不匹配导致的问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更好的安全性：yarn 通过检查安装的每个包的许可证，并提供了一种机制来限制或拒绝具有不安全许可证的包的安装，增强了项目的安全性。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;！！幽灵依赖！！&lt;/h3&gt;
&lt;p&gt;其实扁平化的结构还是存在一些问题的，那就是幽灵依赖。
我们假设 B 并没有在 package.json 中注册，但由于 A 依赖 B，B会被提取到 node_moduls 顶层，那么在项目中就可以直接引用 B，这就是幽灵依赖，当 A 出现一些变动时（升级、删除），会导致出现几个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;环境不一致：由于该模块未在 package.json 文件中声明，当在其他环境（如测试、生产环境或者其他人的开发环境）中部署应用时将无法知道需要包含那些模块。这将导致环境之间存在不一致，可能会导致在其他环境中运行时出现错误。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;版本控制问题：由于未明确声明依赖，可能会出现不同环境中使用的模块版本不一致的问题。这可能导致某些功能在某些环境中无法正常工作，或者出现不可预见的行为。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;代码可读性和可维护性降低：开发人员无法清楚地了解应用程序的依赖项，导致代码理解困难。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而 pnpm 就是为了解决这个问题而出现的。&lt;/p&gt;
&lt;h2&gt;pnpm&lt;/h2&gt;
&lt;h3&gt;硬软链接概念&lt;/h3&gt;
&lt;p&gt;在了解 pnpm 具体机制之前，我们先了解一下硬链接和软链接（符号链接）的概念：&lt;/p&gt;
&lt;p&gt;硬链接（Hard Link）&lt;/p&gt;
&lt;p&gt;概念：硬链接是文件系统中的一个链接，它指向磁盘上的数据。当创建一个硬链接时，实际上是在创建一个和原始文件相同的入口点，但是不占用额外的磁盘空间。这个新的链接和原始文件共享相同的数据块，任何一个文件的修改都会反映在另一个上。
特点：硬链接不能跨文件系统创建，也不能用于链接目录，但如果原始文件被删除，硬链接依然可以访问数据。
使用场景：当你想要在不同位置访问同一个文件内容，而又不想占用额外磁盘空间时，可以使用硬链接。比如，在多个项目中共享相同的库文件，但不需要复制这个文件多份。&lt;/p&gt;
&lt;p&gt;软链接（符号链接，Symbolic Link）&lt;/p&gt;
&lt;p&gt;概念：软链接是一个特殊类型的文件，它包含了另一个文件的路径。类似于 Windows 系统中的快捷方式。与硬链接不同，软链接可以指向目录，也可以跨文件系统。
特点：软链接指向文件或目录的路径，如果原始文件被删除，软链接就会失效，因为它的指向已经不存在了。
使用场景：软链接适用于需要引用特定位置的文件&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;全局存储：pnpm 从 npm 注册表下载包并存储在全局存储目录中，例如 ~/.pnpm-store/v6/files/sha512/xx/xx/xxxx....，通过内容寻址来区分不同内容的文件路径&lt;/li&gt;
&lt;li&gt;pnpm 从全局存储创建硬链接到项目的本地存储，例如 projectA/node_modules/.pnpm/lodash 和 projectB/node_modules/.pnpm/lodash。这样做的目的是节省磁盘空间和加快安装速度。&lt;/li&gt;
&lt;li&gt;在项目的 node_modules 目录中，pnpm 创建符号链接指向本地存储中的硬链接，例如 projectA/node_modules/lodash -&gt; projectA/.pnpm-store/lodash 和 projectB/node_modules/lodash -&gt; projectB/.pnpm-store/lodash&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;./pnpm.png&quot; alt=&quot;Image text&quot;&gt;&lt;/p&gt;
&lt;h3&gt;QA&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;为什么不直接从全局存储使用软链接到项目？
&lt;ul&gt;
&lt;li&gt;一台机器上一个包在可以有不同的依赖集。
在项目A &lt;a href=&quot;mailto:foo@1.0.0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;foo@1.0.0&lt;/a&gt;中可以将依赖项解析为&lt;a href=&quot;mailto:bar@1.0.0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;bar@1.0.0&lt;/a&gt;，但在项目B中，相同的依赖项foo可能解析为&lt;a href=&quot;mailto:bar@1.1.0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;bar@1.1.0&lt;/a&gt;；因此，pnpm 硬链接&lt;a href=&quot;mailto:foo@1.0.0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;foo@1.0.0&lt;/a&gt;到它的每个项目，以便为其创建不同的依赖项集。&lt;/li&gt;
&lt;li&gt;硬链接无法跨文件系统，所以使用软链接来构建依赖树&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;第三方历史幽灵依赖问题
&lt;ul&gt;
&lt;li&gt;对直接依赖严格管理：对于项目的直接依赖，pnpm 保持严格的依赖隔离，确保项目只能访问到它在package.json 中声明的依赖。&lt;/li&gt;
&lt;li&gt;对间接依赖妥协处理：考虑到一些第三方库可能依赖于未直接声明的包（幽灵依赖），pnpm 默认启用了 hoist 配置。这个配置会将一些间接依赖提升（hoist）到一个特殊的目录 node_modules/.pnpm/node_modules中。这样做的目的是在保持依赖隔离的同时，允许某些特殊情况下的间接依赖被访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/pnpm/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[浏览器原理]]></title><link>http://huangbowen.cn/blog/learn-browser/</link><guid isPermaLink="false">http://huangbowen.cn/blog/learn-browser/</guid><pubDate>Mon, 04 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;浏览器架构&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;通过对浏览器多进程架构的学习，可以把网络流程、页面渲染过程、JavaScript执行流程以及Web安全理论这些知识点串起来组成一张网。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;单进程浏览器&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://static001.geekbang.org/resource/image/6d/ca/6ddad2419b049b0eb2a8036f3dfff1ca.png?wh=1142*469&quot; alt=&quot;Image text&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单进程架构浏览器的缺点
&lt;ul&gt;
&lt;li&gt;不稳定
&lt;ul&gt;
&lt;li&gt;一个插件线程或者渲染线程出错了，会导致整个浏览器进程崩溃&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;不流畅
&lt;ul&gt;
&lt;li&gt;所有页面的渲染模块、JavaScript 执行环境以及插件都是运行在同一个线程中的，这就意味着同一时刻只能有一个模块可以执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;不安全
&lt;ul&gt;
&lt;li&gt;c++ 来写插件，可以直接获取到电脑上的资源，从而控制电脑，盗窃密码等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;多进程浏览器时代&lt;/h3&gt;
&lt;p&gt;早期多进程架构，2008 年 Chrome 发布时的进程架构
&lt;img src=&quot;https://static001.geekbang.org/resource/image/cd/60/cdc9215e6c6377fc965b7fac8c3ec960.png?wh=1142*725&quot; alt=&quot;Image text&quot;&gt;&lt;/p&gt;
&lt;p&gt;Chrome 的页面是运行在单独的渲染进程中的，同时页面里的插件也是运行在单独的插件进程之中，而进程之间是通过 IPC 机制进行通信（如图中虚线部分）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于进程是相互隔离的，所以当一个页面或者插件崩溃时，影响到的仅仅是当前的页面进程或者插件进程，并不会影响到浏览器和其他页面，这就完美地解决了页面或者插件的崩溃会导致整个浏览器崩溃，也就是不稳定的问题。&lt;/li&gt;
&lt;li&gt;同样，JavaScript 也是运行在渲染进程中的，所以即使 JavaScript 阻塞了渲染进程，影响到的也只是当前的渲染页面，而并不会影响浏览器和其他页面，因为其他页面的脚本是运行在它们自己的渲染进程中的。所以当我们再在 Chrome 中运行上面那个死循环的脚本时，没有响应的仅仅是当前的页面。&lt;/li&gt;
&lt;li&gt;采用多进程架构的额外好处是可以使用安全沙箱，你可以把沙箱看成是操作系统给进程上了一把锁，沙箱里面的程序可以运行，但是不能在你的硬盘上写入任何数据，也不能在敏感位置读取任何数据，例如你的文档和桌面。Chrome 把插件进程和渲染进程锁在沙箱里面，这样即使在渲染进程或者插件进程里面执行了恶意程序，恶意程序也无法突破沙箱去获取系统权限。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;目前多进程架构&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://static001.geekbang.org/resource/image/b6/fc/b61cab529fa31301bde290813b4587fc.png?wh=1142*494&quot; alt=&quot;Image text&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器进程。主要负责界面显示、用户交互、子进程管理，同时提供存储等功能。&lt;/li&gt;
&lt;li&gt;渲染进程。核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页，排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中，默认情况下，Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑，渲染进程都是运行在沙箱模式下。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;注意&lt;/strong&gt;: 同一站点会放进一个渲染进程里进行执行，A 页面的 JS 是可以直接在 B 页面里运行的，包括进行通信&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;GPU 进程。其实，Chrome 刚开始发布的时候是没有 GPU 进程的。而 GPU 的使用初衷是为了实现 3D CSS 的效果，只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘制，这使得 GPU 成为浏览器普遍的需求。最后，Chrome 在其多进程架构上也引入了 GPU 进程。&lt;/li&gt;
&lt;li&gt;网络进程。主要负责页面的网络资源加载，之前是作为一个模块运行在浏览器进程里面的，直至最近才独立出来，成为一个单独的进程。&lt;/li&gt;
&lt;li&gt;插件进程。主要是负责插件的运行，因插件易崩溃，所以需要通过插件进程来隔离，以保证插件进程崩溃不会对浏览器和页面造成影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不过凡事都有两面性，虽然多进程模型提升了浏览器的稳定性、流畅性和安全性，但同样不可避免地带来了一些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更高的资源占用。因为每个进程都会包含公共基础结构的副本（如 JavaScript 运行环境），这就意味着浏览器会消耗更多的内存资源。&lt;/li&gt;
&lt;li&gt;更复杂的体系架构。浏览器各模块之间耦合性高、扩展性差等问题，会导致现在的架构已经很难适应新的需求了。&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;面向服务架构&lt;/h3&gt;
&lt;p&gt;为了解决这些问题，在 2016 年，Chrome 官方团队使用“面向服务的架构”（Services Oriented Architecture，简称 SOA）的思想设计了新的 Chrome 架构。也就是说 Chrome 整体架构会朝向现代操作系统所采用的“面向服务的架构” 方向发展，原来的各种模块会被重构成独立的服务（Service），每个服务（Service）都可以在独立的进程中运行，访问服务（Service）必须使用定义好的接口，通过 IPC 来通信，从而构建一个更内聚、松耦合、易于维护和扩展的系统，更好实现 Chrome 简单、稳定、高速、安全的目标。如果你对面向服务的架构感兴趣，你可以去网上搜索下资料，这里就不过多介绍了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://static001.geekbang.org/resource/image/32/2a/329658fe821252db47b0964037a1de2a.png?wh=1142*582&quot; alt=&quot;Image text&quot;&gt;&lt;/p&gt;
&lt;p&gt;浏览器缓存是怎样的？&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/learn-browser/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[渲染流程]]></title><link>http://huangbowen.cn/blog/learn-browser/render/</link><guid isPermaLink="false">http://huangbowen.cn/blog/learn-browser/render/</guid><pubDate>Mon, 04 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;流水线可分为如下几个子阶段：构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/learn-browser/render/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[一文了解深拷贝]]></title><link>http://huangbowen.cn/blog/deep-clone/</link><guid isPermaLink="false">http://huangbowen.cn/blog/deep-clone/</guid><pubDate>Thu, 21 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;JS 数据类型&lt;/h2&gt;
&lt;p&gt;开头先来复习下 JS 都有哪些数据类型&lt;/p&gt;
&lt;p&gt;Undefined、Boolean、String、Number、Null、Symbol、BigInt 8 个基本类型和 1 个 Object&lt;/p&gt;
&lt;p&gt;注意: 函数也是具有额外可调用能力的对象&lt;/p&gt;
&lt;!-- set, map, weakset, weakmap? 以及一些新语法 --&gt;
&lt;h2&gt;思路&lt;/h2&gt;
&lt;p&gt;实现深拷贝可以进行递归, 每一层都对数据类型做判断:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果是基本类型, 直接复制&lt;/li&gt;
&lt;li&gt;obj 进行重建&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代码实现时注意:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;代码层级过深时会爆栈(这里可以使用尾递归优化)&lt;/li&gt;
&lt;li&gt;存在循环引用问题怎么处理&lt;/li&gt;
&lt;li&gt;引用丢失(两个对象引用同一个内存)&lt;/li&gt;
&lt;li&gt;set, map, weakset, weakmap 以及一些新语法&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;进阶: 不用递归如何使用循环来求解&lt;/p&gt;
&lt;h2&gt;代码实现&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; objectTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object Met]&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; arrayTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object Met]&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; argsTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object Arguments]&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mapTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object Map]&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; setTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object Set]&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; boolTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object Boolean]&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stringTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object String]&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; numberTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object Number]&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dateTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object Date]&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; errorTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object Error]&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; regTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object RegExp]&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; FunTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[object Function]&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 👇es 6 后无包装类型&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// const symbolTag = &quot;[object Symbol]&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// const bigintTag = &quot;[object BigInt]&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// const nullTag = &quot;[object Null]&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// const undefinedTag = &quot;[object Undefined]&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deepTag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mapTag&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setTag&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; objectTag&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; arrayTag&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; argsTag&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;forEach&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; iteratee&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;iteratee&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; array
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;cloneFunction&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bodyReg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;={)(.|\n)+(?=})&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;m&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; paramReg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;=\().+(?=\)\s+{)&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; funcString &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; func&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;func&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; param &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; paramReg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;funcString&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; body &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bodyReg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;funcString&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;param&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; args &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; param&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 箭头函数没有 prototype&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;funcString&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;cloneOtherType&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Ctor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constructor

  &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; boolTag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; stringTag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; numberTag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; dateTag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; errorTag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Ctor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; regTag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; re &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;\w*$&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; reg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;source&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; re&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      reg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lastIndex &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lastIndex
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; reg
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; FunTag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cloneFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Symbols 以及没有包装类型了, 面试的时候可以提一下可以用 Object.getOwnPropertySymbols() copy symbol&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deepClone &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; map &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WeakMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; target &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; target &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;function&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;
    target &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; source

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; type &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; cloneTarget

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;deepTag&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cloneOtherType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Ctor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constructor
  cloneTarget &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Ctor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 处理循环引用&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;map&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  map&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cloneTarget&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 处理 set&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; setTag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cloneTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;deepClone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cloneTarget
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 处理 map&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; mapTag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cloneTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;deepClone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cloneTarget
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arrayTag &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;keys &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      key &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    cloneTarget&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;deepClone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cloneTarget
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;延伸问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果使用 JSON.stringify(JSON.parse(xx)) 来进行深拷贝会有什么问题?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;丢失循环引用信息&lt;/li&gt;
&lt;li&gt;丢失正则和函数等特殊对象类型&lt;/li&gt;
&lt;li&gt;丢失原型链 等特殊值&lt;/li&gt;
&lt;li&gt;丢失 undefined&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;proto&lt;/strong&gt; 和 prototype 什么区别&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;proto&lt;/strong&gt; 指向构造函数的原型&lt;/li&gt;
&lt;li&gt;prototype 是仅在函数对象上存在的属性，用于定义通过构造函数创建的对象的原型链。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注意&lt;/strong&gt;: for...in 还会枚举继承的属性，用这种遍历方法需要搭配 Object.hasOwnProperty()&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;类数组对象是什么&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript 类型化数组是一种类似数组的对象，并提供了一种用于在内存缓冲中访问原始二进制数据的机制。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;包装类型和 x 是什么&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;引用类型和包装类型的主要区别就是对象的生存期，使用 new 操作符创建的引用类型的实例，在执行流离开当前作用域之前都一直保存在内存中，而自基本类型则只存在于一行代码的执行瞬间，然后立即被销毁，这意味着我们不能在运行时为基本类型添加属性和方法。&lt;/li&gt;
&lt;li&gt;围绕原始数据类型创建一个显式包装器对象从 ECMAScript 6 开始不再被支持, 所以诸如 Symbol BigInt 没有包装类型
&lt;ul&gt;
&lt;li&gt;诸如 new String() 等因为历史的原因留了下来&lt;/li&gt;
&lt;li&gt;对于 Symbol 可以用 Object.getOwnPropertySymbols() copy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;while、for...in、for 效率哪个高?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;while、for 要比其他循环要高，优势是不用执行回调函数等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/deep-clone/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[颜色透明度16进制对照表]]></title><description><![CDATA[dddddd]]></description><link>http://huangbowen.cn/blog/color-transparency-hexadecimal-comparison-table/</link><guid isPermaLink="false">http://huangbowen.cn/blog/color-transparency-hexadecimal-comparison-table/</guid><pubDate>Fri, 15 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;颜色透明度16进制对照表&lt;/h2&gt;
&lt;p&gt;100% — FF
99% — FC
98% — FA
97% — F7
96% — F5
95% — F2
94% — F0
93% — ED
92% — EB
91% — E8
90% — E6
89% — E3
88% — E0
87% — DE
86% — DB
85% — D9
84% — D6
83% — D4
82% — D1
81% — CF
80% — CC
79% — C9
78% — C7
77% — C4
76% — C2
75% — BF
74% — BD
73% — BA
72% — B8
71% — B5
70% — B3
69% — B0
68% — AD
67% — AB
66% — A8
65% — A6
64% — A3
63% — A1
62% — 9E
61% — 9C
60% — 99
59% — 96
58% — 94
57% — 91
56% — 8F
55% — 8C
54% — 8A
53% — 87
52% — 85
51% — 82
50% — 80
49% — 7D
48% — 7A
47% — 78
46% — 75
45% — 73
44% — 70
43% — 6E
42% — 6B
41% — 69
40% — 66
39% — 63
38% — 61
37% — 5E
36% — 5C
35% — 59
34% — 57
33% — 54
32% — 52
31% — 4F
30% — 4D
29% — 4A
28% — 47
27% — 45
26% — 42
25% — 40
24% — 3D
23% — 3B
22% — 38
21% — 36
20% — 33
19% — 30
18% — 2E
17% — 2B
16% — 29
15% — 26
14% — 24
13% — 21
12% — 1F
11% — 1C
10% — 1A
9% — 17
8% — 14
7% — 12
6% — 0F
5% — 0D
4% — 0A
3% — 08
2% — 05
1% — 03
0% — 00&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/color-transparency-hexadecimal-comparison-table/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[经典题目：从输入URL到页面呈现发生了什么]]></title><link>http://huangbowen.cn/blog/classic-topic-what-happened-from-URL-input-to-page-rendering/index2/</link><guid isPermaLink="false">http://huangbowen.cn/blog/classic-topic-what-happened-from-URL-input-to-page-rendering/index2/</guid><pubDate>Wed, 18 Aug 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;chrome浏览器是多进程架构，最上层的是浏览器进程（标签页外面的一切都由浏览器进程处理），然后是实用程序进程、渲染进程、GPU进程、插件进程。&lt;/p&gt;
&lt;p&gt;所以，当我们在地址栏输入aminer.cn&lt;/p&gt;
&lt;h4&gt;导航&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;浏览器进程下面的UI线程去绘制浏览器的按钮和地址栏&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UI线程会判断用户输入的是查询字符串还是URL&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果输入的是URL，UI线程会通知网络线程发起网络调用，获取网站内容（此时会先检查强缓存，如果命中直接返回网站内容）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网络线程进行DNS查询（如果之前解析过这个域名，则直接命中缓存）、建立TLS连接（对于HTTPS）（如果返回301此时网络线程会跟UI线程沟通，再对另一个URL发送请求）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过三次握手建立 TCP 连接(即总共发送3个数据包确认已经建立连接)建立客户端和服务器之间的连接。然后进行数据包发送，接收方接收到数据包后必须要向发送方确认，否则会吃重复发送数据包，最后通过四次挥手断开链接&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;构建请求行、请求头和请求体，发送 HTTP 请求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;收到响应数据，网络线程会检查接收到的前几个字节。响应的Content-Type头部应该包含数据类型，如果没有这个字段，则需要MIME类型嗅探&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果是一个zip文件或其他文件，那就意味着是一个下载请求，需要把数据传给下载管理器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果响应是HTML文件，要进行“安全浏览”检查，所有查检完毕，网络线程确认浏览器可以导航到用户请求的网站，于是会通知UI线程数据已经准备好了。UI线程会联系渲染器进程渲染网页。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提交导航。数据和渲染器进程都有了，就可以通过IPC从浏览器进程向渲染器进程提交导航。渲染器进程也会同时接收到不间断的HTML数据流。当浏览器进程收到渲染器进程的确认消息后，导航完成，文档加载阶段开始。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;此时，地址栏会更新，安全指示图标和网站设置UI也会反映新页面的信息。当前标签页面的会话历史会更新，后退/前进按钮起作用。为便于标签页/会话在关闭标签页或窗口后恢复，会话历史会写入磁盘。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提交导航之后，渲染器进程将负责加载资源和渲染页面（具体细节后面介绍）。而在“完成”渲染后（在所有iframe中的onload事件触发且执行完成后），渲染器进程会通过IPC给浏览器进程发送一个消息。此时，UI线程停止标签页上的旋转图标。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;渲染&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;构建DOM。渲染器进程收到导航的提交消息后，开始接收HTML，其主线程开始解析文本字符串（HTML），并将它转换为DOM（Document Object Model，文档对象模型）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;加载子资源。网站都会用到图片、CSS和JavaScript等外部资源。浏览器需要从缓存或网络加载这些文件。主线程可以在解析并构建DOM的过程中发现一个加载一个，但这样效率太低。为此，Chrome会在解析同时并发运行“预加载扫描器”，当发现HTML文档中有&lt;img/&gt;或&lt;link/&gt;时，预加载扫描器会将请求提交给浏览器进程中的网络线程。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JavaScript可能阻塞解析。如果HTML解析器碰到&lt;script/&gt;标签，会暂停解析HTML文档并加载、解析和执行JavaScript代码。&lt;a href=&quot;&amp;#x27;&amp;#x27;&quot;&gt;defer与async&lt;/a&gt;因为JavaScript有可能通过document.write()修改文档，进而改变DOM结构&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;主线程要解析CSS并计算每个DOM节点的样式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;主线程会遍历DOM元素及其计算样式，然后构造一棵布局树，这棵树的每个节点将带有坐标和大小信息。布局树与DOM树的结构类似，但只包含页面中可见元素的信息。如果元素被应用了display: none，则布局树中不会包含它（visibility: hidden的元素会包含在内）。类似地，通过伪类p::before{content: &apos;Hi!&apos;}添加的内容会包含在布局树中，但DOM树中却没有。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;主线程会遍历布局树并创建绘制记录。绘制记录（绘制顺序）是对绘制过程的注解，比如“先画背景，然后画文本，最后画矩形”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;主线程会遍历布局树并创建分层树，然后主线程就会把这些信息提交给合成器线程。合成器线程接下来负责将每一层转换为像素——栅格化。一层有可能跟页面一样大，此时合成器线程会将它切成小片（tile），再把每一片发给栅格化线程。栅格化线程将每一小片转换为像素后将它们保存在GPU的内存中。will-change则是用来提醒浏览器该分层了&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;合成器线程会安排栅格化线程优先转换视口（及附近）的小片。而构成一层的小片也会转换为不同分辨率的版本，以便在用户缩放时使用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;创建好的合成器帧会通过IPC提交给浏览器进程。与此同时，为更新浏览器界面，UI线程可能还会添加另一个合成器帧；或者因为有扩展，其他渲染器进程也可能添加额外的合成器帧。所有这些合成器帧都会发送给GPU，以便最终显示在屏幕上。如果发生滚动事件，合成器线程会再创建新的合成器帧并发送给GPU。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;交互&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;当用户交互比如触摸事件发生时，浏览器进程首先接收到该手势。但是，浏览器进程仅仅知道手势发生在哪里，因为标签页中的内容是渲染器进程处理。因此浏览器进程会把事件类型（如touchstart）及其坐标发送给渲染器进程。渲染器进程会处理这个事件，即根据事件目标来运行注册的监听程序。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;非快速滚动区”（non-fast scrollable region）。我们知道，运行JavaScript是主线程的活儿。在页面合成后，合成器线程会给附加了事件处理程序的页面区域打上“Non-Fast Scrollable Region”的记号。有了这个记号，合成器线程就可以在该区域发生事件时把事件发送给主线程。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/classic-topic-what-happened-from-URL-input-to-page-rendering/index2/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[一文搞懂this指向问题]]></title><link>http://huangbowen.cn/blog/learn-about-the-problem-of-this-point/</link><guid isPermaLink="false">http://huangbowen.cn/blog/learn-about-the-problem-of-this-point/</guid><pubDate>Sat, 02 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; bar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    myName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;time.geekbang.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;printName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;    
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; myName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;极客时间&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; bar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;printName
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; myName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;极客邦&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; _printName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;_printName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
bar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;printName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;在 printName 函数里面使用的变量 myName 是属于全局作用域下面的，所以最终打印出来的值都是“极客邦”。这是因为 JavaScript 语言的作用域链是由词法作用域决定的，而词法作用域是由代码结构来确定的。&lt;/p&gt;
&lt;p&gt;在对象内部的方法中使用对象内部的属性是一个非常普遍的需求。但是 JavaScript 的作用域机制并不支持这一点，基于这个需求，JavaScript 又搞出来另外一套 this 机制。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://static001.geekbang.org/resource/image/b3/8d/b398610fd8060b381d33afc9b86f988d.png?wh=1142*615&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;arrow function的this指向&lt;/h3&gt;
&lt;p&gt;箭头函数因为其内部 this 的值无法被改变，它与 &lt;strong&gt;创建&lt;/strong&gt; 箭头函数时上下文的this指向相同&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fun&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Window {window: Window, self: Window, document: document, name: &quot;&quot;, location: Location, …}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;new 关键字&lt;/h3&gt;
&lt;p&gt;使用 new 关键字调用函数时，函数中的 this 指向为 JS 创建的新对象&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;news&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// func {}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// func {name: &apos;news&apos;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;bind方法&lt;/h3&gt;
&lt;p&gt;使用 bind 方法可将函数绑定到其外部的 this&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;避免使用 bind 将函数绑定到其外部的 this。使用箭头函数替代，因为这样 this 可以在函数声明就能清楚地看出来，而非在后续代码中看到。&lt;/li&gt;
&lt;li&gt;不要使用 bind 设置 this 为与父对象无关的值；这通常是出乎意料的，这也是 this 获得如此糟糕名声的原因。考虑将值作为参数传递；它更加明确，并且可以使用箭头函数&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; o &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bind&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// { name: &apos;bind&apos; }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;apply和call方法&lt;/h3&gt;
&lt;p&gt;使用 apply 和 call 方法可将this绑定到传入函数的第一个参数。两个方法区别在于通过 apply 调用时实参是放到数组中的，而通过 call 调用时实参是逗号分隔的。&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; o &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bind&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// {name: &quot;bind&quot;} Arguments(5) [5, 6, 2, 3, 7, callee: ƒ, Symbol(Symbol.iterator): ƒ]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// {name: &quot;bind&quot;} Arguments(5) [5, 6, 2, 3, 7, callee: ƒ, Symbol(Symbol.iterator): ƒ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;函数作为对象的成员变量被调用&lt;/h3&gt;
&lt;p&gt;函数作为对象的成员变量被调用时，this的指向为调用函数的对象&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;obj&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// {name: &quot;obj&quot;, func: ƒ}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;当函数没有作为&lt;strong&gt;方法&lt;/strong&gt;被调用，而是被赋值给另一个变量时，则根据那个变量来判断this指向&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;obj&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; func &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;func&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Window {window: Window, self: Window, document: document, name: &quot;&quot;, location: Location, …}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;浏览器和node环境下&lt;/h3&gt;
&lt;p&gt;在浏览器和node环境下全局this的指向会有所不同&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在浏览器里，this 指向 Window。&lt;/li&gt;
&lt;li&gt;在 Node.js 里，this指向 Global&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;this 的设计缺陷以及应对方案&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;嵌套函数中的 this 不会从外层函数中继承&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; myObj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;极客时间&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;token function-variable function&quot;&gt;showThis&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
myObj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showThis&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;普通函数中的 this 默认指向全局对象。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不过这个设计也是一种缺陷，因为在实际工作中，我们并不希望函数执行上下文中的 this 默认指向全局对象，因为这样会打破数据的边界，造成一些误操作。如果要让函数执行上下文中的 this 指向某个对象，最好的方式是通过 call 方法来显示调用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这个问题可以通过设置 JavaScript 的“严格模式”来解决。在严格模式下，默认执行一个函数，其函数的执行上下文中的 this 值是 undefined，这就解决上面的问题了。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- 关于this的指向问题，我通过查阅资料和阅读文章总结了判断this指向的几个优先级, 箭头函数 =》new关键字 =》 bind方法 =》apply和call方法 =》 函数作为对象的成员变量被调用，按照优先级来判断this，多个规则并用取优先级高的那个规则来判断 --&gt;
&lt;!-- 
### 非/严格模式
在**严格模式**下，this 可以是 undefined 或 null。而在**非严格模式**下，如果 this 指向是 undefined 或 null，那么 this 会指向全局对象。

```js
&apos;use strict&apos;;
let obj = {
    name: &apos;obj&apos;,
    func: function (){
        console.log(this)
    }
};

let func = obj.func;
func();

// undefined
``` --&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/learn-about-the-problem-of-this-point/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[js隐式转换]]></title><link>http://huangbowen.cn/blog/js-implicit-conversion/</link><guid isPermaLink="false">http://huangbowen.cn/blog/js-implicit-conversion/</guid><pubDate>Sun, 22 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在判断是否为空数组时，一种是对数组的length属性进行判断即可，第二种进行下图的判断&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;arr &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这就是js的隐式转换，但存在很多摸不清楚的状况，进行今天的学习，希望对js的隐式转换有所了解。&lt;/p&gt;
&lt;h2&gt;Js隐式转换规则&lt;/h2&gt;
&lt;h2&gt;ToBoolean&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;只有false、null、undefined、空字符、0和NaN，其它值转为布尔型都为true。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;ToPrimitive&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;当对象类型需要被转为原始类型时，它会先查找对象的valueOf方法，valueOf方法会返回原始类型的值&lt;/li&gt;
&lt;li&gt;如果valueOf不存在或者返回的不是原始类型的值，就会尝试调用对象的toString方法，也就是会遵循对象的ToString规则，然后使用toString的返回值作为ToPrimitive的结果。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如经典的一道题：如何让if(a == 1 &amp;#x26;&amp;#x26; a == 2)条件成立？&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;ToString&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;null：转为&quot;null&quot;&lt;/li&gt;
&lt;li&gt;undefined：转为&quot;undefined&quot;&lt;/li&gt;
&lt;li&gt;布尔类型：true和false分别被转为&quot;true&quot;和&quot;false&quot;&lt;/li&gt;
&lt;li&gt;数字类型：转为数字的字符串形式，如10转为&quot;10&quot;， 1e21转为&quot;1e+21&quot;&lt;/li&gt;
&lt;li&gt;数组：转为字符串是将所有元素按照&quot;,&quot;连接起来，相当于调用数组的Array.prototype.join()方法，如[1, 2, 3]转为&quot;1,2,3&quot;，空数组[]转为空字符串，数组中的null或undefined，会被当做空字符串处理&lt;/li&gt;
&lt;li&gt;普通对象：转为字符串相当于直接使用Object.prototype.toString()，返回&quot;[object Object]&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;ToNumber&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;null： 转为0&lt;/li&gt;
&lt;li&gt;undefined：转为NaN&lt;/li&gt;
&lt;li&gt;字符串：如果是纯数字形式，则转为对应的数字，空字符转为0, 否则一律按转换失败处理，转为NaN&lt;/li&gt;
&lt;li&gt;布尔型：true和false被转为1和0&lt;/li&gt;
&lt;li&gt;数组/对象：数组首先会被转为原始类型，也就是ToPrimitive，然后根据原始类型按照上面的规则处理&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;布尔类型参与比较&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;布尔类型参与比较，该布尔类型的值首先会被转换为数字类型&lt;/li&gt;
&lt;li&gt;根据布尔类型的ToNumber规则，true转为1，false转为0&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;a == true 布尔值true会转换为数字类型1，即2==1，所以不会执行if里面的语句&lt;/p&gt;
&lt;h2&gt;数字类型和字符串类型参与比较&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;当数字类型和字符串类型做相等比较时，字符串类型会被转换为数字类型&lt;/li&gt;
&lt;li&gt;根据字符串的ToNumber规则，如果是纯数字形式的字符串，则转为对应的数字，空字符转为0, 否则一律按转换失败处理，转为NaN&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;对象类型和原始类型参与比较&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;当对象类型和原始类型做相等比较时，对象类型会依照ToPrimitive规则转换为原始类型&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;null、undefined特殊的转换规则&lt;/h2&gt;
&lt;p&gt;null和undefined==的结果为true&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// false&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ECMAScript规范中规定null和undefined之间互相宽松相等（==），并且也与其自身相等，但和其他所有的值都不宽松相等（==）。&lt;/p&gt;
&lt;h2&gt;==的转换规则&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;两边的类型是否相同，相同的话就比较值的大小，例如1==2，返回false&lt;/li&gt;
&lt;li&gt;判断的是否是null和undefined，是的话就返回true&lt;/li&gt;
&lt;li&gt;判断的类型是否是String和Number，是的话，把String类型转换成Number，再进行比较&lt;/li&gt;
&lt;li&gt;判断其中一方是否是Boolean，是的话就把Boolean转换成Number，再进行比较&lt;/li&gt;
&lt;li&gt;如果其中一方为Object，且另一方为String、Number或者Symbol，会将Object转换成字符串，再进行比较&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/js-implicit-conversion/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[JavaScript模块化总结]]></title><link>http://huangbowen.cn/blog/javascript-modularization-summary/</link><guid isPermaLink="false">http://huangbowen.cn/blog/javascript-modularization-summary/</guid><pubDate>Wed, 07 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;什么是模块化？&lt;/h2&gt;
&lt;p&gt;模块化是以提高代码复用率、减少代码管理的成本为核心思想的开发方式，一个模块有自己的私有作用域，只向外部暴露一些接口(方法，变量)，借此和其他模块进行通信，目前比较热门的js模块化规范：CommonJS、AMD、CMD以及ES6 Module。&lt;/p&gt;
&lt;h2&gt;CommonJS&lt;/h2&gt;
&lt;p&gt;Node.js应用就是采用CommonJS规范组成的，它有四个环境变量为模块化的实现提供支持：global、require、module、exports。在模块中定义的变量、方法都是私有的，外部模块需要使用，需在模块内部用exports暴露。&lt;/p&gt;
&lt;h3&gt;CommonJS运行时&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;模块加载的顺序，按照该模块在代码中出现的顺序(运行时加载)&lt;/li&gt;
&lt;li&gt;所有代码都运行在模块私有作用域，不会污染全局作用域。&lt;/li&gt;
&lt;li&gt;加载模块时会缓存运行结果，后续的加载会直接读取缓存，想要模块再次运行，需要清楚缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CommonJS使用&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;module.exports属性&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;module.exports属性表示当前模块对外输出的接口，其他文件加载该模块，实际上就是读取module.exports变量。&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  add&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;example
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;exports变量&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;exports变量指向module.exports，这相当于在每个模块中都加入var exports = module.exports，也就是对外输出时可以在这个变量上添加方法，&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;exports&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;example &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; example&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;,不能把exports直接指向一个值，这样就相当于切断了exports和module.exports的关系&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 例：&lt;/span&gt;
exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dd&apos;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;require命令&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;require命令用于加载模块文件，相当于读入并执行一个js文件，然后返回该模块的exports对象，没有发现指定模块，则就会报错。
基本使用：&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 引用自定义的模块时，参数包含路径，可省略.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; example &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./example&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
example&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 引用核心模块时，不需要带路径&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; http &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;http&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
http&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;加载规则：&lt;br&gt;
引用阮老师的博客&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;如果参数字符串以“/”开头，则表示加载的是一个位于绝对路径的模块文件。比如，require(&apos;/home/marco/foo.js&apos;)将加载/home/marco/foo.js。&lt;/li&gt;
&lt;li&gt;如果参数字符串以“./”开头，则表示加载的是一个位于相对路径（跟当前执行脚本的位置相比）的模块文件。比如，require(&apos;./circle&apos;)将加载当前脚本同一目录的circle.js。&lt;/li&gt;
&lt;li&gt;如果参数字符串不以“./“或”/“开头，则表示加载的是一个默认提供的核心模块（位于Node的系统安装目录中），或者一个位于各级node_modules目录的已安装模块（全局安装或局部安装）&lt;/li&gt;
&lt;li&gt;如果参数字符串不以“./“或”/“开头，而且是一个路径，比如require(&apos;example-module/path/to/file&apos;)，则将先找到example-module的位置，然后再以它为参数，找到后续路径。&lt;/li&gt;
&lt;li&gt;如果指定的模块文件没有发现，Node会尝试为文件名添加.js、.json、.node后，再去搜索。.js件会以文本格式的JavaScript脚本文件解析，.json文件会以JSON格式的文本文件解析，.node文件会以编译后的二进制文件解析。&lt;/li&gt;
&lt;li&gt;如果想得到require命令加载的确切文件名，使用require.resolve()方法。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;注意
&lt;ul&gt;
&lt;li&gt;(加载方式)：在服务端CommonJS用同步的方式加载模块。&lt;/li&gt;
&lt;li&gt;(加载方式)：在浏览器端，限于网络原因，更合理的方案是使用异步加载。&lt;/li&gt;
&lt;li&gt;(加载机制)：输入的是被输出的值的拷贝。也就是说，一旦输出一个值，模块内部的变化就影响不到这个值，想要影响到外面的值，需要把值暴露写成一个函数形式。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;count
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; count
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  add&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;add
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;ES6 Module&lt;/h2&gt;
&lt;p&gt;ES6 在语言标准的层面上，实现了模块功能，旨在成为浏览器和服务器通用的模块解决方案。主要由两个命令实现：export命令用于规定模块的对外接口，import命令用于输入其他模块提供的功能。&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//定义模块example&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;add &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//引用模块&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;add &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./example&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;使用import命令的时候，用户需要知道所要加载的变量名或函数名。ES6还提供了export default命令，为模块指定默认输出，对应的import语句不需要使用大括号。这也更趋近于ADM的引用写法。&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//定义输出&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;add &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//引入&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; example &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./example&apos;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//调用&lt;/span&gt;
example&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：ES6的模块不是对象，import命令会被 JavaScript 引擎静态分析，在编译时就引入模块代码，而不是在代码运行时加载，所以无法实现条件加载。也正因为这个，使得静态分析成为可能，webpack也可以进行Tree-Sharking&lt;/p&gt;
&lt;h2&gt;AMD&lt;/h2&gt;
&lt;p&gt;AMD规范采用异步方式加载模块，模块的加载不影响它后面语句的运行。允许指定回调函数，所有依赖这个模块的语句，都定义在这个回调函数中，等到加载完成之后，回调函数才会运行。&lt;br&gt;
基本使用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;require.config()指定引用路径等&lt;/li&gt;
&lt;li&gt;define()定义模块&lt;/li&gt;
&lt;li&gt;require()加载模块&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//定义没有依赖的模块&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; 模块
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
定义有依赖的模块
&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;module1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;module2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;m1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; m2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; 模块
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// require.config()指定各模块路径和引用名&lt;/span&gt;
require&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  baseUrl&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;js/lib&quot;&lt;/span&gt;，
  paths&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;jquery&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;jquery.min&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;underscore&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;underscore.min&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 执行基本操作&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;jquery&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;underscore&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;m1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; m2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   使用模块
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;CMD&lt;/h2&gt;
&lt;p&gt;CMD规范专门用于浏览器端，模块的加载是异步的，模块使用时才会加载执行。CMD规范整合了CommonJS和AMD规范的特点。在 Sea.js 中，所有 JavaScript 模块都遵循 CMD模块定义规范。
基本使用：&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//定义模块&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;require&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exports&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; module&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  exports&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//引入模块&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; m1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./m1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; m2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./m2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;主要总结下CommonJS和es module的区别：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CommonJS模块输出的是一个值的拷贝，ES6模块输出的是值的引用。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;CommonJS 模块输出的是值的拷贝，一旦输出一个值，模块内部的变化就影响不到这个值，会将结果进行缓存。&lt;/li&gt;
&lt;li&gt;ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候，遇到模块加载命令import，就会生成一个只读引用。等到脚本真正执行时，再根据这个只读引用，到被加载的那个模块里面去取值。因此ES6模块是动态引用，并且不会缓存值，对此webpack可以做tree-sharking处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;CommonJS模块是运行时加载，ES6模块是编译时输出接口&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;CommonJS是运行时进行加载：模块就是对象，即在输入时是先加载整个模块，生成一个对象，然后再从这个对象上面读取方法，这种加载称为“运行时加载”。&lt;/li&gt;
&lt;li&gt;ES6是编译时加载：模块不是对象，而是通过export命令显式指定输出的代码，import时采用静态命令的形式。即在import时可以指定加载某个输出值，而不是加载整个模块，这种加载称为“编译时加载”。&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/javascript-modularization-summary/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[v8引擎垃圾内存回收机制]]></title><link>http://huangbowen.cn/blog/garbage-collection-mechanism-of-v8-engine/</link><guid isPermaLink="false">http://huangbowen.cn/blog/garbage-collection-mechanism-of-v8-engine/</guid><pubDate>Tue, 11 Aug 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Js不会让程序员自己开辟或释放内存，而是有自己的一套垃圾回收算法，来进行自动的内存管理&lt;/p&gt;
&lt;h2&gt;V8内存限制&lt;/h2&gt;
&lt;p&gt;V8只能使用系统的一部分内存，具体来说，在64位系统下，V8最多只能分配1.4G, 在32位系统中，最多只能分配0.7G。你想想在前端这样的大内存需求其实并不大，但对于后端而言，nodejs如果遇到一个2G多的文件，那么将无法全部将其读入内存进行各种操作了。&lt;br&gt;
所有的对象类型的数据在JS中都是通过堆进行空间分配的。当我们构造一个对象进行赋值操作的时候，其实相应的内存已经分配到了堆上。你可以不断的这样创建对象，让V8为它分配空间，直到堆的大小达到上限。设置内存上限是因为两个方面：&lt;br&gt;
第一，JS是单线程运行的，这意味着一旦进入到垃圾回收，那么其它的各种运行逻辑都要暂停; 另一方面垃圾回收其实是非常耗时间的操作&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以 1.5GB 的垃圾回收堆内存为例，V8 做一次小的垃圾回收需要50ms 以上，做一次非增量式(ps:后面会解释)的垃圾回收甚至要 1s 以上。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可见其耗时之久，而且在这么长的时间内，我们的JS代码执行会一直没有响应，造成应用卡顿，导致应用性能和响应能力直线下降。因此，V8 做了一个简单粗暴的选择，那就是限制堆内存，也算是一种权衡的手段，因为大部分情况是不会遇到操作几个G内存这样的场景的。&lt;/p&gt;
&lt;h2&gt;调整内存限制&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;shell&quot;&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;// 这是调整老生代这部分的内存，单位是MB。后面会详细介绍新生代和老生代内存
node --max-old-space-size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2048&lt;/span&gt; xxx.js&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;或者&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;shell&quot;&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;// 这是调整新生代这部分的内存，单位是 KB。
node --max-new-space-size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2048&lt;/span&gt; xxx.js&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;新生代内存的回收&lt;/h2&gt;
&lt;p&gt;V8把堆内存分成了两部分进行处理——新生代内存和老生代内存。顾名思义，新生代就是临时分配的内存，存活时间短， 老生代是常驻内存，存活的时间长。V8 的堆内存，也就是两个内存之和。&lt;br&gt;
新生代的垃圾回收是怎么做的呢，首先，新生代内存空间一分为二:&lt;br&gt;
其中From部分表示正在使用的内存，To 是目前闲置的内存。&lt;/p&gt;
&lt;p&gt;当进行垃圾回收时，V8将From部分的对象检查一遍，如果是存活对象那么复制到To内存中(在To内存中按照顺序从头放置的)，如果是非存活对象直接回收即可。&lt;/p&gt;
&lt;p&gt;当所有的From中的存活对象按照顺序进入到To内存之后，From 和 To 两者的角色对调，From现在被闲置，To为正在使用，如此循环。&lt;/p&gt;
&lt;h2&gt;老生代内存的回收&lt;/h2&gt;
&lt;p&gt;刚刚学习了新生代的回收方式，那么新生代中的变量如果经过多次回收后依然存在，那么就会被放入到老生代内存中，这种现象就叫晋升。&lt;/p&gt;
&lt;p&gt;发生晋升其实不只是这一种原因，我们来梳理一下会有那些情况触发晋升:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;已经经历过一次 Scavenge 回收。&lt;/li&gt;
&lt;li&gt;To（闲置）空间的内存占用超过25%。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;现在进入到老生代的垃圾回收机制当中，老生代中累积的变量空间一般都是很大的，当然不能用Scavenge算法啦，浪费一半空间不说，对庞大的内存空间进行复制岂不是劳民伤财？&lt;/p&gt;
&lt;p&gt;那么对于老生代而言，究竟是采取怎样的策略进行垃圾回收的呢？&lt;/p&gt;
&lt;p&gt;第一步，进行标记-清除。这个过程在《JavaScript高级程序设计(第三版)》中有过详细的介绍，主要分成两个阶段，即标记阶段和清除阶段。首先会遍历堆中的所有对象，对它们做上标记，然后对于代码环境中使用的变量以及被强引用的变量取消标记，剩下的就是要删除的变量了，在随后的清除阶段对其进行空间的回收。&lt;/p&gt;
&lt;p&gt;当然这又会引发内存碎片的问题，存活对象的空间不连续对后续的空间分配造成障碍。老生代又是如何处理这个问题的呢？&lt;/p&gt;
&lt;p&gt;第二步，整理内存碎片。V8 的解决方式非常简单粗暴，在清除阶段结束后，把存活的对象全部往一端靠拢。&lt;/p&gt;
&lt;h2&gt;增量标记&lt;/h2&gt;
&lt;p&gt;由于JS的单线程机制，V8 在进行垃圾回收的时候，不可避免地会阻塞业务逻辑的执行，倘若老生代的垃圾回收任务很重，那么耗时会非常可怕，严重影响应用的性能。那这个时候为了避免这样问题，V8 采取了增量标记的方案，即将一口气完成的标记任务分为很多小的部分完成，每做完一个小的部分就&quot;歇&quot;一下，就js应用逻辑执行一会儿，然后再执行下面的部分，如果循环，直到标记阶段完成才进入内存碎片的整理上面来。其实这个过程跟React Fiber的思路有点像，这里就不展开了。&lt;/p&gt;
&lt;p&gt;经过增量标记之后，垃圾回收过程对JS应用的阻塞时间减少到原来了1 / 6, 可以看到，这是一个非常成功的改进。&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/garbage-collection-mechanism-of-v8-engine/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[经典题目：从输入URL到页面呈现发生了什么]]></title><link>http://huangbowen.cn/blog/classic-topic-what-happened-from-URL-input-to-page-rendering/</link><guid isPermaLink="false">http://huangbowen.cn/blog/classic-topic-what-happened-from-URL-input-to-page-rendering/</guid><pubDate>Tue, 30 Jun 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;网络世界&lt;/h2&gt;
&lt;p&gt;1.浏览器会构建HTTP请求编码
2.DNS将域名解析为ip地址，浏览器也会提供DNS缓存，如果之前解析过这个域名，则直接命中缓存
3.先查强缓存，命中直接使用缓存
4.可能经过正向代理、反向代理、负载均衡、源服务器
5.建立TCP连接，会经历三次握手、数据包发送、四次挥手
6.发送http请求，包含请求行、请求头、请求体
7.服务器接收到请求，进行网络响应，返回响应行(HTTP协议版本、状态码和状态描述)
8.最后判断connection字段，如果请求头或响应头包含Connection: Keep-Alive，表示建立长连接，TCP连接会一直保持，否则断开连接&lt;/p&gt;
&lt;h2&gt;解析算法&lt;/h2&gt;
&lt;p&gt;1.如果响应头中Content-Type的值是text/html，进行解析和渲染工作
2.构建DOM树，由于浏览器无法直接理解HTML字符串，因此将字节流转换为一种有意义并且方便操作的数据结构，这种数据结构就是DOM树
3.因为HTML是非上下文无关的，所以需要特殊的解析器来完成
4.解析算法分为两步，标记化和建树，标记化可以通过有限状态自动机来完成
5.建树算法，会将DOM对象加入 DOM 树中。还会将对应标记压入存放开放(与闭合标签意思对应)元素的栈中。
6.进行样式计算，浏览器是无法直接识别 CSS 样式文本的，因此渲染引擎接收到 CSS 文本之后第一件事情就是将其转化为一个结构化的对象，即styleSheets。
7.标准化样式，比如em =&gt; px , black =&gt; #000
8.计算每个节点的样式,每个子节点都会默认继承父节点的样式属性，如果父节点中没有找到，就会采用浏览器默认样式，也叫UserAgent样式。这就是继承规则，非常容易理解。
9.生成布局树，过浏览器的布局系统确定元素的位置，遍历DOM树节点，并把他们添加到布局树中，计算布局树节点的坐标位置。&lt;/p&gt;
&lt;h2&gt;渲染过程&lt;/h2&gt;
&lt;p&gt;1.构建图层树，比如进行3D变换的效果，当元素含有层叠上下文时怎样显示或隐藏元素，浏览器在构建完布局树之后，还会对特定的节点进行分层，构建一棵图层树
2.生成绘制列表，渲染引擎会将图层的绘制拆分成一个个绘制指令，按顺序组成绘制列表
3.在渲染进程中，合成线程负责绘制操作，绘制列表准备好了之后，渲染进程的主线程会给合成线程发送commit消息，把绘制列表提交给合成线程。
4.合成线程会将将图层分块，这样会加速首屏显示
5.因为图块上传到GPU内存会比较慢，在首次绘制时会先绘制低分辨率的图片，绘制好后再进行替换
6.合成线程会选择视口附近的图块，把它交给栅格化线程池生成位图，过程中使用GPU进行加速，生成的位图最后发送给合成线程
7.栅格化操作完成后，合成线程会生成一个绘制命令，并发送给浏览器进程
8.浏览器进程把页面内容绘制到内存，也就是生成了页面，然后把这部分内存发送给显卡&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/classic-topic-what-happened-from-URL-input-to-page-rendering/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[浏览器缓存]]></title><link>http://huangbowen.cn/blog/browser-cache/</link><guid isPermaLink="false">http://huangbowen.cn/blog/browser-cache/</guid><pubDate>Sun, 21 Jun 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;概念扫盲：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;1.浏览器缓存分为三个部分：强缓存 协商缓存 缓存位置&lt;/li&gt;
&lt;li&gt;2.浏览器缓存分为两种情况：需要发送HTTP请求 不需要发送HTTP请求&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;强缓存&lt;/h2&gt;
&lt;p&gt;强缓存是不需要发送HTTP请求的，可通过相应的字段来进行：HTTP/1.0时期使用的是Expires，而HTTP/1.1使用的是Cache-Control&lt;/p&gt;
&lt;h3&gt;Expires&lt;/h3&gt;
&lt;p&gt;Expires即过期时间，存在于服务端返回的响应头中，用以告诉浏览器在这个过期时间内可以直接从缓存里面获取数据，无需再次请求，例：&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Expires: Wed, 22 Nov 2019 08:41:00 GMT&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;表示资源在这段时间后过期，过期后就需要从新向服务端发请求&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;然而服务器和浏览器的时间可能不一致，那这个过期时间就是不准确的，因此这种方式很快在后来的HTTP1.1中被抛弃来了&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Cache-Control&lt;/h3&gt;
&lt;p&gt;Cache-Control没有采取过期时间的方式，而采用了过期时长来控制缓存，对应字段是max-age=3600&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Cache-Control: max-age=3600&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;代表在这段时间内，可以直接使用缓存&lt;/p&gt;
&lt;p&gt;Cache-Control可以组合很多的命令，如：
public：代理服务器和浏览器都可以进行缓存&lt;br&gt;
private： 仅浏览器可缓存&lt;br&gt;
no-cache：跳过强缓存，直接进入协商缓存阶段&lt;br&gt;
no-store：不进行任何形式的缓存&lt;br&gt;
s-maxage： 针对代理服务器的缓存时间&lt;br&gt;
must-revalidate：一旦过期，必须回到源服务器验证&lt;/p&gt;
&lt;p&gt;&lt;font color=red&gt;Cache-Control比Expires的优先级高&lt;/font&gt;&lt;br&gt;
缓存时间超时了，进入协商缓存&lt;/p&gt;
&lt;h2&gt;协商缓存&lt;/h2&gt;
&lt;p&gt;强缓存失效后，浏览器在请求头中携带相应的缓存tag来向服务器发请求，服务器根据tag来决定是否使用缓存，缓存tag分为两种：Last-Modified和ETag&lt;/p&gt;
&lt;h3&gt;Last-Modified&lt;/h3&gt;
&lt;p&gt;即最后修改时间，浏览器第一次给服务器发送请求后，服务器会在相应头中加上这个字段。&lt;br&gt;
浏览器接受后，如果再次请求，会在请求头中携带If-Modified-Since字段，值也就是服务器传来的最后修改时间，例：&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;If-Modified-Since: Sat, 29 Feb 2020 10:02:10 GMT&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;服务器拿到请求头的If-Modified-Since后，会和服务器中该资源的最后修改时间对比：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这个值小于最后修改时间，说明是时候更新了，返回新的资源，跟常规的HTTP请求响应的流程一样&lt;/li&gt;
&lt;li&gt;否则返回304，告诉浏览器直接用缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ETag&lt;/h3&gt;
&lt;p&gt;ETag是服务器根据当前文件的内容，给文件生成的唯一标识，服务器通过相应头把这个值给浏览器&lt;br&gt;
浏览器接受后，如果再次请求，会将这个值作为If-None-Match的内容，放到请求头中，例：&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;If-None-Match: W/&quot;69d9-17090656aef&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;服务器拿到请求头的If-None-Match后，会和服务器中该资源的ETag进行对比：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;两者不一样，说明是时候更新了，返回新的资源，跟常规的HTTP请求响应的流程一样&lt;/li&gt;
&lt;li&gt;否则返回304，告诉浏览器直接用缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;两者对比&lt;/h3&gt;
&lt;p&gt;1.精准度上，ETag优于Last-Modified，上标识要比修改时间能更准确的感知资源的变化，例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;编辑了文件，内容未更改，这样也会造成缓存失效&lt;/li&gt;
&lt;li&gt;Last-Modified能够感知的单位时间是秒，如果文件在1秒内改变多次，那么这时候就体现不出修改了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2.性能上反而是Last-Modified优于ETag，一个是记录时间，一个是生成哈希值&lt;br&gt;
两种方式都支持的话，服务器会优先考虑ETag&lt;/p&gt;
&lt;h2&gt;缓存位置&lt;/h2&gt;
&lt;p&gt;当强缓存命中或者协商缓存命中，服务器返回304的时候，我们直接从缓存中获取资源，但这些资源缓存在哪里呢？&lt;br&gt;
浏览器中的缓存位置一共有四种，按优先级从高到低排列分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service Worker&lt;/li&gt;
&lt;li&gt;Memory Cache&lt;/li&gt;
&lt;li&gt;Disk Cache&lt;/li&gt;
&lt;li&gt;Push Cache&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Service Worker&lt;/h3&gt;
&lt;p&gt;Service Worker借鉴了Web Worker的思路，即让JS运行在主线程之外，由于它脱离了浏览器的窗体，无法直接访问DOM，可完成的功能，比如：离线缓存、消息推送、网络代理等，Service Worker同时也是PWA的重要实现机制&lt;/p&gt;
&lt;h3&gt;Memory Cache和Disk Cache&lt;/h3&gt;
&lt;p&gt;Memory Cache就是在内存缓存，存取效率最快，存活时间最短，当渲染进程结束后，内存缓存就不存在了&lt;br&gt;
Disk Cache是指存储在磁盘中的缓存，存取要比内存缓存慢，但它的优势在于存储容量和存储时长&lt;br&gt;
浏览器缓存资源策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;比较大的Js、CSS文件会放进磁盘，反之丢进内存&lt;/li&gt;
&lt;li&gt;内存使用率比较高的时候，文件优先进入磁盘&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Push Cache&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;扩展链接&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;浏览器的缓存机制为：先通过Cache-Control监测强缓存是否可用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可用，直接使用强缓存&lt;/li&gt;
&lt;li&gt;否则进入协商缓存，即发送HTTP请求，服务器通过请求头中的If-Modified-Since或者If-None-Match这些字段请求检查资源是否更新：&lt;/li&gt;
&lt;li&gt;若资源更新，返回资源和200状态码&lt;/li&gt;
&lt;li&gt;否则，返回304，告诉浏览器直接从缓存获取资源即可&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/browser-cache/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[什么是 XSS 攻击？如何防范 XSS 攻击 ？]]></title><link>http://huangbowen.cn/blog/how-to-prevent-xss-attack/</link><guid isPermaLink="false">http://huangbowen.cn/blog/how-to-prevent-xss-attack/</guid><pubDate>Wed, 13 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;XSS是什么？&lt;/h2&gt;
&lt;p&gt;XSS 攻击指的是跨站脚本攻击，是一种代码注入攻击。攻击者通过在网站注入恶意脚本，使之在用户的浏览器上运行，从而盗取用户的信息如 cookie 等。&lt;br&gt;
XSS 的本质是因为网站没有对恶意代码进行过滤，与正常的代码混合在一起了，浏览器没有办法分辨哪些脚本是可信的，从而导致了恶意代码的执行。&lt;/p&gt;
&lt;h2&gt;XSS类型？&lt;/h2&gt;
&lt;p&gt;XSS 一般分为存储型、反射型和 DOM 型。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存储型指的是恶意代码提交到了网站的数据库中，当用户请求数据的时候，服务器将其拼接为 HTML 后返回给了用户，从而导致了恶意代码的执行。&lt;/li&gt;
&lt;li&gt;反射型指的是攻击者构建了特殊的 URL，当服务器接收到请求后，从 URL 中获取数据，拼接到 HTML 后返回，从而导致了恶意代码的执行。&lt;/li&gt;
&lt;li&gt;DOM 型指的是攻击者构建了特殊的 URL，用户打开网站后，js 脚本从 URL 中获取数据，从而导致了恶意代码的执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;XSS的预防&lt;/h2&gt;
&lt;p&gt;XSS 攻击的预防可以从两个方面入手，一个是恶意代码提交的时候，一个是浏览器执行恶意代码的时候。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于第一个方面，如果我们对存入数据库的数据都进行的转义处理，但是一个数据可能在多个地方使用，有的地方可能不需要转义，由于我们没有办法判断数据最后的使用场景，所以直接在输入端进行恶意代码的处理，其实是不太可靠的。&lt;/li&gt;
&lt;li&gt;因此我们可以从浏览器的执行来进行预防，一种是使用纯前端的方式，不用服务器端拼接后返回。另一种是对需要插入到 HTML 中的代码做好充分的转义。对于 DOM 型的攻击，主要是前端脚本的不可靠而造成的，我们对于数据获取渲染和字符串拼接的时候应该对可能出现的恶意代码情况进行判断。&lt;/li&gt;
&lt;li&gt;还有一些方式，比如使用 CSP ，CSP 的本质是建立一个白名单，告诉浏览器哪些外部资源可以加载和执行，从而防止恶意代码的注入攻击。&lt;/li&gt;
&lt;li&gt;还可以对一些敏感信息进行保护，比如 cookie 使用 http-only ，使得脚本无法获取。也可以使用验证码，避免脚本伪装成用户执行一些操作。&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/how-to-prevent-xss-attack/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[什么是 CSRF 攻击？如何防范 CSRF 攻击 ？]]></title><link>http://huangbowen.cn/blog/how-to-prevent-csrf-attack/</link><guid isPermaLink="false">http://huangbowen.cn/blog/how-to-prevent-csrf-attack/</guid><pubDate>Sat, 09 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;什么是CSRF攻击？&lt;/h2&gt;
&lt;p&gt;CSRF 攻击指的是跨站请求伪造攻击，攻击者诱导用户进入一个第三方网站，然后该网站向被攻击网站发送跨站请求。如果用户在被
攻击网站中保存了登录状态，那么攻击者就可以利用这个登录状态，绕过后台的用户验证，冒充用户向服务器执行一些操作。&lt;br&gt;
CSRF 攻击的本质是利用了 cookie 会在同源请求中携带发送给服务器的特点，以此来实现用户的冒充。&lt;/p&gt;
&lt;h2&gt;CSRF类型&lt;/h2&gt;
&lt;p&gt;一般的 CSRF 攻击类型有三种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一种是 GET 类型的 CSRF 攻击，比如在网站中的一个 img 标签里构建一个请求，当用户打开这个网站的时候就会自动发起提&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;交。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第二种是 POST 类型的 CSRF 攻击，比如说构建一个表单，然后隐藏它，当用户进入页面时，自动提交这个表单。&lt;/li&gt;
&lt;li&gt;第三种是链接类型的 CSRF 攻击，比如说在 a 标签的 href 属性里构建一个请求，然后诱导用户去点击。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;CSRF攻击预防&lt;/h2&gt;
&lt;p&gt;CSRF 可以用下面几种方法来防护：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一种是同源检测的方法，服务器根据 http 请求头中 origin 或者 referer 信息来判断请求是否为允许访问的站点，从而对请求进行过滤。当 origin 或者 referer 信息都不存在的时候，直接阻止。这种方式的缺点是有些情况下 referer 可以被伪造。还有就是我们这种方法同时把搜索引擎的链接也给屏蔽了，所以一般网站会允许搜索引擎的页面请求，但是相应的页面请求这种请求方式也可能被攻击者给利用。&lt;/li&gt;
&lt;li&gt;第二种方法是使用 CSRF Token 来进行验证，服务器向用户返回一个随机数 Token ，当网站再次发起请求时，在请求参数中加入服务器端返回的 token ，然后服务器对这个 token 进行验证。这种方法解决了使用 cookie 单一验证方式时，可能会被冒用的问题，但是这种方法存在一个缺点就是，我们需要给网站中的所有请求都添加上这个 token，操作比较繁琐。还有一个问题是一般不会只有一台网站服务器，如果我们的请求经过负载平衡转移到了其他的服务器，但是这个服务器的 session 中没有保留这个 token 的话，就没有办法验证了。这种情况我们可以通过改变 token 的构建方式来解决。&lt;/li&gt;
&lt;li&gt;第三种方式使用双重 Cookie 验证的办法，服务器在用户访问网站页面时，向请求域名注入一个Cookie，内容为随机字符串，然后当用户再次向服务器发送请求的时候，从 cookie 中取出这个字符串，添加到 URL 参数中，然后服务器通过对 cookie 中的数据和参数中的数据进行比较，来进行验证。使用这种方式是利用了攻击者只能利用 cookie，但是不能访问获取 cookie 的特点。并且这种方法比 CSRF Token 的方法更加方便，并且不涉及到分布式访问的问题。这种方法的缺点是如果网站存在 XSS 漏洞的，那么这种方式会失效。同时这种方式不能做到子域名的隔离。&lt;/li&gt;
&lt;li&gt;第四种方式是使用在设置 cookie 属性的时候设置 Samesite ，限制 cookie 不能作为被第三方使用，从而可以避免被攻击者利用。Samesite 一共有两种模式，一种是严格模式，在严格模式下 cookie 在任何情况下都不可能作为第三方 Cookie 使用，在宽松模式下，cookie 可以被请求是 GET 请求，且会发生页面跳转的请求所使用。&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/how-to-prevent-csrf-attack/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[热门技术]]></title><link>http://huangbowen.cn/blog/hot-technology/</link><guid isPermaLink="false">http://huangbowen.cn/blog/hot-technology/</guid><pubDate>Thu, 16 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;作为一名前端小学生，底层的机制和知识，还没有学完，所以对上层的应用不能从根本上理解，比如以前没有接触过深度优先遍历和递归的概念，那么Vue中虚拟DOM整个patch.js的源码你是基本不可能看懂的。但了解下所从事的行业的热门技术也是必要的&lt;/p&gt;
&lt;h2&gt;Flutter&lt;/h2&gt;
&lt;p&gt;Fultter最近可是火的一塌糊涂，几乎从前端圈的各处都可以接触到Flutter教程和推广，那么Flutter到底是什么意思呢？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Flutter是一款 Google 开源的 SDK，可跨平台地为移动端，Web 端，桌面端构建高性能的应用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是官方的解释，而在实践方面，对我的视野里面来说，闲鱼可以说是Flutter的深度应用者，Flutter可以跨Android，iOS两个平台，可以提高成员利用率，降低人力成本&lt;/p&gt;
&lt;h2&gt;Serverless&lt;/h2&gt;
&lt;p&gt;serverless算是最近几年里比较火热的词汇了，第一次知其原由，是在狼叔的书里，那serverless到底是什么？从字面上来理解，大概是“无服务器”的，详细的解释为用户在使用服务时，不需要关心服务器的硬件资源、软件资源等，用户只需要关注自己代码本身即可，比较著名的有以AWS Lambda为代表的serverless，其初衷是搭建一套轻量级的，无状态的，并且较少依赖于环境的API接口。其优势在于经济（节省成本）、快捷（不需要浪费太多精力在配置web server、load balancer、log、堡垒机等基础设施上）。&lt;/p&gt;
&lt;h2&gt;微前端&lt;/h2&gt;
&lt;p&gt;微前端是一种将巨大工程应用拆分为一个个相对小的应用来解决工程膨胀、开发维护困难的拆分治理方案。推荐文章：&lt;a href=&quot;https://juejin.im/post/5e57b6f0f265da57547794c9&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;微前端在美团外卖的实践
&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Docker&lt;/h2&gt;
&lt;p&gt;Docker用来解决手动部署成本太高、服务器环境污染、以及重装系统成本太高，难以迁移的问题，具体来说就是可以将应用程序打包封装到一个容器中，该容器包含了应用程序的代码、运行环境、依赖库、配置文件等必需的资源，通过容器就可以实现方便快速并且与平台解耦的自动化部署方式，无论你部署时的环境如何，容器中的应用程序都会运行在同一种环境下。&lt;/p&gt;
&lt;h2&gt;前端架构&lt;/h2&gt;
&lt;p&gt;？
好像在大型项目上、开发场景比价复杂的情况下，前端架构设计的重要性才体现出来，大概的用意是，增加项目的可管理性、稳定性。&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/hot-technology/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[了解js内存机制]]></title><link>http://huangbowen.cn/blog/learn-about-the-js-memory-mechanism/</link><guid isPermaLink="false">http://huangbowen.cn/blog/learn-about-the-js-memory-mechanism/</guid><pubDate>Fri, 10 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;分数据类型进行存储&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;基本数据类型用栈存储
&lt;ul&gt;
&lt;li&gt;boolean&lt;/li&gt;
&lt;li&gt;null&lt;/li&gt;
&lt;li&gt;undefined&lt;/li&gt;
&lt;li&gt;number&lt;/li&gt;
&lt;li&gt;string&lt;/li&gt;
&lt;li&gt;symbol&lt;/li&gt;
&lt;li&gt;bigint&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;引用数据类型用堆存储&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原始类型的数据直接存储变量值，引用类型的数据存储引用地址，是因为引用类型有可能很大，那样的话存储太慢，内存空间占有太大，cpu耗时，所以需要在堆中存储引用地址&lt;/p&gt;
&lt;p&gt;对于系统栈来说，它的功能除了保存变量之外，还有创建并切换函数执行上下文的功能。&lt;/p&gt;
&lt;p&gt;所以如果采用栈来存储相对基本类型更加复杂的对象数据，那么切换上下文的开销将变得巨大！不过堆内存虽然空间大，能存放大量的数据，但与此同时垃圾内存的回收会带来更大的开销。&lt;/p&gt;
&lt;p&gt;借此我们也可以了解&lt;strong&gt;深拷贝&lt;/strong&gt;的原理就是新建引用类型，存储新的指针，里面保存了一个一摸一样的对象，这样修改新对象不会影响到原对象&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/learn-about-the-js-memory-mechanism/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[强大的grid网格布局方案]]></title><link>http://huangbowen.cn/blog/powerful-grid-layout-scheme/</link><guid isPermaLink="false">http://huangbowen.cn/blog/powerful-grid-layout-scheme/</guid><pubDate>Sat, 04 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;概述&lt;/h2&gt;
&lt;p&gt;grid网格布局擅长将页面分为不同区域(网格)，控制各部分之间在大小，位置和层的不同方面的联系，可以做出各种各样的布局。&lt;/p&gt;
&lt;h2&gt;Grid布局与Flex布局 ？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Grid 布局与 Flex 布局有一定的相似性，都可以指定容器内部多个项目的位置。但是，它们也存在重大区别。 Flex 布局是轴线布局，只能指定&quot;项目&quot;针对轴线的位置，可以看作是一维布局。Grid 布局则是将容器划分成&quot;行&quot;和&quot;列&quot;，产生单元格，然后指定&quot;项目所在&quot;的单元格，可以看作是二维布局。Grid 布局远比 Flex 布局强大。   -阮一峰老师博客&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意:设置网格布局后容器子元素的 float display:inline-block | table-cell vertical-align column将失效&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;display : grid | inline-grid&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;默认容器为块级元素 可设置为行内元素&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-template-columns: 100px 100px 100px&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;列宽&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-template-rows: 10% 10% 10%&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;行高&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-template-areas  : &quot;a a a&quot;  &quot; b b b&quot;  &quot;c c c&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上三个属性可简写为grid-template&lt;br&gt;
grid是 grid-template-rows、grid-template-columns、grid-template-areas、 grid-auto-rows、grid-auto-columns、grid-auto-flow的简写&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-template-columns: repeat(3,100px)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;repeat()函数可以简化重复的值,第一个参数是重复的次数,第二个参数为重复的值
也可重复某种模式: repeat(3,100px 100px)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;auto-fill: grid-template-columns: repeat(auto-fill,100px)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当单元格的大小是固定的,容器的大小不固定时,使用auto-fill关键字自动填充&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fr: grid-template-columns: 100px 2fr 1fr&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;fraction的缩写,意为片段 , 2fr 1fr 表示前者是后者的二倍&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-template-columns: minmax(100px, 1fr)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表示一个长度范围&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-template-columns: 100px auto 100px&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;长度由浏览器决定&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;网格线名称: grid-template-columns: [c1] 100px [fifth c2] 100px&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以指定网格线名称,方便以后引用,一个网格线可以有多个名字&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-row-gap: 20px | grid-column-gap: 20px&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(根据新的标准改写为:row-gap column-gap gap)&lt;br&gt;
单元格之间的空隙,可以合并为 grid-gap: 20px 20px&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-auto-flow: row | column&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;单元格填充顺序 默认为row:先行后列, row dense尽量填满空格&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;justify-items: start | end | center | stretch&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;单元格内容的水平位置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;align-items: start | end | center | stretch&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;单元格内容的垂直位置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;place-items: start end&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;justify-items 和 align-items 的合并方式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;justify-content: start | end | center | stretch | space-around | space-between | space-evenly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;单元格内容区域在容器里的水平位置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;align-content: start | end | center | stretch | space-around | space-between | space-evenly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;单元格内容区域在容器里的垂直位置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;place-content: start end&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;justify-content 和 align-content 的合并方式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-auto-rows | grid-auto-columns&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;自动产生的单元格的大小&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-column-start:2 | grid-column-end | grid-row-start | grid-row-end&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;项目的位置是可以指定的(也可指定网格线的名字)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grid-column属性是grid-column-start和grid-column-end的合并简写形式，grid-row属性是grid-row-start属性和grid-row-end的合并简写形式&lt;/li&gt;
&lt;li&gt;grid-area：&lt;br&gt;
指定项目放在哪一个区域&lt;/li&gt;
&lt;li&gt;grid-area属性还可用作grid-row-start、         grid-column-start、grid-row-end、grid-column-end的合并简写形式，直接指定项目的位置&lt;/li&gt;
&lt;li&gt;justify-self | align-self | place-self&lt;br&gt;
单个项目的位置&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/powerful-grid-layout-scheme/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[理解css的z-index属性(层叠上下文)]]></title><link>http://huangbowen.cn/blog/z-index-attribute-of-css/</link><guid isPermaLink="false">http://huangbowen.cn/blog/z-index-attribute-of-css/</guid><pubDate>Thu, 10 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;简介&lt;/h2&gt;
&lt;p&gt;在MDN中层叠上下文的定义如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我们假定用户正面向（浏览器）视窗或网页，而 HTML 元素沿着其相对于用户的一条虚构的 z 轴排开，层叠上下文就是对这些 HTML 元素的一个三维构想。众 HTML 元素基于其元素属性按照优先级顺序占据这个空间。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;层叠上下文&lt;/h2&gt;
&lt;p&gt;我们知道某些元素的渲染顺序是由z-index的值影响，这其实是因为这些元素具有能够使他们形成一个层叠上下文的特殊属性。&lt;br&gt;
元素具有层叠上下文特性的触发条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文档根元素(html)&lt;/li&gt;
&lt;li&gt;position值为absolute(绝对定位)或relative(相对定位)且z-index值不为auto的元素&lt;/li&gt;
&lt;li&gt;position值为fixed(固定定位)或sticky(粘滞定位)的元素（沾滞定位适配所有移动设备上的浏览器，但老的桌面浏览器不支持)&lt;/li&gt;
&lt;li&gt;flex(flexbox)容器的子元素，且z-index值不为auto&lt;/li&gt;
&lt;li&gt;grid (grid) 容器的子元素，且z-index值不为auto&lt;/li&gt;
&lt;li&gt;opacity: 属性值小于1的元素&lt;/li&gt;
&lt;li&gt;mix-blend-mode 属性值不为normal的元素&lt;/li&gt;
&lt;li&gt;以下任意属性值不为none的元素：
&lt;ul&gt;
&lt;li&gt;transform&lt;/li&gt;
&lt;li&gt;filter&lt;/li&gt;
&lt;li&gt;perspective&lt;/li&gt;
&lt;li&gt;clip-path&lt;/li&gt;
&lt;li&gt;mask / mask-image / mask-border&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;isolation 属性值为 isolate 的元素&lt;/li&gt;
&lt;li&gt;-webkit-overflow-scrolling 属性值为 touch 的元素&lt;/li&gt;
&lt;li&gt;will-change 值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素&lt;/li&gt;
&lt;li&gt;contain属性值为 layout、paint&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在层叠上下文中，子元素同样也按照上面的规则进行层叠。 重要的是，其子级层叠上下文的 z-index 值只在父级中才有意义。子级层叠上下文被自动视为父级层叠上下文的一个独立单元。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;层叠上下文可以包含在其他层叠上下文中，并且一起创建一个层叠上下文的层级。&lt;/li&gt;
&lt;li&gt;每个层叠上下文都完全独立于它的兄弟元素：当处理层叠时只考虑子元素。&lt;/li&gt;
&lt;li&gt;每个层叠上下文都是自包含的：当一个元素的内容发生层叠后，该元素将被作为整体在父级层叠上下文中按顺序进行层叠。&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/z-index-attribute-of-css/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[css优先级]]></title><link>http://huangbowen.cn/blog/css-priority/</link><guid isPermaLink="false">http://huangbowen.cn/blog/css-priority/</guid><pubDate>Mon, 30 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;引言&lt;/h2&gt;
&lt;p&gt;有时通过不同的选择器匹配同一个元素，虽然知道几个优先级比如内联样式是最高级，但还是在开发中不那么得心应手，这次就来详细的学习下，不同种类选择器的匹配规则。&lt;/p&gt;
&lt;h2&gt;优先级是如何计算的？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;优先级就是分配给指定的CSS声明的一个权重，它由匹配的选择器中的每一种选择器类型的数值决定。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是MDN上的官方定义，我们也知道当多个CSS声明中优先级相等的时候，CSS中最后的那个声明将会被应用到元素上。而对于从祖先元素继承而来的规则会被直接作用于元素的CSS规则总是会接管/覆盖（take over）&lt;/p&gt;
&lt;h2&gt;选择器类型优先级(递减)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;内联样式 style=&quot;font-weight:bold&quot;&lt;/li&gt;
&lt;li&gt;id选择器 #example&lt;/li&gt;
&lt;li&gt;类选择器 .example，属性选择器 [type=&quot;radio&quot;]和伪类 :hover&lt;/li&gt;
&lt;li&gt;类型选择器 h1和伪元素 ::before&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;通配选择符&lt;/strong&gt; * &lt;strong&gt;关系选择符&lt;/strong&gt; +, &gt;, ~, &apos; &apos;, || &lt;strong&gt;否定伪类&lt;/strong&gt;:not()对&lt;strong&gt;优先级&lt;/strong&gt;没有影响。但是，在 :not() 内部声明的选择器会影响优先级。&lt;/p&gt;
&lt;h2&gt;!important&lt;/h2&gt;
&lt;p&gt;这个规则很熟悉，在不确定优先级时，就愣用!important,就可以让选择器生效，但这是个&lt;strong&gt;坏习惯&lt;/strong&gt;，还有从可维护性角度考虑，破坏了样式表中的固有的级联规则 使得调试找bug变得更加困难了，还是少用这个规则为好。&lt;br&gt;
当两条相互冲突的带有 !important 规则的声明被应用到相同的元素上时，拥有更大优先级的声明将会被采用。
在MDN上还有一些使用!important的经验法则&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1.一定要优化考虑使用样式规则的优先级来解决问题而不是 !important&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;2.只有在需要覆盖全站或外部 CSS 的特定页面中使用     !important&lt;br&gt;
3.永远不要在你的插件中使用 !important&lt;br&gt;
4.永远不要在全站范围的 CSS 代码中使用 !important&lt;/p&gt;
&lt;h2&gt;避开!important的方法&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;更好地利用 CSS 级联属性&lt;/li&gt;
&lt;li&gt;使用更具体的规则。在选择的元素之前，增加一个或多个其他元素，使选择器变得更加具体，并获得更高的优先级。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;怎样覆盖 !important&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;只需再添加一条带!important 的CSS规则，再给这个给选择器更高的优先级，或是添加一样选择器，把它的位置放在原有声明的后面&lt;/li&gt;
&lt;li&gt;或者使用相同的选择器，但是置于已有的样式之后&lt;/li&gt;
&lt;li&gt;改写原来的规则，以避免使用!important&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/css-priority/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[什么是BFC ？]]></title><description><![CDATA[dddddd]]></description><link>http://huangbowen.cn/blog/bfc-block-level-formatting-context/</link><guid isPermaLink="false">http://huangbowen.cn/blog/bfc-block-level-formatting-context/</guid><pubDate>Mon, 09 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;基本概念&lt;/h2&gt;
&lt;p&gt;块格式化上下文（BlockFormattingContext，BFC）是Web页面的可视化CSS渲染的一部分，是布局过程中生成块级盒子的区域，也是浮动元素与其他元素的交互限定区域&lt;br&gt;
简单来说：&lt;code class=&quot;language-text&quot;&gt;BFC&lt;/code&gt;是一个独立的布局环境，可以理解为一个容器，在这个容器中按照一定规则进行物品摆放，并且不会影响其它环境中的物品。&lt;br&gt;
如果一个元素符合触发BFC的条件，则BFC中的元素布局不受外部影响&lt;/p&gt;
&lt;h2&gt;触发条件&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;W3C对BFC的定义如下： 浮动元素和绝对定位元素，非块级盒子的块级容器（例如 inline-blocks, table-cells, 和 table-captions），以及overflow值不为&quot;visiable&quot;的块级盒子，都会为他们的内容创建新的BFC（Block Fromatting Context， 即块级格式上下文&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;根元素或包含根元素的元素(&amp;#x3C;html&gt;)&lt;/li&gt;
&lt;li&gt;浮动元素：float：&lt;strong&gt;left|right&lt;/strong&gt;或&lt;strong&gt;inherit&lt;/strong&gt;（≠none）&lt;/li&gt;
&lt;li&gt;绝对定位元素：position：&lt;strong&gt;absolute&lt;/strong&gt;或&lt;strong&gt;fixed&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;display：&lt;strong&gt;inline-block | flex | inline-flex | table-cell&lt;/strong&gt;或&lt;strong&gt;table-caption&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;overflow：&lt;strong&gt;hidden|auto&lt;/strong&gt;或&lt;strong&gt;scroll&lt;/strong&gt;(≠visible)&lt;/li&gt;
&lt;li&gt;弹性元素（display为&lt;strong&gt;flex&lt;/strong&gt;或&lt;strong&gt;inline-flex&lt;/strong&gt;元素的直接子元素）&lt;/li&gt;
&lt;li&gt;网格元素（display为&lt;strong&gt;grid&lt;/strong&gt;或&lt;strong&gt;inline-grid&lt;/strong&gt;元素的直接子元素）&lt;/li&gt;
&lt;li&gt;contain 值为&lt;strong&gt;layout&lt;/strong&gt;、&lt;strong&gt;content&lt;/strong&gt;或&lt;strong&gt;paint&lt;/strong&gt;的元素&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;渲染规则&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;BFC边距不会合并&lt;/li&gt;
&lt;li&gt;BFC的区域不会与浮动元素的box重叠&lt;/li&gt;
&lt;li&gt;BFC是一个独立的容器，外面的元素不会影响里面的元素&lt;/li&gt;
&lt;li&gt;计算BFC高度的时候浮动元素也会参与计算&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;应用场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;让浮动内容和周围的内容等高(overflow: auto)&lt;/li&gt;
&lt;li&gt;防止浮动导致父元素高度塌陷&lt;/li&gt;
&lt;li&gt;外边距塌陷(创建新的BFC避免两个相邻&amp;#x3C;div&gt;之间的 外边距合并问题)&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/bfc-block-level-formatting-context/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[理解事件循环-node]]></title><link>http://huangbowen.cn/blog/learn-about-the-event-loop-node/</link><guid isPermaLink="false">http://huangbowen.cn/blog/learn-about-the-event-loop-node/</guid><pubDate>Wed, 21 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;经过上面的浏览器的事件循环学习，我们已经对事件循环基本有所理解，也接触到了宏任务和微任务，在阅读狼叔的过程中，发现node事件循环的实现是依靠的libuv引擎，和浏览器的事件循环有所不同&lt;/p&gt;
&lt;h2&gt;Node中的事件循环&lt;/h2&gt;
&lt;p&gt;node中的事件循环模型是这样的&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;http://huangbowen.cn/blog/static/6ef8c1bb3b43b44f880a696b025ca441/0e904/eventLoop.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 61.48648648648649%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABBUlEQVQoz5WSyQqEQAxE/f//8ybu+757zPACERlQZw7B7tC+rkq103Wd1HUtwzBInueSZZn0fS/0t22Tfd/P71PZGadpGqmqSqZpUliSJDLPs9CndxzHK/B6sYOytm1VXZqmEkWRQlEN8G+F2DNoURQKLctSbV+B33V3kQKxbOqCIJA4jhU+jqNatsOsbX+n+lTIzIAwR+zTY5YAUMqaC6hXhVgEyOwomylf1KPcdV3xPE/PAb8FogQohwjCwqBnQC7xfV9hKFyW5X2GgFBCsca+KbE9xfoReFXID9hf11UftqX8HchjKNgAQsqkS8phGOoMLeW/ng0qUINte9zUVeEvD9uAH3hbko9gTvjyAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Image text&quot;
        title=&quot;Image text&quot;
        src=&quot;http://huangbowen.cn/blog/static/6ef8c1bb3b43b44f880a696b025ca441/fcda8/eventLoop.png&quot;
        srcset=&quot;http://huangbowen.cn/blog/static/6ef8c1bb3b43b44f880a696b025ca441/12f09/eventLoop.png 148w,http://huangbowen.cn/blog/static/6ef8c1bb3b43b44f880a696b025ca441/e4a3f/eventLoop.png 295w,http://huangbowen.cn/blog/static/6ef8c1bb3b43b44f880a696b025ca441/fcda8/eventLoop.png 590w,http://huangbowen.cn/blog/static/6ef8c1bb3b43b44f880a696b025ca441/efc66/eventLoop.png 885w,http://huangbowen.cn/blog/static/6ef8c1bb3b43b44f880a696b025ca441/c83ae/eventLoop.png 1180w,http://huangbowen.cn/blog/static/6ef8c1bb3b43b44f880a696b025ca441/0e904/eventLoop.png 1384w&quot;
        sizes=&quot;(max-width: 590px) 100vw, 590px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;从模型中，我们可以大致对node中的事件循环的顺序有个大概的了解：
输入数据--&gt;轮询阶段(poll)--&gt;检查阶段(check)--&gt;关闭事件回调阶段(close callback)--&gt;定时器检测阶段(timer)--&gt;I/O事件回调阶段(I/O callbacks)--&gt;闲置阶段(idle, prepare)--&gt;轮询阶段.下面来详细的了解下各个阶段的工作。&lt;/p&gt;
&lt;h2&gt;阶段概述&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;timers(定时器检测阶段)：本阶段执行 timer 的回调，即 setTimeout、setInterval 里面的回调函数。&lt;/li&gt;
&lt;li&gt;I/O callbacks(I/O事件回调阶段)：执行几乎所有的回调。执行延迟到下一个循环迭代的 I/O 回调，即上一轮循环中未被执行的一些I/O回调。&lt;/li&gt;
&lt;li&gt;idle, prepare(闲置阶段)：仅系统内部使用。&lt;/li&gt;
&lt;li&gt;poll(轮询阶段)：检索新的i/o事件,node可能会阻塞在这个阶段&lt;/li&gt;
&lt;li&gt;check(检查阶段)：setImmediate()回调函数在这个阶段执行&lt;/li&gt;
&lt;li&gt;close callback(关闭事件回调阶段)：例如socket.on(&apos;close&apos;, ...)一些关闭的回调函数&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;poll阶段&lt;/h2&gt;
&lt;p&gt;这个阶段可以说是比较重要的阶段，当代码被传入libuv引擎后，循环会首先进入poll阶段。&lt;br&gt;
poll会先查看poll queue中是否有事件，有任务就按先进先出的顺序依次执行回调。 当queue为空时，会检查是否有setImmediate()的callback，如果有就进入check阶段执行这些callback。但同时也会检查是否有到期的timer，如果有，就把这些到期的timer的callback按照调用顺序放到timer queue中，之后循环会进入timer阶段执行queue中的 callback。 这两者的顺序是不固定的，收到代码运行的环境的影响。如果两者的queue都是空的，那么loop会在poll阶段停留，直到有一个i/o事件返回，循环会进入i/o callback阶段并立即执行这个事件的callback。&lt;/p&gt;
&lt;h2&gt;node和浏览器中事件循环的区别&lt;/h2&gt;
&lt;p&gt;两者最主要的区别在于浏览器中的微任务是在每个相应的宏任务完成后执行的，而node中的微任务是在不同阶段之间执行的。&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/learn-about-the-event-loop-node/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[理解事件循环-浏览器]]></title><link>http://huangbowen.cn/blog/learn-about-the-event-loop-browser/</link><guid isPermaLink="false">http://huangbowen.cn/blog/learn-about-the-event-loop-browser/</guid><pubDate>Thu, 08 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;引&lt;/h2&gt;
&lt;p&gt;先来看一手题目：&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;当我看到这个题目时，觉得它能出现在题目中，绝对不是1，2，3那么简单。虽然把答案蒙对了(1,3,2)，但是为什么还不太清楚。当然这是小聪明的做法，那么现在就来探索下背后的知识点把。&lt;/p&gt;
&lt;h2&gt;执行栈与事件队列&lt;/h2&gt;
&lt;p&gt;当Js代码执行的时候会将不同的变量存于内存中的不同位置：堆（heap）和栈（stack）中来加以区分。其中，堆里存放着一些对象。而栈中则存放着一些基础类型变量以及对象的指针。 但是这里我们说的执行栈和上面这个栈的意义却有些不同。&lt;/p&gt;
&lt;h3&gt;可视化描述&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 584px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;http://huangbowen.cn/blog/static/93d18483d228e3e938b1b3ea80cb4a57/e05eb/Js_Runtime.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 94.5945945945946%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAACXBIWXMAABYlAAAWJQFJUiTwAAAETUlEQVQ4y2WUXUyTVxzGT5DscsuyG7dk2YZZ9iHZkm03i1mWXbq5gNvNLpZt2XQYd7Es3gwxDnWK0wkoBUVFUalUnOjwA6gKLZby0e+3tbYVEKQf79uiBWlpK8JveV8ENbt4ct7/ycnvPP/nnPOKvB9OkP9rO6LkIsUHuhlOzuKKpPDE0niVLDcTOXxKFknJaHNm/ziWOwl6hxR88SytZjuGzl4Mxl46HUFE3hYX+aX9iE19FB1xcvteFrsKVLJYQjKdvlHMt2X6hye0uQvdDvZu2YvhognvxCzttgDNnVaqG89yzmRH5NVD/nEQ9VDUEmMokcYeSSMpWW6EZKq37+eI7hR9IxN4k/P09YcoF6/S9Y8J3zRIsQz++3PcSoIvMYvI02XJr59H1MxR1DyuAR2RNK5oGt8k1Lz/JSe+2YQ/A+5oGvfYFMYz1+j3hfEkctrGkpzBHcvgjKQQebU58g+D0EGRYRE4gzu2ILPJg3VwSHN4+lofTV0DWEbv4U/O47g7hVG6Q3cohiWk4IllEPm1GZ47PIfQPaLYMM5tFRhdgKkupfuP8MSzeB/AybJqdn/8NaZbEfrHkljVTc50ULl1Hx2DAaR4DiFqQagOa2CNYSFDFajCVKgzPI1jbBJfGi5UHOPw6nVa+NVVR2mzB2jbfZyK59/DEUpoEYi36wJ81BDgrTo/3xn8BBMZHCosmsYVm0FScvjiD/EqOTzxHP5ZMLUPslW8jLnDhn34HtcvWXHencItzyDM297hTtkyRn4XNDXtxzkB7si0BlMdXrEFaLF6aBvwa5mp7asHYvirAbNrBLs8g3dyfikicbnyc3z7CnFUvEm9/hjuRWA0rTnqGghS8cWPnDvdruWpXnqXnKHVKnGg9gTnu+145MxSROLfHatw/7EcR9mLHGs6iGsRGEkhTcwy4Bpl3+ufcrWpU7t3zrEpfA/AqDdSvmwFFstNpOSctl4DtlYWM7DnA3r+XMlB/XHNoeuxQ62NSArH6KR2OAt1Gk/iIVbHCBcqmxgMyFonSw7P7/wMaedrOMuX06CvX3K4mIl2H5XMM/ViHL4UuJXsk3UqsOXvtXTv+pDO8kJq9Y3POFySmtvTdWxhVF0/XWuHcmXXJwxXvEJwx0s0nj6ENAHe6BTeWApJ/ePEUo+V1sL/n2Iz2gtZlGjZvZrr5e/SsbmAmpNH6YmDOfyInvAc1vEs5giaLOGH2MaSTzSaxDY+hS2SwhaexhZ+oElsbP+JnZ1r2GYs4qv+/VTd+JaDPWvZ07eedR4ddaZiDvWspdS+mTeicQqiMgWRGAVynILQECtsDgqCQwsKDSEaLr5AV7OgvVnwS/BnWs8KrusF+rY8Nnq/59opwdVTgj2mQgQ8q8kkoqMDcfkS4qoRYe1FbHeVoXNuoMq+kfXBk1S5f0PnKKHCXcqGUCN1zhJ09hJKfXtZKSsUyjKFcuzxKFMYiTz5VhT+A7IGxkzzlrRRAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Image text&quot;
        title=&quot;Image text&quot;
        src=&quot;http://huangbowen.cn/blog/static/93d18483d228e3e938b1b3ea80cb4a57/e05eb/Js_Runtime.png&quot;
        srcset=&quot;http://huangbowen.cn/blog/static/93d18483d228e3e938b1b3ea80cb4a57/12f09/Js_Runtime.png 148w,http://huangbowen.cn/blog/static/93d18483d228e3e938b1b3ea80cb4a57/e4a3f/Js_Runtime.png 295w,http://huangbowen.cn/blog/static/93d18483d228e3e938b1b3ea80cb4a57/e05eb/Js_Runtime.png 584w&quot;
        sizes=&quot;(max-width: 584px) 100vw, 584px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;栈&lt;/h3&gt;
&lt;p&gt;函数调用会形成一个由若干帧组成的栈，即先调用帧被压入栈，接着第二个调用帧再被压入栈，随后第二个函数执行完后返回时，第二个帧会被弹出栈，接着第一帧也被弹出&lt;/p&gt;
&lt;h3&gt;堆&lt;/h3&gt;
&lt;p&gt;对象被分配在堆中，堆是一个用来表示一大块（通常是非结构化的）内存区域的计算机术语。&lt;/p&gt;
&lt;h3&gt;队列&lt;/h3&gt;
&lt;p&gt;JavaScript运行时包含了一个待处理消息的消息队列。每一个消息都关联着一个用以处理这个消息的回调函数。&lt;br&gt;
在事件循环期间的某个时刻，运行时会从最先进入队列的消息开始处理队列中的消息。被处理的消息会被移出队列，并作为输入参数来调用与之关联的函数。正如前面所提到的，调用一个函数总是会为其创造一个新的栈帧。&lt;br&gt;
函数的处理会一直进行到执行栈再次为空为止；然后事件循环将会处理队列中的下一个消息（如果还有的话）。&lt;/p&gt;
&lt;h3&gt;执行栈&lt;/h3&gt;
&lt;p&gt;当我们调用一个函数时，Js会生成与这个函数或方法对应的执行上下文(context)，这个执行环境中存在着这个函数的作用域，上层作用域的指向，函数的参数，函数私有作用域定义的变量，以及this指向，而当很多函数被调用时，我们知到Js是单线程的，同一时间只能执行一个函数，于是这些函数被存放在一个地方，这个地方被称做执行栈。&lt;br&gt;
一个方法执行会向执行栈中加入这个方法的执行环境，在这个执行环境中还可以调用其他方法，甚至是自己，其结果不过是在执行栈中再添加一个执行环境。这个过程可以是无限进行下去的，除非发生了栈溢出，即超过了所能使用内存的最大值。&lt;/p&gt;
&lt;h3&gt;事件队列&lt;/h3&gt;
&lt;p&gt;但是上面是同步代码的执行时，当遇到异步事件的时候，并不会一直等待其返回结果，而是会将这个事件挂起，继续执行执行栈中的其他任务，当一个异步事件返回结果后，js会将这个事件加入与当前执行栈不同的另一个队列，我们称之为事件队列。被放入事件队列不会立刻执行其回调，而是等待当前执行栈中的所有任务都执行完毕，主线程会去查找事件队列是否有任务。如果有，那么主线程会从中取出排在第一位的事件，并把这个事件对应的回调放入执行栈中，然后执行其中的同步代码。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;到此为止，其实我们已经了解了Js的运行时的相关概念，知道了Js引擎会先运行完所有的同步任务，再去事件队列中获取异步事件相应的回调，然后去执行，已经可以解释了，为什么console.log(3)会在setTimeout之前加入事件循环了，但本着刨根问底的态度，我又去了解了不同的异步任务，以及它们的优先级&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;宏任务(macro-task)&lt;/h2&gt;
&lt;p&gt;宏任务可以理解是每次执行栈执行的代码就是一个宏任务（包括每次从事件队列中获取一个事件回调并放到执行栈中执行）。
浏览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行，会在一个(macro)task执行结束后，在下一个(macro)task 执行开始前，对页面进行重新渲染。&lt;br&gt;
宏任务大概包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;script(整体代码)&lt;/li&gt;
&lt;li&gt;setTimeout&lt;/li&gt;
&lt;li&gt;setInterval&lt;/li&gt;
&lt;li&gt;setImmediate&lt;/li&gt;
&lt;li&gt;I/O&lt;/li&gt;
&lt;li&gt;UI render
&lt;ul&gt;
&lt;li&gt;当接收到 HTML 文档数据，渲染引擎就会将“解析 DOM”事件添加到消息队列中，&lt;/li&gt;
&lt;li&gt;当用户改变了 Web 页面的窗口大小，渲染引擎就会将“重新布局”的事件添加到消息队列中。&lt;/li&gt;
&lt;li&gt;当触发了 JavaScript 引擎垃圾回收机制，渲染引擎会将“垃圾回收”任务添加到消息队列中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;微任务(micro-task)&lt;/h2&gt;
&lt;p&gt;微任务可以理解是在当前task 行结束后立即执行的任务。也就是说，在当前task任务后，下一个task之前，在渲染之前。
所以它的响应速度相比setTimeout（setTimeout是task）会更快，因为无需等渲染。也就是说，在某一个macrotask执行完后，就会将在它执行期间产生的所有microtask都执行完毕（在渲染前）
微任务大概包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Promise&lt;/li&gt;
&lt;li&gt;Async/Await&lt;/li&gt;
&lt;li&gt;Object.observe(已被废弃)&lt;/li&gt;
&lt;li&gt;MutaionObserver(H5新特性)&lt;/li&gt;
&lt;li&gt;process.nextTick(Node.js环境)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简单总结下，当当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件，然后再去宏任务队列中取出一个事件。同一次事件循环中，微任务永远在宏任务之前执行。&lt;/p&gt;
&lt;h2&gt;结论&lt;/h2&gt;
&lt;p&gt;在一个事件循环中，Js会先执行全部的同步代码，如遇到异步事件，会将这个事件挂起，继续执行执行栈中的其他任务，当异步事件返回结果后，Js会将这个事件加入事件队列中，根据这个异步事件的类型，这个事件会被对应的宏任务队列或者微任务队列中去。并且在当前执行栈为空的时候，主线程会查看微任务队列是否有事件存在。如果不存在，那么再去宏任务队列中取出一个事件并把对应的回到加入当前执行栈；如果存在，则会依次执行队列中事件对应的回调，直到微任务队列为空，然后去宏任务队列中取出最前面的一个事件，把对应的回调加入当前执行栈，这就构成了一个完整的事件循环？ 结束！&lt;/p&gt;
&lt;h2&gt;Tip（TODO 总结逐字稿 + 顶层向下 + 需要注意的点）&lt;/h2&gt;
&lt;p&gt;浏览器会为每个tab页开一个渲染进程，每个渲染进程都有一个消息队列，页面的主线程按照顺序来执行消息队列中的时间，如js事件、解析dom事件等，消息队列和主线程的循环机制保证了页面有条不紊的运行。&lt;/p&gt;
&lt;p&gt;setTimeout 是直接将延迟任务添加到延迟队列中，而 XMLHttpRequest 发起请求，是由浏览器的其他进程或者线程去执行，然后再将执行结果利用 IPC 的方式通知渲染进程，之后渲染进程再将对应的消息添加到消息队列中。如果你搞懂了 setTimeout 和 XMLHttpRequest 的工作机制后，再来理解其他 WebAPI 就会轻松很多了，因为大部分 WebAPI 的工作逻辑都是类似的&lt;/p&gt;
&lt;p&gt;通常情况下，在当前宏任务中的 JavaScript 快执行完成时，也就在 JavaScript 引擎准备退出全局执行上下文并清空调用栈的时候，JavaScript 引擎会检查全局执行上下文中的微任务队列，然后按照顺序执行队列中的微任务。WHATWG 把执行微任务的时间点称为检查点。当然除了在退出全局执行上下文式这个检查点之外，还有其他的检查点，不过不是太重要，这里就不做介绍了。如果在执行微任务的过程中，产生了新的微任务，同样会将该微任务添加到微任务队列中，V8 引擎一直循环执行微任务队列中的任务，直到队列为空才算执行结束。也就是说在执行微任务过程中产生的新的微任务并不会推迟到下个宏任务中执行，而是在当前的宏任务中继续执行。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;微任务和宏任务是绑定的，每个宏任务在执行时，会创建自己的微任务队列。&lt;/li&gt;
&lt;li&gt;微任务的执行时长会影响到当前宏任务的时长。比如一个宏任务在执行过程中，产生了 100 个微任务，执行每个微任务的时间是 10 毫秒，那么执行这 100 个微任务的时间就是 1000 毫秒，也可以说这 100 个微任务让宏任务的执行时间延长了 1000 毫秒。所以你在写代码的时候一定要注意控制微任务的执行时长。&lt;/li&gt;
&lt;li&gt;在一个宏任务中，分别创建一个用于回调的宏任务和微任务，无论什么情况下，微任务都早于宏任务执行。&lt;/li&gt;
&lt;li&gt;需要异步来提高效率 需要微任务来提高实效性&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/learn-about-the-event-loop-browser/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[手画深拷贝]]></title><link>http://huangbowen.cn/blog/hand-painted-deep-copy/</link><guid isPermaLink="false">http://huangbowen.cn/blog/hand-painted-deep-copy/</guid><pubDate>Fri, 12 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; map &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WeakMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; target
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; type &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; cloneTarget
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deepTag&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    cloneTarget &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getInit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;cloneOtherType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 克隆set类型&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; setTag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cloneTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cloneTarget
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 克隆map类型&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; mapTag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cloneTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cloneTarget
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; arrayTag &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;keys &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      key &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    cloneTarget&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cloneTarget
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/hand-painted-deep-copy/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[让 position:absolute 生效,父元素必须为 relative ？]]></title><link>http://huangbowen.cn/blog/for-position-absolute-to-take-effect-the-parent-element-must-be-relative/</link><guid isPermaLink="false">http://huangbowen.cn/blog/for-position-absolute-to-take-effect-the-parent-element-must-be-relative/</guid><pubDate>Fri, 21 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在很多课程上，甚至在开发中的了解，我收集到的信息都是，要让子元素的绝对定位生效，必须把父元素设置为相对定位，这个听起来也很讲道理，所以在后面的实践中我也都是如此做的，直到我碰到了这个场景：&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;http://huangbowen.cn/blog/static/fa0c8d00366060319a229c040b2474cc/f6386/quesPosition.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 70.27027027027026%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAABkElEQVQ4y52SzUobURiGT3TivbhXl6667Cabqr0Amwvowo22lqqJMvEOvIAutMYkM20DSmoCgUJ1IRhz5ijaUYvgTxSjpHMeyWTEUpo/X3jgcOA8vB/fETenJc7L37lwCq2ReS5VEa92Tz1aa/4XcfLjE6XlCcpr7yknp5rwjr3VSZzMDLXqdWvh7+0kTvoj6usC6st8c+wYB9lFanc3bYRbn5GpDyg7jrLmUPYTjhULzjEca5b9bya1u3YNf64gk9Oo+mNrFmU/8kzh6U6KvWwMubGItE1kykSmTRwr/pe0C+HtzARXw/1UXgxSSQ5wdTZI5XCAw9xbnMxC9w2JRECIBivCv6pzXBz32zbG70KoX4+ihUALA2/NwCOMh4FbjD5TODriC+ntRQ+F0JEQ+qXAXYois4lgUY/CRAcjj7zyx9VGT0Mc4MbfIDdMVDoQZjptOBY0DBvocAjdF4KwwE1EkesJVGbO/6OdNyztQi4HhTw6vwkB978k1UuX6vnRExcu2vvTRvhPdECrNJPVhQ/oEcThA9gzdwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Image text&quot;
        title=&quot;Image text&quot;
        src=&quot;http://huangbowen.cn/blog/static/fa0c8d00366060319a229c040b2474cc/fcda8/quesPosition.png&quot;
        srcset=&quot;http://huangbowen.cn/blog/static/fa0c8d00366060319a229c040b2474cc/12f09/quesPosition.png 148w,http://huangbowen.cn/blog/static/fa0c8d00366060319a229c040b2474cc/e4a3f/quesPosition.png 295w,http://huangbowen.cn/blog/static/fa0c8d00366060319a229c040b2474cc/fcda8/quesPosition.png 590w,http://huangbowen.cn/blog/static/fa0c8d00366060319a229c040b2474cc/f6386/quesPosition.png 686w&quot;
        sizes=&quot;(max-width: 590px) 100vw, 590px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;最外层父元素的定位为position:relative;里面的子元素定位为position:absolute;最里面的孙元素也是绝对定位(absolute)且top值为0,那么按照平时的所学，孙元素必定按照最外层父元素来定位，那么top:0;孙元素的上边应该和最外层父元素的上边重合，但它明显并没有如此，这是为什么呢？？？此时我开始了思考，那么它既然没有上去，也就是说，孙元素是参照子元素的定位的，接着，我修改了孙元素的right:0;果不其然，但这背后的原理是啥呢？说好的父元素必须relative呢？看来一定有我不知道的知识再等待着我。
将问题定位到未知领域后，我进行了搜索查阅，最终找到了新的知识点。&lt;/p&gt;
&lt;h2&gt;Containing Block(包含块模型)&lt;/h2&gt;
&lt;p&gt;什么是包含块模型呢？官方定义如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The size and position of an element are often impacted by its containing block. Most often, the containing block is the content area of an element&apos;s nearest block-level ancestor, but this is not always the case. In this article, we examine the factors that determine an element&apos;s containing block.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;什么意思呢？简单说就是，一个元素的尺寸和位置会受其包含块的影响。大多数情况下，包含块就是这个元素最近的祖先块元素的内容区。&lt;/p&gt;
&lt;h3&gt;内容区？&lt;/h3&gt;
&lt;p&gt;内容区就是经典盒模型，最里层的就是内容区了&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 544px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;http://huangbowen.cn/blog/static/cbf327fd26a7ce18a3bbeccefac4c9f3/b3e51/box-model.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 55.4054054054054%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAABEklEQVQoz6WTW6uCQBSF+/+P/g7BxwRFTAPvFiIKXpAsL089BD6I2TpsQTtpnTrnDCxGYebbe9aaWd1uN/x1tG2L6/WKkUHzij6OxyNM04TrunAc50ftdjvYto31eg2GYcDz/ADr+/4O1HUdvu8jSRLEcfxSURQhCAIIggCWZbHZbCDL8hJIFbMsQ13XKMvyqaqqGmY6iaIoyPMcp9MJ2+32wYYBaFnW0B1toEWvVBTFVID+ySqO46CqKvb7Pc7n8x2Ypulb4Bx+OBwgSRIulwuapkHXdb/rcA4km6i7xZE/8fCZp+Tj6CEFMoWiadqUMiX5iSj1MAwhiuISSJUMw3h7B+eiPZ7nPQL/81LG8f2lfAF/Iylxy2oR0AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Image text1&quot;
        title=&quot;Image text1&quot;
        src=&quot;http://huangbowen.cn/blog/static/cbf327fd26a7ce18a3bbeccefac4c9f3/b3e51/box-model.png&quot;
        srcset=&quot;http://huangbowen.cn/blog/static/cbf327fd26a7ce18a3bbeccefac4c9f3/12f09/box-model.png 148w,http://huangbowen.cn/blog/static/cbf327fd26a7ce18a3bbeccefac4c9f3/e4a3f/box-model.png 295w,http://huangbowen.cn/blog/static/cbf327fd26a7ce18a3bbeccefac4c9f3/b3e51/box-model.png 544w&quot;
        sizes=&quot;(max-width: 544px) 100vw, 544px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;确定元素包含块&lt;/h2&gt;
&lt;p&gt;我之前认为一个元素的包含块就是其父元素的内容区。但明显事情没有这么简单。&lt;br&gt;
确定一个元素的包含块的过程完全依赖于这个元素的position属性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果position属性为 &lt;strong&gt;static&lt;/strong&gt; 或 &lt;strong&gt;relative&lt;/strong&gt; ，包含块就是由它的最近的祖先块元素（比如说inline-block, block 或 list-item元素）或格式化上下文(table,flex,grid)的内容区的边缘组成的。&lt;/li&gt;
&lt;li&gt;如果position属性为&lt;strong&gt;absolute&lt;/strong&gt;，包含块就是它最近的position的值不是 &lt;strong&gt;static&lt;/strong&gt;的元素的内边距区的边缘组成。(fixed, absolute, relative 或 &lt;a href=&quot;https://www.qianduan.net/position-sticky-introduction/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;sticky&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;如果position属性是&lt;strong&gt;fixed&lt;/strong&gt;，在连续媒体的情况下(continuous media)包含块是 viewport(视口) ,在分页媒体(paged media)下的情况下包含块是分页区域(page area)&lt;/li&gt;
&lt;li&gt;如果position属性是&lt;strong&gt;absolute&lt;/strong&gt;或&lt;strong&gt;fixed&lt;/strong&gt;，包含块也可能是由满足以下条件的最近父级元素的内边距区的边缘组成的：
&lt;ul&gt;
&lt;li&gt;transform或perspective不为none&lt;/li&gt;
&lt;li&gt;将改变transform或perspective的值&lt;/li&gt;
&lt;li&gt;contain的值为paint&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;根据包含块计算百分值&lt;/h2&gt;
&lt;p&gt;包含块还是计算元素的百分比值的参照物：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;计算height、top、bottom的百分比值，要通过包含块的height的值，&lt;strong&gt;但，如果包含块的 height 值会根据它的内容变化，而且包含块的 position 属性的值被赋予 relative 或 static ，那么，这些值的计算值为0&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;计算width,left,right,padding, margin 这些属性由包含块的 width 属性的值来计算它的百分值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;解决问题&lt;/h2&gt;
&lt;p&gt;想要孙元素参照最外层父元素定位，直接把子元素的positin给删掉即可，默认就是static&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;http://huangbowen.cn/blog/static/581670ced2da71c71dbba9c19c2cb2fe/f6386/resPosition.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 70.27027027027026%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAABoElEQVQ4y52SzU8TQRiH11IhJNz9k0zUGx8K3JUYT+qNAwTYLV8t1YP/gAeOtQkuC5LQBA5wIYSLIrNDIxTSBtoQCKvUfR+zuwU90Jb6Jk/mMvPM731nDDIZGB2BhIVYJgSYJucbNuX8JhW1TvXXe4RxRJKInBOUiHBbGTx+BIYRIrU14GBikN1lE5UdxjvrRDDwfQORQk3o1xEODkSSzg6kPQ4B99s4mnuJm0uz71hcXT4It0IXcEwUro5Qnj0Nk0k8hsSMkOCCwuwL1GoKbZuUdvo4+faQ091e/Gq5ccvSXxO2x5G2exExg0JyCLWaRNsWaiHNXjaNa3+g6l00mWF3983c/uVo+jkqlwqFeslCOxPkV2ao/mzyKGcfUxRfPaH0to/Sm56I1z3k54dxl6fRiwm0M4m7aLH/JdlcePzV5ntuBrX+jr219A3XMteZbE1Y3MqgsqNoO4H+bP3lWtZqwuL2J9TCGNqZCg/WIxKmWhO6QapbCIX2nRNmI+FSo4RTd094dXGKV/6BVznEKx80plJA/N9N/uF/VD1ZIPwDXse79JP/K48AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Image text&quot;
        title=&quot;Image text&quot;
        src=&quot;http://huangbowen.cn/blog/static/581670ced2da71c71dbba9c19c2cb2fe/fcda8/resPosition.png&quot;
        srcset=&quot;http://huangbowen.cn/blog/static/581670ced2da71c71dbba9c19c2cb2fe/12f09/resPosition.png 148w,http://huangbowen.cn/blog/static/581670ced2da71c71dbba9c19c2cb2fe/e4a3f/resPosition.png 295w,http://huangbowen.cn/blog/static/581670ced2da71c71dbba9c19c2cb2fe/fcda8/resPosition.png 590w,http://huangbowen.cn/blog/static/581670ced2da71c71dbba9c19c2cb2fe/f6386/resPosition.png 686w&quot;
        sizes=&quot;(max-width: 590px) 100vw, 590px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;完美！&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/for-position-absolute-to-take-effect-the-parent-element-must-be-relative/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[console的小技巧]]></title><link>http://huangbowen.cn/blog/tips-of-console/</link><guid isPermaLink="false">http://huangbowen.cn/blog/tips-of-console/</guid><pubDate>Tue, 28 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;!-- ## 在掘金上发现的小技巧 --&gt;
&lt;h3&gt;使用占位符&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// %s 字符串占位符&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;经典%s占位符&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;还就那个&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;   
&lt;span class=&quot;token comment&quot;&gt;// %c css格式字符串&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;经典%c占位符&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;color:red;font-weight:bold;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 175px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;http://huangbowen.cn/blog/static/9281e941b4140c1cbda3977422be99fb/4edbd/placeholder.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 24.324324324324326%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA6klEQVQY022Q/UvCYBCA/f+h/pAM6UP7kkLDNldr/RhhRG7qltNw+m4qe3dP7KWClQfHcXfcw8PVALTWfExjJmFEMBoTz2aMJ6Hph37ANI5ZLBLSLGM+/zT7MIoQEYqiqGTNAIuCO9uhddGmcdzE6t9z1Dzn9OySxkmL55cB70Mf23HpWQ7dnsXVdac8RYRKGGCuNauVQilFnucss4x0vTF9lmbGpJwnyRKVpsZ0s93+s6sYOg8e7ZuOMaN7C/VDOKjD3j4SRewK+dYr60/+Av1gxOD1zfxM233Ee0IePcR1EaWQP4e7YCXwCzCGeFA4Fp7jAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Image text1&quot;
        title=&quot;Image text1&quot;
        src=&quot;http://huangbowen.cn/blog/static/9281e941b4140c1cbda3977422be99fb/4edbd/placeholder.png&quot;
        srcset=&quot;http://huangbowen.cn/blog/static/9281e941b4140c1cbda3977422be99fb/12f09/placeholder.png 148w,http://huangbowen.cn/blog/static/9281e941b4140c1cbda3977422be99fb/4edbd/placeholder.png 175w&quot;
        sizes=&quot;(max-width: 175px) 100vw, 175px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;占位符列表：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;center&quot;&gt;占位符&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;%s&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;%d&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;整数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;%i&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;整数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;%f&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;浮点数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;%o&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;对象的链接&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;%c&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;css格式字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/tips-of-console/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[了解console家族]]></title><link>http://huangbowen.cn/blog/learn-about-the-console-family/</link><guid isPermaLink="false">http://huangbowen.cn/blog/learn-about-the-console-family/</guid><pubDate>Thu, 23 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;console.log()&lt;/h2&gt;
&lt;p&gt;经典的调试的代码，用来调试程序，看是否会准确的输出你所预期的东西&lt;/p&gt;
&lt;h2&gt;console.dir()&lt;/h2&gt;
&lt;p&gt;当你用&apos;正常&apos;的值去测试这两个的，会发现没什么不同，但当你用元素节点来作为参数时，会发现不一样的东西，这是一种更对象化的方式去观察元素节点。当你想监测元素节点的时候，就可以用console.dir()&lt;/p&gt;
&lt;h2&gt;console.table()&lt;/h2&gt;
&lt;p&gt;以列表做为展示数据的形式，更整洁的输出对象数组&lt;/p&gt;
&lt;h2&gt;console.count()&lt;/h2&gt;
&lt;p&gt;作为计数器使用，可传入标签，在调用时会将数字（调用次数）写入到控制台。&lt;/p&gt;
&lt;h2&gt;console.assert()&lt;/h2&gt;
&lt;p&gt;assert()在第一个参数是falsely变量时和log()一样。当第一个参数为真值时也什么都不做。&lt;/p&gt;
&lt;h2&gt;console.trace()&lt;/h2&gt;
&lt;p&gt;这应该是个比较实用的方法，用于在混乱的依赖中寻找问题所在，console.log() 只能知道执行了哪一个库，并不知道执行的具体位置。但是，堆栈轨迹会清楚的告诉我们具体为止。&lt;/p&gt;
&lt;h2&gt;console.time()&lt;/h2&gt;
&lt;p&gt;我经常用于测试算法的时间复杂度，在开始执行时，调用console.time();,结束运算时调用console.timeEnd();就可以完美显示了，执行时间，无需其他的变量和算法&lt;/p&gt;
&lt;h2&gt;console.group()&lt;/h2&gt;
&lt;p&gt;它擅长展示代码中存在的结构关系，是个有意思的方法。&lt;/p&gt;
&lt;h2&gt;console.warn()&lt;/h2&gt;
&lt;p&gt;当用相同的‘角度’去使用 console.warn()。就会发现区别在于输出是一抹黄色。确切的说，输出是一个warn级别而不是一个info级别的信息，因此浏览器的处理稍稍有些不同。在一堆杂乱的输出中高亮你的输出是很有效果的。&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/learn-about-the-console-family/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[https如何做到加密通信的]]></title><link>http://huangbowen.cn/blog/how-to-encrypt-communication-with-https/</link><guid isPermaLink="false">http://huangbowen.cn/blog/how-to-encrypt-communication-with-https/</guid><pubDate>Fri, 17 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;http的缺点&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;不能验证通信方的身份&lt;/li&gt;
&lt;li&gt;通信使用明文进行传输，内容会被窃听&lt;/li&gt;
&lt;li&gt;无法证明报文的完整性，有可能已被恶意篡改&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;被广泛使用的wireshark，它可以获取http请求和响应内容，并对其进行解析，如请求方法、响应码、响应报文等。&lt;/p&gt;
&lt;h2&gt;加密协议&lt;/h2&gt;
&lt;p&gt;http中没有加密机制，但可以通过SSL(secure socket layer,安全套接层)或TLS(transport layer security,安全传输协议)组合使用，加密http的通信内容。&lt;br&gt;
用SSL建立安全的通信线路后，就可以在这条线路上进行http通信了，与SSL组合使用的http被称为https(HTTP secure 超文本传输安全协议)&lt;/p&gt;
&lt;h2&gt;加密算法&lt;/h2&gt;
&lt;p&gt;在搞懂SSL之前，需要明确两个加密算法，目前加密算法都是公开的，但密钥却是保密的，通过这种方式来保持加密算法的安全性。&lt;/p&gt;
&lt;h3&gt;共享密钥加密&lt;/h3&gt;
&lt;p&gt;加密和解密都使用同一个密钥的方式被称为共享密钥加密，也被叫做对称加密，但密钥的安全传递给对方是个问题，一旦密钥被攻击者截获，也就失去了加密的意义，单凭这一个算法无法解决问题，要是密钥能被安全传递，那么数据也该被安全传递。&lt;/p&gt;
&lt;h3&gt;公开密钥加密&lt;/h3&gt;
&lt;p&gt;公开密钥加密，也就是说加密时，采用对方的公开密钥进行加密，对方收到后，再用自己的私钥进行解密即可，也被称为非对称加密。利用这种方式，不用发送密钥，那么也不用担心被窃听者盗走了。&lt;br&gt;
但安全的另一方面，就代表着要根据密钥和密文来解密是相当困难的，解密的过程就是对离散对数进行求值，这并非简单就能办到。&lt;/p&gt;
&lt;h3&gt;https采用混合加密机制&lt;/h3&gt;
&lt;p&gt;既然那个方法不一定安全，这个方法又很复杂，那么应该充分利用两者的优势，https就采用了两者混合的加密机制，在交换密钥环节用复杂、安全的公开密钥算法进行处理速度较快的共享密钥的传输，之后的报文再用安全传递的共享密钥的算法进行加密，很舒服。觉得设计真的挺巧妙的。&lt;/p&gt;
&lt;h2&gt;无法验证通信方的身份？&lt;/h2&gt;
&lt;p&gt;通过上面两个共享密钥和公开密钥的加密算法相结合，已经增强了http的安全性，但还没解决，验证通信方身份的问题，因为，无法验证公开密钥就是货真价实的，有可能在传输的途中就被攻击者替换掉了。这时就请来网站上经常能看到的证书来参与通信了，使用客户端与服务器双方都可信赖的数字证书认证机构颁发的公开密钥的证书。&lt;br&gt;
首先，需要服务器方向数字证书认证机构提出公开密钥的申请。数字证书认证机构在判明提出申请者的身份之后，会对已申请的公开密钥做数字签名，然后分配这个已签名的公开密钥，并将该公开密钥放入公钥证书后绑定在一起。&lt;br&gt;
服务器会将这份由数字证书认证机构颁发的公钥证书发送给客户端，以进行公开密钥加密方式通信。接到证书的客户端可使用数字证书认证机构的公开密钥，对那张证书上的数字签名进行验证。&lt;br&gt;
一旦验证通过，客户端便可明确两件事：一，认证服务器的公开密钥的是真实有效的数字证书认证机构。二，服务器的公开密钥是值得信赖的。
此处认证机关的公开密钥必须安全地转交给客户端。使用通信方式时，如何安全转交是一件很困难的事，因此，多数浏览器会事先在内部植入常用认证机关的公开密钥。这样就解决了验证通信方身份的问题。&lt;/p&gt;
&lt;h2&gt;通信使用明文进行传输，内容会被窃听?&lt;/h2&gt;
&lt;p&gt;在解决无法确认通信方的身份的问题时提到了，使用共享加密(对称加密)方式，加密密文，如果共享密钥被安全的送达，那么报文的内容也就无从被获取了。&lt;/p&gt;
&lt;h2&gt;无法证明报文的完整性，有可能已被恶意篡改?&lt;/h2&gt;
&lt;p&gt;在https通信时，应用层会在发送数据时附加一种叫做MAC(Message authentication Code)的报文摘要，MAC能够查知报文是否遭到篡改，从而保护报文的完整性&lt;/p&gt;
&lt;h2&gt;https性能&lt;/h2&gt;
&lt;p&gt;https也存在着一些问题，当使用SSL加密通信时，它的处理速度会变慢，一种是通信变慢，一种是消耗大量的cpu，内存资源，导致处理速度变慢。针对https性能方面，目前没有根本性的解决方案，只有使用SSL加速器(专用服务器)硬件来改善该问题，仅在SSL处理时，提高数倍的SSL的计算速度，以分担负载。&lt;/p&gt;
&lt;h2&gt;合理的使用https&lt;/h2&gt;
&lt;p&gt;与http通信相比https会耗费很多的cpu及内存资源，如果滥用或者一直使用https通信，会浪费很多资源，平摊到一台计算机上时，能够处理的请求数量也会随之减少，还有加大购买证书的开销。因此，合理的使用http会节约资源，只有在涉及私人或敏感信息时，再使用https进行通信&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/how-to-encrypt-communication-with-https/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[http2的新特性]]></title><link>http://huangbowen.cn/blog/new-features-of-http2/</link><guid isPermaLink="false">http://huangbowen.cn/blog/new-features-of-http2/</guid><pubDate>Tue, 07 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;头部压缩&lt;/h2&gt;
&lt;p&gt;http2针对头部字段，使用HPACK压缩算法，对请求头进行压缩。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在服务器和客户端之间，建立哈希表，将用到的字段存放在这张表中，那么在传输的时候对于之前出现过的值，只需要把索引(比如0，1，2，...)传给对方即可，对方拿到索引查表就行了。这种传索引的方式，可以说让请求头字段得到极大程度的精简和复用&lt;/li&gt;
&lt;li&gt;其次是对于整数和字符串进行哈夫曼编码，哈夫曼编码的原理就是先将所有出现的字符建立一张索引表，然后让出现次数多的字符对应的索引尽可能短，传输的时候也是传输这样的索引序列，可以达到非常高的压缩率。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;http2废除了起始行的概念，将起始行中的请求方法、URI、状态码转换成了头字段，不过这些字段都有一个&quot;:&quot;前缀，用来和其它请求头区分开。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;二进制分帧&lt;/h2&gt;
&lt;p&gt;http2认为明文传输太麻烦了，不方便计算机去解析，干脆全部转换为二进制格式，01串，headers+body的报文格式被拆分为一个个二进制帧，headers帧存放头部字段，data帧存放请求体数据，这样服务器看到的不再是一个个完整的http请求报文，而是一堆乱序的二进制帧，这些二进制帧不存在先后关系，因此也就不会排队等待，也就没有了 HTTP 的队头阻塞问题。&lt;/p&gt;
&lt;h2&gt;多路复用&lt;/h2&gt;
&lt;p&gt;在 HTTP/2 中，有了二进制分帧之后，HTTP /2 不再依赖 TCP 链接去实现多流并行了，在 HTTP/2中,通信双方都可以给对方发送二进制帧，这种二进制帧的双向传输的序列，也叫做流(Stream)。HTTP/2 用流来在一个 TCP 连接上来进行多个数据帧的通信，这就是多路复用的概念。&lt;br&gt;
比如请求html css js 三个文件，http1.x需要三个TCP连接，而http2只需要一个TCP连接，同个域名只需要占用一个 TCP 连接，使用一个连接并行发送多个请求和响应,这样整个页面资源的下载过程只需要一次慢启动，同时也避免了多个TCP连接竞争带宽所带来的问题&lt;/p&gt;
&lt;h2&gt;服务器推送&lt;/h2&gt;
&lt;p&gt;HTTP/2 的服务器推送(Server Push)。在HTTP/2当中，服务器已经不再是完全被动地接收请求，响应请求，它也能新建stream来给客户端发送消息，当TCP连接建立之后，比如浏览器请求一个HTML文件，服务器就可以在返回HTML的基础上，将HTML 中引用到的其他资源文件一起返回给客户端，减少客户端的等待。另外,服务端可以主动推送，客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过，浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略，换句话说，服务器不能随便将第三方资源推送给客户端，而必须是经过双方确认才行。&lt;/p&gt;
&lt;h2&gt;可设置优先级&lt;/h2&gt;
&lt;p&gt;在HTTP/2中，每个请求都可以带一个31bit的优先值，0表示最高优先级， 数值越大优先级越低。有了这个优先值，客户端和服务器就可以在处理不同的流时采取不同的策略，以最优的方式发送流、消息和帧，优化用户体验。&lt;/p&gt;
&lt;h2&gt;流量控制&lt;/h2&gt;
&lt;p&gt;HTTP/2利用流来实现多路复用，这引入了对TCP连接的使用争夺，会造成流被阻塞。流量控制方案确保在同一连接上的多个流之间不会造成破坏性的干扰。流量控制会用于各个独立的流，也会用于整个连接。&lt;br&gt;
HTTP/2通过使用WINDOW_UPDATE帧来进行流量控制。&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/new-features-of-http2/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[JavaScript的哈希表实现]]></title><link>http://huangbowen.cn/blog/implementation-of-hash-table-in-javascript/</link><guid isPermaLink="false">http://huangbowen.cn/blog/implementation-of-hash-table-in-javascript/</guid><pubDate>Sun, 05 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;hashMap的数据结构的组成&lt;/h2&gt;
&lt;p&gt;数组、链表、红黑树&lt;/p&gt;
&lt;h2&gt;哈希函数的实现&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;table &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;simpleHash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;simpleHash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;table&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; pos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;simpleHash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;table&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; pos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;simpleHash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;table&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;table&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; HashMap&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;冲突|碰撞的解决方法&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;1.开链法&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果pos冲突,即在此位置创建二维数组或者链表？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2.线性探测法&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于hashMap散列表是不规则的,冲突后查询下一个位置是否为空,直至结束,返回undefined&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3.红黑树?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当某个节点后出现过多的链表节点的时候,就会转化为红黑树以提升查询效率&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/implementation-of-hash-table-in-javascript/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[http1.0和1.1的一些区别]]></title><link>http://huangbowen.cn/blog/some-differences-between-http1.0-and-1.1/</link><guid isPermaLink="false">http://huangbowen.cn/blog/some-differences-between-http1.0-and-1.1/</guid><pubDate>Mon, 29 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;缓存处理&lt;/strong&gt;，在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准，HTTP1.1则引入了更多的缓存控制策略例如Entity tag，If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;带宽优化&lt;/strong&gt;，HTTP1.0中，存在一些浪费带宽的现象，例如客户端只是需要某个对象的一部分，而服务器却将整个对象送过来了，并且不支持断点续传功能，HTTP1.1则在请求头引入了range头域，它允许只请求资源的某个部分，即返回码是206（Partial Content），这样就方便了开发者自由的选择以便于充分利用带宽和连接&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;长连接&lt;/strong&gt;，HTTP 1.1支持长连接（PersistentConnection）和请求的流水线（Pipelining）处理，在一个TCP连接上可以传送多个HTTP请求和响应，减少了建立和关闭连接的消耗和延迟，在HTTP1.1中默认开启Connection： keep-alive，一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误通知的管理&lt;/strong&gt;，在HTTP1.1中新增了24个错误状态响应码，如409（Conflict）表示请求的资源与资源的当前状态发生冲突；410（Gone）表示服务器上的某个资源被永久性的删除&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host头处理&lt;/strong&gt;，在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址，因此，请求消息中的URL并没有传递主机名（hostname）。但随着虚拟主机技术的发展，在一台物理服务器上可以存在多个虚拟主机（Multi-homed Web Servers），并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域，且请求消息中如果没有Host头域会报告一个错误（400 Bad Request&lt;/li&gt;
&lt;/ul&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/some-differences-between-http1.0-and-1.1/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[http状态码]]></title><link>http://huangbowen.cn/blog/http-status-code/</link><guid isPermaLink="false">http://huangbowen.cn/blog/http-status-code/</guid><pubDate>Sat, 27 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;2XX&lt;/h2&gt;
&lt;p&gt;2XX的响应结果表明请求被正常处理了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;200 正确的执行了请求&lt;/li&gt;
&lt;li&gt;204 正确的执行了请求，但没有资源可返回&lt;/li&gt;
&lt;li&gt;206 正确的执行了范围请求 (HTTP 1.1新)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3XX&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;301&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;永久性重定向&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;302&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;临时重定向&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;303&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;临时重定向，并希望将POST方法改为GET去请求 (HTTP 1.1新)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;304&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;文件未被修改，使用未过期的缓存即可&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;305 客户请求的文档应该通过Location头所指明的代理服务器提取（HTTP 1.1新）&lt;/li&gt;
&lt;li&gt;307&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;遵守浏览器标准，不会将POST方法改为GET去请求 (HTTP 1.1新)&lt;/p&gt;
&lt;h2&gt;4XX&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;401&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表示请求的发送需要有HTTP认证(BASIC认证、DIGEST认证)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;403&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;服务器拒绝访问请求资源，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;404&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;请求资源找不到&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;405 请求方法（GET、POST、HEAD、DELETE、PUT、TRACE等）对指定的资源不适用（HTTP 1.1新）&lt;/li&gt;
&lt;li&gt;406 指定的资源已经找到，但它的MIME类型和客户在Accpet头中所指定的不兼容（HTTP 1.1新）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5XX&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;500&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;服务器内部错误&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;503&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;服务器可能正在维护&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;505 HTTP Version Not Supported 服务器不支持请求中所指明的HTTP版本。（HTTP 1.1新）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;被记录在RFC2616的状态码&lt;/a&gt;&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/http-status-code/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[排序算法复习]]></title><link>http://huangbowen.cn/blog/review-of-sorting-algorithm/</link><guid isPermaLink="false">http://huangbowen.cn/blog/review-of-sorting-algorithm/</guid><pubDate>Wed, 24 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;介绍&lt;/h2&gt;
&lt;p&gt;对计算机中存储的数据执行最常见的操作是排序和检索，本章将复习数据排序的基本算法和高级算法，以及如何应用使操作其中的数据时更简洁高效。&lt;/p&gt;
&lt;h2&gt;一、基本排序算法&lt;/h2&gt;
&lt;p&gt;基本排序算法其核心思想是对一组数据按照一定顺序重新排列，核心理念是一组嵌套的for循环，外层遍历数组每一项，内循环则用于比较元素，这些算法逼真的模拟了人类在现实生活中对数据的排序。&lt;/p&gt;
&lt;h3&gt;1.冒泡排序&lt;/h3&gt;
&lt;p&gt;冒泡排序是最慢的排序算法之一，也是最容易实现的排序算法，之所以叫冒泡排序是因为使用这种排序算法排序时，数据值会像气泡一样从数组的一端漂到另一端，较大的值浮动到数组右侧，较小的浮动到数组的左侧，算法会多次在数组中移动，比较相邻数据，依照大小进行位置互换。&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bubbleSort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; outer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; len&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; outer &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;outer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; inner &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; inner &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; outer &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                temp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; temp
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2.选择排序&lt;/h3&gt;
&lt;p&gt;选择排序从数组的开头开始，将第一个元素和其他元素进行比较。检查完所有元素后，最小的元素会被放到数组的第一个位置，然后算法会从第二个位置继续，当进行到数组的倒数第二个位置时，所有数据便完成了排序。&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;selectionSort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; min&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; outer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; outer &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;outer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        min &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; outer
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; inner &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; outer &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; inner &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;min&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          min &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; inner
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          temp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
          arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
          arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; temp
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;3.插入排序&lt;/h3&gt;
&lt;p&gt;插入排序类似于按姓氏进行排序，先拿出第一个人，把他放在表头，再拿起第二个人，比较他们的姓氏，进行排序，再拿起第三个人，假如他是姓安，那么这条必须插入到最前面，所有人为他往后移动一格，这就输插入排序的原理。&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;insertionSort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; inner&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; outer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;outer &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;outer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        temp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;outer&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        inner &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; outer
        &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inner &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; temp
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;基本排序算法的计时比较&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;对于10000个元素执行冒泡排序的时间为：1096毫秒&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对于10000个元素执行选择排序的时间为：591毫秒&lt;br&gt;
对于10000个元素执行插入排序的时间为：471毫秒&lt;/p&gt;
&lt;p&gt;对于10000个数字来说，插入排序是最快的，要比冒泡排序差不多快一倍&lt;/p&gt;
&lt;h2&gt;二、高级排序算法&lt;/h2&gt;
&lt;p&gt;高级排序算法通常被认为是处理大型数据集的最高效排序算法，它们处理的数据集可以达到上百万个元素，并且还能高效的完成排序。&lt;/p&gt;
&lt;h3&gt;1.希尔排序&lt;/h3&gt;
&lt;p&gt;希尔排序是以它的创造者(Donald Shell)命名的，希尔排序在插入排序的基础上做了很大改善，希尔排序的理念与插入排序不同的是，它会先比较距离较远的元素，而非相邻的元素，和简单的与相邻的元素相比，使用这种方法可以使离正确位置很远的元素更快的找到适合的位置，使用这个算法进行遍历时所有的元素之间的距离会不断减小，知道处理到数据集末尾，这时算法比较的就是相邻元素了。&lt;/p&gt;
&lt;h4&gt;间隔序列&lt;/h4&gt;
&lt;p&gt;希尔排序的关键在于需要一个间隔序列来表示在排序过程中进行比较的元素之间有多远的间隔，我们可以动态定义间隔序列，不过对于大部分的实际应用场景，算法要用到间隔序列可以提前定义好，有些公开的定义序列，在这里我们用到了Matcin Ciura在他2001年发表的论文 &quot;&lt;a href=&quot;https://bitly.com/1b04YFv&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Best Increments for the Average Caseof Shellsort&lt;/a&gt;&quot;中定义的间隔序列：[701,301,132,57,23,10,4,1]&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shellSort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;gaps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;701&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;301&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;132&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;57&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; g &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;g &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; gaps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;g&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; gaps&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;g&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; temp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;j &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; gaps&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;g&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; gaps&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;g&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;j &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; gaps&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;g&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; gaps&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;g&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; temp
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;在一个长度为12的数据集中，算法在第一次处理时，会检查所有间隔为10的元素，下一次遍历会检查所有间隔为4的元素，最后一次则会对间隔为1的元素，也就是标准的插入排序，在做最后处理的时，大部分元素都将在正确的位置，算法不必对很多元素做交换，这就是希尔排序比插入排序高效的地方。&lt;/p&gt;
&lt;h4&gt;动态计算间隔序列&lt;/h4&gt;
&lt;p&gt;Robert Sedgewick定义了一个希尔函数，这个函数可以通过一个公式来对希尔排序用到的间隔序列进行动态计算，让我们来改造代码把，哈哈。&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;dynamicShellSort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;h &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; len&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; h &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;h &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; h&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; len&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;j &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; h &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;h&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;j &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt;h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                temp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;h&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;h&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; temp
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;h&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;效率比较&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;对于同样采用100000个数据进行排序的耗时为&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;硬编码间隔序列的希尔排序消耗时间为：43毫秒&lt;br&gt;
动态间隔序列的希尔排序消耗时间为：43毫秒&lt;/p&gt;
&lt;h3&gt;2.归并排序&lt;/h3&gt;
&lt;p&gt;归并排序的命名来自与它的实现原理：把一系列排好序的子序列合并成一个大的完整有序序列，但在一个数据集很大的场景下，需要相当大的空间来合并存储两个子数组，这是个问题。现在来探讨内存不那么昂贵，空间不是问题的场景下，去实现下归并排序&lt;/p&gt;
&lt;h4&gt;自顶向下的归并排序&lt;/h4&gt;
&lt;p&gt;排序一个数组，我们先把数组从中间分成前后两部分，然后对前后两部分分别排序，再将排好序的两部分合并在一起，这样整个数组就都有序了。&lt;/p&gt;
&lt;h4&gt;自底向上的归并排序&lt;/h4&gt;
&lt;p&gt;首先先将数据集分解为一组只有一个元素的数组，然后通过创建一组左右子数组将它们慢慢合并起来，每次合并都保存一部分排好的数据，直到剩下的这个数组所有的数据已完美排序&lt;/p&gt;
&lt;h3&gt;3.快速排序&lt;/h3&gt;
&lt;p&gt;快速排序是处理大数据集最快的排序算法之一，它是一种分而治之的算法，通过递归的方式将数据分解为包含较小的元素和较大元素的不同子序列，该算法不断重复这个步骤直到所有数据都是有序的。这个算法需要在数组中选择一个元素作为基准值(pivot)，数据排序围绕基准值进行，将列表中小于基准值的元素移动到数组的地步，将大于基准值的元素移动到数组的顶部。&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;qSort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;len &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lesser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; greater &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; pivot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; len&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; pivot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            lesser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            greater&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;qSort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lesser&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pivot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;qSort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;greater&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;快速排序非常适用于大型数据集合，在处理小数据集时性能反而会下降&lt;/p&gt;
&lt;h3&gt;算法可视化工具&lt;/h3&gt;
&lt;p&gt;传送门： &lt;a href=&quot;https://github.com/algorithm-visualizer/algorithm-visualizer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;algorithm-visualizer&lt;/a&gt;&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/review-of-sorting-algorithm/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item><item><title><![CDATA[Sweet Pandas Eating Sweets]]></title><link>http://huangbowen.cn/blog/sweet-pandas-eating-sweets/</link><guid isPermaLink="false">http://huangbowen.cn/blog/sweet-pandas-eating-sweets/</guid><pubDate>Thu, 10 Aug 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Pandas are really sweet.
Here&apos;s a video of a panda eating sweets.&lt;/p&gt;
                &lt;div style=&quot;margin-top=55px; font-style: italic;&quot;&gt;(This is an article posted to my blog at huangbowen.cn/blog. You can read it online by &lt;a href=&quot;http://huangbowen.cn/blog/sweet-pandas-eating-sweets/&quot;&gt;clicking here&lt;/a&gt;.)&lt;/div&gt;
              </content:encoded></item></channel></rss>